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

Work with transactions

parent 46a42d7f
Branches
Tags
No related merge requests found
......@@ -19,7 +19,7 @@ func initDB(dbPath string) (*gorm.DB, error) {
return nil, err
}
db.AutoMigrate(&Member{}, &Product{}, &PurchasedProduct{}, &Purchase{})
db.AutoMigrate(&Member{}, &Product{}, &Purchase{}, &Transaction{})
return db, err
}
......@@ -41,7 +41,7 @@ func Init(dbPath string, signKey string, r *mux.Router) error {
r.HandleFunc("/member/{num:[0-9]+}", a.auth(a.GetMember)).Methods("GET")
r.HandleFunc("/member/{num:[0-9]+}", a.auth(a.UpdateMember)).Methods("PUT")
r.HandleFunc("/member/{num:[0-9]+}", a.auth(a.DeleteMember)).Methods("DELETE")
r.HandleFunc("/member/{num:[0-9]+}/purchase", a.auth(a.GetMemberPurchases)).Methods("GET")
r.HandleFunc("/member/{num:[0-9]+}/purchase", a.auth(a.GetMemberTransactions)).Methods("GET")
r.HandleFunc("/product", a.auth(a.ListProducts)).Methods("GET")
r.HandleFunc("/product", a.auth(a.AddProduct)).Methods("POST")
......@@ -49,9 +49,10 @@ func Init(dbPath string, signKey string, r *mux.Router) error {
r.HandleFunc("/product/{code:[0-9]+}", a.auth(a.UpdateProduct)).Methods("PUT")
r.HandleFunc("/product/{code:[0-9]+}", a.auth(a.DeleteProduct)).Methods("DELETE")
r.HandleFunc("/purchase", a.auth(a.ListPurchases)).Methods("GET")
r.HandleFunc("/transaction", a.auth(a.ListTransactions)).Methods("GET")
r.HandleFunc("/transaction/{id:[0-9]+}", a.auth(a.GetTransaction)).Methods("GET")
r.HandleFunc("/transaction/mine", a.authNum(a.getTransactionsByMember)).Methods("GET")
r.HandleFunc("/purchase", a.authNum(a.AddPurchase)).Methods("POST")
r.HandleFunc("/purchase/{id:[0-9]+}", a.auth(a.GetPurchase)).Methods("GET")
r.HandleFunc("/purchase/mine", a.authNum(a.getPurchasesByMember)).Methods("GET")
return nil
}
......@@ -9,7 +9,7 @@ var testMember = Member{
Num: 10,
Name: "foo",
Email: "foo@example.com",
Balance: 2000,
Balance: 10000,
}
func TestMemberAddList(t *testing.T) {
......
......@@ -4,58 +4,30 @@ import (
"encoding/json"
"log"
"net/http"
"strconv"
"time"
"github.com/gorilla/mux"
"gorm.io/gorm"
)
type Purchase struct {
gorm.Model
MemberNum int `json:"member" gorm:"column:member"`
Member Member `json:"-" gorm:"foreignKey:MemberNum;references:Num"`
Date time.Time `json:"date"`
Total int `json:"total"`
Products []PurchasedProduct `json:"products"`
}
type PurchasedProduct struct {
gorm.Model `json:"-"`
PurchaseID int `json:"-" gorm:"column:purchase"`
ProductCode int `json:"product" gorm:"column:product"`
Product Product `gorm:"foreignKey:ProductCode;references:Code"`
Price int `json:"price"`
Ammount int `json:"ammount"`
}
func (a *api) ListPurchases(w http.ResponseWriter, req *http.Request) {
var purchases []Purchase
err := a.db.Preload("Products.Product").Find(&purchases).Error
if err != nil {
log.Printf("Can't list purchases: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(purchases)
if err != nil {
log.Printf("Can't encode purchases: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
gorm.Model `json:"-"`
TransactionID int `json:"-" gorm:"column:transaction"`
ProductCode int `json:"product" gorm:"column:product"`
Product Product `gorm:"foreignKey:ProductCode;references:Code"`
Price int `json:"price"`
Ammount int `json:"ammount"`
}
func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
var products []PurchasedProduct
err := json.NewDecoder(req.Body).Decode(&products)
var purchase []Purchase
err := json.NewDecoder(req.Body).Decode(&purchase)
if err != nil {
log.Printf("Can't create purchase: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
total := 0
for i, p := range products {
for i, p := range purchase {
var product Product
err = a.db.Where("code = ?", p.ProductCode).First(&product).Error
if err != nil {
......@@ -65,7 +37,7 @@ func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
}
total += product.Price * p.Ammount
products[i].Price = product.Price
purchase[i].Price = product.Price
}
var member Member
......@@ -76,7 +48,7 @@ func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
return
}
if member.Balance < total {
log.Printf("Member %d don't have enough money (%d-%d): %v", num, member.Balance, total, err)
log.Printf("Member %d don't have enough money (%d-%d)", num, member.Balance, total)
w.WriteHeader(http.StatusBadRequest)
return
}
......@@ -89,20 +61,21 @@ func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
return
}
purchase := Purchase{
transaction := Transaction{
MemberNum: num,
Date: time.Now(),
Products: products,
Purchase: purchase,
Type: "purchase",
Total: total,
}
err = a.db.Create(&purchase).Error
err = a.db.Create(&transaction).Error
if err != nil {
log.Printf("Can't create purchase: %v\n%v", err, purchase)
w.WriteHeader(http.StatusInternalServerError)
return
}
for _, p := range products {
for _, p := range purchase {
err := a.db.Model(&Product{}).
Where("code = ?", p.ProductCode).
Update("stock", gorm.Expr("stock - ?", p.Ammount)).Error
......@@ -113,60 +86,10 @@ func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(purchase)
err = json.NewEncoder(w).Encode(transaction)
if err != nil {
log.Printf("Can't encode added purchase: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
func (a *api) GetPurchase(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
var purchase Purchase
err := a.db.Where("id = ?", vars["id"]).
Preload("Products.Product").
First(&purchase).Error
if err != nil {
if err.Error() == "record not found" {
w.WriteHeader(http.StatusNotFound)
return
}
log.Printf("Can't get purchase %s: %v", vars["code"], err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(purchase)
if err != nil {
log.Printf("Can't encode purchase: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *api) GetMemberPurchases(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
num, _ := strconv.Atoi(vars["num"])
a.getPurchasesByMember(num, w, req)
}
func (a *api) getPurchasesByMember(num int, w http.ResponseWriter, req *http.Request) {
var purchases []Purchase
err := a.db.Where("member = ?", num).
Preload("Products.Product").
Find(&purchases).Error
if err != nil {
log.Printf("Can't list purchases: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(purchases)
if err != nil {
log.Printf("Can't encode purchases: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
......@@ -11,7 +11,7 @@ func TestPurchaseAddListMine(t *testing.T) {
tapi.addTestMember()
tapi.addTestProducts()
products := []PurchasedProduct{
products := []Purchase{
{
ProductCode: testProduct.Code,
Ammount: 5,
......@@ -21,26 +21,26 @@ func TestPurchaseAddListMine(t *testing.T) {
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create purchase:", resp.Status)
}
var purchases []Purchase
resp = tapi.do("GET", "/purchase/mine", nil, &purchases)
var transactions []Transaction
resp = tapi.do("GET", "/transaction/mine", nil, &transactions)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get purchases:", resp.Status)
t.Fatal("Can't get transactions:", resp.Status)
}
if len(purchases) != 1 {
t.Fatal("Wrong number of purchases", len(purchases), purchases)
if len(transactions) != 1 {
t.Fatal("Wrong number of transactions", len(transactions), transactions)
}
if purchases[0].Total != testProduct.Price*products[0].Ammount {
t.Error("Wrong total:", purchases[0].Total)
if transactions[0].Total != testProduct.Price*products[0].Ammount {
t.Error("Wrong total:", transactions[0].Total)
}
if len(purchases[0].Products) != 1 {
t.Fatal("Wrong number of products", len(purchases[0].Products), purchases[0].Products)
if len(transactions[0].Purchase) != 1 {
t.Fatal("Wrong number of products", len(transactions[0].Purchase), transactions[0].Purchase)
}
if purchases[0].Products[0].ProductCode != testProduct.Code {
t.Error("Wrong product code:", purchases[0].Products[0].ProductCode)
if transactions[0].Purchase[0].ProductCode != testProduct.Code {
t.Error("Wrong product code:", transactions[0].Purchase[0].ProductCode)
}
if purchases[0].Products[0].Price != testProduct.Price {
t.Error("Wrong product price:", purchases[0].Products[0].Price)
if transactions[0].Purchase[0].Price != testProduct.Price {
t.Error("Wrong product price:", transactions[0].Purchase[0].Price)
}
var product Product
......
package api
import (
"encoding/json"
"log"
"net/http"
"strconv"
"time"
"github.com/gorilla/mux"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Transaction struct {
gorm.Model
MemberNum int `json:"-" gorm:"column:member"`
Member Member `json:"member" gorm:"foreignKey:MemberNum;references:Num"`
Date time.Time `json:"date"`
Total int `json:"total"`
Type string `json:"type"`
Purchase []Purchase `json:"purchase"`
}
func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) {
var transactions []Transaction
err := a.db.Preload("Purchase.Product").
Preload(clause.Associations).
Find(&transactions).Error
if err != nil {
log.Printf("Can't list transactions: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(transactions)
if err != nil {
log.Printf("Can't encode transactions: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
func (a *api) GetTransaction(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
var transaction Transaction
err := a.db.Preload("Purchase.Product").
Preload(clause.Associations).
First(&transaction, vars["id"]).Error
if err != nil {
if err.Error() == "record not found" {
w.WriteHeader(http.StatusNotFound)
return
}
log.Printf("Can't get transaction %s: %v", vars["code"], err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(transaction)
if err != nil {
log.Printf("Can't encode transaction: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *api) GetMemberTransactions(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
num, _ := strconv.Atoi(vars["num"])
a.getTransactionsByMember(num, w, req)
}
func (a *api) getTransactionsByMember(num int, w http.ResponseWriter, req *http.Request) {
var transactions []Transaction
err := a.db.Where("member = ?", num).
Preload("Purchase.Product").
Preload(clause.Associations).
Find(&transactions).Error
if err != nil {
log.Printf("Can't list transactions: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(transactions)
if err != nil {
log.Printf("Can't encode transactions: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment