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

Update order purchases API

parent 85998571
Branches
Tags
No related merge requests found
......@@ -58,7 +58,6 @@ func Init(dbPath string, signKey string, mail *Mail, r *mux.Router) error {
r.HandleFunc("/order", a.authNum(a.AddOrder)).Methods("POST")
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")
r.HandleFunc("/order/{id:[0-9]+}/purchase", a.authNum(a.AddOrderPurchase)).Methods("POST")
return nil
}
......@@ -62,11 +62,8 @@ func (d *DB) AddOrder(order *Order) error {
return d.db.Create(&order).Error
}
func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurchase) (transaction Transaction, err error) {
var order Order
err = d.db.Preload("Products").
Preload("Transactions").
First(&order, orderID).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 {
return
}
......@@ -75,13 +72,6 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
log.Printf("Order is not active %d: %v", order.ID, purchase)
return
}
for _, t := range order.Transactions {
if t.MemberNum == memberNum {
log.Printf("Purchase by %d for %d when there is already one by this member: %v", memberNum, order.ID, purchase)
err = ErrorInvalidRequest
return
}
}
total := 0
for i, p := range purchase {
......@@ -102,6 +92,11 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
}
}
if transaction.ID != 0 {
err = d.updateOrderPurchase(memberNum, &transaction, total, purchase)
return
}
transaction = Transaction{
MemberNum: memberNum,
Total: -total,
......@@ -114,6 +109,29 @@ func (d *DB) AddOrderPurchase(memberNum int, orderID uint, purchase []OrderPurch
return
}
func (d *DB) updateOrderPurchase(memberNum int, transaction *Transaction, total int, purchase []OrderPurchase) error {
totalDiff := -(transaction.Total + total)
transaction.Total = -total
transaction.Date = time.Now()
for i, p := range transaction.OrderPurchase {
for _, new_purchase := range purchase {
if new_purchase.ProductCode == p.ProductCode {
transaction.OrderPurchase[i].Amount = new_purchase.Amount
break
}
}
}
return d.db.Transaction(func(tx *gorm.DB) error {
err := updateMemberBalance(tx, memberNum, totalDiff)
if err != nil {
return err
}
return tx.Save(&transaction).Error
})
}
func (d *DB) DeactivateOrders() []Order {
var orders []Order
now := time.Now()
......
......@@ -137,24 +137,30 @@ func (d *DB) transactionQuery() *gorm.DB {
func createTransaction(db *gorm.DB, transaction *Transaction) error {
return db.Transaction(func(tx *gorm.DB) error {
var member Member
err := tx.Where("num = ?", transaction.MemberNum).Find(&member).Error
err := updateMemberBalance(tx, transaction.MemberNum, transaction.Total)
if err != nil {
log.Printf("Can't find member for transaction %d: %v", transaction.MemberNum, err)
return ErrorNotFound
}
if member.Balance < -transaction.Total {
log.Printf("Member %d don't have enough money (%d-%d)", member.Num, member.Balance, transaction.Total)
return ErrorInvalidRequest
}
err = tx.Model(&Member{}).
Where("num = ?", transaction.MemberNum).
Update("balance", gorm.Expr("balance + ?", transaction.Total)).Error
if err != nil {
log.Printf("Can't update update member balance %d-%d: %v", member.Num, transaction.Total, err)
return err
}
return tx.Create(&transaction).Error
})
}
func updateMemberBalance(tx *gorm.DB, memberNum int, amount int) error {
var member Member
err := tx.Where("num = ?", memberNum).Find(&member).Error
if err != nil {
log.Printf("Can't find member for transaction %d: %v", memberNum, err)
return ErrorNotFound
}
if member.Balance < -amount {
log.Printf("Member %d don't have enough money (%d-%d)", member.Num, member.Balance, amount)
return ErrorInvalidRequest
}
err = tx.Model(&Member{}).
Where("num = ?", memberNum).
Update("balance", gorm.Expr("balance + ?", amount)).Error
if err != nil {
log.Printf("Can't update update member balance %d-%d: %v", member.Num, amount, err)
}
return err
}
......@@ -17,11 +17,6 @@ type OrderGetResponse struct {
Transaction *db.Transaction `json:"transaction"`
}
type OrderPurchaseRequest struct {
Purchase []db.OrderPurchase `json:"purchase"`
OrderID uint `json:"order"`
}
func (a *api) refundOrders() {
const refundSleeptime = 10 * time.Minute
for {
......@@ -120,27 +115,29 @@ func (a *api) AddOrder(num int, w http.ResponseWriter, req *http.Request) {
}
func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request) {
var request OrderPurchaseRequest
err := json.NewDecoder(req.Body).Decode(&request)
vars := mux.Vars(req)
id, _ := strconv.Atoi(vars["id"])
var purchase []db.OrderPurchase
err := json.NewDecoder(req.Body).Decode(&purchase)
if err != nil {
log.Printf("Can't parse order purchase: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if len(request.Purchase) == 0 {
if len(purchase) == 0 {
log.Printf("Empty order purchase")
w.WriteHeader(http.StatusBadRequest)
return
}
transaction, err := a.db.AddOrderPurchase(num, request.OrderID, request.Purchase)
transaction, err := a.db.AddOrderPurchase(num, id, purchase)
if err != nil {
if errors.Is(err, db.ErrorNotFound) {
w.WriteHeader(http.StatusNotAcceptable)
} else if errors.Is(err, db.ErrorInvalidRequest) {
w.WriteHeader(http.StatusBadRequest)
} else {
log.Printf("Can't get order %d: %v", request.OrderID, err)
log.Printf("Can't get order %d: %v", id, err)
w.WriteHeader(http.StatusInternalServerError)
}
return
......@@ -152,6 +149,5 @@ func (a *api) AddOrderPurchase(num int, w http.ResponseWriter, req *http.Request
if err != nil {
log.Printf("Can't encode order transaction: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
package api
import (
"fmt"
"net/http"
"path"
"strconv"
......@@ -77,16 +78,13 @@ func TestOrderPurchase(t *testing.T) {
t.Fatal("Can't get orders:", resp.Status)
}
purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
purchase := []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
}
resp = tapi.do("POST", "/order/purchase", purchase, nil)
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)
}
......@@ -176,16 +174,13 @@ func TestOrderDeactivation(t *testing.T) {
t.Fatal("Didn't find my new order")
}
purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
purchase := []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
}
resp = tapi.doAdmin("POST", "/order/purchase", purchase, nil)
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:", resp.Status)
}
......@@ -263,16 +258,13 @@ func TestGetOrder(t *testing.T) {
t.Error("Wrong name:", body.Order.Name)
}
purchase := OrderPurchaseRequest{
OrderID: orders[0].ID,
Purchase: []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
purchase := []db.OrderPurchase{
{
ProductCode: testProduct.Code,
Amount: 3,
},
}
resp = tapi.do("POST", "/order/purchase", purchase, nil)
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)
}
......@@ -289,6 +281,66 @@ func TestGetOrder(t *testing.T) {
}
}
func TestUpdateOrderPurchase(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{
{
ProductCode: testProduct.Code,
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)
}
purchase[0].Amount = 2
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)
}
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 := 2 * testProduct.Price
if transactions[0].Total != -total {
t.Fatal("Wrong total", transactions[0].Total)
}
resp = tapi.do("GET", "/order/active", nil, &orders)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get orders:", resp.Status)
}
if len(orders[0].Transactions[0].OrderPurchase) != 1 {
t.Fatal("Wrong number of product purchases:", orders[0].Transactions[0].OrderPurchase)
}
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 (tapi *testAPI) addTestOrder() {
resp := tapi.do("POST", "/order", testOrder, nil)
if resp.StatusCode != http.StatusCreated {
......
......@@ -49,12 +49,9 @@ class PurchaseOrder extends React.Component {
amount: parseInt(p.amount),
};
});
const body = JSON.stringify({
order: this.props.order.ID,
purchase,
});
const body = JSON.stringify(purchase);
console.log(body);
fetch("/api/order/purchase", {
fetch("/api/order/" + this.props.order.ID + "purchase", {
headers: { "x-authentication": this.context.token },
method: "POST",
body,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment