transaction.go 3.93 KiB
package api
import (
"encoding/json"
"fmt"
"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,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
Date time.Time `json:"date"`
Total int `json:"total"`
Type string `json:"type"`
Purchase []Purchase `json:"purchase"`
Topup *Topup `json:"topup"`
Order []OrderPurchase `json:"order"`
Refund *Order `json:"refund"`
}
func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) {
var transactions []Transaction
err := a.db.Preload("Purchase.Product").
Preload(clause.Associations).
Order("date desc").
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(num int, role string, 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["id"], err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if transaction.MemberNum != num && role != "admin" {
w.WriteHeader(http.StatusUnauthorized)
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).
Order("date desc").
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 createTransaction(db *gorm.DB, transaction *Transaction) (httpStatus int, err error) {
httpStatus = http.StatusOK
err = db.Transaction(func(tx *gorm.DB) error {
var member Member
err := tx.Where("num = ?", transaction.MemberNum).Find(&member).Error
if err != nil {
httpStatus = http.StatusNotAcceptable
return fmt.Errorf("Can't find member %d: %v", transaction.MemberNum, err)
}
if member.Balance < -transaction.Total {
httpStatus = http.StatusBadRequest
return fmt.Errorf("Member %d don't have enough money (%d-%d)", member.Num, member.Balance, transaction.Total)
}
err = tx.Model(&Member{}).
Where("num = ?", transaction.MemberNum).
Update("balance", gorm.Expr("balance + ?", transaction.Total)).Error
if err != nil {
httpStatus = http.StatusNotAcceptable
fmt.Errorf("Can't update update member balance %d-%d: %v", member.Num, transaction.Total, err)
}
err = tx.Create(&transaction).Error
if err != nil {
httpStatus = http.StatusInternalServerError
return fmt.Errorf("Can't create transaction: %v\n%v", err, transaction)
}
return nil
})
return
}