Skip to content
Snippets Groups Projects
Commit f2fcb2b3 authored by meskio's avatar meskio :tent:
Browse files

Redesign orders in the db

parent 481a01c5
No related branches found
No related tags found
No related merge requests found
...@@ -16,13 +16,13 @@ type Order struct { ...@@ -16,13 +16,13 @@ type Order struct {
gorm.Model gorm.Model
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
MemberNum int `json:"-" gorm:"column:member"` MemberNum int `json:"member_num" gorm:"column:member"`
Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"` Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
Deadline time.Time `json:"deadline"` Deadline time.Time `json:"deadline"`
Active bool `json:"active" gorm:"index"` Active bool `json:"active" gorm:"index"`
Products []Product `json:"products" gorm:"many2many:order_products;References:Code;JoinReferences:ProductCode"` Products []Product `json:"products" gorm:"many2many:order_products;References:Code;JoinReferences:ProductCode"`
Purchases []OrderPurchase `json:"purchases"` Transactions []Transaction `json:"transactions" gorm:"foreignKey:OrderID"`
TransactionID *uint `json:"-" gorm:"column:transaction"` TransactionID *uint `json:"-" gorm:"column:transaction"`
} }
...@@ -31,8 +31,6 @@ type OrderPurchase struct { ...@@ -31,8 +31,6 @@ type OrderPurchase struct {
TransactionID uint `json:"-"` TransactionID uint `json:"-"`
ProductCode int `json:"product_code"` ProductCode int `json:"product_code"`
Product *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"` Product *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
OrderID uint `json:"order_id"`
Order *Order `json:"-"`
Price int `json:"price"` Price int `json:"price"`
Amount int `json:"amount"` Amount int `json:"amount"`
} }
...@@ -42,6 +40,11 @@ type OrderGetResponse struct { ...@@ -42,6 +40,11 @@ type OrderGetResponse struct {
Transaction *Transaction `json:"transaction"` Transaction *Transaction `json:"transaction"`
} }
type OrderPurchaseRequest struct {
Purchase []OrderPurchase `json:"purchase"`
OrderID uint `json:"order"`
}
func (a *api) refundOrders() { func (a *api) refundOrders() {
const refundSleeptime = 10 * time.Minute const refundSleeptime = 10 * time.Minute
for { for {
...@@ -55,7 +58,7 @@ func (a *api) deactivateOrders() { ...@@ -55,7 +58,7 @@ func (a *api) deactivateOrders() {
now := time.Now() now := time.Now()
t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local) t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
err := a.db.Where("active = ? AND deadline < ?", true, t). err := a.db.Where("active = ? AND deadline < ?", true, t).
Preload("Purchases"). Preload("Transactions.OrderPurchase").
Find(&orders).Error Find(&orders).Error
if err != nil { if err != nil {
log.Println("Error refunding orders:", err) log.Println("Error refunding orders:", err)
...@@ -64,9 +67,11 @@ func (a *api) deactivateOrders() { ...@@ -64,9 +67,11 @@ func (a *api) deactivateOrders() {
for _, order := range orders { for _, order := range orders {
total := 0 total := 0
for _, purchase := range order.Purchases { for _, transaction := range order.Transactions {
for _, purchase := range transaction.OrderPurchase {
total += purchase.Price * purchase.Amount total += purchase.Price * purchase.Amount
} }
}
transaction := Transaction{ transaction := Transaction{
MemberNum: order.MemberNum, MemberNum: order.MemberNum,
...@@ -105,7 +110,8 @@ func (a *api) ListActiveOrders(w http.ResponseWriter, req *http.Request) { ...@@ -105,7 +110,8 @@ func (a *api) ListActiveOrders(w http.ResponseWriter, req *http.Request) {
func (a *api) listOrders(active bool, w http.ResponseWriter, req *http.Request) { func (a *api) listOrders(active bool, w http.ResponseWriter, req *http.Request) {
var orders []Order var orders []Order
query := a.db.Preload(clause.Associations) query := a.db.Preload(clause.Associations).
Preload("Transactions.OrderPurchase")
if active { if active {
query = query.Where("active = ?", true) query = query.Where("active = ?", true)
} }
...@@ -129,6 +135,8 @@ func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) { ...@@ -129,6 +135,8 @@ func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
var order Order var order Order
err := a.db.Preload(clause.Associations). err := a.db.Preload(clause.Associations).
Preload("Transactions.OrderPurchase").
Preload("Transactions.Member").
First(&order, vars["id"]).Error First(&order, vars["id"]).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
...@@ -143,10 +151,8 @@ func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) { ...@@ -143,10 +151,8 @@ func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) {
body.Order = order body.Order = order
var transaction Transaction var transaction Transaction
err = a.db.Where("member = ? AND type = 'order' AND id IN (?)", num, err = a.db.Where("member = ? AND type = 'order' AND order_id = ?", num, vars["id"]).
a.db.Table("order_purchases"). Preload("OrderPurchase.Product").
Where("order_id = ?", order.ID).
Select("transaction_id")).
Find(&transaction).Error Find(&transaction).Error
if err != nil { if err != nil {
log.Printf("Can't get order transaction %s: %v", vars["id"], err) log.Printf("Can't get order transaction %s: %v", vars["id"], err)
...@@ -196,14 +202,14 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) { ...@@ -196,14 +202,14 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) {
} }
func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) { func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) {
var purchase []OrderPurchase var request OrderPurchaseRequest
err := json.NewDecoder(req.Body).Decode(&purchase) err := json.NewDecoder(req.Body).Decode(&request)
if err != nil { if err != nil {
log.Printf("Can't parse order: %v", err) log.Printf("Can't parse order purchase: %v", err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if len(purchase) == 0 { if len(request.Purchase) == 0 {
log.Printf("Empty order purchase") log.Printf("Empty order purchase")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
...@@ -211,32 +217,40 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request ...@@ -211,32 +217,40 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
var order Order var order Order
err = a.db.Preload("Products"). err = a.db.Preload("Products").
First(&order, purchase[0].OrderID).Error Preload("Transactions").
First(&order, request.OrderID).Error
if err != nil { if err != nil {
log.Printf("Can't get order %d: %v", purchase[0].OrderID, err) log.Printf("Can't get order %d: %v", request.OrderID, err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if !order.Active { if !order.Active {
log.Printf("Order is not active %d: %v", order.ID, purchase) log.Printf("Order is not active %d: %v", order.ID, request)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
for _, t := range order.Transactions {
if t.MemberNum == num {
log.Printf("Purchase by %d for %d when there is already one by this member: %v", num, order.ID, request)
w.WriteHeader(http.StatusBadRequest)
return
}
}
total := 0 total := 0
for i, p := range purchase { for i, p := range request.Purchase {
found := false found := false
for _, product := range order.Products { for _, product := range order.Products {
if product.Code == p.ProductCode { if product.Code == p.ProductCode {
total += product.Price * p.Amount total += product.Price * p.Amount
purchase[i].Price = product.Price request.Purchase[i].Price = product.Price
found = true found = true
break break
} }
} }
if !found { 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.ProductCode, request)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
...@@ -247,7 +261,8 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request ...@@ -247,7 +261,8 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
Total: -total, Total: -total,
Type: "order", Type: "order",
Date: time.Now(), Date: time.Now(),
Order: purchase, OrderPurchase: request.Purchase,
OrderID: &order.ID,
} }
httpStatus, err := createTransaction(a.db, &transaction) httpStatus, err := createTransaction(a.db, &transaction)
if err != nil { if err != nil {
......
...@@ -75,11 +75,13 @@ func TestOrderPurchase(t *testing.T) { ...@@ -75,11 +75,13 @@ func TestOrderPurchase(t *testing.T) {
t.Fatal("Can't get orders:", resp.Status) t.Fatal("Can't get orders:", resp.Status)
} }
purchase := []OrderPurchase{ purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []OrderPurchase{
{ {
ProductCode: testProduct.Code, ProductCode: testProduct.Code,
Amount: 3, Amount: 3,
OrderID: orders[0].ID, },
}, },
} }
resp = tapi.do("POST", "/order/purchase", purchase, nil) resp = tapi.do("POST", "/order/purchase", purchase, nil)
...@@ -170,11 +172,13 @@ func TestOrderDeactivation(t *testing.T) { ...@@ -170,11 +172,13 @@ func TestOrderDeactivation(t *testing.T) {
t.Fatal("Didn't find my new order") t.Fatal("Didn't find my new order")
} }
purchase := []OrderPurchase{ purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []OrderPurchase{
{ {
ProductCode: testProduct.Code, ProductCode: testProduct.Code,
Amount: 3, Amount: 3,
OrderID: orders[0].ID, },
}, },
} }
resp = tapi.doAdmin("POST", "/order/purchase", purchase, nil) resp = tapi.doAdmin("POST", "/order/purchase", purchase, nil)
...@@ -253,11 +257,13 @@ func TestGetOrder(t *testing.T) { ...@@ -253,11 +257,13 @@ func TestGetOrder(t *testing.T) {
t.Error("Wrong name:", body.Order.Name) t.Error("Wrong name:", body.Order.Name)
} }
purchase := []OrderPurchase{ purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []OrderPurchase{
{ {
ProductCode: testProduct.Code, ProductCode: testProduct.Code,
Amount: 3, Amount: 3,
OrderID: orders[0].ID, },
}, },
} }
resp = tapi.do("POST", "/order/purchase", purchase, nil) resp = tapi.do("POST", "/order/purchase", purchase, nil)
......
...@@ -22,16 +22,17 @@ type Transaction struct { ...@@ -22,16 +22,17 @@ type Transaction struct {
Total int `json:"total"` Total int `json:"total"`
Type string `json:"type"` Type string `json:"type"`
Purchase []Purchase `json:"purchase"` Purchase []Purchase `json:"purchase,omitempty"`
Topup *Topup `json:"topup"` Topup *Topup `json:"topup,omitempty"`
Order []OrderPurchase `json:"order"` OrderPurchase []OrderPurchase `json:"order_purchase,omitempty" gorm:"foreignKey:TransactionID"`
Refund *Order `json:"refund"` Order *Order `json:"order,omitempty"`
OrderID *uint `json:"-"`
Refund *Order `json:"refund,omitempty" gorm:"foreignKey:TransactionID"`
} }
func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) { func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) {
var transactions []Transaction var transactions []Transaction
err := a.db.Preload("Purchase.Product"). err := a.transactionQuery().
Preload(clause.Associations).
Order("date desc"). Order("date desc").
Find(&transactions).Error Find(&transactions).Error
if err != nil { if err != nil {
...@@ -51,8 +52,7 @@ func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) { ...@@ -51,8 +52,7 @@ func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) {
func (a *api) GetTransaction(num int, role string, w http.ResponseWriter, req *http.Request) { func (a *api) GetTransaction(num int, role string, w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
var transaction Transaction var transaction Transaction
err := a.db.Preload("Purchase.Product"). err := a.transactionQuery().
Preload(clause.Associations).
First(&transaction, vars["id"]).Error First(&transaction, vars["id"]).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
...@@ -87,9 +87,8 @@ func (a *api) GetMemberTransactions(w http.ResponseWriter, req *http.Request) { ...@@ -87,9 +87,8 @@ func (a *api) GetMemberTransactions(w http.ResponseWriter, req *http.Request) {
func (a *api) getTransactionsByMember(num int, w http.ResponseWriter, req *http.Request) { func (a *api) getTransactionsByMember(num int, w http.ResponseWriter, req *http.Request) {
var transactions []Transaction var transactions []Transaction
err := a.db.Where("member = ?", num). err := a.transactionQuery().
Preload("Purchase.Product"). Where("member = ?", num).
Preload(clause.Associations).
Order("date desc"). Order("date desc").
Find(&transactions).Error Find(&transactions).Error
if err != nil { if err != nil {
...@@ -136,3 +135,10 @@ func createTransaction(db *gorm.DB, transaction *Transaction) (httpStatus int, e ...@@ -136,3 +135,10 @@ func createTransaction(db *gorm.DB, transaction *Transaction) (httpStatus int, e
}) })
return return
} }
func (a *api) transactionQuery() *gorm.DB {
return a.db.Preload("Purchase.Product").
Preload("Order.Products").
Preload("OrderPurchase.Product").
Preload(clause.Associations)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment