From e83e6003f25b05c059eda480e62998020539b99b Mon Sep 17 00:00:00 2001
From: meskio <meskio@sindominio.net>
Date: Thu, 24 Dec 2020 14:25:14 +0100
Subject: [PATCH] New DB schema for order prices/products

---
 api/db/order.go            | 41 ++++++++++++++++++++++----------------
 api/db/transaction.go      |  2 +-
 api/mail.go                |  2 +-
 api/order_test.go          | 27 ++++++++++++++-----------
 src/order/CreateOrder.js   |  2 +-
 src/order/PurchaseOrder.js | 10 +++++-----
 src/order/ShowOrder.js     | 12 +++++------
 7 files changed, 53 insertions(+), 43 deletions(-)

diff --git a/api/db/order.go b/api/db/order.go
index 015b140..e4cfc5c 100644
--- a/api/db/order.go
+++ b/api/db/order.go
@@ -18,18 +18,25 @@ type Order struct {
 	Deadline    time.Time `json:"deadline"`
 	Active      bool      `json:"active" gorm:"index"`
 
-	Products      []Product     `json:"products" gorm:"many2many:order_products;References:Code;JoinReferences:ProductCode"`
-	Transactions  []Transaction `json:"transactions" gorm:"foreignKey:OrderID"`
-	TransactionID *uint         `json:"-" gorm:"column:transaction"`
+	Products      []OrderProduct `json:"products"`
+	Transactions  []Transaction  `json:"transactions" gorm:"foreignKey:OrderID"`
+	TransactionID *uint          `json:"-" gorm:"column:transaction"`
+}
+
+type OrderProduct struct {
+	gorm.Model
+	OrderID     uint     `json:"-"`
+	ProductCode int      `json:"code"`
+	Product     *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
+	Price       int      `json:"price"`
 }
 
 type OrderPurchase struct {
-	gorm.Model    `json:"-"`
-	TransactionID uint     `json:"-"`
-	ProductCode   int      `json:"product_code"`
-	Product       *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
-	Price         int      `json:"price"`
-	Amount        int      `json:"amount"`
+	gorm.Model     `json:"-"`
+	TransactionID  uint          `json:"-"`
+	OrderProductID uint          `json:"order_product_id"`
+	OrderProduct   *OrderProduct `json:"order_product"`
+	Amount         int           `json:"amount"`
 }
 
 func (d *DB) ListOrders(active bool) (orders []Order, err error) {
@@ -54,6 +61,7 @@ func (d *DB) ListOrderPicks(num int) (orders []Order, err error) {
 
 func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transaction, err error) {
 	err = d.db.Preload(clause.Associations).
+		Preload("Products.Product").
 		Preload("Transactions.OrderPurchase").
 		Preload("Transactions.Member").
 		First(&order, id).Error
@@ -65,7 +73,7 @@ func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transacti
 		return
 	}
 	err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id).
-		Preload("OrderPurchase.Product").
+		Preload("OrderPurchase.OrderProduct").
 		Find(&transaction).Error
 	return
 }
@@ -128,19 +136,18 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurcha
 	}
 
 	total := 0
