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

Update order

parent e83e6003
Branches
No related tags found
No related merge requests found
...@@ -58,6 +58,7 @@ func Init(dbPath string, signKey string, mail *Mail, r *mux.Router) error { ...@@ -58,6 +58,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.auth(a.ListOrders)).Methods("GET")
r.HandleFunc("/order", a.authOrderNum(a.AddOrder)).Methods("POST") r.HandleFunc("/order", a.authOrderNum(a.AddOrder)).Methods("POST")
r.HandleFunc("/order/{id:[0-9]+}", a.authNum(a.GetOrder)).Methods("GET") r.HandleFunc("/order/{id:[0-9]+}", a.authNum(a.GetOrder)).Methods("GET")
r.HandleFunc("/order/{id:[0-9]+}", a.authNumRole(a.UpdateOrder)).Methods("PUT")
r.HandleFunc("/order/{id:[0-9]+}", a.authNumRole(a.DeleteOrder)).Methods("DELETE") 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/active", a.auth(a.ListActiveOrders)).Methods("GET")
r.HandleFunc("/order/picks", a.authOrderNum(a.ListOrderPicks)).Methods("GET") r.HandleFunc("/order/picks", a.authOrderNum(a.ListOrderPicks)).Methods("GET")
......
...@@ -68,10 +68,14 @@ func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transacti ...@@ -68,10 +68,14 @@ func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transacti
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
err = ErrorNotFound err = ErrorNotFound
}
return return
} }
if memberNum == 0 {
return return
} }
err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id). err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id).
Preload("OrderPurchase.OrderProduct"). Preload("OrderPurchase.OrderProduct").
Find(&transaction).Error Find(&transaction).Error
...@@ -82,18 +86,133 @@ func (d *DB) AddOrder(order *Order) error { ...@@ -82,18 +86,133 @@ func (d *DB) AddOrder(order *Order) error {
return d.db.Create(&order).Error return d.db.Create(&order).Error
} }
func (d *DB) DeleteOrder(memberNum int, id int) error { func (d *DB) UpdateOrder(memberNum int, id int, order *Order) error {
var order Order dbOrder, _, err := d.GetOrder(0, id)
err := d.db.Preload(clause.Associations). if err != nil {
Preload("Transactions.OrderPurchase"). return err
Preload("Transactions.Member"). }
First(&order, id).Error
if memberNum != 0 && dbOrder.MemberNum != memberNum {
return ErrorInvalidRequest
}
if dbOrder.Deadline.Add(5 * 24 * time.Hour).Before(time.Now()) {
return ErrorInvalidRequest
}
for _, p := range order.Products {
err = d.orderProductExist(&p)
if err != nil {
return err
}
}
dbOrder.Name = order.Name
dbOrder.Description = order.Description
dbOrder.Deadline = order.Deadline
return d.db.Transaction(func(tx *gorm.DB) error {
for _, product := range order.Products {
var err error
dbProduct := findOrderProduct(product.ProductCode, dbOrder.Products)
if dbProduct != nil {
dbProduct.Price = product.Price
err = tx.Save(&dbProduct).Error
} else {
err = tx.Create(&product).Error
}
if err != nil {
return err
}
}
for _, product := range dbOrder.Products {
if findOrderProduct(product.ProductCode, order.Products) == nil {
err = tx.Delete(&product).Error
if err != nil {
return err
}
}
}
totalSum := 0
for i, t := range dbOrder.Transactions {
var transaction Transaction
err := tx.Preload("OrderPurchase.OrderProduct").First(&transaction, id).Error
if err != nil { if err != nil {
return err
}
total, _ := calculateOrderPurchaseTotal(transaction.OrderPurchase, order.Products)
err = updateOrderPurchase(tx, t.MemberNum, &dbOrder.Transactions[i], total, t.OrderPurchase)
if err != nil {
return err
}
totalSum += total
}
if dbOrder.TransactionID != nil {
updateOrderTransaction(tx, int(*dbOrder.TransactionID), totalSum, &dbOrder)
}
err := tx.Save(&dbOrder).Error
if err != nil {
return err
}
return nil
})
}
func updateOrderTransaction(tx *gorm.DB, id int, total int, order *Order) error {
var transaction Transaction
err := tx.First(&transaction, id).Error
if err != nil {
return err
}
if order.Deadline.After(time.Now()) {
err := updateMemberBalance(tx, order.MemberNum, -transaction.Total)
if err != nil {
return err
}
err = tx.Delete(&transaction).Error
if err != nil {
return err
}
order.Active = true
order.TransactionID = nil
} else {
totalDiff := total - transaction.Total
err := updateMemberBalance(tx, order.MemberNum, totalDiff)
if err != nil {
return err
}
transaction.Total = total
err = tx.Save(&transaction).Error
if err != nil {
return err
}
}
return nil
}
func findOrderProduct(code int, products []OrderProduct) *OrderProduct {
for _, p := range products {
if p.ProductCode == code {
return &p
}
}
return nil
}
func (d *DB) orderProductExist(product *OrderProduct) error {
err := d.db.Where("code = ?", product.ProductCode).Find(&Product{}).Error
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrorNotFound err = ErrorNotFound
} }
return err return err
} }
func (d *DB) DeleteOrder(memberNum int, id int) error {
order, _, err := d.GetOrder(0, id)
if err != nil {
return err
}
if memberNum != 0 && order.MemberNum != memberNum { if memberNum != 0 && order.MemberNum != memberNum {
return ErrorInvalidRequest return ErrorInvalidRequest
} }
...@@ -135,26 +254,14 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurcha ...@@ -135,26 +254,14 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurcha
return return
} }
total := 0 total, err := calculateOrderPurchaseTotal(purchase, order.Products)
for _, p := range purchase { if err != nil {
found := false
for _, product := range order.Products {
if product.ID == p.OrderProductID {
total += product.Price * p.Amount
found = true
break
}
}
if !found {
log.Printf("Order purchase product %d not in order: %v", p.OrderProductID, purchase)
err = ErrorInvalidRequest
return return
} }
}
if transaction.ID != 0 { if transaction.ID != 0 {
err = d.updateOrderPurchase(memberNum, &transaction, total, purchase) transaction.Date = time.Now()
err = updateOrderPurchase(d.db, memberNum, &transaction, total, purchase)
return return
} }
...@@ -170,32 +277,92 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurcha ...@@ -170,32 +277,92 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID int, purchase []OrderPurcha
return return
} }
func (d *DB) updateOrderPurchase(memberNum int, transaction *Transaction, total int, purchase []OrderPurchase) error { func calculateOrderPurchaseTotal(purchase []OrderPurchase, products []OrderProduct) (total int, err error) {
total = 0
for _, p := range purchase {
found := false
for _, product := range products {
log.Printf("%v", p.OrderProduct)
if (p.OrderProduct != nil && product.ProductCode == p.OrderProduct.ProductCode) ||
product.ID == p.OrderProductID {
total += product.Price * p.Amount
found = true
break
}
}
if !found {
log.Printf("Order purchase product %d not in order: %v", p.OrderProductID, purchase)
err = ErrorInvalidRequest
}
}
return total, err
}
func updateOrderPurchase(tx *gorm.DB, memberNum int, transaction *Transaction, total int, purchase []OrderPurchase) error {
totalDiff := -(transaction.Total + total) totalDiff := -(transaction.Total + total)
transaction.Total = -total transaction.Total = -total
transaction.Date = time.Now()
for i, p := range transaction.OrderPurchase { var updatePurchases []OrderPurchase
var newPurchases []OrderPurchase
for _, new_purchase := range purchase { for _, new_purchase := range purchase {
found := false
for i, p := range transaction.OrderPurchase {
if new_purchase.OrderProductID == p.OrderProductID { if new_purchase.OrderProductID == p.OrderProductID {
transaction.OrderPurchase[i].Amount = new_purchase.Amount transaction.OrderPurchase[i].Amount = new_purchase.Amount
updatePurchases = append(updatePurchases, transaction.OrderPurchase[i])
found = true
break break
} }
} }
if !found {
newPurchases = append(newPurchases, OrderPurchase{
Amount: new_purchase.Amount,
TransactionID: transaction.ID,
OrderProductID: new_purchase.OrderProductID,
})
}
} }
return d.db.Transaction(func(tx *gorm.DB) error { var delPurchases []OrderPurchase
for _, p := range transaction.OrderPurchase {
found := false
for _, p2 := range purchase {
if p.OrderProductID == p2.OrderProductID {
found = true
break
}
}
if !found {
delPurchases = append(delPurchases, p)
}
}
return tx.Transaction(func(tx *gorm.DB) error {
err := updateMemberBalance(tx, memberNum, totalDiff) err := updateMemberBalance(tx, memberNum, totalDiff)
if err != nil { if err != nil {
return err return err
} }
for _, p := range transaction.OrderPurchase { for _, p := range delPurchases {
err = tx.Delete(&p).Error
if err != nil {
return err
}
}
for _, p := range updatePurchases {
err = tx.Save(&p).Error err = tx.Save(&p).Error
if err != nil { if err != nil {
return err return err
} }
} }
for _, p := range newPurchases {
err = tx.Create(&p).Error
if err != nil {
return err
}
}
return tx.Save(&transaction).Error return tx.Save(&transaction).Error
}) })
} }
......
...@@ -154,6 +154,45 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) { ...@@ -154,6 +154,45 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) {
} }
} }
func (a *api) UpdateOrder(num int, role string, w http.ResponseWriter, req *http.Request) {
var order db.Order
err := json.NewDecoder(req.Body).Decode(&order)
if err != nil {
log.Printf("Can't parse order: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
vars := mux.Vars(req)
id, _ := strconv.Atoi(vars["id"])
if role == "admin" {
num = 0
}
err = a.db.UpdateOrder(num, id, &order)
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 update order %s: %v", vars["id"], err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted)
err = json.NewEncoder(w).Encode(order)
if err != nil {
log.Printf("Can't encode order: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) { func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
id, _ := strconv.Atoi(vars["id"]) id, _ := strconv.Atoi(vars["id"])
......
...@@ -423,6 +423,230 @@ func TestUpdateOrderPurchase(t *testing.T) { ...@@ -423,6 +423,230 @@ func TestUpdateOrderPurchase(t *testing.T) {
} }
} }
func TestOrderUpdate(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
tapi.addTestMember()
tapi.addTestOrder()
var orders []db.Order
resp := tapi.do("GET", "/order/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
purchase := []db.OrderPurchase{
{
OrderProductID: orders[0].Products[0].ID,
Amount: 3,
},
}
resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create order:", resp.Status)
}
order := testOrder
order.Products[0].Price = 1000
resp = tapi.doOrder("PUT", fmt.Sprintf("/order/%d", orders[0].ID), order, nil)
if resp.StatusCode != http.StatusAccepted {
tapi.t.Fatal("Can't update order:", resp.Status)
}
var transactions []db.Transaction
resp = tapi.do("GET", "/transaction/mine", nil, &transactions)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get transactions:", resp.Status)
}
if len(transactions) != 1 {
t.Fatal("Wrong number of transactions", len(orders), orders)
}
total := 3 * order.Products[0].Price
if transactions[0].Total != -total {
t.Error("Wrong total", transactions[0].Total)
}
var member db.Member
resp = tapi.do("GET", "/member/me", nil, &member)
if resp.StatusCode != http.StatusOK {
t.Error("Can't find the member:", resp.Status)
}
if member.Balance != testMember.Balance-total {
t.Error("Wrong product balance:", member.Balance)
}
}
func TestOrderUpdateProduct(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
tapi.addTestMember()
tapi.addTestOrder()
var orders []db.Order
resp := tapi.do("GET", "/order/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
purchase := []db.OrderPurchase{
{
OrderProductID: orders[0].Products[0].ID,
Amount: 3,
},
}
resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create order:", resp.Status)
}
testProduct2 := db.Product{
Code: 123,
Name: "Huevos",
Price: 120,
Stock: 15,
}
resp = tapi.doAdmin("POST", "/product", testProduct2, nil)
if resp.StatusCode != http.StatusCreated {
tapi.t.Fatal("Can't create product:", resp.Status)
}
order := testOrder
order.Products[0].Price = testProduct2.Price
order.Products[0].ProductCode = testProduct2.Code
resp = tapi.doOrder("PUT", fmt.Sprintf("/order/%d", orders[0].ID), order, nil)
if resp.StatusCode != http.StatusAccepted {
tapi.t.Fatal("Can't update order:", resp.Status)
}
var transactions []db.Transaction
resp = tapi.do("GET", "/transaction/mine", nil, &transactions)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get transactions:", resp.Status)
}
if len(transactions) != 1 {
t.Fatal("Wrong number of transactions", len(orders), orders)
}
if transactions[0].Total != 0 {
t.Error("Wrong total", transactions[0].Total)
}
}
func TestOrderUpdateReactivate(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
tapi.addTestMember()
tapi.addTestProducts()
order := testOrder
now := time.Now()
order.Deadline = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local)
resp := tapi.doOrder("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/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
purchase := []db.OrderPurchase{
{
OrderProductID: orders[0].Products[0].ID,
Amount: 3,
},
}
resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create order:", resp.Status)
}
orders = tapi.deactivateOrders()
if len(orders) != 1 {
t.Error("Deactivated none orders:", orders)
}
order.Deadline = testOrder.Deadline
resp = tapi.doOrder("PUT", fmt.Sprintf("/order/%d", orders[0].ID), order, nil)
if resp.StatusCode != http.StatusAccepted {
tapi.t.Fatal("Can't update order:", resp.Status)
}
resp = tapi.do("GET", "/order/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
if len(orders) != 1 {
t.Error("The order is not being reactivated", orders)
}
var transactions []db.Transaction
resp = tapi.doOrder("GET", "/transaction/mine", nil, &transactions)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get transactions:", resp.Status)
}
if len(transactions) != 0 {
t.Fatal("Wrong number of transactions", transactions)
}
}
func TestOrderUpdateDeactivated(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
tapi.addTestMember()
tapi.addTestProducts()
order := testOrder
now := time.Now()
order.Deadline = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local)
resp := tapi.doOrder("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/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
purchase := []db.OrderPurchase{
{
OrderProductID: orders[0].Products[0].ID,
Amount: 3,
},
}
resp = tapi.do("POST", fmt.Sprintf("/order/%d/purchase", orders[0].ID), purchase, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create order:", resp.Status)
}
orders = tapi.deactivateOrders()
if len(orders) != 1 {
t.Error("Deactivated none orders:", orders)
}
order.Products[0].Price = 1000
resp = tapi.doOrder("PUT", fmt.Sprintf("/order/%d", orders[0].ID), order, nil)
if resp.StatusCode != http.StatusAccepted {
tapi.t.Fatal("Can't update order:", resp.Status)
}
total := 3 * order.Products[0].Price
var transactions []db.Transaction
resp = tapi.doOrder("GET", "/transaction/mine", nil, &transactions)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get transactions:", resp.Status)
}
if len(transactions) != 1 {
t.Fatal("Wrong number of transactions", transactions)
}
if transactions[0].Total != total {
t.Fatal("Wrong updated total", transactions[0].Total, total)
}
}
func TestOrderPicks(t *testing.T) { func TestOrderPicks(t *testing.T) {
tapi := newTestAPI(t) tapi := newTestAPI(t)
defer tapi.close() defer tapi.close()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment