diff --git a/components/estimates.vue b/components/estimates.vue index 8e18241..744f0e9 100644 --- a/components/estimates.vue +++ b/components/estimates.vue @@ -33,12 +33,15 @@

Saved Estimates

-{{e.id}} - {{e.property}} - ${{e.price/100}} + + {{e.id}} - {{e.property}} - ${{e.price/100}} +
{{estimate}} - + +
@@ -86,6 +89,25 @@ function getEstimates() { } +function summarize() { + fetch(`/api/estimate/summarize`, + {method: 'POST', + headers: { + "Accept": "application/json", + "Authorization": `Bearer ${props.token}`, + }, + body: JSON.stringify(estimate.value), + }).then(response => { + if (response.ok) { return response.json() } else { + response.text().then(t => console.log(t)) + } + }).then (result => { + if (!result || !result.length) return // Exit if token is invalid or no fees are saved + console.log('done', result) + }) + +} + onMounted(() => { getEstimates() }) diff --git a/components/new/summary.vue b/components/new/summary.vue index d9670e7..21369c2 100644 --- a/components/new/summary.vue +++ b/components/new/summary.vue @@ -42,9 +42,7 @@ function amortize(principle, rate, periods) { return principle * rate*(1+rate)**periods / ((1+rate)**periods - 1) } -const loanPayment = computed(() => { - let amount = props.loan.amount - +const loanPayment = computed(() => { return amortize(props.loan.amount, props.loan.interest / 100 / 12, props.loan.term*12) diff --git a/skouter.go b/skouter.go index 8da99c9..b44c43b 100644 --- a/skouter.go +++ b/skouter.go @@ -16,6 +16,7 @@ import ( "time" "errors" "strings" + "math" // pdf "github.com/SebastiaanKlippert/go-wkhtmltopdf" "github.com/golang-jwt/jwt/v4" ) @@ -94,6 +95,7 @@ type Loan struct { Ltv float32 `json:"ltv"` Dti float32 `json:"dti"` Hoi int `json:"hoi"` + Hazard int `json:"hazard"` Tax int `json:"hoi"` Interest float32 `json:"interest"` Mi MI `json:"mi"` @@ -116,15 +118,15 @@ type MI struct { } type Result struct { - User int `json:"user"` - Borrower Borrower `json:"borrower"` - Transaction string `json:"transaction"` - Price int `json:"price"` - Property string `json:"property"` - Occupancy string `json:"occupancy"` + Id int `json:"loanId"` + LoanId int `json:"loanId"` + LoanPayment int `json:"loanPayment"` + TotalMonthly int `json:"totalMonthly"` + Fees int `json:"fees"` + Credits int `json:"credits"` + CashToClose int `json:"cashToClose"` Zip string `json:"zip"` Pud bool `json:"pud"` - Loans []Loan `json:"loans"` } type Estimate struct { @@ -209,6 +211,41 @@ func match(path, pattern string, args *[]string) bool { return true } +func summarize(w http.ResponseWriter, db *sql.DB, r *http.Request) { + var estimate Estimate + var result Result + err := json.NewDecoder(r.Body).Decode(&estimate) + if err != nil { http.Error(w, "Invalid estimate.", 422); return } + + amortize := func(principle float64, rate float64, periods float64) int { + exp := math.Pow(1+rate, periods) + return int(principle * rate * exp / (exp - 1)) + } + loan := estimate.Loans[0] + result.LoanPayment = amortize(float64(loan.Amount), + float64(loan.Interest / 100 / 12), + float64(loan.Term * 12)) + + result.TotalMonthly = result.LoanPayment + loan.Hoi + loan.Tax + loan.Hazard + if loan.Mi.Monthly { + result.TotalMonthly = result.TotalMonthly + + int(loan.Mi.Rate/100*float32(loan.Amount)) + } + + for i := range loan.Fees { + if loan.Fees[i].Amount > 0 { + result.Fees = result.Fees + loan.Fees[i].Amount + } else { + result.Credits = result.Credits + loan.Fees[i].Amount + } + } + + result.CashToClose = + result.Fees + result.Credits + (estimate.Price - loan.Amount) + + json.NewEncoder(w).Encode(result) +} + func getLoanType( db *sql.DB, user int, @@ -249,10 +286,11 @@ func getLoanType( func getFees(db *sql.DB, loan int) ([]Fee, error) { var fees []Fee - rows, err := db.Query( - "SELECT * FROM fees " + - "WHERE loan_id = ?", - loan) + query := `SELECT id, loan_id, amount, perc, type, notes, name, category + FROM fee + WHERE loan_id = ?` + + rows, err := db.Query(query, loan) if err != nil { return nil, fmt.Errorf("Fee query error %v", err) @@ -340,9 +378,14 @@ func getMi(db *sql.DB, loan int) (MI, error) { initial_premium, initial_rate, initial_amount FROM mi WHERE loan_id = ?` - row := db.QueryRow(query, loan) + rows, err := db.Query(query, loan) + if err != nil { return mi, err } + + defer rows.Close() - if err := row.Scan( + if (!rows.Next()) { return mi, nil } + + if err := rows.Scan( &mi.Type, &mi.Label, &mi.Lender, @@ -361,53 +404,6 @@ func getMi(db *sql.DB, loan int) (MI, error) { return mi, nil } -func getLoans(db *sql.DB, estimate int) ([]Loan, error) { - var loans []Loan - - query := `SELECT - l.id, l.amount, l.term, l.interest, l.ltv, l.dti, l.hoi, - lt.id, lt.user_id, lt.branch_id, lt.name - FROM loan l INNER JOIN loan_type lt ON l.type_id = lt.id - WHERE l.estimate_id = ? - ` - rows, err := db.Query(query, estimate) - - if err != nil { - return nil, fmt.Errorf("Loan query error %v", err) - } - - defer rows.Close() - - for rows.Next() { - var loan Loan - - if err := rows.Scan( - &loan.Id, - &loan.Amount, - &loan.Term, - &loan.Interest, - &loan.Ltv, - &loan.Dti, - &loan.Hoi, - &loan.Type.Id, - &loan.Type.User, - &loan.Type.Branch, - &loan.Type.Name, - ) - err != nil { - return loans, fmt.Errorf("Loans scanning error: %v", err) - } - mi, err := getMi(db, loan.Id) - if err != nil { - return loans, err - } - loan.Mi = mi - loans = append(loans, loan) - } - - return loans, nil -} - func getBorrower(db *sql.DB, id int) (Borrower, error) { var borrower Borrower @@ -867,7 +863,7 @@ func queryBorrower(db *sql.DB, id int) ( Borrower, error ) { } // Must have an estimate ID 'e', but not necessarily a loan id 'id' -func queryLoan(db *sql.DB, e int, id int) ( []Loan, error ) { +func getLoans(db *sql.DB, e int, id int) ( []Loan, error ) { var loans []Loan var query string var rows *sql.Rows @@ -913,6 +909,18 @@ func queryLoan(db *sql.DB, e int, id int) ( []Loan, error ) { err != nil { return loans, err } + + mi, err := getMi(db, loan.Id) + if err != nil { + return loans, err + } + loan.Mi = mi + fees, err := getFees(db, loan.Id) + if err != nil { + return loans, err + } + loan.Fees = fees + loans = append(loans, loan) } @@ -922,7 +930,7 @@ func queryLoan(db *sql.DB, e int, id int) ( []Loan, error ) { return loans, nil } -func queryEstimate(db *sql.DB, id int, user int) ( []Estimate, error ) { +func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) { var estimates []Estimate var query string var rows *sql.Rows @@ -974,7 +982,7 @@ func queryEstimate(db *sql.DB, id int, user int) ( []Estimate, error ) { if len(estimates) == 0 { return estimates, errors.New("Estimate not found.") } for i := range estimates { - estimates[i].Loans, err = queryLoan(db, estimates[i].Id, 0) + estimates[i].Loans, err = getLoans(db, estimates[i].Id, 0) if err != nil { return estimates, err } } @@ -1010,6 +1018,13 @@ func insertBorrower(db *sql.DB, borrower Borrower) (int, error) { return id, nil } +func insertFee(db *sql.DB, fee Fee) (int, error) { + query := `INSERT INTO fee + id, loan_id, amount, perc, type, notes, name, category + FROM fee + WHERE loan_id = ?` +} + func insertLoan(db *sql.DB, loan Loan) (Loan, error){ var query string var row *sql.Row @@ -1048,7 +1063,7 @@ func insertLoan(db *sql.DB, loan Loan) (Loan, error){ err = row.Scan(&id) if err != nil { return Loan{}, err } - loans, err := queryLoan(db, id, 0) + loans, err := getLoans(db, id, 0) if err != nil { return Loan{}, err } return loans[0], nil @@ -1098,7 +1113,7 @@ func insertEstimate(db *sql.DB, estimate Estimate) (Estimate, error){ if err != nil { return estimate, err } } - estimates, err := queryEstimate(db, estimate.Id, 0) + estimates, err := getEstimates(db, estimate.Id, 0) if err != nil { return Estimate{}, err } return estimates[0], nil @@ -1122,7 +1137,7 @@ func fetchEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) { var estimates []Estimate claims, err := getClaims(r) - estimates, err = queryEstimate(db, 0, claims.Id) + estimates, err = getEstimates(db, 0, claims.Id) if err != nil { http.Error(w, err.Error(), 500); return } json.NewEncoder(w).Encode(estimates) @@ -1300,6 +1315,10 @@ func api(w http.ResponseWriter, r *http.Request) { r.Method == http.MethodPost && guard(r, 1): validateEstimate(w, db, r) + case match(p, "/api/estimate/summarize", &args) && + r.Method == http.MethodPost && + guard(r, 1): + summarize(w, db, r) default: http.Error(w, "Invalid route or token", 404) }