Initial commit
This commit is contained in:
322
server/internal/handler/order_settle.go
Normal file
322
server/internal/handler/order_settle.go
Normal file
@@ -0,0 +1,322 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user