From 606b639211e460906c4e2ec295a7815a6af91c0a Mon Sep 17 00:00:00 2001
From: meskio <meskio@sindominio.net>
Date: Tue, 6 Oct 2020 07:46:51 +0200
Subject: [PATCH] Use 'normal' products for orders

---
 api/api.go         |  4 +--
 api/member_test.go |  2 +-
 api/order.go       | 89 +++++++++++++++++++++++++---------------------
 api/order_test.go  | 23 ++++++------
 4 files changed, 62 insertions(+), 56 deletions(-)

diff --git a/api/api.go b/api/api.go
index 6d87d7e..e072e36 100644
--- a/api/api.go
+++ b/api/api.go
@@ -20,7 +20,7 @@ func initDB(dbPath string) (*gorm.DB, error) {
 	}
 
 	db.AutoMigrate(&Member{}, &Product{}, &Purchase{}, &Topup{}, &Transaction{},
-		&OrderPurchase{}, &OrderProduct{}, &Order{})
+		&OrderPurchase{}, &Order{})
 	return db, err
 }
 
@@ -62,7 +62,7 @@ func Init(dbPath string, signKey string, r *mux.Router) error {
 
 	r.HandleFunc("/order", a.auth(a.ListOrders)).Methods("GET")
 	r.HandleFunc("/order", a.authNum(a.AddOrder)).Methods("POST")
-	r.HandleFunc("/order/{id:[0-9]+}", a.auth(a.GetOrder)).Methods("GET")
+	r.HandleFunc("/order/{id:[0-9]+}", a.authNum(a.GetOrder)).Methods("GET")
 	r.HandleFunc("/order/active", a.auth(a.ListActiveOrders)).Methods("GET")
 	r.HandleFunc("/order/purchase", a.authNum(a.AddOrderPurchase)).Methods("POST")
 	// TODO: r.HandleFunc("/order/purchase", a.authNum(a.UpdateOrderPurchase)).Methods("PUT")
diff --git a/api/member_test.go b/api/member_test.go
index b58cfe1..2712ab4 100644
--- a/api/member_test.go
+++ b/api/member_test.go
@@ -28,7 +28,7 @@ var testMemberAdmin = struct {
 		Name:    "bar",
 		Email:   "bar@example.com",
 		Role:    "admin",
-		Balance: 5000,
+		Balance: 15000,
 	},
 	Password: "password",
 }
