Skip to content
Snippets Groups Projects
Select Git revision
  • c63e80c5bb8bd2a96230b04bb8243804b2ecf051
  • main default protected
  • renovate/pre-commit-pre-commit-hooks-6.x
3 results

.python-version

Blame
  • 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
    }