-	for i, p := range purchase {
+	for _, p := range purchase {
 		found := false
 		for _, product := range order.Products {
-			if product.Code == p.ProductCode {
+			if product.ID == p.OrderProductID {
 				total += product.Price * p.Amount
-				purchase[i].Price = product.Price
 				found = true
 				break
 			}
 		}
 
 		if !found {
-			log.Printf("Order purchase product %d not in order: %v", p.ProductCode, purchase)
+			log.Printf("Order purchase product %d not in order: %v", p.OrderProductID, purchase)
 			err = ErrorInvalidRequest
 			return
 		}
@@ -170,7 +177,7 @@ func (d *DB) updateOrderPurchase(memberNum int, transaction *Transaction, total
 
 	for i, p := range transaction.OrderPurchase {
 		for _, new_purchase := range purchase {
-			if new_purchase.ProductCode == p.ProductCode {
+			if new_purchase.OrderProductID == p.OrderProductID {
 				transaction.OrderPurchase[i].Amount = new_purchase.Amount
 				break
 			}
@@ -199,7 +206,7 @@ func (d *DB) DeactivateOrders() []Order {
 	t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
 	err := d.db.Where("active = ? AND deadline < ?", true, t).
 		Preload("Member").
-		Preload("Transactions.OrderPurchase.Product").
+		Preload("Transactions.OrderPurchase.OrderProduct").
 		Preload("Transactions.Member").
 		Find(&orders).Error
 	if err != nil {
@@ -212,7 +219,7 @@ func (d *DB) DeactivateOrders() []Order {
 		total := 0
 		for _, transaction := range order.Transactions {
 			for _, purchase := range transaction.OrderPurchase {
-				total += purchase.Price * purchase.Amount
+				total += purchase.OrderProduct.Price * purchase.Amount
 			}
 		}
 
diff --git a/api/db/transaction.go b/api/db/transaction.go
index bab6274..884d6bd 100644
--- a/api/db/transaction.go
+++ b/api/db/transaction.go
@@ -132,7 +132,7 @@ func (d *DB) AddPurchase(adminNum int, memberNum int, purchase []Purchase) (tran
 func (d *DB) transactionQuery() *gorm.DB {
 	return d.db.Preload("Purchase.Product").
 		Preload("Order.Products").
-		Preload("OrderPurchase.Product").
+		Preload("OrderPurchase.OrderProduct").
 		Preload(clause.Associations)
 }
 
diff --git a/api/mail.go b/api/mail.go
index 11aa0c4..1b709af 100644
--- a/api/mail.go
+++ b/api/mail.go
@@ -108,7 +108,7 @@ func (m Mail) sendOrder(to string, order *db.Order) error {
 			if p.Amount == 0 {
 				continue
 			}
-			products[p.Product.Name] += p.Amount
+			products[p.OrderProduct.Product.Name] += p.Amount
 			purchase = append(purchase, p)
 		}
 		purchases[t.Member.Name] = purchase
diff --git a/api/order_test.go b/api/order_test.go
index 1f312e2..5833fbb 100644
--- a/api/order_test.go
+++ b/api/order_test.go
@@ -15,8 +15,11 @@ var testOrder = db.Order{
 	Name:        "huevos",
 	Description: "huevos frescos",
 	Deadline:    time.Now().Add(24 * time.Hour),
-	Products: []db.Product{
-		testProduct,
+	Products: []db.OrderProduct{
+		{
+			ProductCode: testProduct.Code,
+			Price:       testProduct.Price,
+		},
 	},
 }
 
@@ -89,8 +92,8 @@ func TestOrderDelete(t *testing.T) {
 
 	purchase := []db.OrderPurchase{
 		{
-			ProductCode: testProduct.Code,
-			Amount:      3,
+			OrderProductID: orders[0].Products[0].ID,
+			Amount:         3,
 		},
 	}
 	resp = tapi.doAdmin("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
@@ -157,8 +160,8 @@ func TestOrderPurchase(t *testing.T) {
 
 	purchase := []db.OrderPurchase{
 		{
-			ProductCode: testProduct.Code,
-			Amount:      3,
+			OrderProductID: orders[0].Products[0].ID,
+			Amount:         3,
 		},
 	}
 	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
@@ -250,8 +253,8 @@ func TestOrderDeactivation(t *testing.T) {
 
 	purchase := []db.OrderPurchase{
 		{
-			ProductCode: testProduct.Code,
-			Amount:      3,
+			OrderProductID: orders[0].Products[0].ID,
+			Amount:         3,
 		},
 	}
 	resp = tapi.doAdmin("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
@@ -335,8 +338,8 @@ func TestGetOrder(t *testing.T) {
 
 	purchase := []db.OrderPurchase{
 		{
-			ProductCode: testProduct.Code,
-			Amount:      3,
+			OrderProductID: orders[0].Products[0].ID,
+			Amount:         3,
 		},
 	}
 	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
@@ -371,8 +374,8 @@ func TestUpdateOrderPurchase(t *testing.T) {
 
 	purchase := []db.OrderPurchase{
 		{
-			ProductCode: testProduct.Code,
-			Amount:      3,
+			OrderProductID: orders[0].Products[0].ID,
+			Amount:         3,
 		},
 	}
 	resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
diff --git a/src/order/CreateOrder.js b/src/order/CreateOrder.js
index 3a265e8..d3caa3e 100644
--- a/src/order/CreateOrder.js
+++ b/src/order/CreateOrder.js
@@ -29,7 +29,7 @@ function CreateOrder() {
 
   const body = () => {
     const products = picks.map((p) => {
-      return { code: p.code };
+      return { code: p.code, price: p.price };
     });
     return { name, description, deadline, products };
   };
diff --git a/src/order/PurchaseOrder.js b/src/order/PurchaseOrder.js
index 11ed2b2..7d995ba 100644
--- a/src/order/PurchaseOrder.js
+++ b/src/order/PurchaseOrder.js
@@ -17,7 +17,7 @@ class PurchaseOrder extends React.Component {
         p.amount = 0;
         if (props.purchase) {
           const my_purchase = props.purchase.find(
-            (e) => e.product_code === p.code
+            (e) => e.order_product.code === p.code
           );
           if (my_purchase) {
             p.amount = my_purchase.amount;
@@ -26,10 +26,10 @@ class PurchaseOrder extends React.Component {
         return p;
       })
       .sort((p1, p2) => {
-        if (p1.name > p2.name) {
+        if (p1.product.name > p2.product.name) {
           return 1;
         }
-        if (p1.name < p2.name) {
+        if (p1.product.name < p2.product.name) {
           return -1;
         }
         return 0;
@@ -56,7 +56,7 @@ class PurchaseOrder extends React.Component {
   body() {
     return this.state.order.map((p) => {
       return {
-        product_code: p.code,
+        order_product_id: p.ID,
         amount: parseInt(p.amount),
       };
     });
@@ -88,7 +88,7 @@ class PurchaseOrder extends React.Component {
     const formEntries = this.state.order.map((p, i) => (
       <Form.Group key={p.code} as={Row}>
         <Form.Label column className="text-right">
-          {p.name} ({p.code}):
+          {p.product.name} ({p.code}):
         </Form.Label>
         <Col>
           <InputGroup>
diff --git a/src/order/ShowOrder.js b/src/order/ShowOrder.js
index 7451a93..ad23d13 100644
--- a/src/order/ShowOrder.js
+++ b/src/order/ShowOrder.js
@@ -9,8 +9,8 @@ import { printMoney, url } from "../util";
 
 function ShowOrderTransaction(props) {
   const list = props.transaction.order_purchase.map((o) => (
-    <li key={o.product.code}>
-      {o.product.name} ({o.product.code}): {o.amount}
+    <li key={o.order_product.code}>
+      {o.order_product.product.name} ({o.order_product.code}): {o.amount}
     </li>
   ));
   return (
@@ -29,17 +29,17 @@ function ShowOrderResults(props) {
   });
   const transactions = props.order.transactions.map((t) => {
     const list = t.order_purchase.map((purchase) => {
-      const i = products.findIndex((p) => p.code === purchase.product_code);
+      const i = products.findIndex((p) => p.ID === purchase.order_product_id);
       if (i === -1) {
         return null;
       }
       products[i].total += purchase.amount;
       if (purchase.amount) {
         const key =
-          t.member.num.toString() + "-" + purchase.product_code.toString();
+          t.member.num.toString() + "-" + purchase.order_product_id.toString();
         return (
           <li key={key}>
-            {products[i].name} {purchase.amount}
+            {products[i].product.name} {purchase.amount}
           </li>
         );
       }
@@ -55,7 +55,7 @@ function ShowOrderResults(props) {
 
   const product_list = products.map((p) => (
     <li key={p.code}>
-      {p.name}: {p.total}
+      {p.product.name}: {p.total}
     </li>
   ));
   return (
-- 
GitLab