ded24ddccc
- 用户管理: 显示资格数和消费金额,支持编辑资格 - 订单管理: 添加订单详情查看功能 - 后端: AdminGetUsers返回消费金额, AdminGetByID获取订单详情 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
649 lines
19 KiB
Go
649 lines
19 KiB
Go
package handlers
|
|
|
|
import (
|
|
"math"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"sale/internal/models"
|
|
"sale/internal/schemas"
|
|
"sale/internal/utils"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type CartHandler struct{}
|
|
|
|
func NewCartHandler() *CartHandler {
|
|
return &CartHandler{}
|
|
}
|
|
|
|
func (h *CartHandler) List(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var carts []models.Cart
|
|
utils.DB.Where("user_id = ?", userID).Preload("Product").Find(&carts)
|
|
c.JSON(http.StatusOK, gin.H{"data": carts})
|
|
}
|
|
|
|
func (h *CartHandler) Add(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req schemas.AddToCartRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// 获取商品信息
|
|
var product models.Product
|
|
if err := utils.DB.First(&product, req.ProductID).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Product not found"})
|
|
return
|
|
}
|
|
|
|
// 检查商品是否上架
|
|
if !product.IsActive {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Product is not available"})
|
|
return
|
|
}
|
|
|
|
// 检查购物资格(需要资格的商品,每个订单消耗1个资格)
|
|
if product.RequireCredit {
|
|
var user models.User
|
|
utils.DB.First(&user, userID)
|
|
if user.PurchaseCredits < 1 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient purchase credits. This product requires 1 credit per order."})
|
|
return
|
|
}
|
|
}
|
|
|
|
// 检查库存
|
|
var inventory models.Inventory
|
|
if err := utils.DB.Where("product_id = ?", req.ProductID).First(&inventory).Error; err == nil {
|
|
if inventory.Quantity < req.Quantity {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock. Available: " + strconv.Itoa(inventory.Quantity)})
|
|
return
|
|
}
|
|
}
|
|
|
|
// 检查购物车中是否已存在该商品
|
|
var existingCart models.Cart
|
|
var totalQuantity int
|
|
result := utils.DB.Where("user_id = ? AND product_id = ?", userID, req.ProductID).First(&existingCart)
|
|
if result.Error == nil {
|
|
totalQuantity = existingCart.Quantity + req.Quantity
|
|
} else {
|
|
totalQuantity = req.Quantity
|
|
}
|
|
|
|
// 检查最大购买数量
|
|
if product.MaxPurchase != nil && *product.MaxPurchase > 0 && totalQuantity > *product.MaxPurchase {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Maximum purchase quantity is " + strconv.Itoa(*product.MaxPurchase)})
|
|
return
|
|
}
|
|
|
|
// 添加或更新购物车
|
|
var cart models.Cart
|
|
if result.Error == nil {
|
|
existingCart.Quantity = totalQuantity
|
|
utils.DB.Save(&existingCart)
|
|
cart = existingCart
|
|
} else {
|
|
cart = models.Cart{
|
|
UserID: userID,
|
|
ProductID: req.ProductID,
|
|
Quantity: req.Quantity,
|
|
}
|
|
utils.DB.Create(&cart)
|
|
}
|
|
|
|
utils.DB.Preload("Product").First(&cart, cart.ID)
|
|
c.JSON(http.StatusOK, gin.H{"data": cart})
|
|
}
|
|
|
|
func (h *CartHandler) Update(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var cart models.Cart
|
|
if err := utils.DB.Where("id = ? AND user_id = ?", id, userID).First(&cart).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Cart item not found"})
|
|
return
|
|
}
|
|
|
|
var req schemas.UpdateCartRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
cart.Quantity = req.Quantity
|
|
utils.DB.Save(&cart)
|
|
utils.DB.Preload("Product").First(&cart, cart.ID)
|
|
c.JSON(http.StatusOK, gin.H{"data": cart})
|
|
}
|
|
|
|
func (h *CartHandler) Delete(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
if err := utils.DB.Where("id = ? AND user_id = ?", id, userID).Delete(&models.Cart{}).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete cart item"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Cart item deleted successfully"})
|
|
}
|
|
|
|
type OrderHandler struct{}
|
|
|
|
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 + 1"))
|
|
}
|
|
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")
|
|
|
|
var orders []models.Order
|
|
query := utils.DB.Model(&models.Order{})
|
|
|
|
if role == "user" {
|
|
query = query.Where("user_id = ?", userID)
|
|
} else if role == "supplier" {
|
|
query = query.Where("supplier_id = ?", userID)
|
|
}
|
|
|
|
query.Preload("OrderItems.Product").Preload("ShippingAddress").
|
|
Order("created_at DESC").Find(&orders)
|
|
|
|
checkOrdersExpired(orders)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": orders})
|
|
}
|
|
|
|
func (h *OrderHandler) GetByID(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
role, _ := c.Get("role")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
query := utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").Preload("User")
|
|
|
|
if role == "user" {
|
|
query = query.Where("user_id = ?", userID)
|
|
} else if role == "supplier" {
|
|
query = query.Where("supplier_id = ?", userID)
|
|
}
|
|
|
|
if err := query.First(&order, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
checkOrderExpired(&order)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": order})
|
|
}
|
|
|
|
func (h *OrderHandler) Create(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req schemas.CreateOrderRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
var carts []models.Cart
|
|
cartQuery := utils.DB.Where("user_id = ?", userID).Preload("Product")
|
|
if len(req.CartItemIDs) > 0 {
|
|
cartQuery = cartQuery.Where("id IN ?", req.CartItemIDs)
|
|
}
|
|
cartQuery.Find(&carts)
|
|
|
|
if len(carts) == 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Cart is empty"})
|
|
return
|
|
}
|
|
|
|
var subtotal float64
|
|
var totalQuantity int
|
|
var orderItems []models.OrderItem
|
|
supplierMap := make(map[uint]bool)
|
|
|
|
for _, cart := range carts {
|
|
if !cart.Product.IsActive {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Product " + cart.Product.Name + " is no longer available"})
|
|
return
|
|
}
|
|
|
|
if cart.Product.MinPurchase > 0 && cart.Quantity < cart.Product.MinPurchase {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": cart.Product.Name + " minimum purchase is " + strconv.Itoa(cart.Product.MinPurchase)})
|
|
return
|
|
}
|
|
if cart.Product.MaxPurchase != nil && *cart.Product.MaxPurchase > 0 && cart.Quantity > *cart.Product.MaxPurchase {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": cart.Product.Name + " maximum purchase is " + strconv.Itoa(*cart.Product.MaxPurchase)})
|
|
return
|
|
}
|
|
|
|
if cart.Product.RequireCredit {
|
|
var user models.User
|
|
utils.DB.First(&user, userID)
|
|
if user.PurchaseCredits < 1 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient purchase credits for " + cart.Product.Name})
|
|
return
|
|
}
|
|
}
|
|
|
|
var inventory models.Inventory
|
|
if err := utils.DB.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err == nil {
|
|
if inventory.Quantity < cart.Quantity {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock for " + cart.Product.Name})
|
|
return
|
|
}
|
|
}
|
|
|
|
subtotal += cart.Product.Price * float64(cart.Quantity)
|
|
totalQuantity += cart.Quantity
|
|
orderItems = append(orderItems, models.OrderItem{
|
|
ProductID: cart.ProductID,
|
|
Quantity: cart.Quantity,
|
|
Price: cart.Product.Price,
|
|
})
|
|
|
|
if inventory.SupplierID != 0 {
|
|
supplierMap[inventory.SupplierID] = true
|
|
}
|
|
}
|
|
|
|
var supplierID *uint
|
|
for sid := range supplierMap {
|
|
sid := sid
|
|
supplierID = &sid
|
|
break
|
|
}
|
|
|
|
var shippingFeeFirstWeight, shippingFeePerGram, serviceFeeRate, taxRate float64
|
|
var setting models.SystemSetting
|
|
if err := utils.DB.Where("`key` = ?", "shipping_fee_first_weight").First(&setting).Error; err == nil {
|
|
shippingFeeFirstWeight, _ = strconv.ParseFloat(setting.Value, 64)
|
|
}
|
|
if err := utils.DB.Where("`key` = ?", "shipping_fee_per_gram").First(&setting).Error; err == nil {
|
|
shippingFeePerGram, _ = strconv.ParseFloat(setting.Value, 64)
|
|
}
|
|
if err := utils.DB.Where("`key` = ?", "service_fee_rate").First(&setting).Error; err == nil {
|
|
serviceFeeRate, _ = strconv.ParseFloat(setting.Value, 64)
|
|
}
|
|
if err := utils.DB.Where("`key` = ?", "tax_rate").First(&setting).Error; err == nil {
|
|
taxRate, _ = strconv.ParseFloat(setting.Value, 64)
|
|
}
|
|
|
|
shippingFee := shippingFeeFirstWeight
|
|
if subtotal >= 99 || shippingFeeFirstWeight == 0 {
|
|
shippingFee = 0
|
|
} else if totalQuantity > 500 {
|
|
shippingFee += shippingFeePerGram * float64(totalQuantity-500)
|
|
}
|
|
|
|
serviceFee := subtotal * serviceFeeRate / 100
|
|
tax := subtotal * taxRate / 100
|
|
totalAmount := subtotal + shippingFee + serviceFee + tax
|
|
|
|
order := models.Order{
|
|
UserID: userID,
|
|
SupplierID: supplierID,
|
|
Subtotal: subtotal,
|
|
ShippingFee: shippingFee,
|
|
ServiceFee: serviceFee,
|
|
Tax: tax,
|
|
TotalAmount: totalAmount,
|
|
Status: models.OrderStatusPendingPayment,
|
|
ShippingAddressID: &req.ShippingAddressID,
|
|
PaymentMethod: req.PaymentMethod,
|
|
}
|
|
|
|
tx := utils.DB.Begin()
|
|
if err := tx.Create(&order).Error; err != nil {
|
|
tx.Rollback()
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create order"})
|
|
return
|
|
}
|
|
|
|
for i := range orderItems {
|
|
orderItems[i].OrderID = order.ID
|
|
}
|
|
if err := tx.Create(&orderItems).Error; err != nil {
|
|
tx.Rollback()
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create order items"})
|
|
return
|
|
}
|
|
|
|
for _, cart := range carts {
|
|
if cart.Product.RequireCredit {
|
|
if err := tx.Model(&models.User{}).Where("id = ?", userID).
|
|
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits - 1")).Error; err != nil {
|
|
tx.Rollback()
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to deduct credits"})
|
|
return
|
|
}
|
|
}
|
|
if cart.Product.CreditReward > 0 {
|
|
tx.Model(&models.User{}).Where("id = ?", userID).
|
|
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits + ?", cart.Product.CreditReward*cart.Quantity))
|
|
}
|
|
|
|
var inventory models.Inventory
|
|
if err := tx.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err == nil {
|
|
if inventory.Quantity >= cart.Quantity {
|
|
tx.Model(&inventory).UpdateColumn("quantity", inventory.Quantity-cart.Quantity)
|
|
}
|
|
}
|
|
}
|
|
|
|
cartIDs := make([]uint, len(carts))
|
|
for i, cart := range carts {
|
|
cartIDs[i] = cart.ID
|
|
}
|
|
if err := tx.Where("id IN ? AND user_id = ?", cartIDs, userID).Delete(&models.Cart{}).Error; err != nil {
|
|
tx.Rollback()
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to clear cart"})
|
|
return
|
|
}
|
|
|
|
tx.Commit()
|
|
|
|
utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").First(&order, order.ID)
|
|
c.JSON(http.StatusCreated, gin.H{"data": order})
|
|
}
|
|
|
|
func (h *OrderHandler) Refund(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Where("id = ? AND user_id = ?", id, userID).First(&order).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
if order.Status == models.OrderStatusShipped || order.Status == models.OrderStatusCompleted {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot refund a shipped or completed order"})
|
|
return
|
|
}
|
|
|
|
if order.RefundStatus == models.RefundStatusPending {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Refund already requested"})
|
|
return
|
|
}
|
|
|
|
var req schemas.RefundRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
utils.DB.Model(&order).Updates(map[string]interface{}{
|
|
"refund_status": models.RefundStatusPending,
|
|
"refund_reason": req.Reason,
|
|
"status": models.OrderStatusRefunding,
|
|
})
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Refund request submitted successfully"})
|
|
}
|
|
|
|
func (h *OrderHandler) ConfirmOrder(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Where("id = ? AND supplier_id = ?", id, userID).First(&order).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
if order.Status != models.OrderStatusPendingConfirm {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Order cannot be confirmed"})
|
|
return
|
|
}
|
|
|
|
utils.DB.Model(&order).Update("status", models.OrderStatusPendingShip)
|
|
c.JSON(http.StatusOK, gin.H{"message": "Order confirmed successfully"})
|
|
}
|
|
|
|
func (h *OrderHandler) ShipOrder(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Where("id = ? AND supplier_id = ?", id, userID).First(&order).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
if order.Status != models.OrderStatusPendingShip {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Order cannot be shipped"})
|
|
return
|
|
}
|
|
|
|
var req schemas.ShipOrderRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
utils.DB.Model(&order).Updates(map[string]interface{}{
|
|
"status": models.OrderStatusShipped,
|
|
"tracking_number": req.TrackingNumber,
|
|
"shipping_photo": req.ShippingPhoto,
|
|
"express_photo": req.ExpressPhoto,
|
|
"customs_photo": req.CustomsPhoto,
|
|
})
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Order shipped successfully"})
|
|
}
|
|
|
|
func (h *OrderHandler) AdminList(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
var total int64
|
|
utils.DB.Model(&models.Order{}).Count(&total)
|
|
|
|
var orders []models.Order
|
|
offset := (page - 1) * pageSize
|
|
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,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total": total,
|
|
"total_pages": totalPages,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (h *OrderHandler) AdminGetByID(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").Preload("User").First(&order, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
checkOrderExpired(&order)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": order})
|
|
}
|
|
|
|
func (h *OrderHandler) ProcessRefund(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Preload("OrderItems").First(&order, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
var req schemas.ProcessRefundRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if req.Status == "approved" {
|
|
var setting models.SystemSetting
|
|
feeRate := 0.0
|
|
if err := utils.DB.Where("`key` = ?", "payment_channel_fee_rate").First(&setting).Error; err == nil {
|
|
feeRate, _ = strconv.ParseFloat(setting.Value, 64)
|
|
}
|
|
|
|
refundAmount := order.TotalAmount * (1 - feeRate/100)
|
|
|
|
tx := utils.DB.Begin()
|
|
|
|
tx.Model(&order).Updates(map[string]interface{}{
|
|
"refund_status": models.RefundStatusCompleted,
|
|
"refund_amount": refundAmount,
|
|
"status": models.OrderStatusRefunded,
|
|
})
|
|
|
|
for _, item := range order.OrderItems {
|
|
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 + 1"))
|
|
}
|
|
if product.CreditReward > 0 {
|
|
tx.Model(&models.User{}).Where("id = ?", order.UserID).
|
|
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits - ?", product.CreditReward*item.Quantity))
|
|
}
|
|
}
|
|
|
|
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()
|
|
} else {
|
|
utils.DB.Model(&order).Updates(map[string]interface{}{
|
|
"refund_status": models.RefundStatusRejected,
|
|
"status": models.OrderStatusPendingConfirm,
|
|
})
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Refund processed successfully"})
|
|
}
|
|
|
|
func (h *OrderHandler) Export(c *gin.Context) {
|
|
var orders []models.Order
|
|
utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").Preload("User").
|
|
Order("created_at DESC").Find(&orders)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": orders})
|
|
}
|
|
|
|
func (h *OrderHandler) CancelOrder(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Preload("OrderItems").Where("id = ? AND user_id = ?", id, userID).First(&order).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
if order.Status != models.OrderStatusPendingPayment && order.Status != models.OrderStatusPendingConfirm {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Order cannot be cancelled"})
|
|
return
|
|
}
|
|
|
|
tx := utils.DB.Begin()
|
|
tx.Model(&order).Update("status", models.OrderStatusCancelled)
|
|
|
|
for _, item := range order.OrderItems {
|
|
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 + 1"))
|
|
}
|
|
if product.CreditReward > 0 {
|
|
tx.Model(&models.User{}).Where("id = ?", order.UserID).
|
|
UpdateColumn("purchase_credits", utils.DB.Raw("purchase_credits - ?", product.CreditReward*item.Quantity))
|
|
}
|
|
}
|
|
|
|
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.StatusOK, gin.H{"message": "Order cancelled successfully"})
|
|
}
|
|
|
|
func (h *OrderHandler) ConfirmReceipt(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
|
|
var order models.Order
|
|
if err := utils.DB.Where("id = ? AND user_id = ?", id, userID).First(&order).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
|
return
|
|
}
|
|
|
|
if order.Status != models.OrderStatusShipped {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Order cannot be confirmed"})
|
|
return
|
|
}
|
|
|
|
utils.DB.Model(&order).Update("status", models.OrderStatusCompleted)
|
|
c.JSON(http.StatusOK, gin.H{"message": "Order confirmed successfully"})
|
|
}
|