package logic import ( "context" "fmt" "time" "healthapi/internal/model" "healthapi/internal/svc" "healthapi/internal/types" "healthapi/pkg/errorx" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type CreateOrderLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic { return &CreateOrderLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq) (resp *types.Order, err error) { userID, err := GetUserIDFromCtx(l.ctx) if err != nil { return nil, errorx.ErrUnauthorized } // 获取用户信息(会员等级) var user model.User if err := l.svcCtx.DB.First(&user, userID).Error; err != nil { return nil, errorx.ErrUserNotFound } levelConfig := model.MemberLevelConfigs[user.MemberLevel] if levelConfig.Level == "" { levelConfig = model.MemberLevelConfigs[model.MemberLevelNormal] } // 验证收货地址 var address model.Address if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.AddressID, userID).First(&address).Error; err != nil { return nil, errorx.NewCodeError(404, "收货地址不存在") } // 获取购物车项 var cartItems []model.CartItem if err := l.svcCtx.DB.Where("id IN ? AND user_id = ?", req.CartItemIDs, userID).Find(&cartItems).Error; err != nil { return nil, err } if len(cartItems) == 0 { return nil, errorx.NewCodeError(400, "购物车为空") } // 计算订单金额 var totalAmount float64 orderItems := make([]model.OrderItem, 0, len(cartItems)) for _, cartItem := range cartItems { var product model.Product if err := l.svcCtx.DB.First(&product, cartItem.ProductID).Error; err != nil { return nil, errorx.NewCodeError(404, fmt.Sprintf("商品 %d 不存在", cartItem.ProductID)) } if !product.IsActive { return nil, errorx.NewCodeError(400, fmt.Sprintf("商品 %s 已下架", product.Name)) } price := product.Price stock := product.Stock skuName := "" image := product.MainImage if cartItem.SkuID > 0 { var sku model.ProductSku if err := l.svcCtx.DB.First(&sku, cartItem.SkuID).Error; err != nil { return nil, errorx.NewCodeError(404, "商品规格不存在") } price = sku.Price stock = sku.Stock skuName = sku.Name if sku.Image != "" { image = sku.Image } } if stock < cartItem.Quantity { return nil, errorx.NewCodeError(400, fmt.Sprintf("商品 %s 库存不足", product.Name)) } itemTotal := price * float64(cartItem.Quantity) totalAmount += itemTotal orderItems = append(orderItems, model.OrderItem{ ProductID: cartItem.ProductID, SkuID: cartItem.SkuID, ProductName: product.Name, SkuName: skuName, Image: image, Price: price, Quantity: cartItem.Quantity, TotalAmount: itemTotal, }) } // 计算会员折扣 discountAmount := totalAmount * (1 - levelConfig.Discount) // 计算运费 shippingFee := float64(0) afterDiscount := totalAmount - discountAmount if afterDiscount < levelConfig.FreeShippingMin { shippingFee = 10 // 默认运费 } // 计算积分抵扣(100积分=1元) pointsDiscount := float64(0) pointsUsed := req.PointsUsed if pointsUsed > 0 { if pointsUsed > user.Points { pointsUsed = user.Points } maxPointsDiscount := afterDiscount * 0.2 // 最多抵扣20% pointsDiscount = float64(pointsUsed) / 100 if pointsDiscount > maxPointsDiscount { pointsDiscount = maxPointsDiscount pointsUsed = int(maxPointsDiscount * 100) } } // 最终支付金额 payAmount := afterDiscount + shippingFee - pointsDiscount // 生成订单号 orderNo := fmt.Sprintf("%s%d%04d", time.Now().Format("20060102150405"), userID, time.Now().Nanosecond()%10000) // 计算获得积分 pointsEarned := int(payAmount * levelConfig.PointsMultiplier) // 创建订单(使用事务) order := model.Order{ UserID: userID, OrderNo: orderNo, Status: model.OrderStatusPending, TotalAmount: totalAmount, DiscountAmount: discountAmount, ShippingFee: shippingFee, PayAmount: payAmount, PointsUsed: pointsUsed, PointsEarned: pointsEarned, ReceiverName: address.ReceiverName, ReceiverPhone: address.Phone, ReceiverAddr: fmt.Sprintf("%s%s%s%s", address.Province, address.City, address.District, address.DetailAddr), Remark: req.Remark, } err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { // 创建订单 if err := tx.Create(&order).Error; err != nil { return err } // 创建订单项 for i := range orderItems { orderItems[i].OrderID = uint(order.ID) } if err := tx.Create(&orderItems).Error; err != nil { return err } // 扣减库存 for _, cartItem := range cartItems { if cartItem.SkuID > 0 { if err := tx.Model(&model.ProductSku{}).Where("id = ?", cartItem.SkuID). Update("stock", gorm.Expr("stock - ?", cartItem.Quantity)).Error; err != nil { return err } } else { if err := tx.Model(&model.Product{}).Where("id = ?", cartItem.ProductID). Update("stock", gorm.Expr("stock - ?", cartItem.Quantity)).Error; err != nil { return err } } } // 删除购物车项 if err := tx.Where("id IN ?", req.CartItemIDs).Delete(&model.CartItem{}).Error; err != nil { return err } // 扣除积分 if pointsUsed > 0 { if err := tx.Model(&user).Update("points", gorm.Expr("points - ?", pointsUsed)).Error; err != nil { return err } // 记录积分变动 tx.Create(&model.PointsRecord{ UserID: userID, Type: model.PointsTypeSpend, Points: -pointsUsed, Balance: user.Points - pointsUsed, Source: model.PointsSourceOrder, ReferenceID: uint(order.ID), Remark: fmt.Sprintf("订单 %s 使用积分", orderNo), }) } return nil }) if err != nil { return nil, err } // 构建响应 respItems := make([]types.OrderItem, 0, len(orderItems)) for _, item := range orderItems { respItems = append(respItems, types.OrderItem{ ID: uint(item.ID), ProductID: item.ProductID, SkuID: item.SkuID, ProductName: item.ProductName, SkuName: item.SkuName, Image: item.Image, Price: item.Price, Quantity: item.Quantity, TotalAmount: item.TotalAmount, }) } resp = &types.Order{ ID: uint(order.ID), OrderNo: order.OrderNo, Status: order.Status, TotalAmount: order.TotalAmount, DiscountAmount: order.DiscountAmount, ShippingFee: order.ShippingFee, PayAmount: order.PayAmount, PointsUsed: order.PointsUsed, PointsEarned: order.PointsEarned, ReceiverName: order.ReceiverName, ReceiverPhone: order.ReceiverPhone, ReceiverAddr: order.ReceiverAddr, Remark: order.Remark, Items: respItems, CreatedAt: order.CreatedAt.Format("2006-01-02 15:04:05"), } return resp, nil }