From 6887e1f8247b5692243b50b5a590d12de30a4339 Mon Sep 17 00:00:00 2001
From: Immanuel Onyeka <immanuel@onyeka.ca>
Date: Mon, 21 Nov 2022 20:09:09 -0500
Subject: [PATCH] Seperate loans from estimates in models

---
 migrations/0_29092022_create_main_tables.sql |  39 +++--
 migrations/reset.sql                         |   2 +-
 skouter.go                                   | 170 ++++++++++++++-----
 3 files changed, 153 insertions(+), 58 deletions(-)

diff --git a/migrations/0_29092022_create_main_tables.sql b/migrations/0_29092022_create_main_tables.sql
index 22d49c9..6f56d96 100644
--- a/migrations/0_29092022_create_main_tables.sql
+++ b/migrations/0_29092022_create_main_tables.sql
@@ -1,10 +1,5 @@
 /* Precision for all money amounts assumes cents are excluded. */
 
-CREATE TABLE comparison (
-	id 				INT AUTO_INCREMENT,
-	PRIMARY KEY (id)
-);
-
 CREATE TABLE branch (
 	id 				INT AUTO_INCREMENT,
 	type 			ENUM('NMLS', 'FSRA') NOT NULL,
@@ -30,7 +25,8 @@ CREATE TABLE user (
 	status 			ENUM('Trial',
 					'Free',
 					'Subscribed',
-					'Branch Subscribed'),
+					'Branch',
+					'Admin'),
 	PRIMARY KEY (`id`),
 	FOREIGN KEY (branch_id) REFERENCES branch(id)
 );
@@ -52,7 +48,7 @@ CREATE TABLE loan_type (
 	id 				INT AUTO_INCREMENT,
 	branch_id 		INT NOT NULL,
 	user_id 		INT NOT NULL,
-	name 			VARCHAR(30) NOT NULL,
+	name 			VARCHAR(30) UNIQUE NOT NULL,
 	/* FOREIGN KEY (branch_id) REFERENCES branch(id), */
 	/* FOREIGN KEY (user_id) REFERENCES user(id), */
 	PRIMARY KEY (`id`)
@@ -70,10 +66,7 @@ CREATE TABLE estimate (
 	id 			INT AUTO_INCREMENT,
 	user_id 		INT NOT NULL,
 	borrower_id 		INT NOT NULL,
-	comparison_id  		INT,
 	transaction 		ENUM('Purchase', 'Refinance'),
-	loan_type_id 		INT NOT NULL,
-	loan_amount 		INT NOT NULL,
 	price 			INT NOT NULL,
 	property 		ENUM('Single Detached',
 					'Single Attached',
@@ -82,24 +75,34 @@ CREATE TABLE estimate (
 	occupancy 		ENUM('Primary', 'Secondary', 'Investment'),
 	zip 			VARCHAR(10),
 	pud 			BOOLEAN, /* Property under development */
+	PRIMARY KEY (`id`),
+	FOREIGN KEY (borrower_id) REFERENCES borrower(id)
+);
+
+CREATE TABLE loan (
+	id  	INT,
+	estimate_id 		INT NOT NULL,
+	type_id 		INT NOT NULL,
+	amount 		INT NOT NULL,
 	term 			INT, /* In years */
 	interest 		INT, /* Per year, precise to 2 decimals */
-	hoi 			INT, /* Hazard insurance annual payments */
-	mi_name 		VARCHAR(50), /* Mortgage insurance title shown in menu */
+	hoi 			INT DEFAULT 0, /* Hazard insurance annual payments */
+	mi_name 		VARCHAR(50) NOT NULL,
+	/* Mortgage insurance title shown in menu */
 	mi_amount 		INT, /* Mortgage insurance amount */
-	lender 			VARCHAR(30) DEFAULT "",
-	name 			VARCHAR(30) DEFAULT "",
+	lender 			VARCHAR(30) DEFAULT '',
+	name 			VARCHAR(30) DEFAULT '',
 	PRIMARY KEY (`id`),
+	FOREIGN KEY (estimate_id) REFERENCES estimate(id),
 	FOREIGN KEY (loan_type_id) REFERENCES loan_type(id)
-	ON UPDATE RESTRICT,
-	FOREIGN KEY (borrower_id) REFERENCES borrower(id)
+	ON UPDATE RESTRICT
 );
 
 /* template = true fees are saved for users or branches. If template or default
  * are true, estimate_id should be null.*/
 CREATE TABLE fee (
 	id 				INT AUTO_INCREMENT NOT NULL,
-	estimate_id 	INT,
+	loan_id 	INT,
 	amount 			INT NOT NULL,
 	perc 			SMALLINT, /* Percentage of sale price instead of amount */
 	type 			ENUM('Goverment', 'Title', 'Required', 'Lender', 'Other'),
@@ -108,7 +111,7 @@ CREATE TABLE fee (
 	/* Group heading shown in report */
 	category 		VARCHAR(60),
 	PRIMARY KEY (`id`),
-	FOREIGN KEY (estimate_id) REFERENCES estimate(id)
+	FOREIGN KEY (loan_id) REFERENCES loan(id)
 );
 
 /* Templates to be reused by users or branches. Either user_id or branch_id must
diff --git a/migrations/reset.sql b/migrations/reset.sql
index 661455c..e5228f8 100644
--- a/migrations/reset.sql
+++ b/migrations/reset.sql
@@ -1,7 +1,7 @@
 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 comparison;
 DROP TABLE IF EXISTS borrower;
 DROP TABLE IF EXISTS loan_type;
 DROP TABLE IF EXISTS license;
diff --git a/skouter.go b/skouter.go
index 375540a..650cd20 100644
--- a/skouter.go
+++ b/skouter.go
@@ -21,11 +21,11 @@ type Page struct {
 	Name string
 }
 
-type LoanType struct {
-	Id 	int 	`json:"id"`
-	User 	int 	`json:"user"`
-	Branch 	int 	`json:"branch"`
-	Name 	string 	`json:"name"`
+type Borrower struct {
+	Id	int	`json:"id"`
+	Credit	int 	`json:"credit"`
+	Income	int 	`json:"income"`
+	Num	int	`json:"num"`
 }
 
 type FeeTemplate struct {
@@ -41,34 +41,52 @@ type FeeTemplate struct {
 	Auto	bool 	`json:"auto"`
 }
 
+type Fee struct {
+	Id		int 	`json:"id"`
+	LoanId	int 	`json:"loan_id"`
+	Amount	int 	`json:"amount"`
+	Perc	int 	`json:"perc"`
+	Type	string 	`json:"type"`
+	Notes	string 	`json:"notes"`
+	Name	string 	`json:"name"`
+	Category	string 	`json:"category"`
+}
+
+type LoanType struct {
+	Id 	int 	`json:"id"`
+	User 	int 	`json:"user"`
+	Branch 	int 	`json:"branch"`
+	Name 	string 	`json:"name"`
+}
+
+type Loan struct {
+	Id  	int 	`json:id`
+	EstimateId  	int 	`json:estimate_id`
+	Type	LoanType 	`json:"loanType"`
+	LoanAmount	int 	`json:"loanAmount"`
+	Term		int 	`json:"term"`
+	Ltv 	int 	`json:"ltv"`
+	Dti 	int 	`json:"dti"`
+	Hoi		int 	`json:"hoi"`
+	Interest	int 	`json:"interest"`
+	Lender		string 	`json:"lender"`
+	MiName		string 	`json:"miName"`
+	MiAmount	int 	`json:"miAmount"`
+	Fees		[]Fee 	`json:"fees"`
+	Name		string 	`json:"name"`
+}
+
 type Estimate struct {
 	Id		int 	`json:"id"`
 	User		int 	`json:"user"`
 	Borrower	Borrower 	`json:"borrower"`
-	Comparison	int 	`json:"comparison"`
 	Transaction	string 	`json:"transaction"`
-	LoanType	LoanType 	`json:"loanType"`
-	LoanAmount	int 	`json:"loanAmount"`
 	Price		int 	`json:"price"`
 	Property	string 	`json:"property"`
 	Occupancy	string	`json:"occupancy"`
 	Zip		string 	`json:"zip"`
 	Pud		bool 	`json:"pud"`
-	Term		int 	`json:"term"`
-	Interest	int 	`json:"interest"`
-	Hoi		int 	`json:"hoi"`
-	MiName		string 	`json:"miName"`
-	MiAmount	int 	`json:"miAmount"`
-	Lender		string 	`json:"lender"`
-	Name		string 	`json:"name"`
-	Fees		[]Fee 	`json:"fees"`
-}
-
-type Borrower struct {
-	Id	int	`json:"id"`
-	Credit	int 	`json:"credit"`
-	Income	int 	`json:"income"`
-	Num	int	`json:"num"`
+	Loans 	[]Loan 	`json:"loans"`
 }
 
 var (
@@ -165,31 +183,24 @@ func getLoanType(
 func getEstimate(db *sql.DB, id int) (Estimate, error) {
 	var estimate Estimate
 
+	// Inner join should always be valid because a borrower is a required
+	// foreign key.
 	row := db.QueryRow(
-		"SELECT * FROM estimate " +
-		"WHERE id = ? LIMIT 1",
+		"SELECT * FROM estimate "+
+		"WHERE id = ? " + 
+		"INNER JOIN borrower ON estimate.borrower = borrower.id",
 	id)
 	
 	if err := row.Scan(
 		&estimate.Id,
 		&estimate.User,
 		&estimate.Borrower.Id,
-		&estimate.Comparison,
 		&estimate.Transaction,
-		&estimate.LoanType.Id,
-		&estimate.LoanAmount,
 		&estimate.Price,
 		&estimate.Property,
 		&estimate.Occupancy,
 		&estimate.Zip,
 		&estimate.Pud,
-		&estimate.Term,
-		&estimate.Interest,
-		&estimate.Hoi,
-		&estimate.MiName,
-		&estimate.MiAmount,
-		&estimate.Lender,
-		&estimate.Name,
 		)
 	err != nil {
 		return estimate, fmt.Errorf("Estimate scanning error: %v", err)
@@ -198,8 +209,45 @@ func getEstimate(db *sql.DB, id int) (Estimate, error) {
 	return estimate, nil
 }
 
+func getFees(db *sql.DB, loan int) ([]Fee, error) {
+	var fees []Fee
+
+	rows, err := db.Query(
+		"SELECT * FROM fees " +
+		"WHERE loan_id = ?",
+	loan)
+	
+	if err != nil {
+		return nil, fmt.Errorf("Fee query error %v", err)
+	}
+
+	defer rows.Close()
+
+	for rows.Next() {
+		var fee FeeTemplate
+
+		if err := rows.Scan(
+			&fee.Id,
+			&fee.LoanId,
+			&fee.Amount,
+			&fee.Perc,
+			&fee.Ftype,
+			&fee.Notes,
+			&fee.Name,
+			&fee.Category,
+			)
+		err != nil {
+			return nil, fmt.Errorf("Fees scanning error: %v", err)
+        }
+
+		fees = append(fees, fee)
+	}
+	
+	return fees, nil
+}
+
 // Fetch fees from the database
-func getFees(db *sql.DB, user int) ([]FeeTemplate, error) {
+func getFeesTemp(db *sql.DB, user int) ([]FeeTemplate, error) {
 	var fees []FeeTemplate
 
 	rows, err := db.Query(
@@ -208,7 +256,7 @@ func getFees(db *sql.DB, user int) ([]FeeTemplate, error) {
 	user)
 	
 	if err != nil {
-		return nil, fmt.Errorf("Fee query error %v", err)
+		return nil, fmt.Errorf("Fee template query error %v", err)
 	}
 
 	defer rows.Close()
@@ -222,13 +270,57 @@ func getFees(db *sql.DB, user int) ([]FeeTemplate, error) {
 			&fee.Branch,
 			&fee.Amount,
 			&fee.Perc,
+			&fee.Type,
+			&fee.Notes,
+			&fee.Name,
+			&fee.Category,
+			&fee.Auto)
+		err != nil {
+			return nil, fmt.Errorf("FeesTemplate scanning error: %v", err)
+        }
+
+		fees = append(fees, fee)
+	}
+	
+	est, err := getEstimate(db, 1)
+	fmt.Printf("the estimate: %v,\nthe error %v\n", est, err)
+	// getMi(db, getEstimate(db, 1), getBorrower(db, 1))
+
+	return fees, nil
+}
+
+func getLoans(db *sql.DB, estimate int) {
+	var loans []Loan
+
+	rows, err := db.Query(
+		"SELECT loan.id, loan.amount, loan.term, loan.interest, loan.ltv,
+		loan.dti, loan.hoi, loan.mi_name, loan.mi_amount FROM loan " +
+		"INNER JOIN loan_type ON loan.type_id = loan_type(id)" +
+		"WHERE loan.estimate_id = ?",
+	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.EstimateId,
+			&loan.Branch,
+			&fee.Amount,
+			&fee.Perc,
 			&fee.Ftype,
 			&fee.Notes,
 			&fee.Name,
 			&fee.Category,
 			&fee.Auto)
 		err != nil {
-			return nil, fmt.Errorf("Fees scanning error: %v", err)
+			return nil, fmt.Errorf("FeesTemplate scanning error: %v", err)
         }
 
 		fees = append(fees, fee)
@@ -387,7 +479,7 @@ func api(w http.ResponseWriter, r *http.Request) {
 		}
 
 	case match(p, "/api/fees", &args):
-		resp, err := getFees(db, 0)
+		resp, err := getFeesTemp(db, 0)
 
 		if resp != nil {
 			json.NewEncoder(w).Encode(resp)