feat: 订单自动过期-查看时检查并取消超时订单,收银台倒计时结束自动取消

This commit is contained in:
2026-05-28 02:17:47 +08:00
parent 23badb4526
commit 38b03878e8
4 changed files with 74 additions and 8 deletions
+42
View File
@@ -4,6 +4,7 @@ import (
"math"
"net/http"
"strconv"
"time"
"sale/internal/models"
"sale/internal/schemas"
@@ -91,6 +92,41 @@ func NewOrderHandler() *OrderHandler {
return &OrderHandler{}
}
func checkOrderExpired(order *models.Order) {
if order.Status != models.OrderStatusPendingPayment || order.PaymentExpiresAt == nil {
return
}
if time.Now().After(*order.PaymentExpiresAt) {
tx := utils.DB.Begin()
tx.Model(order).Update("status", models.OrderStatusCancelled)
for _, item := range order.OrderItems {
var inventory models.Inventory
if err := tx.Where("product_id = ?", item.ProductID).First(&inventory).Error; err == nil {
tx.Model(&inventory).UpdateColumn("quantity", inventory.Quantity+item.Quantity)
}
var product models.Product
if err := tx.First(&product, item.ProductID).Error; err == nil {
if product.RequireCredit {
tx.Model(&models.User{}).Where("id = ?", order.UserID).
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits + ?", product.CreditCost*item.Quantity))
}
if product.CreditReward > 0 {
tx.Model(&models.User{}).Where("id = ?", order.UserID).
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits - ?", product.CreditReward*item.Quantity))
}
}
}
tx.Commit()
order.Status = models.OrderStatusCancelled
}
}
func checkOrdersExpired(orders []models.Order) {
for i := range orders {
checkOrderExpired(&orders[i])
}
}
func (h *OrderHandler) List(c *gin.Context) {
userID := c.GetUint("user_id")
role, _ := c.Get("role")
@@ -107,6 +143,8 @@ func (h *OrderHandler) List(c *gin.Context) {
query.Preload("OrderItems.Product").Preload("ShippingAddress").
Order("created_at DESC").Find(&orders)
checkOrdersExpired(orders)
c.JSON(http.StatusOK, gin.H{"data": orders})
}
@@ -129,6 +167,8 @@ func (h *OrderHandler) GetByID(c *gin.Context) {
return
}
checkOrderExpired(&order)
c.JSON(http.StatusOK, gin.H{"data": order})
}
@@ -400,6 +440,8 @@ func (h *OrderHandler) AdminList(c *gin.Context) {
utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").Preload("User").
Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&orders)
checkOrdersExpired(orders)
totalPages := int(math.Ceil(float64(total) / float64(pageSize)))
c.JSON(http.StatusOK, gin.H{
"data": orders,
+22 -2
View File
@@ -39,7 +39,7 @@ func (h *PaymentHandler) CreatePayment(c *gin.Context) {
orderID, _ := strconv.Atoi(c.Param("id"))
var order models.Order
if err := utils.DB.Where("id = ? AND user_id = ?", orderID, userID).First(&order).Error; err != nil {
if err := utils.DB.Preload("OrderItems").Where("id = ? AND user_id = ?", orderID, userID).First(&order).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
return
}
@@ -49,6 +49,20 @@ func (h *PaymentHandler) CreatePayment(c *gin.Context) {
return
}
if order.PaymentExpiresAt != nil && time.Now().After(*order.PaymentExpiresAt) {
tx := utils.DB.Begin()
tx.Model(&order).Update("status", models.OrderStatusCancelled)
for _, item := range order.OrderItems {
var inventory models.Inventory
if err := tx.Where("product_id = ?", item.ProductID).First(&inventory).Error; err == nil {
tx.Model(&inventory).UpdateColumn("quantity", inventory.Quantity+item.Quantity)
}
}
tx.Commit()
c.JSON(http.StatusBadRequest, gin.H{"error": "支付已超时,订单已取消"})
return
}
var channels []models.PaymentChannel
utils.DB.Where("is_enabled = ? AND type = ?", true, "bepusdt").Order("sort_order ASC").Find(&channels)
if len(channels) == 0 {
@@ -169,15 +183,21 @@ func (h *PaymentHandler) CreatePayment(c *gin.Context) {
}
var remainingSeconds int64
var expiresAt *time.Time
if expiration > 0 {
remainingSeconds = expiration - time.Now().Unix()
if remainingSeconds < 0 {
remainingSeconds = 0
}
if remainingSeconds > 0 {
t := time.Now().Add(time.Duration(remainingSeconds) * time.Second)
expiresAt = &t
}
}
utils.DB.Model(&order).Updates(map[string]interface{}{
"payment_method": "bepusdt",
"payment_method": "bepusdt",
"payment_expires_at": expiresAt,
})
paymentInfo := map[string]interface{}{