|
|
@@ -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) |
|
|
|
} |
|
|
|