diff --git a/components/estimates.vue b/components/estimates.vue
index d1de280..a2ed294 100644
--- a/components/estimates.vue
+++ b/components/estimates.vue
@@ -55,6 +55,7 @@ ${{(estimate.price / 100).toLocaleString()}}
+
@@ -64,6 +65,11 @@ ${{(estimate.price / 100).toLocaleString()}}
:fileName="`estimate-${estimate.id}.pdf`" :url="dlink">
+
+
@@ -71,6 +77,7 @@ ${{(estimate.price / 100).toLocaleString()}}
import { ref, computed, onMounted } from 'vue'
import FeeDialog from "./fee-dialog.vue"
import DDialog from "./download-dialog.vue"
+import Dialog from "./dialog.vue"
import { format } from "../helpers.js"
const props = defineProps(['user', 'fees', 'token'])
@@ -79,6 +86,7 @@ let edit = ref(null)
let estimates = ref([])
let estimate = ref()
let dlink = ref("")
+let deleting = ref()
function newFee(fee, isDebit) {
if (!isDebit) {
@@ -142,6 +150,23 @@ function getEstimates() {
})
}
+function del(e) {
+ fetch(`/api/estimate`,
+ {method: 'DELETE',
+ body: JSON.stringify(e),
+ headers: {
+ "Accept": "application/json",
+ "Authorization": `Bearer ${props.token}`,
+ },
+ }).then(response => {
+ if (response.ok) {
+ estimates.value = estimates.value.filter(e => e.id != estimate.value.id)
+ estimate.value = null
+ deleting.value = false
+ }
+ })
+}
+
function download(estimate) {
fetch(`/api/pdf`,
{method: 'POST',
diff --git a/migrations/0_29092022_setup_tables.sql b/migrations/0_29092022_setup_tables.sql
index 945a4a4..7009ba9 100644
--- a/migrations/0_29092022_setup_tables.sql
+++ b/migrations/0_29092022_setup_tables.sql
@@ -78,18 +78,9 @@ CREATE TABLE loan_type (
PRIMARY KEY (`id`)
);
-CREATE TABLE borrower (
- id INT AUTO_INCREMENT,
- credit_score SMALLINT NOT NULL,
- monthly_income INT NOT NULL,
- num TINYINT NOT NULL, /* Number of people borrowing. */
- PRIMARY KEY (`id`)
-);
-
CREATE TABLE estimate (
id INT AUTO_INCREMENT,
user_id INT NOT NULL,
- borrower_id INT NOT NULL,
transaction ENUM('Purchase', 'Refinance'),
price INT NOT NULL,
property ENUM('Single Detached',
@@ -99,10 +90,31 @@ CREATE TABLE estimate (
occupancy ENUM('Primary', 'Secondary', 'Investment'),
zip VARCHAR(10),
pud BOOLEAN, /* Property under development */
+ PRIMARY KEY (`id`)
+);
+
+CREATE TABLE borrower (
+ id INT AUTO_INCREMENT,
+ credit_score SMALLINT NOT NULL,
+ monthly_income INT NOT NULL,
+ num TINYINT NOT NULL, /* Number of people borrowing. */
+ estimate_id INT UNIQUE NOT NULL,
PRIMARY KEY (`id`),
- FOREIGN KEY (borrower_id) REFERENCES borrower(id)
+ FOREIGN KEY (estimate_id) REFERENCES estimate(id)
+ ON DELETE CASCADE
);
+CREATE TABLE estimate_template (
+ id INT AUTO_INCREMENT,
+ estimate_id INT UNIQUE NOT NULL,
+ user_id INT NOT NULL, /* User who created the template */
+ branch_id INT NOT NULL DEFAULT 0,
+/* Specific branch allowed to use it. 0 is only user. */
+ PRIMARY KEY (`id`),
+ FOREIGN KEY (estimate_id) REFERENCES estimate(id)
+);
+
+
CREATE TABLE loan (
id INT AUTO_INCREMENT,
estimate_id INT NOT NULL,
@@ -117,8 +129,9 @@ CREATE TABLE loan (
tax INT DEFAULT 0, /* Real estate taxes */
name VARCHAR(30) DEFAULT '',
PRIMARY KEY (`id`),
- FOREIGN KEY (estimate_id) REFERENCES estimate(id),
+ FOREIGN KEY (estimate_id) REFERENCES estimate(id) ON DELETE CASCADE,
FOREIGN KEY (type_id) REFERENCES loan_type(id)
+ ON DELETE CASCADE
ON UPDATE RESTRICT
);
@@ -137,6 +150,7 @@ CREATE TABLE mi (
initial_amount INT DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (loan_id) REFERENCES loan(id)
+ ON DELETE CASCADE
);
/* template = true fees are saved for users or branches. If template or default
@@ -153,6 +167,7 @@ CREATE TABLE fee (
category VARCHAR(60),
PRIMARY KEY (`id`),
FOREIGN KEY (loan_id) REFERENCES loan(id)
+ ON DELETE CASCADE
);
/* Templates to be reused by users or branches. Either user_id or branch_id must
@@ -185,5 +200,5 @@ CREATE TABLE estimate_result (
total_credits INT NOT NULL,
cash_to_close INT NOT NULL,
PRIMARY KEY (`id`),
- FOREIGN KEY (loan_id) REFERENCES loan(id)
+ FOREIGN KEY (loan_id) REFERENCES loan(id) ON DELETE CASCADE
);
diff --git a/migrations/reset.sql b/migrations/reset.sql
index 2d39b17..b268e1c 100644
--- a/migrations/reset.sql
+++ b/migrations/reset.sql
@@ -1,10 +1,11 @@
+DROP TABLE IF EXISTS estimate_template;
DROP TABLE IF EXISTS estimate_result;
DROP TABLE IF EXISTS mi;
DROP TABLE IF EXISTS fee;
DROP TABLE IF EXISTS fee_template;
DROP TABLE IF EXISTS loan;
-DROP TABLE IF EXISTS estimate;
DROP TABLE IF EXISTS borrower;
+DROP TABLE IF EXISTS estimate;
DROP TABLE IF EXISTS loan_type;
DROP TABLE IF EXISTS license;
DROP TABLE IF EXISTS user;
diff --git a/skouter.go b/skouter.go
index 8f0ec03..b2bdf61 100644
--- a/skouter.go
+++ b/skouter.go
@@ -189,6 +189,13 @@ type Estimate struct {
Loans []Loan `json:"loans"`
}
+type ETemplate struct {
+ Id int `json:"id"`
+ Estimate Estimate `json:"estimate"`
+ UserId int `json:"userId"`
+ BranchId int `json:"branchId"`
+}
+
type Report struct {
Title string
Name string
@@ -574,6 +581,19 @@ func deleteFeeTemp(w http.ResponseWriter, db *sql.DB, r *http.Request) {
if err != nil { w.WriteHeader(500); return }
}
+func deleteEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+ var estimate Estimate
+ var err error
+
+ err = json.NewDecoder(r.Body).Decode(&estimate)
+ if err != nil { w.WriteHeader(422); return }
+
+ claims, err := getClaims(r)
+ err = estimate.del(db, claims.Id)
+ if err != nil { http.Error(w, err.Error(), 500); return }
+}
+
+
func getMi(db *sql.DB, loan int) (MI, error) {
var mi MI
@@ -608,25 +628,23 @@ func getMi(db *sql.DB, loan int) (MI, error) {
return mi, nil
}
-func getBorrower(db *sql.DB, id int) (Borrower, error) {
- var borrower Borrower
+func (estimate *Estimate) getBorrower(db *sql.DB) error {
+ query := `SELECT id, credit_score, monthly_income, num FROM borrower
+ WHERE estimate_id = ? LIMIT 1`
- row := db.QueryRow(
- "SELECT * FROM borrower " +
- "WHERE id = ? LIMIT 1",
- id)
+ row := db.QueryRow(query, estimate.Id)
if err := row.Scan(
- &borrower.Id,
- &borrower.Credit,
- &borrower.Income,
- &borrower.Num,
+ &estimate.Borrower.Id,
+ &estimate.Borrower.Credit,
+ &estimate.Borrower.Income,
+ &estimate.Borrower.Num,
)
err != nil {
- return borrower, fmt.Errorf("Borrower scanning error: %v", err)
+ return fmt.Errorf("Borrower scanning error: %v", err)
}
- return borrower, nil
+ return nil
}
// Query Lender APIs and parse responses into MI structs
@@ -1740,6 +1758,14 @@ func getLoans(db *sql.DB, e int, id int) ( []Loan, error ) {
return loans, nil
}
+func getEstimate(db *sql.DB, id int) ( Estimate, error ) {
+ estimates, err := getEstimates(db, id, 0)
+
+ if err != nil { return Estimate{}, err }
+
+ return estimates[0], nil
+}
+
func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
var estimates []Estimate
var query string
@@ -1749,7 +1775,6 @@ func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
query = `SELECT
id,
user_id,
- borrower_id,
transaction,
price,
property,
@@ -1773,7 +1798,6 @@ func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
if err := rows.Scan(
&estimate.Id,
&estimate.User,
- &estimate.Borrower.Id,
&estimate.Transaction,
&estimate.Price,
&estimate.Property,
@@ -1785,11 +1809,10 @@ func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
return estimates, err
}
- borrower, err := getBorrower(db, estimate.Borrower.Id)
+ err := estimate.getBorrower(db)
if err != nil {
return estimates, err
}
- estimate.Borrower = borrower
estimates = append(estimates, estimate)
}
@@ -1804,33 +1827,80 @@ func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
return estimates, nil
}
+func getETemplate(db *sql.DB, id int, user int) ( []ETemplate, error ) {
+ var eTemplates []ETemplate
+ var query string
+ var rows *sql.Rows
+ var err error
+
+ query = `SELECT
+ id,
+ estimate_id,
+ user_id,
+ branch_id,
+ FROM estimate_template WHERE id = CASE @e := ? WHEN 0 THEN id ELSE @e END AND
+ user_id = CASE @e := ? WHEN 0 THEN user_id ELSE @e END
+ `
+ rows, err = db.Query(query, id, user)
+
+ if err != nil {
+ return eTemplates, err
+ }
+
+ defer rows.Close()
+
+ for rows.Next() {
+ var e ETemplate
+
+ if err := rows.Scan(
+ &e.Id,
+ &e.Estimate.Id,
+ &e.UserId,
+ &e.BranchId,
+ )
+ err != nil {
+ return eTemplates, err
+ }
+
+ e.Estimate, err = getEstimate(db, e.Estimate.Id)
+ if err != nil {
+ return eTemplates, err
+ }
+
+ eTemplates = append(eTemplates, e)
+ }
+
+ return eTemplates, nil
+}
+
// Accepts a borrower struct and returns the id of the inserted borrower and
// any related error.
-func insertBorrower(db *sql.DB, borrower Borrower) (int, error) {
+func (estimate *Estimate) insertBorrower(db *sql.DB) error {
var query string
var row *sql.Row
var err error
- var id int // Inserted loan's id
query = `INSERT INTO borrower
(
+ estimate_id,
credit_score,
monthly_income,
num
)
- VALUES (?, ?, ?)
+ VALUES (?, ?, ?, ?)
RETURNING id
`
row = db.QueryRow(query,
- borrower.Credit,
- borrower.Income,
- borrower.Num,
+ estimate.Id,
+ estimate.Borrower.Credit,
+ estimate.Borrower.Income,
+ estimate.Borrower.Num,
)
- err = row.Scan(&id)
- if err != nil { return 0, err }
+ err = row.Scan(&estimate.Borrower.Id)
+ if err != nil { return err }
- return id, nil
+ return nil
}
func insertMi(db *sql.DB, mi MI) (int, error) {
@@ -1968,13 +2038,9 @@ func (estimate *Estimate) insertEstimate(db *sql.DB) (error){
var err error
// var id int // Inserted estimate's id
- estimate.Borrower.Id, err = insertBorrower(db, estimate.Borrower)
- if err != nil { return err }
-
query = `INSERT INTO estimate
(
user_id,
- borrower_id,
transaction,
price,
property,
@@ -1982,12 +2048,11 @@ func (estimate *Estimate) insertEstimate(db *sql.DB) (error){
zip,
pud
)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ VALUES (?, ?, ?, ?, ?, ?, ?)
RETURNING id
`
row = db.QueryRow(query,
estimate.User,
- estimate.Borrower.Id,
estimate.Transaction,
estimate.Price,
estimate.Property,
@@ -1998,6 +2063,9 @@ func (estimate *Estimate) insertEstimate(db *sql.DB) (error){
err = row.Scan(&estimate.Id)
if err != nil { return err }
+
+ err = estimate.insertBorrower(db)
+ if err != nil { return err }
for i := range estimate.Loans {
estimate.Loans[i].EstimateId = estimate.Id
@@ -2008,6 +2076,44 @@ func (estimate *Estimate) insertEstimate(db *sql.DB) (error){
return nil
}
+func (estimate *Estimate) del(db *sql.DB, user int) (error) {
+ var query string
+ var err error
+
+ query = `DELETE FROM estimate WHERE id = ? AND user_id = ?`
+
+ _, err = db.Exec(query, estimate.Id, user)
+ if err != nil { return err }
+
+ return nil
+}
+
+func (eTemplate *ETemplate) insert(db *sql.DB) (error) {
+ var query string
+ var row *sql.Row
+ var err error
+
+ query = `INSERT INTO estimate_template
+ (
+ user_id,
+ branch_id,
+ estimate_id,
+ )
+ VALUES (?, ?, ?)
+ RETURNING id
+ `
+ row = db.QueryRow(query,
+ eTemplate.UserId,
+ eTemplate.BranchId,
+ eTemplate.Estimate.Id,
+ )
+
+ err = row.Scan(&eTemplate.Id)
+ if err != nil { return err }
+
+ return nil
+}
+
func createEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
var estimate Estimate
err := json.NewDecoder(r.Body).Decode(&estimate)
@@ -2383,6 +2489,10 @@ func api(w http.ResponseWriter, r *http.Request) {
r.Method == http.MethodPost &&
guard(r, 1):
createEstimate(w, db, r)
+ case match(p, "/api/estimate", &args) &&
+ r.Method == http.MethodDelete &&
+ guard(r, 1):
+ deleteEstimate(w, db, r)
case match(p, "/api/estimate/validate", &args) &&
r.Method == http.MethodPost &&
guard(r, 1):