fix(force-recharge): 补充强充配置缺失的接口和数据库字段
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m19s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m19s
- 订单管理:增加 payment_method 字段支持,合并代购订单逻辑 - 套餐系列分配:增加强充配置字段(enable_force_recharge、force_recharge_amount、force_recharge_trigger_type) - 数据库迁移:添加 force_recharge_trigger_type 字段 - 测试:更新订单服务测试用例 - OpenSpec:归档 fix-force-recharge-missing-interfaces 变更
This commit is contained in:
@@ -95,6 +95,14 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderRequest, buyer
|
||||
userID := middleware.GetUserIDFromContext(ctx)
|
||||
configVersion := s.snapshotCommissionConfig(ctx, validationResult.Allocation.ID)
|
||||
|
||||
orderBuyerType := buyerType
|
||||
orderBuyerID := buyerID
|
||||
totalAmount := validationResult.TotalPrice
|
||||
paymentMethod := req.PaymentMethod
|
||||
paymentStatus := model.PaymentStatusPending
|
||||
var paidAt *time.Time
|
||||
isPurchaseOnBehalf := false
|
||||
|
||||
var seriesID *uint
|
||||
var sellerShopID *uint
|
||||
var sellerCostPrice int64
|
||||
@@ -102,6 +110,22 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderRequest, buyer
|
||||
if validationResult.Allocation != nil {
|
||||
seriesID = &validationResult.Allocation.SeriesID
|
||||
sellerShopID = &validationResult.Allocation.ShopID
|
||||
}
|
||||
|
||||
if req.PaymentMethod == model.PaymentMethodOffline {
|
||||
purchaseBuyerID, buyerCostPrice, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderBuyerType = model.BuyerTypeAgent
|
||||
orderBuyerID = purchaseBuyerID
|
||||
totalAmount = buyerCostPrice
|
||||
paymentMethod = model.PaymentMethodOffline
|
||||
paymentStatus = model.PaymentStatusPaid
|
||||
paidAt = purchasePaidAt
|
||||
isPurchaseOnBehalf = true
|
||||
sellerCostPrice = buyerCostPrice
|
||||
} else if validationResult.Allocation != nil {
|
||||
sellerCostPrice = utils.CalculateCostPrice(validationResult.Allocation, validationResult.TotalPrice)
|
||||
}
|
||||
|
||||
@@ -112,25 +136,68 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderRequest, buyer
|
||||
},
|
||||
OrderNo: s.orderStore.GenerateOrderNo(),
|
||||
OrderType: req.OrderType,
|
||||
BuyerType: buyerType,
|
||||
BuyerID: buyerID,
|
||||
BuyerType: orderBuyerType,
|
||||
BuyerID: orderBuyerID,
|
||||
IotCardID: req.IotCardID,
|
||||
DeviceID: req.DeviceID,
|
||||
TotalAmount: validationResult.TotalPrice,
|
||||
PaymentStatus: model.PaymentStatusPending,
|
||||
TotalAmount: totalAmount,
|
||||
PaymentMethod: paymentMethod,
|
||||
PaymentStatus: paymentStatus,
|
||||
PaidAt: paidAt,
|
||||
CommissionStatus: model.CommissionStatusPending,
|
||||
CommissionConfigVersion: configVersion,
|
||||
SeriesID: seriesID,
|
||||
SellerShopID: sellerShopID,
|
||||
SellerCostPrice: sellerCostPrice,
|
||||
IsPurchaseOnBehalf: isPurchaseOnBehalf,
|
||||
}
|
||||
|
||||
var items []*model.OrderItem
|
||||
for _, pkg := range validationResult.Packages {
|
||||
items := s.buildOrderItems(userID, validationResult.Packages)
|
||||
|
||||
if req.PaymentMethod == model.PaymentMethodOffline {
|
||||
if err := s.createOrderWithActivation(ctx, order, items); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.enqueueCommissionCalculation(ctx, order.ID)
|
||||
return s.buildOrderResponse(order, items), nil
|
||||
}
|
||||
|
||||
if err := s.orderStore.Create(ctx, order, items); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.buildOrderResponse(order, items), nil
|
||||
}
|
||||
|
||||
func (s *Service) resolvePurchaseOnBehalfInfo(ctx context.Context, result *purchase_validation.PurchaseValidationResult) (uint, int64, *time.Time, error) {
|
||||
var resourceShopID *uint
|
||||
if result.Card != nil {
|
||||
resourceShopID = result.Card.ShopID
|
||||
} else if result.Device != nil {
|
||||
resourceShopID = result.Device.ShopID
|
||||
}
|
||||
|
||||
if resourceShopID == nil || *resourceShopID == 0 {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商,无法代购")
|
||||
}
|
||||
|
||||
buyerAllocation, err := s.seriesAllocationStore.GetByShopAndSeries(ctx, *resourceShopID, result.Allocation.SeriesID)
|
||||
if err != nil {
|
||||
return 0, 0, nil, errors.New(errors.CodeInvalidParam, "买家没有该套餐系列的分配配置")
|
||||
}
|
||||
|
||||
buyerCostPrice := utils.CalculateCostPrice(buyerAllocation, result.TotalPrice)
|
||||
now := time.Now()
|
||||
return *resourceShopID, buyerCostPrice, &now, nil
|
||||
}
|
||||
|
||||
func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package) []*model.OrderItem {
|
||||
items := make([]*model.OrderItem, 0, len(packages))
|
||||
for _, pkg := range packages {
|
||||
item := &model.OrderItem{
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: userID,
|
||||
Updater: userID,
|
||||
Creator: operatorID,
|
||||
Updater: operatorID,
|
||||
},
|
||||
PackageID: pkg.ID,
|
||||
PackageName: pkg.PackageName,
|
||||
@@ -141,11 +208,24 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderRequest, buyer
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
if err := s.orderStore.Create(ctx, order, items); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
return s.buildOrderResponse(order, items), nil
|
||||
func (s *Service) createOrderWithActivation(ctx context.Context, order *model.Order, items []*model.OrderItem) error {
|
||||
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(order).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "创建代购订单失败")
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
item.OrderID = order.ID
|
||||
}
|
||||
if err := tx.CreateInBatches(items, 100).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "创建订单明细失败")
|
||||
}
|
||||
|
||||
return s.activatePackage(ctx, tx, order)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) Get(ctx context.Context, id uint) (*dto.OrderResponse, error) {
|
||||
@@ -544,6 +624,7 @@ func (s *Service) buildOrderResponse(order *model.Order, items []*model.OrderIte
|
||||
PaymentStatus: order.PaymentStatus,
|
||||
PaymentStatusText: statusText,
|
||||
PaidAt: order.PaidAt,
|
||||
IsPurchaseOnBehalf: order.IsPurchaseOnBehalf,
|
||||
CommissionStatus: order.CommissionStatus,
|
||||
CommissionConfigVersion: order.CommissionConfigVersion,
|
||||
Items: itemResponses,
|
||||
@@ -751,119 +832,3 @@ func (s *Service) GetPurchaseCheck(ctx context.Context, req *dto.PurchaseCheckRe
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *Service) CreatePurchaseOnBehalf(ctx context.Context, req *dto.CreatePurchaseOnBehalfRequest, operatorID uint) (*dto.OrderResponse, error) {
|
||||
var validationResult *purchase_validation.PurchaseValidationResult
|
||||
var resourceShopID *uint
|
||||
var err error
|
||||
|
||||
if req.OrderType == model.OrderTypeSingleCard {
|
||||
if req.IotCardID == nil {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "单卡购买必须指定IoT卡ID")
|
||||
}
|
||||
validationResult, err = s.purchaseValidationService.ValidateCardPurchase(ctx, *req.IotCardID, req.PackageIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if validationResult.Card != nil {
|
||||
resourceShopID = validationResult.Card.ShopID
|
||||
}
|
||||
} else if req.OrderType == model.OrderTypeDevice {
|
||||
if req.DeviceID == nil {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "设备购买必须指定设备ID")
|
||||
}
|
||||
validationResult, err = s.purchaseValidationService.ValidateDevicePurchase(ctx, *req.DeviceID, req.PackageIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if validationResult.Device != nil {
|
||||
resourceShopID = validationResult.Device.ShopID
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "无效的订单类型")
|
||||
}
|
||||
|
||||
if resourceShopID == nil || *resourceShopID == 0 {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商,无法代购")
|
||||
}
|
||||
|
||||
buyerID := *resourceShopID
|
||||
buyerAllocation, err := s.seriesAllocationStore.GetByShopAndSeries(ctx, buyerID, validationResult.Allocation.SeriesID)
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "买家没有该套餐系列的分配配置")
|
||||
}
|
||||
|
||||
buyerCostPrice := utils.CalculateCostPrice(buyerAllocation, validationResult.TotalPrice)
|
||||
|
||||
configVersion := s.snapshotCommissionConfig(ctx, validationResult.Allocation.ID)
|
||||
|
||||
var seriesID *uint
|
||||
var sellerShopID *uint
|
||||
if validationResult.Allocation != nil {
|
||||
seriesID = &validationResult.Allocation.SeriesID
|
||||
sellerShopID = &validationResult.Allocation.ShopID
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
order := &model.Order{
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: operatorID,
|
||||
Updater: operatorID,
|
||||
},
|
||||
OrderNo: s.orderStore.GenerateOrderNo(),
|
||||
OrderType: req.OrderType,
|
||||
BuyerType: model.BuyerTypeAgent,
|
||||
BuyerID: buyerID,
|
||||
IotCardID: req.IotCardID,
|
||||
DeviceID: req.DeviceID,
|
||||
TotalAmount: buyerCostPrice,
|
||||
PaymentMethod: model.PaymentMethodOffline,
|
||||
PaymentStatus: model.PaymentStatusPaid,
|
||||
PaidAt: &now,
|
||||
CommissionStatus: model.CommissionStatusPending,
|
||||
CommissionConfigVersion: configVersion,
|
||||
SeriesID: seriesID,
|
||||
SellerShopID: sellerShopID,
|
||||
SellerCostPrice: buyerCostPrice,
|
||||
IsPurchaseOnBehalf: true,
|
||||
}
|
||||
|
||||
var items []*model.OrderItem
|
||||
for _, pkg := range validationResult.Packages {
|
||||
item := &model.OrderItem{
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: operatorID,
|
||||
Updater: operatorID,
|
||||
},
|
||||
PackageID: pkg.ID,
|
||||
PackageName: pkg.PackageName,
|
||||
Quantity: 1,
|
||||
UnitPrice: pkg.SuggestedRetailPrice,
|
||||
Amount: pkg.SuggestedRetailPrice,
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(order).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "创建代购订单失败")
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
item.OrderID = order.ID
|
||||
}
|
||||
if err := tx.CreateInBatches(items, 100).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "创建订单明细失败")
|
||||
}
|
||||
|
||||
return s.activatePackage(ctx, tx, order)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.enqueueCommissionCalculation(ctx, order.ID)
|
||||
|
||||
return s.buildOrderResponse(order, items), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user