Select Git revision
.python-version
order.go 5.95 KiB
package db
import (
"errors"
"log"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Order struct {
gorm.Model
Name string `json:"name"`
Description string `json:"description"`
MemberNum int `json:"member_num" gorm:"column:member"`
Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
Deadline time.Time `json:"deadline"`
Active bool `json:"active" gorm:"index"`
Products []Product `json:"products" gorm:"many2many:order_products;References:Code;JoinReferences:ProductCode"`
Transactions []Transaction `json:"transactions" gorm:"foreignKey:OrderID"`
TransactionID *uint `json:"-" gorm:"column:transaction"`
}
type OrderPurchase struct {
gorm.Model `json:"-"`
TransactionID uint `json:"-"`
ProductCode int `json:"product_code"`
Product *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
Price int `json:"price"`
Amount int `json:"amount"`
}
func (d *DB) ListOrders(active bool) (orders []Order, err error) {
query := d.db.Preload(clause.Associations).
Preload("Transactions.OrderPurchase")
if active {
query = query.Where("active = ?", true)
}
err = query.Order("deadline desc").
Find(&orders).Error
return
}
func (d *DB) GetOrder(memberNum int, id int) (order Order, transaction Transaction, err error) {
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) {
err = ErrorNotFound
return
}
return
}
err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id).
Preload("OrderPurchase.Product").
Find(&transaction).Error
return
}
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 {
return
}
if !order.Active {
err = ErrorInvalidRequest
log.Printf("Order is not active %d: %v", order.ID, purchase)
return
}
total := 0
for i, p := range purchase {
found := false
for _, product := range order.Products {
if product.Code == p.ProductCode {
total += product.Price * p.Amount
purchase[i].Price = product.Price
found = true
break
}
}
if !found {
log.Printf("Order purchase product %d not in order: %v", p.ProductCode, purchase)
err = ErrorInvalidRequest
return
}
}
if transaction.ID != 0 {
err = d.updateOrderPurchase(memberNum, &transaction, total, purchase)
return
}
transaction = Transaction{
MemberNum: memberNum,
Total: -total,
Type: "order",
Date: time.Now(),
OrderPurchase: purchase,
OrderID: &order.ID,
}
err = createTransaction(d.db, &transaction)
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
}
for _, p := range transaction.OrderPurchase {
err = tx.Save(&p).Error
if err != nil {
return err
}
}
return tx.Save(&transaction).Error
})
}
func (d *DB) DeactivateOrders() []Order {
var orders []Order
now := time.Now()
t := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
err := d.db.Where("active = ? AND deadline < ?", true, t).
Preload("Member").
Preload("Transactions.OrderPurchase.Product").
Preload("Transactions.Member").
Find(&orders).Error
if err != nil {
log.Println("Error refunding orders:", err)
return []Order{}
}
var deactivatedOrders []Order
for _, order := range orders {
total := 0
for _, transaction := range order.Transactions {
for _, purchase := range transaction.OrderPurchase {
total += purchase.Price * purchase.Amount
}
}
transaction := Transaction{
MemberNum: order.MemberNum,
Date: time.Now(),
Type: "refund",
Total: total,
}
err = d.db.Transaction(func(tx *gorm.DB) error {
err := createTransaction(tx, &transaction)
if err != nil {
return err
}
return tx.Model(&Order{}).
Where("id = ?", order.ID).
Updates(map[string]interface{}{
"active": false,
"transaction": transaction.ID}).
Error
})
if err != nil {
log.Printf("Can't create refund: %v\n%v", err, order)
continue
}
deactivatedOrders = append(deactivatedOrders, order)
log.Println("Refund order", order.Name, total)
}
return deactivatedOrders
}