Files
ai_dianshang/server/internal/handler/order_settle.go
2025-11-17 14:11:46 +08:00

322 lines
11 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"dianshang/internal/service"
"dianshang/pkg/response"
"dianshang/pkg/utils"
"fmt"
"github.com/gin-gonic/gin"
)
// OrderSettleHandler 订单结算处理器
type OrderSettleHandler struct {
orderService *service.OrderService
productService *service.ProductService
userService *service.UserService
}
// NewOrderSettleHandler 创建订单结算处理器
func NewOrderSettleHandler(orderService *service.OrderService, productService *service.ProductService, userService *service.UserService) *OrderSettleHandler {
return &OrderSettleHandler{
orderService: orderService,
productService: productService,
userService: userService,
}
}
// SettleOrderRequest 订单结算请求
type SettleOrderRequest struct {
UserAddressReq *UserAddressRequest `json:"userAddressReq"`
CouponList []CouponRequest `json:"couponList"`
GoodsRequestList []GoodsRequest `json:"goodsRequestList"`
StoreInfoList []StoreInfo `json:"storeInfoList"` // 添加门店信息列表
}
// UserAddressRequest 用户地址请求
type UserAddressRequest struct {
AddressID uint `json:"addressId"`
Name string `json:"name"`
Phone string `json:"phone"`
Address string `json:"address"`
DetailAddress string `json:"detailAddress"` // 添加详细地址字段支持前端address-card组件
ProvinceCode string `json:"provinceCode"`
CityCode string `json:"cityCode"`
DistrictCode string `json:"districtCode"`
}
// CouponRequest 优惠券请求
type CouponRequest struct {
CouponID uint `json:"couponId"` // 优惠券模板ID
UserCouponID uint `json:"userCouponId"` // 用户优惠券ID (ai_user_coupons表的id)
Type int `json:"type"`
Value int `json:"value"`
Status string `json:"status"`
}
// StoreInfo 门店信息
type StoreInfo struct {
StoreID string `json:"storeId"`
StoreName string `json:"storeName"`
}
// GoodsRequest 商品请求
type GoodsRequest struct {
StoreID string `json:"storeId"`
SpuID string `json:"spuId"`
SkuID interface{} `json:"skuId"` // 改为interface{}以支持数字和字符串
Title string `json:"title"`
GoodsName string `json:"goodsName"` // 添加商品名称字段
PrimaryImage string `json:"primaryImage"`
Thumb string `json:"thumb"` // 添加缩略图字段
Quantity int `json:"quantity"`
Price int `json:"price"`
OriginPrice int `json:"originPrice"`
Available int `json:"available"` // 添加可用性字段
SpecInfo []SpecInfo `json:"specInfo"`
RoomID interface{} `json:"roomId"`
}
// SpecInfo 规格信息
type SpecInfo struct {
SpecID string `json:"specId"`
SpecTitle string `json:"specTitle"`
SpecValue string `json:"specValue"`
}
// SettleOrder 订单结算
func (h *OrderSettleHandler) SettleOrder(c *gin.Context) {
_, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
var req SettleOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误: "+err.Error())
return
}
// 验证商品信息并计算价格
var totalAmount float64
var totalGoodsCount int
var skuDetailVos []map[string]interface{}
for _, goods := range req.GoodsRequestList {
// 转换SkuID为字符串
var skuIDStr string
switch v := goods.SkuID.(type) {
case string:
skuIDStr = v
case float64:
skuIDStr = fmt.Sprintf("%.0f", v)
case int:
skuIDStr = fmt.Sprintf("%d", v)
default:
skuIDStr = fmt.Sprintf("%v", v)
}
spuID := utils.StringToUint(goods.SpuID)
if spuID == 0 {
response.BadRequest(c, "无效的商品ID: "+goods.SpuID)
return
}
// 获取商品信息
product, err := h.productService.GetProductDetail(spuID)
if err != nil {
response.BadRequest(c, "商品不存在: "+goods.SpuID)
return
}
// 检查库存
if product.Stock < goods.Quantity {
response.BadRequest(c, "商品库存不足: "+product.Name)
return
}
// 获取实际价格优先使用SKU价格如果没有SKU则使用SPU价格
var actualPrice float64
skuID := utils.StringToUint(skuIDStr)
if skuID > 0 {
// 根据SKU ID获取SKU详情和价格
sku, err := h.productService.GetSKUByID(skuID)
if err != nil {
// 如果SKU不存在使用SPU价格
actualPrice = product.Price
} else {
// 使用SKU价格
actualPrice = sku.Price
}
} else {
// 没有SKU ID使用SPU价格
actualPrice = product.Price
}
// 计算商品总价(数据库中价格以分为单位存储,直接计算)
itemTotal := actualPrice * float64(goods.Quantity)
totalAmount += itemTotal
totalGoodsCount += goods.Quantity
// 构建商品详情
skuDetail := map[string]interface{}{
"storeId": goods.StoreID,
"spuId": goods.SpuID,
"skuId": skuIDStr,
"goodsName": product.Name,
"image": product.MainImage,
"reminderStock": product.Stock,
"quantity": goods.Quantity,
"payPrice": actualPrice,
"totalSkuPrice": itemTotal,
"discountSettlePrice": actualPrice,
"realSettlePrice": actualPrice,
"settlePrice": actualPrice,
"oriPrice": actualPrice,
"tagPrice": nil,
"tagText": nil,
"skuSpecLst": goods.SpecInfo,
"promotionIds": nil,
"weight": 0.0,
"unit": "KG",
"volume": nil,
"masterGoodsType": 0,
"viceGoodsType": 0,
"roomId": goods.RoomID,
"egoodsName": nil,
}
skuDetailVos = append(skuDetailVos, skuDetail)
}
// 计算优惠券折扣
var totalCouponAmount float64
for _, coupon := range req.CouponList {
if coupon.Status == "default" {
if coupon.Type == 1 {
// 固定金额优惠券数据库中value以分为单位存储直接累加
totalCouponAmount += float64(coupon.Value)
} else if coupon.Type == 2 {
// 折扣优惠券 - 修复:计算折扣金额而不是最终价格
// 例如8折券(value=80)9900分商品的折扣金额 = 9900 * (100-80) / 100 = 1980分
totalCouponAmount += totalAmount * (100 - float64(coupon.Value)) / 100
}
}
}
// 计算最终支付金额
totalPromotionAmount := 0.0 // 暂时没有促销活动
totalDeliveryFee := 0.0 // 免运费
totalPayAmount := totalAmount - totalCouponAmount - totalPromotionAmount + totalDeliveryFee
// 获取用户地址信息
var userAddress interface{}
settleType := 0
if req.UserAddressReq != nil {
settleType = 1
// 如果有地址ID从数据库获取完整的地址信息
if req.UserAddressReq.AddressID > 0 {
userID, exists := c.Get("user_id")
if exists {
// 获取完整的地址信息
fullAddress, err := h.userService.GetAddressByID(userID.(uint), req.UserAddressReq.AddressID)
if err == nil && fullAddress != nil {
// 构建包含完整信息的地址对象
userAddress = map[string]interface{}{
"addressId": fullAddress.ID,
"name": fullAddress.Name,
"phone": fullAddress.Phone,
"address": fmt.Sprintf("%s%s%s%s", fullAddress.ProvinceName, fullAddress.CityName, fullAddress.DistrictName, fullAddress.DetailAddress),
"detailAddress": fullAddress.DetailAddress,
"provinceName": fullAddress.ProvinceName,
"cityName": fullAddress.CityName,
"districtName": fullAddress.DistrictName,
"provinceCode": req.UserAddressReq.ProvinceCode,
"cityCode": req.UserAddressReq.CityCode,
"districtCode": req.UserAddressReq.DistrictCode,
"isDefault": fullAddress.IsDefault,
}
} else {
// 如果获取失败,使用原始请求数据
userAddress = req.UserAddressReq
}
} else {
// 如果没有用户ID使用原始请求数据
userAddress = req.UserAddressReq
}
} else {
// 如果没有地址ID使用原始请求数据
userAddress = req.UserAddressReq
}
}
// 获取店铺信息
storeID := uint(1000) // 默认店铺ID实际应该从商品信息中获取
if len(req.GoodsRequestList) > 0 {
// 从第一个商品获取店铺ID
if storeIDFromGoods := utils.StringToUint(req.GoodsRequestList[0].StoreID); storeIDFromGoods > 0 {
storeID = storeIDFromGoods
}
}
// 动态获取店铺名称
storeName := "默认店铺" // 默认店铺名
store, err := h.productService.GetStoreByID(storeID)
if err == nil && store != nil {
storeName = store.Name
}
// 构建返回数据(前端期望接收以分为单位的金额字符串)
result := map[string]interface{}{
"settleType": settleType,
"userAddress": userAddress,
"totalGoodsCount": totalGoodsCount,
"packageCount": 1,
"totalAmount": utils.FloatToString(totalAmount), // 已经是分为单位
"totalPayAmount": utils.FloatToString(totalPayAmount), // 已经是分为单位
"totalDiscountAmount": "0",
"totalPromotionAmount": utils.FloatToString(totalPromotionAmount), // 已经是分为单位
"totalCouponAmount": utils.FloatToString(totalCouponAmount), // 已经是分为单位
"totalSalePrice": utils.FloatToString(totalAmount), // 已经是分为单位
"totalGoodsAmount": utils.FloatToString(totalAmount), // 已经是分为单位
"totalDeliveryFee": utils.FloatToString(totalDeliveryFee), // 已经是分为单位
"invoiceRequest": nil,
"skuImages": nil,
"deliveryFeeList": nil,
"storeGoodsList": []map[string]interface{}{
{
"storeId": fmt.Sprintf("%d", storeID),
"storeName": storeName,
"remark": nil,
"goodsCount": totalGoodsCount,
"deliveryFee": utils.FloatToString(totalDeliveryFee), // 已经是分为单位
"deliveryWords": nil,
"storeTotalAmount": utils.FloatToString(totalAmount), // 已经是分为单位
"storeTotalPayAmount": utils.FloatToString(totalPayAmount), // 已经是分为单位
"storeTotalDiscountAmount": "0",
"storeTotalCouponAmount": utils.FloatToString(totalCouponAmount), // 已经是分为单位
"skuDetailVos": skuDetailVos,
"couponList": func() []map[string]interface{} {
var couponList []map[string]interface{}
for _, coupon := range req.CouponList {
if coupon.Status == "default" {
couponList = append(couponList, map[string]interface{}{
"couponId": coupon.UserCouponID, // 使用用户优惠券ID
"storeId": fmt.Sprintf("%d", storeID),
})
}
}
return couponList
}(),
},
},
"inValidGoodsList": nil,
"outOfStockGoodsList": nil,
"limitGoodsList": nil,
"abnormalDeliveryGoodsList": nil,
"invoiceSupport": 1,
}
response.Success(c, result)
}