订单总价和订单明细单价在代购/成本价场景会不一致,已改为同一套价格来源并支持多套餐求和
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m24s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m24s
This commit is contained in:
@@ -207,10 +207,20 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
seriesID = validationResult.Device.SeriesID
|
||||
}
|
||||
|
||||
// 先按零售价构建明细价格快照,后续在代购/成本价场景覆盖
|
||||
sellerShopIDValue := uint(0)
|
||||
if resourceShopID != nil {
|
||||
sellerShopIDValue = *resourceShopID
|
||||
}
|
||||
itemUnitPriceMap, retailTotalAmount, err := s.buildRetailPriceMap(ctx, validationResult.Packages, sellerShopIDValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 初始化订单字段
|
||||
orderBuyerType := buyerType
|
||||
orderBuyerID := buyerID
|
||||
totalAmount := validationResult.TotalPrice
|
||||
totalAmount := retailTotalAmount
|
||||
paymentMethod := req.PaymentMethod
|
||||
paymentStatus := model.PaymentStatusPaid
|
||||
var paidAt *time.Time
|
||||
@@ -244,18 +254,19 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
actualPaidAmount = nil
|
||||
} else {
|
||||
// ==== 子场景 1.2:平台代购(资源属于代理商,平台代为购买)====
|
||||
purchaseBuyerID, buyerCostPrice, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
|
||||
purchaseBuyerID, buyerCostPriceMap, buyerTotalCost, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = purchaseBuyerID
|
||||
totalAmount = buyerCostPrice
|
||||
itemUnitPriceMap = buyerCostPriceMap
|
||||
totalAmount = buyerTotalCost
|
||||
paymentMethod = model.PaymentMethodOffline
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = purchasePaidAt
|
||||
isPurchaseOnBehalf = true
|
||||
sellerCostPrice = buyerCostPrice
|
||||
sellerCostPrice = buyerTotalCost
|
||||
|
||||
// 设置操作者信息(平台代购)
|
||||
operatorID = nil
|
||||
@@ -277,22 +288,17 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
return nil, errors.New(errors.CodeInternalError, "资源店铺ID为空")
|
||||
}
|
||||
|
||||
// 获取第一个套餐ID用于查询成本价
|
||||
if len(validationResult.Packages) == 0 {
|
||||
return nil, errors.New(errors.CodeInternalError, "套餐列表为空")
|
||||
}
|
||||
firstPackageID := validationResult.Packages[0].ID
|
||||
|
||||
if *resourceShopID == operatorShopID {
|
||||
// ==== 子场景 2.1:代理自购 ====
|
||||
costPrice, err := s.getCostPrice(ctx, operatorShopID, firstPackageID)
|
||||
operatorCostPriceMap, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = operatorShopID
|
||||
totalAmount = costPrice
|
||||
itemUnitPriceMap = operatorCostPriceMap
|
||||
totalAmount = operatorTotalCost
|
||||
paymentMethod = model.PaymentMethodWallet
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = &now
|
||||
@@ -300,28 +306,29 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
|
||||
operatorID = &operatorShopID
|
||||
operatorType = "agent"
|
||||
actualPaidAmountVal := costPrice
|
||||
actualPaidAmountVal := operatorTotalCost
|
||||
actualPaidAmount = &actualPaidAmountVal
|
||||
purchaseRole = model.PurchaseRoleSelfPurchase
|
||||
sellerCostPrice = costPrice
|
||||
sellerCostPrice = operatorTotalCost
|
||||
|
||||
} else {
|
||||
// ==== 子场景 2.2:代理代购(给下级购买)====
|
||||
// 获取买家成本价
|
||||
buyerCostPrice, err := s.getCostPrice(ctx, *resourceShopID, firstPackageID)
|
||||
buyerCostPriceMap, buyerTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, *resourceShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取操作者成本价
|
||||
operatorCostPrice, err := s.getCostPrice(ctx, operatorShopID, firstPackageID)
|
||||
_, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = *resourceShopID
|
||||
totalAmount = buyerCostPrice
|
||||
itemUnitPriceMap = buyerCostPriceMap
|
||||
totalAmount = buyerTotalCost
|
||||
paymentMethod = model.PaymentMethodWallet
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = &now
|
||||
@@ -329,10 +336,11 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
|
||||
operatorID = &operatorShopID
|
||||
operatorType = "agent"
|
||||
actualPaidAmount = &operatorCostPrice
|
||||
actualPaidAmountVal := operatorTotalCost
|
||||
actualPaidAmount = &actualPaidAmountVal
|
||||
purchaseRole = model.PurchaseRolePurchaseForSubordinate
|
||||
// 代理代购下级时,佣金差额基准应是操作方(代理自己)的成本价,而非下级的成本价
|
||||
sellerCostPrice = operatorCostPrice
|
||||
sellerCostPrice = operatorTotalCost
|
||||
}
|
||||
} else {
|
||||
// 兜底检查:后台不支持其他支付方式(DTO 验证已拒绝,此为防御性编程)
|
||||
@@ -407,7 +415,7 @@ func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrde
|
||||
order.BuyerPhone, order.BuyerNickname = s.fetchBuyerSnapshot(ctx, orderBuyerID)
|
||||
}
|
||||
|
||||
items := s.buildOrderItems(userID, validationResult.Packages)
|
||||
items := s.buildOrderItems(userID, validationResult.Packages, itemUnitPriceMap)
|
||||
|
||||
idempotencyKey := buildOrderIdempotencyKey(buyerType, buyerID, orderType, carrierType, carrierID, req.PackageIDs)
|
||||
|
||||
@@ -502,10 +510,20 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
seriesID = validationResult.Device.SeriesID
|
||||
}
|
||||
|
||||
// 先按零售价构建明细价格快照,后续在代购/成本价场景覆盖
|
||||
sellerShopIDValue := uint(0)
|
||||
if resourceShopID != nil {
|
||||
sellerShopIDValue = *resourceShopID
|
||||
}
|
||||
itemUnitPriceMap, retailTotalAmount, err := s.buildRetailPriceMap(ctx, validationResult.Packages, sellerShopIDValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 初始化订单字段
|
||||
orderBuyerType := buyerType
|
||||
orderBuyerID := buyerID
|
||||
totalAmount := validationResult.TotalPrice
|
||||
totalAmount := retailTotalAmount
|
||||
paymentMethod := req.PaymentMethod
|
||||
paymentStatus := model.PaymentStatusPending
|
||||
var paidAt *time.Time
|
||||
@@ -522,18 +540,19 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
// 场景判断:offline(平台代购)、wallet(代理钱包支付)、其他(待支付)
|
||||
if req.PaymentMethod == model.PaymentMethodOffline {
|
||||
// ==== 场景 1:平台代购(offline)====
|
||||
purchaseBuyerID, buyerCostPrice, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
|
||||
purchaseBuyerID, buyerCostPriceMap, buyerTotalCost, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = purchaseBuyerID
|
||||
totalAmount = buyerCostPrice
|
||||
itemUnitPriceMap = buyerCostPriceMap
|
||||
totalAmount = buyerTotalCost
|
||||
paymentMethod = model.PaymentMethodOffline
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = purchasePaidAt
|
||||
isPurchaseOnBehalf = true
|
||||
sellerCostPrice = buyerCostPrice
|
||||
sellerCostPrice = buyerTotalCost
|
||||
|
||||
// 设置操作者信息(平台代购)
|
||||
operatorID = nil
|
||||
@@ -554,22 +573,17 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
return nil, errors.New(errors.CodeInternalError, "资源店铺ID为空")
|
||||
}
|
||||
|
||||
// 获取第一个套餐ID用于查询成本价
|
||||
if len(validationResult.Packages) == 0 {
|
||||
return nil, errors.New(errors.CodeInternalError, "套餐列表为空")
|
||||
}
|
||||
firstPackageID := validationResult.Packages[0].ID
|
||||
|
||||
if *resourceShopID == operatorShopID {
|
||||
// ==== 子场景 2.1:代理自购 ====
|
||||
costPrice, err := s.getCostPrice(ctx, operatorShopID, firstPackageID)
|
||||
operatorCostPriceMap, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = operatorShopID
|
||||
totalAmount = costPrice
|
||||
itemUnitPriceMap = operatorCostPriceMap
|
||||
totalAmount = operatorTotalCost
|
||||
paymentMethod = model.PaymentMethodWallet
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = &now
|
||||
@@ -577,28 +591,29 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
|
||||
operatorID = &operatorShopID
|
||||
operatorType = "agent"
|
||||
actualPaidAmountVal := costPrice
|
||||
actualPaidAmountVal := operatorTotalCost
|
||||
actualPaidAmount = &actualPaidAmountVal
|
||||
purchaseRole = model.PurchaseRoleSelfPurchase
|
||||
sellerCostPrice = costPrice
|
||||
sellerCostPrice = operatorTotalCost
|
||||
|
||||
} else {
|
||||
// ==== 子场景 2.2:代理代购(给下级购买)====
|
||||
// 获取买家成本价
|
||||
buyerCostPrice, err := s.getCostPrice(ctx, *resourceShopID, firstPackageID)
|
||||
buyerCostPriceMap, buyerTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, *resourceShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取操作者成本价
|
||||
operatorCostPrice, err := s.getCostPrice(ctx, operatorShopID, firstPackageID)
|
||||
_, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = *resourceShopID
|
||||
totalAmount = buyerCostPrice
|
||||
itemUnitPriceMap = buyerCostPriceMap
|
||||
totalAmount = buyerTotalCost
|
||||
paymentMethod = model.PaymentMethodWallet
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = &now
|
||||
@@ -606,10 +621,11 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
|
||||
operatorID = &operatorShopID
|
||||
operatorType = "agent"
|
||||
actualPaidAmount = &operatorCostPrice
|
||||
actualPaidAmountVal := operatorTotalCost
|
||||
actualPaidAmount = &actualPaidAmountVal
|
||||
purchaseRole = model.PurchaseRolePurchaseForSubordinate
|
||||
// 代理代购下级时,佣金差额基准应是操作方(代理自己)的成本价,而非下级的成本价
|
||||
sellerCostPrice = operatorCostPrice
|
||||
sellerCostPrice = operatorTotalCost
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +675,7 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
PaymentConfigID: h5PaymentConfigID,
|
||||
}
|
||||
|
||||
items := s.buildOrderItems(userID, validationResult.Packages)
|
||||
items := s.buildOrderItems(userID, validationResult.Packages, itemUnitPriceMap)
|
||||
|
||||
idempotencyKey := buildOrderIdempotencyKey(buyerType, buyerID, req.OrderType, carrierType, carrierID, req.PackageIDs)
|
||||
|
||||
@@ -700,7 +716,7 @@ func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) resolvePurchaseOnBehalfInfo(ctx context.Context, result *purchase_validation.PurchaseValidationResult) (uint, int64, *time.Time, error) {
|
||||
func (s *Service) resolvePurchaseOnBehalfInfo(ctx context.Context, result *purchase_validation.PurchaseValidationResult) (uint, map[uint]int64, int64, *time.Time, error) {
|
||||
var resourceShopID *uint
|
||||
var seriesID *uint
|
||||
|
||||
@@ -713,30 +729,38 @@ func (s *Service) resolvePurchaseOnBehalfInfo(ctx context.Context, result *purch
|
||||
}
|
||||
|
||||
if resourceShopID == nil || *resourceShopID == 0 {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商,无法代购")
|
||||
return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商,无法代购")
|
||||
}
|
||||
|
||||
if seriesID == nil || *seriesID == 0 {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "资源未关联套餐系列")
|
||||
return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "资源未关联套餐系列")
|
||||
}
|
||||
|
||||
if len(result.Packages) == 0 {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "订单中没有套餐")
|
||||
return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "订单中没有套餐")
|
||||
}
|
||||
|
||||
firstPackageID := result.Packages[0].ID
|
||||
buyerAllocation, err := s.shopPackageAllocationStore.GetByShopAndPackage(ctx, *resourceShopID, firstPackageID)
|
||||
buyerCostPriceMap, buyerTotalCost, err := s.buildCostPriceMap(ctx, result.Packages, *resourceShopID)
|
||||
if err != nil {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "买家没有该套餐的分配配置")
|
||||
return 0, nil, 0, nil, err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
return *resourceShopID, buyerAllocation.CostPrice, &now, nil
|
||||
return *resourceShopID, buyerCostPriceMap, buyerTotalCost, &now, nil
|
||||
}
|
||||
|
||||
func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package) []*model.OrderItem {
|
||||
func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package, unitPriceMap map[uint]int64) []*model.OrderItem {
|
||||
items := make([]*model.OrderItem, 0, len(packages))
|
||||
for _, pkg := range packages {
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
unitPrice := pkg.SuggestedRetailPrice
|
||||
if price, ok := unitPriceMap[pkg.ID]; ok {
|
||||
unitPrice = price
|
||||
}
|
||||
|
||||
item := &model.OrderItem{
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: operatorID,
|
||||
@@ -746,8 +770,8 @@ func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package) []
|
||||
PackageName: pkg.PackageName,
|
||||
PackageType: &pkg.PackageType,
|
||||
Quantity: 1,
|
||||
UnitPrice: pkg.SuggestedRetailPrice,
|
||||
Amount: pkg.SuggestedRetailPrice,
|
||||
UnitPrice: unitPrice,
|
||||
Amount: unitPrice,
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
@@ -755,6 +779,49 @@ func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package) []
|
||||
return items
|
||||
}
|
||||
|
||||
// buildRetailPriceMap 构建订单明细零售价映射和总价(分)
|
||||
// sellerShopID > 0 时取代理分配零售价,=0 时取套餐建议零售价
|
||||
func (s *Service) buildRetailPriceMap(ctx context.Context, packages []*model.Package, sellerShopID uint) (map[uint]int64, int64, error) {
|
||||
priceMap := make(map[uint]int64, len(packages))
|
||||
var total int64
|
||||
|
||||
for _, pkg := range packages {
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
price, err := s.purchaseValidationService.GetPurchasePrice(ctx, pkg, sellerShopID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
priceMap[pkg.ID] = price
|
||||
total += price
|
||||
}
|
||||
|
||||
return priceMap, total, nil
|
||||
}
|
||||
|
||||
// buildCostPriceMap 构建订单明细成本价映射和总价(分)
|
||||
func (s *Service) buildCostPriceMap(ctx context.Context, packages []*model.Package, shopID uint) (map[uint]int64, int64, error) {
|
||||
priceMap := make(map[uint]int64, len(packages))
|
||||
var total int64
|
||||
|
||||
for _, pkg := range packages {
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
costPrice, err := s.getCostPrice(ctx, shopID, pkg.ID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
priceMap[pkg.ID] = costPrice
|
||||
total += costPrice
|
||||
}
|
||||
|
||||
return priceMap, total, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchBuyerSnapshot(ctx context.Context, customerID uint) (phone, nickname *string) {
|
||||
if customerID == 0 {
|
||||
return nil, nil
|
||||
|
||||
Reference in New Issue
Block a user