From 4f058ca1aab301cf56684ec1b44fe7c5501eff18 Mon Sep 17 00:00:00 2001 From: meskio <meskio@sindominio.net> Date: Fri, 30 Oct 2020 19:13:20 +0100 Subject: [PATCH] Delete orders --- api/api.go | 1 + api/db/order.go | 49 +++++++++++++++++++++++++-- api/db/transaction.go | 4 +-- api/order.go | 23 +++++++++++++ api/order_test.go | 79 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 4 deletions(-) diff --git a/api/api.go b/api/api.go index d4ea173..3801c13 100644 --- a/api/api.go +++ b/api/api.go @@ -57,6 +57,7 @@ func Init(dbPath string, signKey string, mail *Mail, 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.authNum(a.GetOrder)).Methods("GET") + r.HandleFunc("/order/{id:[0-9]+}", a.authNumRole(a.DeleteOrder)).Methods("DELETE") r.HandleFunc("/order/active", a.auth(a.ListActiveOrders)).Methods("GET") r.HandleFunc("/order/{id:[0-9]+}/purchase", a.authNum(a.AddOrderPurchase)).Methods("POST") return nil diff --git a/api/db/order.go b/api/db/order.go index 3a4cc7e..e00e4b8 100644 --- a/api/db/order.go +++ b/api/db/order.go @@ -48,8 +48,11 @@ func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transacti Preload("Transactions.OrderPurchase"). Preload("Transactions.Member"). First(&order, id).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - err = ErrorNotFound + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + err = ErrorNotFound + return + } return } err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id). @@ -62,6 +65,48 @@ func (d *DB) AddOrder(order *Order) error { return d.db.Create(&order).Error } +func (d *DB) DeleteOrder(memberNum int, id int) error { + var order Order + err := d.db.Preload(clause.Associations). + Preload("Transactions.OrderPurchase"). + Preload("Transactions.Member"). + First(&order, id).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrorNotFound + } + return err + } + if memberNum != 0 && order.MemberNum != memberNum { + return ErrorInvalidRequest + } + + return d.db.Transaction(func(tx *gorm.DB) error { + if order.TransactionID != nil { + var transaction Transaction + err = tx.First(&transaction, order.TransactionID).Error + if err != nil { + return err + } + order.Transactions = append(order.Transactions, transaction) + } + + for _, transaction := range order.Transactions { + err := updateMemberBalance(tx, transaction.MemberNum, -transaction.Total) + if err != nil { + return err + } + + err = tx.Select("OrderPurchase").Delete(&transaction).Error + if err != nil { + return err + } + } + + return tx.Delete(&order).Error + }) +} + func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurchase) (transaction Transaction, err error) { order, transaction, err := d.GetOrder(memberNum, orderID) if err != nil { diff --git a/api/db/transaction.go b/api/db/transaction.go index f51fad7..151c3df 100644 --- a/api/db/transaction.go +++ b/api/db/transaction.go @@ -20,8 +20,8 @@ type Transaction struct { Purchase []Purchase `json:"purchase,omitempty"` Topup *Topup `json:"topup,omitempty"` - OrderPurchase []OrderPurchase `json:"order_purchase,omitempty" gorm:"foreignKey:TransactionID"` - Order *Order `json:"order,omitempty"` + OrderPurchase []OrderPurchase `json:"order_purchase,omitempty" gorm:"foreignKey:TransactionID;constraint:OnDelete:CASCADE"` + Order *Order `json:"order,omitempty" gorm:"constraint:OnDelete:CASCADE"` OrderID *uint `json:"-"` Refund *Order `json:"refund,omitempty" gorm:"foreignKey:TransactionID"` } diff --git a/api/order.go b/api/order.go index 36fea27..1945e24 100644 --- a/api/order.go +++ b/api/order.go @@ -86,6 +86,29 @@ func (a *api) GetOrder(num int, w http.ResponseWriter, req *http.Request) { } } +func (a *api) DeleteOrder(num int, role string, w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + id, _ := strconv.Atoi(vars["id"]) + if role == "admin" { + num = 0 + } + err := a.db.DeleteOrder(num, id) + if err != nil { + if errors.Is(err, db.ErrorNotFound) { + w.WriteHeader(http.StatusNotFound) + return + } + if errors.Is(err, db.ErrorInvalidRequest) { + w.WriteHeader(http.StatusUnauthorized) + return + } + log.Printf("Can't get order %s: %v", vars["id"], err) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) +} + func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) { var order db.Order err := json.NewDecoder(req.Body).Decode(&order) diff --git a/api/order_test.go b/api/order_test.go index f78827f..f8ceb39 100644 --- a/api/order_test.go +++ b/api/order_test.go @@ -66,6 +66,85 @@ func TestOrderActive(t *testing.T) { } } +func TestOrderDelete(t *testing.T) { + tapi := newTestAPI(t) + defer tapi.close() + tapi.addTestMember() + + order := testOrder + order.Deadline = time.Now().Add(-24 * time.Hour) + resp := tapi.do("POST", "/order", order, nil) + if resp.StatusCode != http.StatusCreated { + t.Fatal("Can't create order:", resp.Status) + } + + var orders []db.Order + resp = tapi.do("GET", "/order", nil, &orders) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't get orders:", resp.Status) + } + + purchase := []db.OrderPurchase{ + { + ProductCode: testProduct.Code, + Amount: 3, + }, + } + resp = tapi.doAdmin("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil) + if resp.StatusCode != http.StatusCreated { + t.Fatal("Can't create order purchase:", resp.Status) + } + + dbPath := path.Join(tapi.testPath, "test.db") + database, err := db.Init(dbPath) + if err != nil { + t.Fatal("Can't initialize the db:", err) + } + orders = database.DeactivateOrders() + if len(orders) != 1 { + t.Error("Deactivated wrong orders:", orders) + } + + resp = tapi.do("DELETE", fmt.Sprintf("/order/%d", orders[0].ID), nil, nil) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't delete order:", resp.Status) + } + + resp = tapi.do("GET", "/order", nil, &orders) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't get orders:", resp.Status) + } + if len(orders) != 0 { + t.Error("The order didn't get removed", orders) + } + + var transactions []db.Transaction + resp = tapi.doAdmin("GET", "/transaction", nil, &transactions) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't get orders:", resp.Status) + } + if len(transactions) != 0 { + t.Error("The transactions didn't get removed", transactions) + } + + var member db.Member + resp = tapi.doAdmin("GET", fmt.Sprintf("/member/%d", testMember.Num), nil, &member) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't get orders:", resp.Status) + } + if member.Balance != testMember.Balance { + t.Error("Wrong balance on test member:", member.Balance) + } + + resp = tapi.doAdmin("GET", fmt.Sprintf("/member/%d", testMemberAdmin.Num), nil, &member) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't get orders:", resp.Status) + } + if member.Balance != testMemberAdmin.Balance { + t.Error("Wrong balance on admin member:", member.Balance) + } +} + func TestOrderPurchase(t *testing.T) { tapi := newTestAPI(t) defer tapi.close() -- GitLab