From ae64cc635d6c22840c1d46d67469000567131b89 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Wed, 27 May 2026 00:36:24 -0700 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D(#85):=20=E6=8C=89=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E5=8C=B9=E9=85=8D=E8=AE=A2=E9=98=85=E4=BF=83=E9=94=80?= =?UTF-8?q?=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: multica-agent --- apis/types.api | 2 +- common.json | 6 +- .../database/02154_promo_system.up.sql | 57 +++++++++++++++- internal/logic/common/promoEligibility.go | 6 +- .../logic/public/order/preCreateOrderLogic.go | 30 +++++++- internal/logic/public/order/promoPricing.go | 2 +- .../logic/public/order/promoPricing_test.go | 68 +++++++++++++++++-- internal/logic/public/subscribe/promo.go | 18 +++-- .../subscribe/querySubscribeListLogic.go | 8 ++- internal/model/promo/model.go | 6 +- internal/model/promo/promo.go | 1 + internal/types/types.go | 10 +-- node.json | 6 +- queue/logic/order/activateOrderLogic.go | 24 +++---- user.json | 6 +- 15 files changed, 209 insertions(+), 41 deletions(-) diff --git a/apis/types.api b/apis/types.api index fe1ded4..060fc9a 100644 --- a/apis/types.api +++ b/apis/types.api @@ -229,6 +229,7 @@ type ( Quantity int64 `json:"quantity"` Discount float64 `json:"discount"` MapApple string `json:"map_apple"` + Promo *SubscribePromo `json:"promo"` } SubscribePromo { RuleName string `json:"rule_name"` @@ -250,7 +251,6 @@ type ( UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` Discount []SubscribeDiscount `json:"discount"` - Promo *SubscribePromo `json:"promo"` NodeCount int64 `json:"node_count"` Replacement int64 `json:"replacement"` Inventory int64 `json:"inventory"` diff --git a/common.json b/common.json index edb009d..a941c06 100644 --- a/common.json +++ b/common.json @@ -4316,12 +4316,16 @@ "discount": { "type": "number", "format": "double" + }, + "promo": { + "$ref": "#/definitions/SubscribePromo" } }, "title": "SubscribeDiscount", "required": [ "quantity", - "discount" + "discount", + "promo" ] }, "SubscribeGroup": { diff --git a/initialize/migrate/database/02154_promo_system.up.sql b/initialize/migrate/database/02154_promo_system.up.sql index 2bb4e0f..0890a8a 100644 --- a/initialize/migrate/database/02154_promo_system.up.sql +++ b/initialize/migrate/database/02154_promo_system.up.sql @@ -18,15 +18,70 @@ CREATE TABLE IF NOT EXISTS `promo_rule` ( CREATE TABLE IF NOT EXISTS `subscribe_promo` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `subscribe_id` BIGINT UNSIGNED NOT NULL COMMENT '套餐规格 ID', + `quantity` BIGINT NOT NULL DEFAULT 1 COMMENT '购买数量', `promo_rule_id` BIGINT UNSIGNED NOT NULL COMMENT '促销规则 ID', `promo_price` BIGINT NOT NULL DEFAULT 0 COMMENT '该规格在此规则下的优惠价(分)', `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE KEY `uk_subscribe_rule` (`subscribe_id`, `promo_rule_id`), + UNIQUE KEY `uk_subscribe_quantity_rule` (`subscribe_id`, `quantity`, `promo_rule_id`), KEY `idx_promo_rule_id` (`promo_rule_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规格促销价表'; +SET @column_exists = ( + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'subscribe_promo' + AND COLUMN_NAME = 'quantity' +); + +SET @sql = IF( + @column_exists = 0, + 'ALTER TABLE `subscribe_promo` ADD COLUMN `quantity` BIGINT NOT NULL DEFAULT 1 COMMENT ''购买数量'' AFTER `subscribe_id`', + 'SELECT ''Column quantity already exists in subscribe_promo table''' +); + +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @index_exists = ( + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'subscribe_promo' + AND INDEX_NAME = 'uk_subscribe_rule' +); + +SET @sql = IF( + @index_exists = 1, + 'ALTER TABLE `subscribe_promo` DROP INDEX `uk_subscribe_rule`', + 'SELECT ''Index uk_subscribe_rule does not exist on subscribe_promo table''' +); + +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @index_exists = ( + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'subscribe_promo' + AND INDEX_NAME = 'uk_subscribe_quantity_rule' +); + +SET @sql = IF( + @index_exists = 0, + 'ALTER TABLE `subscribe_promo` ADD UNIQUE KEY `uk_subscribe_quantity_rule` (`subscribe_id`, `quantity`, `promo_rule_id`)', + 'SELECT ''Index uk_subscribe_quantity_rule already exists on subscribe_promo table''' +); + +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + CREATE TABLE IF NOT EXISTS `promo_usage` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` BIGINT UNSIGNED NOT NULL COMMENT '用户 ID', diff --git a/internal/logic/common/promoEligibility.go b/internal/logic/common/promoEligibility.go index f50a4bb..885c7c0 100644 --- a/internal/logic/common/promoEligibility.go +++ b/internal/logic/common/promoEligibility.go @@ -27,13 +27,13 @@ type promoRuleParams struct { InactiveMonths int `json:"inactive_months"` } -func EvaluatePromo(ctx context.Context, svcCtx *svc.ServiceContext, userID int64, subscribeID int64) (*PromoResult, error) { +func EvaluatePromo(ctx context.Context, svcCtx *svc.ServiceContext, userID int64, subscribeID int64, quantity int64) (*PromoResult, error) { result := &PromoResult{} - if svcCtx == nil || svcCtx.PromoModel == nil || svcCtx.DB == nil || userID <= 0 || subscribeID <= 0 { + if svcCtx == nil || svcCtx.PromoModel == nil || svcCtx.DB == nil || userID <= 0 || subscribeID <= 0 || quantity <= 0 { return result, nil } - rules, err := svcCtx.PromoModel.QueryEligibleRules(ctx, subscribeID) + rules, err := svcCtx.PromoModel.QueryEligibleRules(ctx, subscribeID, quantity) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query promo rules failed: %v", err.Error()) } diff --git a/internal/logic/public/order/preCreateOrderLogic.go b/internal/logic/public/order/preCreateOrderLogic.go index ac9ba92..c4ee0a4 100644 --- a/internal/logic/public/order/preCreateOrderLogic.go +++ b/internal/logic/public/order/preCreateOrderLogic.go @@ -49,6 +49,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r } targetSubscribeID := req.SubscribeId + orderType := uint8(1) isSingleModeRenewal := false decision, routeErr := commonLogic.ResolvePurchaseRoute( l.ctx, @@ -68,6 +69,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r targetSubscribeID = decision.ResolvedSubscribeID isSingleModeRenewal = decision.Route == commonLogic.PurchaseRoutePurchaseToRenewal if isSingleModeRenewal && decision.Anchor != nil { + orderType = 2 l.Infow("[PreCreateOrder] single mode purchase routed to renewal preview", logger.Field("mode", "single"), logger.Field("route", "purchase_to_renewal"), @@ -77,6 +79,32 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r } } + // Keep promo eligibility preview aligned with Purchase: an existing paid subscription + // routes the request to renewal semantics, where first-purchase promos are disabled. + if !l.svcCtx.Config.Subscribe.SingleModel && orderType == 1 { + var existSub user.Subscribe + if e := l.svcCtx.DB.WithContext(l.ctx). + Model(&user.Subscribe{}). + Where("user_id = ? AND token != '' AND (order_id > 0 OR token LIKE 'iap:%')", u.Id). + Order("expire_time DESC"). + Order("updated_at DESC"). + Order("id DESC"). + First(&existSub).Error; e == nil && existSub.Id > 0 && existSub.Token != "" { + orderType = 2 + l.Infow("[PreCreateOrder] purchase preview routed to renewal because an existing subscription was found", + logger.Field("route_mode", "global_single_subscription"), + logger.Field("route", "purchase_to_existing_subscription"), + logger.Field("existing_subscribe_id", existSub.Id), + logger.Field("existing_status", existSub.Status), + logger.Field("user_id", u.Id), + logger.Field("resolved_subscribe_id", targetSubscribeID), + ) + } else if e != nil && !errors.Is(e, gorm.ErrRecordNotFound) { + l.Errorw("[PreCreateOrder] Database query error", logger.Field("error", e.Error()), logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find existing subscription error: %v", e.Error()) + } + } + // find subscribe plan sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, targetSubscribeID) if err != nil { @@ -123,7 +151,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r req.Quantity, newUserDiscount.Discounts, newUserDiscount.EligibleForDiscount, - !isSingleModeRenewal, + orderType == 1, ) if err != nil { l.Errorw("[PreCreateOrder] Promo price calculation error", diff --git a/internal/logic/public/order/promoPricing.go b/internal/logic/public/order/promoPricing.go index 119328e..77b6e93 100644 --- a/internal/logic/public/order/promoPricing.go +++ b/internal/logic/public/order/promoPricing.go @@ -36,7 +36,7 @@ func calculatePurchasePrice( } if allowPromo { - promoResult, err := commonLogic.EvaluatePromo(ctx, svcCtx, userID, subscribeID) + promoResult, err := commonLogic.EvaluatePromo(ctx, svcCtx, userID, subscribeID, quantity) if err != nil { return nil, err } diff --git a/internal/logic/public/order/promoPricing_test.go b/internal/logic/public/order/promoPricing_test.go index 2c3f579..4daf226 100644 --- a/internal/logic/public/order/promoPricing_test.go +++ b/internal/logic/public/order/promoPricing_test.go @@ -11,21 +11,30 @@ import ( ) type fakePromoModel struct { - rules []*promo.RuleWithPrice + rules []*promo.RuleWithPrice + lastSubscribeID int64 + lastQuantity int64 + requireQuantity int64 + quantityMismatch []*promo.RuleWithPrice } -func (m fakePromoModel) QueryEligibleRules(context.Context, int64) ([]*promo.RuleWithPrice, error) { +func (m *fakePromoModel) QueryEligibleRules(_ context.Context, subscribeID int64, quantity int64) ([]*promo.RuleWithPrice, error) { + m.lastSubscribeID = subscribeID + m.lastQuantity = quantity + if m.requireQuantity > 0 && quantity != m.requireQuantity { + return m.quantityMismatch, nil + } return m.rules, nil } -func (m fakePromoModel) InsertUsage(context.Context, *promo.Usage, ...*gorm.DB) error { +func (m *fakePromoModel) InsertUsage(context.Context, *promo.Usage, ...*gorm.DB) error { return nil } func TestCalculatePurchasePricePromoSkipsPercentDiscount(t *testing.T) { svcCtx := &svc.ServiceContext{ DB: &gorm.DB{}, - PromoModel: fakePromoModel{rules: []*promo.RuleWithPrice{ + PromoModel: &fakePromoModel{rules: []*promo.RuleWithPrice{ { Rule: promo.Rule{ Id: 9, @@ -73,7 +82,7 @@ func TestCalculatePurchasePricePromoSkipsPercentDiscount(t *testing.T) { func TestCalculatePurchasePriceIgnoresInvalidPromoPrice(t *testing.T) { svcCtx := &svc.ServiceContext{ DB: &gorm.DB{}, - PromoModel: fakePromoModel{rules: []*promo.RuleWithPrice{ + PromoModel: &fakePromoModel{rules: []*promo.RuleWithPrice{ { Rule: promo.Rule{ Id: 10, @@ -111,3 +120,52 @@ func TestCalculatePurchasePriceIgnoresInvalidPromoPrice(t *testing.T) { t.Fatalf("promo fields = (%d, %d), want (0, 0)", result.PromoRuleId, result.PromoDiscount) } } + +func TestCalculatePurchasePricePassesQuantityToPromoEvaluation(t *testing.T) { + promoModel := &fakePromoModel{ + requireQuantity: 6, + rules: []*promo.RuleWithPrice{ + { + Rule: promo.Rule{ + Id: 11, + Name: "quantity campaign", + Type: promo.RuleTypeCampaign, + Enabled: true, + }, + PromoPrice: 500, + }, + }, + } + svcCtx := &svc.ServiceContext{ + DB: &gorm.DB{}, + PromoModel: promoModel, + } + + result, err := calculatePurchasePrice( + context.Background(), + svcCtx, + 1, + 2, + 1000, + 6, + []types.SubscribeDiscount{{Quantity: 6, Discount: 80}}, + true, + true, + ) + if err != nil { + t.Fatalf("calculatePurchasePrice returned error: %v", err) + } + + if promoModel.lastSubscribeID != 2 { + t.Fatalf("lastSubscribeID = %d, want 2", promoModel.lastSubscribeID) + } + if promoModel.lastQuantity != 6 { + t.Fatalf("lastQuantity = %d, want 6", promoModel.lastQuantity) + } + if result.PayableBase != 3000 { + t.Fatalf("PayableBase = %d, want 3000", result.PayableBase) + } + if result.PromoRuleId != 11 { + t.Fatalf("PromoRuleId = %d, want 11", result.PromoRuleId) + } +} diff --git a/internal/logic/public/subscribe/promo.go b/internal/logic/public/subscribe/promo.go index 1456d3c..276e005 100644 --- a/internal/logic/public/subscribe/promo.go +++ b/internal/logic/public/subscribe/promo.go @@ -25,6 +25,7 @@ const ( type subscribePromoCandidate struct { SubscribeId int64 `gorm:"column:subscribe_id"` + Quantity int64 `gorm:"column:quantity"` RuleName string `gorm:"column:rule_name"` RuleType string `gorm:"column:rule_type"` PromoPrice int64 `gorm:"column:promo_price"` @@ -38,8 +39,8 @@ type promoRuleParams struct { InactiveMonths int `json:"inactive_months"` } -func loadSubscribePromoMap(ctx context.Context, svcCtx *svc.ServiceContext, subscribeIDs []int64) (map[int64]*types.SubscribePromo, error) { - result := make(map[int64]*types.SubscribePromo) +func loadSubscribePromoMap(ctx context.Context, svcCtx *svc.ServiceContext, subscribeIDs []int64) (map[int64]map[int64]*types.SubscribePromo, error) { + result := make(map[int64]map[int64]*types.SubscribePromo) if len(subscribeIDs) == 0 || svcCtx == nil || svcCtx.DB == nil { return result, nil } @@ -56,7 +57,13 @@ func loadSubscribePromoMap(ctx context.Context, svcCtx *svc.ServiceContext, subs evaluator := promoEligibilityEvaluator{ctx: ctx, db: svcCtx.DB, userInfo: userInfo} now := time.Now() for _, candidate := range candidates { - if _, exists := result[candidate.SubscribeId]; exists { + if candidate.Quantity <= 0 { + continue + } + if result[candidate.SubscribeId] == nil { + result[candidate.SubscribeId] = make(map[int64]*types.SubscribePromo) + } + if _, exists := result[candidate.SubscribeId][candidate.Quantity]; exists { continue } if !candidate.isActive(now) { @@ -69,7 +76,7 @@ func loadSubscribePromoMap(ctx context.Context, svcCtx *svc.ServiceContext, subs if !ok { continue } - result[candidate.SubscribeId] = &types.SubscribePromo{ + result[candidate.SubscribeId][candidate.Quantity] = &types.SubscribePromo{ RuleName: candidate.RuleName, RuleType: candidate.RuleType, PromoPrice: candidate.PromoPrice, @@ -84,7 +91,7 @@ func querySubscribePromoCandidates(ctx context.Context, svcCtx *svc.ServiceConte var candidates []subscribePromoCandidate query := svcCtx.DB.WithContext(ctx). Table("subscribe_promo AS sp"). - Select("sp.subscribe_id, sp.promo_price, pr.name AS rule_name, pr.type AS rule_type, pr.params, pr.start_time, pr.end_time"). + Select("sp.subscribe_id, sp.quantity, sp.promo_price, pr.name AS rule_name, pr.type AS rule_type, pr.params, pr.start_time, pr.end_time"). Joins("JOIN promo_rule AS pr ON pr.id = sp.promo_rule_id AND pr.deleted_at IS NULL"). Where("sp.subscribe_id IN ? AND sp.promo_price > 0 AND pr.enabled = ?", subscribeIDs, true) if !loggedIn { @@ -92,6 +99,7 @@ func querySubscribePromoCandidates(ctx context.Context, svcCtx *svc.ServiceConte } err := query. Order("sp.subscribe_id ASC"). + Order("sp.quantity ASC"). Order("pr.priority DESC"). Order("pr.id ASC"). Scan(&candidates).Error diff --git a/internal/logic/public/subscribe/querySubscribeListLogic.go b/internal/logic/public/subscribe/querySubscribeListLogic.go index 4b7dda0..386e6d8 100644 --- a/internal/logic/public/subscribe/querySubscribeListLogic.go +++ b/internal/logic/public/subscribe/querySubscribeListLogic.go @@ -77,7 +77,13 @@ func (l *QuerySubscribeListLogic) QuerySubscribeList(req *types.QuerySubscribeLi return nil, err } for i := range list { - list[i].Promo = promos[list[i].Id] + subscribePromos := promos[list[i].Id] + for j := range list[i].Discount { + if subscribePromos == nil { + continue + } + list[i].Discount[j].Promo = subscribePromos[list[i].Discount[j].Quantity] + } } resp.List = list diff --git a/internal/model/promo/model.go b/internal/model/promo/model.go index ff48935..4ab95bd 100644 --- a/internal/model/promo/model.go +++ b/internal/model/promo/model.go @@ -13,7 +13,7 @@ type RuleWithPrice struct { } type Model interface { - QueryEligibleRules(ctx context.Context, subscribeId int64) ([]*RuleWithPrice, error) + QueryEligibleRules(ctx context.Context, subscribeId int64, quantity int64) ([]*RuleWithPrice, error) InsertUsage(ctx context.Context, data *Usage, tx ...*gorm.DB) error } @@ -25,13 +25,13 @@ func NewModel(db *gorm.DB, _ *redis.Client) Model { return &defaultPromoModel{db: db} } -func (m *defaultPromoModel) QueryEligibleRules(ctx context.Context, subscribeId int64) ([]*RuleWithPrice, error) { +func (m *defaultPromoModel) QueryEligibleRules(ctx context.Context, subscribeId int64, quantity int64) ([]*RuleWithPrice, error) { var list []*RuleWithPrice err := m.db.WithContext(ctx). Table("promo_rule AS pr"). Select("pr.*, sp.promo_price"). Joins("JOIN subscribe_promo AS sp ON sp.promo_rule_id = pr.id"). - Where("sp.subscribe_id = ? AND sp.promo_price > 0 AND pr.enabled = ?", subscribeId, true). + Where("sp.subscribe_id = ? AND sp.quantity = ? AND sp.promo_price > 0 AND pr.enabled = ?", subscribeId, quantity, true). Where("pr.deleted_at IS NULL"). Order("pr.priority DESC"). Order("pr.id ASC"). diff --git a/internal/model/promo/promo.go b/internal/model/promo/promo.go index 1a6f26f..5218d29 100644 --- a/internal/model/promo/promo.go +++ b/internal/model/promo/promo.go @@ -33,6 +33,7 @@ func (Rule) TableName() string { type SubscribePromo struct { Id int64 `gorm:"primaryKey"` SubscribeId int64 `gorm:"type:bigint unsigned;not null;comment:Subscribe ID"` + Quantity int64 `gorm:"type:bigint;not null;default:1;comment:Quantity"` PromoRuleId int64 `gorm:"type:bigint unsigned;not null;comment:Promo Rule ID"` PromoPrice int64 `gorm:"type:bigint;not null;default:0;comment:Promo Price"` CreatedAt time.Time `gorm:"<-:create;comment:Create Time"` diff --git a/internal/types/types.go b/internal/types/types.go index 1e282c3..c824633 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -2800,7 +2800,6 @@ type Subscribe struct { UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` Discount []SubscribeDiscount `json:"discount"` - Promo *SubscribePromo `json:"promo"` NodeCount int64 `json:"node_count"` Replacement int64 `json:"replacement"` Inventory int64 `json:"inventory"` @@ -2861,10 +2860,11 @@ type SubscribeConfig struct { } type SubscribeDiscount struct { - Quantity int64 `json:"quantity"` - Discount float64 `json:"discount"` - NewUserOnly bool `json:"new_user_only"` - MapApple string `json:"map_apple"` + Quantity int64 `json:"quantity"` + Discount float64 `json:"discount"` + NewUserOnly bool `json:"new_user_only"` + MapApple string `json:"map_apple"` + Promo *SubscribePromo `json:"promo"` } type SubscribeGroup struct { diff --git a/node.json b/node.json index 2918ade..65f3765 100644 --- a/node.json +++ b/node.json @@ -3680,12 +3680,16 @@ "discount": { "type": "number", "format": "double" + }, + "promo": { + "$ref": "#/definitions/SubscribePromo" } }, "title": "SubscribeDiscount", "required": [ "quantity", - "discount" + "discount", + "promo" ] }, "SubscribeGroup": { diff --git a/queue/logic/order/activateOrderLogic.go b/queue/logic/order/activateOrderLogic.go index 955d502..a2525b3 100644 --- a/queue/logic/order/activateOrderLogic.go +++ b/queue/logic/order/activateOrderLogic.go @@ -149,7 +149,14 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) return err } - l.recordPromoUsage(ctx, orderInfo) + if err = l.recordPromoUsage(ctx, orderInfo); err != nil { + logger.WithContext(ctx).Error("[ActivateOrderLogic] 促销使用记录写入失败,将重试", + logger.Field("order_no", orderInfo.OrderNo), + logger.Field("promo_rule_id", orderInfo.PromoRuleId), + logger.Field("error", err.Error()), + ) + return err + } l.finalizeCouponAndOrder(ctx, orderInfo) commonLogic.SubscriptionTraceInfo(logger.WithContext(ctx), commonLogic.SubscriptionTraceFlowOrder, "activation_finished", @@ -159,9 +166,9 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) return nil } -func (l *ActivateOrderLogic) recordPromoUsage(ctx context.Context, orderInfo *order.Order) { +func (l *ActivateOrderLogic) recordPromoUsage(ctx context.Context, orderInfo *order.Order) error { if orderInfo == nil || orderInfo.PromoRuleId <= 0 || orderInfo.Quantity <= 0 || orderInfo.SubscribeId <= 0 || orderInfo.OrderNo == "" { - return + return nil } promoPrice := int64(0) @@ -169,10 +176,10 @@ func (l *ActivateOrderLogic) recordPromoUsage(ctx context.Context, orderInfo *or promoPrice = (orderInfo.Price - orderInfo.PromoDiscount) / orderInfo.Quantity } if promoPrice <= 0 { - return + return nil } - err := l.svc.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + return l.svc.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { var count int64 if e := tx.Model(&promo.Usage{}).Where("order_no = ?", orderInfo.OrderNo).Count(&count).Error; e != nil { return e @@ -188,13 +195,6 @@ func (l *ActivateOrderLogic) recordPromoUsage(ctx context.Context, orderInfo *or PromoPrice: promoPrice, }, tx) }) - if err != nil { - logger.WithContext(ctx).Error("Insert promo usage failed", - logger.Field("error", err.Error()), - logger.Field("order_no", orderInfo.OrderNo), - logger.Field("promo_rule_id", orderInfo.PromoRuleId), - ) - } } // parsePayload unMarshals the task payload into a structured format diff --git a/user.json b/user.json index 0c076cf..e99b819 100644 --- a/user.json +++ b/user.json @@ -5900,12 +5900,16 @@ "discount": { "type": "number", "format": "double" + }, + "promo": { + "$ref": "#/definitions/SubscribePromo" } }, "title": "SubscribeDiscount", "required": [ "quantity", - "discount" + "discount", + "promo" ] }, "SubscribeGroup": {