diff --git a/api/order.go b/api/order.go
index a9c25b6..59b82e6 100644
--- a/api/order.go
+++ b/api/order.go
@@ -20,25 +20,20 @@ type Order struct {
 	Deadline    time.Time `json:"deadline"`
 	Active      bool      `json:"active" gorm:"index"`
 
-	Products      []OrderProduct `json:"products"`
-	TransactionID *uint          `json:"transaction" gorm:"column:transaction"`
-}
-
-type OrderProduct struct {
-	gorm.Model
-	Name    string `json:"name"`
-	Price   int    `json:"price"`
-	OrderID uint   `json:"-"`
-
-	Purchases []OrderPurchase `json:"purchases"`
+	Products      []Product       `json:"products" gorm:"many2many:order_products;References:Code;JoinReferences:ProductCode"`
+	Purchases     []OrderPurchase `json:"purchases"`
+	TransactionID *uint           `json:"-" gorm:"column:transaction"`
 }
 
 type OrderPurchase struct {
-	gorm.Model
-	OrderProductID uint  `json:"product_id"`
-	OrderProduct   Order `json:"product"`
-	TransactionID  uint  `json:"-"`
-	Ammount        int   `json:"ammount"`
+	gorm.Model    `json:"-"`
+	TransactionID uint     `json:"-"`
+	ProductCode   int      `json:"product_code"`
+	Product       *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
+	OrderID       uint     `json:"order_id"`
+	Order         *Order   `json:"-"`
+	Price         int      `json:"price"`
+	Ammount       int      `json:"ammount"`
 }
 
 func (a *api) refundOrders() {
@@ -54,7 +49,7 @@ func (a *api) deactivateOrders() {
 	now := time.Now()
 	t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
 	err := a.db.Where("active = ? AND deadline < ?", true, t).
-		Preload("Products.Purchases").
+		Preload("Purchases").
 		Find(&orders).Error
 	if err != nil {
 		log.Println("Error refunding orders:", err)
@@ -62,13 +57,9 @@ func (a *api) deactivateOrders() {
 	}
 
 	for _, order := range orders {
-		log.Println("Refund order", order.Name)
-
 		total := 0
-		for _, product := range order.Products {
-			for _, purchase := range product.Purchases {
-				total += product.Price * purchase.Ammount
-			}
+		for _, purchase := range order.Purchases {
+			total += purchase.Price * purchase.Ammount
 		}
 
 		transaction := Transaction{
@@ -93,6 +84,8 @@ func (a *api) deactivateOrders() {
 			log.Printf("Can't create refund: %v\n%v", err, order)
 			continue
 		}
+
+		log.Println("Refund order", order.Name, total)
 	}
 }
 
@@ -106,8 +99,7 @@ func (a *api) ListActiveOrders(w http.ResponseWriter, req *http.Request) {
 
 func (a *api) listOrders(active bool, w http.ResponseWriter, req *http.Request) {
 	var orders []Order
-	query := a.db.Preload("Products.Purchases").
-		Preload(clause.Associations)
+	query := a.db.Preload(clause.Associations)
 	if active {
 		query = query.Where("active = ?", true)
 	}
@@ -127,11 +119,10 @@ func (a *api) listOrders(active bool, w http.ResponseWriter, req *http.Request)
 	}
 }
 
-func (a *api) GetOrder(w http.ResponseWriter, req *http.Request) {
+func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) {
 	vars := mux.Vars(req)
 	var order Order
-	err := a.db.Preload("Products.Purchases").
-		Preload(clause.Associations).
+	err := a.db.Preload(clause.Associations).
 		First(&order, vars["id"]).Error
 	if err != nil {
 		if err.Error() == "record not found" {
@@ -142,10 +133,29 @@ func (a *api) GetOrder(w http.ResponseWriter, req *http.Request) {
 		w.WriteHeader(http.StatusInternalServerError)
 		return
 	}
+	var body struct {
+		Order       Order        `json:"order"`
+		Transaction *Transaction `json:"transaction"`
+	}
+	body.Order = order
+
+	var transaction Transaction
+	err = a.db.Joins("OrderPurchase").
+		Where("member = ? AND type = 'order' AND order_purchases.order_id = ?", num, order.ID).
+		Find(&transaction).Error
+	if err != nil {
+		if err.Error() != "record not found" {
+			log.Printf("Can't get order transaction %s: %v", vars["id"], err)
+			w.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+	} else {
+		body.Transaction = &transaction
+	}
 
 	w.Header().Set("Content-Type", "application/json")
 	w.WriteHeader(http.StatusOK)
-	err = json.NewEncoder(w).Encode(order)
+	err = json.NewEncoder(w).Encode(body)
 	if err != nil {
 		log.Printf("Can't encode order: %v", err)
 		w.WriteHeader(http.StatusInternalServerError)
@@ -196,15 +206,11 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
 	}
 
 	var order Order
-	err = a.db.Where("id = (?)",
-		a.db.Table("order_products").
-			Where("id = ?", purchase[0].OrderProductID).
-			Select("order_id")).
-		Preload("Products").
-		First(&order).Error
+	err = a.db.Preload("Products").
+		First(&order, purchase[0].OrderID).Error
 	if err != nil {
-		log.Printf("Can't get order from product %d: %v", purchase[0].OrderProductID, err)
-		w.WriteHeader(http.StatusNotAcceptable)
+		log.Printf("Can't get order %d: %v", purchase[0].OrderID, err)
+		w.WriteHeader(http.StatusInternalServerError)
 		return
 	}
 	if !order.Active {
@@ -214,19 +220,20 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
 	}
 
 	total := 0
-	for _, p := range purchase {
+	for i, p := range purchase {
 		found := false
 		for _, product := range order.Products {
-			if product.ID == p.OrderProductID {
+			if product.Code == p.ProductCode {
 				total += product.Price * p.Ammount
+				purchase[i].Price = product.Price
 				found = true
 				break
 			}
 		}
 
 		if !found {
-			log.Printf("Order purchase product %d not in order: %v", p.OrderProductID, purchase)
-			w.WriteHeader(http.StatusNotAcceptable)
+			log.Printf("Order purchase product %d not in order: %v", p.ProductCode, purchase)
+			w.WriteHeader(http.StatusBadRequest)
 			return
 		}
 	}
diff --git a/api/order_test.go b/api/order_test.go
index 29887a5..da66d14 100644
--- a/api/order_test.go
+++ b/api/order_test.go
@@ -11,11 +11,8 @@ var testOrder = Order{
 	Name:        "huevos",
 	Description: "huevos frescos",
 	Deadline:    time.Now().Add(24 * time.Hour),
-	Products: []OrderProduct{
-		{
-			Name:  "huevos",
-			Price: 234,
-		},
+	Products: []Product{
+		testProduct,
 	},
 }
 
@@ -40,7 +37,7 @@ func TestOrderAddList(t *testing.T) {
 	if len(orders[0].Products) != 1 {
 		t.Fatal("Wrong number of products", len(orders[0].Products), orders[0].Products)
 	}
-	if orders[0].Products[0].Price != testOrder.Products[0].Price {
+	if orders[0].Products[0].Price != testProduct.Price {
 		t.Error("Wrong product price:", orders[0].Products[0].Price)
 	}
 }
@@ -79,8 +76,9 @@ func TestOrderPurchase(t *testing.T) {
 
 	purchase := []OrderPurchase{
 		{
-			OrderProductID: orders[0].Products[0].ID,
-			Ammount:        3,
+			ProductCode: testProduct.Code,
+			Ammount:     3,
+			OrderID:     orders[0].ID,
 		},
 	}
 	resp = tapi.do("POST", "/order/purchase", purchase, nil)
@@ -96,7 +94,7 @@ func TestOrderPurchase(t *testing.T) {
 	if len(transactions) != 1 {
 		t.Fatal("Wrong number of transactions", len(orders), orders)
 	}
-	total := 3 * testOrder.Products[0].Price
+	total := 3 * testProduct.Price
 	if transactions[0].Total != -total {
 		t.Fatal("Wrong total", transactions[0].Total)
 	}
@@ -173,8 +171,9 @@ func TestOrderDeactivation(t *testing.T) {
 
 	purchase := []OrderPurchase{
 		{
-			OrderProductID: orders[0].Products[0].ID,
-			Ammount:        3,
+			ProductCode: testProduct.Code,
+			Ammount:     3,
+			OrderID:     orders[0].ID,
 		},
 	}
 	resp = tapi.doAdmin("POST", "/order/purchase", purchase, nil)
@@ -198,7 +197,7 @@ func TestOrderDeactivation(t *testing.T) {
 		t.Fatal("I found some orders")
 	}
 
-	total := 3 * testOrder.Products[0].Price
+	total := 3 * testProduct.Price
 
 	var transactions []Transaction
 	resp = tapi.do("GET", "/transaction/mine", nil, &transactions)
-- 
GitLab