Newer
Older
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 []OrderProduct `json:"products"`
Transactions []Transaction `json:"transactions" gorm:"foreignKey:OrderID"`
TransactionID *uint `json:"-" gorm:"column:transaction"`
}
type OrderProduct struct {
gorm.Model
OrderID uint `json:"-"`
ProductCode int `json:"code"`
Product *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
Price int `json:"price"`
gorm.Model `json:"-"`
TransactionID uint `json:"-"`
OrderProductID uint `json:"order_product_id"`
OrderProduct *OrderProduct `json:"order_product" gorm:"constraint:OnDelete:CASCADE"`
}
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) ListOrderPicks(num int) (orders []Order, err error) {
err = d.db.Select("*, member = ? as member_selected", num).
Table("(?) as orders", d.db.Model(&Order{}).Order("deadline desc")).
Group("name").Order("member_selected desc, deadline desc").Limit(15).
Preload(clause.Associations).
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
}
err = d.db.Where("member = ? AND type = 'order' AND order_id = ?", memberNum, id).
Preload("OrderPurchase.OrderProduct.Product").
Find(&transaction).Error
return
}
func (d *DB) AddOrder(order *Order) error {
return d.db.Create(&order).Error
}
func (d *DB) UpdateOrder(memberNum int, id int, order *Order) error {
dbOrder, _, err := d.GetOrder(0, id)
return err
}
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 {
totalSum := 0
for i, t := range dbOrder.Transactions {
var transaction Transaction
err = tx.Preload("OrderPurchase.OrderProduct").First(&transaction, t.ID).Error
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 {
err = updateOrderTransaction(tx, int(*dbOrder.TransactionID), totalSum, &dbOrder)
if err != nil {
return err
}
}
dbOrder.Products = products
dbOrder.Transactions = []Transaction{}
return tx.Save(&dbOrder).Error
func updateOrderProducts(tx *gorm.DB, order Order, dbOrder Order) (products []OrderProduct, err error) {
for _, product := range order.Products {
dbProduct := findOrderProduct(product.ProductCode, dbOrder.Products)
if dbProduct != nil {
dbProduct.Price = product.Price
products = append(products, *dbProduct)
} else {
product.OrderID = uint(dbOrder.ID)
err = tx.Create(&product).Error
products = append(products, product)
}
if err != nil {
return
}
}
for _, product := range dbOrder.Products {
if findOrderProduct(product.ProductCode, order.Products) == nil {
err = tx.Where("order_product_id = ?", product.ID).Delete(&OrderPurchase{}).Error
if err != nil {
return
}
err = tx.Delete(&product).Error
if err != nil {
return
}
}
}
return
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
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) {
err = ErrorNotFound
}
return err
}
func (d *DB) DeleteOrder(memberNum int, id int) error {
order, _, err := d.GetOrder(0, id)
if err != nil {
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
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, err := calculateOrderPurchaseTotal(purchase, order.Products)
if err != nil {
return
transaction.Date = time.Now()
err = updateOrderPurchase(d.db, memberNum, &transaction, total, purchase)
transaction = Transaction{
MemberNum: memberNum,
Total: -total,
Type: "order",
Date: time.Now(),
OrderPurchase: purchase,
OrderID: &order.ID,
}
err = createTransaction(d.db, &transaction)
return
}
func calculateOrderPurchaseTotal(purchase []OrderPurchase, products []OrderProduct) (total int, err error) {
total = 0
for _, p := range purchase {
found := false
for _, product := range products {
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, products)
err = ErrorInvalidRequest
}
}
return total, err
}
func updateOrderPurchase(tx *gorm.DB, memberNum int, transaction *Transaction, total int, purchase []OrderPurchase) error {
totalDiff := -(transaction.Total + total)
transaction.Total = -total
var updatePurchases []OrderPurchase
var newPurchases []OrderPurchase
for _, new_purchase := range purchase {
found := false
for i, p := range transaction.OrderPurchase {
if new_purchase.OrderProductID == p.OrderProductID {
transaction.OrderPurchase[i].Amount = new_purchase.Amount
updatePurchases = append(updatePurchases, transaction.OrderPurchase[i])
found = true
if !found {
newPurchases = append(newPurchases, OrderPurchase{
Amount: new_purchase.Amount,
TransactionID: transaction.ID,
OrderProductID: new_purchase.OrderProductID,
})
}
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)
if err != nil {
return err
}
for _, p := range delPurchases {
err = tx.Delete(&p).Error
if err != nil {
return err
}
}
for _, p := range updatePurchases {
err = tx.Save(&p).Error
if err != nil {
return err
}
}
for _, p := range newPurchases {
err = tx.Create(&p).Error
if err != nil {
return err
}
}
func (d *DB) DeactivateOrders() []Order {
var orders []Order
err := d.db.Where("active = ? AND deadline < ?", true, now).
Preload("Transactions.OrderPurchase.OrderProduct.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.OrderProduct.Price * purchase.Amount
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
}
}
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
}