diff --git a/common.json b/common.json index a941c06..3acfcaa 100644 --- a/common.json +++ b/common.json @@ -4324,8 +4324,7 @@ "title": "SubscribeDiscount", "required": [ "quantity", - "discount", - "promo" + "discount" ] }, "SubscribeGroup": { diff --git a/initialize/migrate/database/02154_promo_system.up.sql b/initialize/migrate/database/02154_promo_system.up.sql index 0890a8a..d9c02b0 100644 --- a/initialize/migrate/database/02154_promo_system.up.sql +++ b/initialize/migrate/database/02154_promo_system.up.sql @@ -11,10 +11,63 @@ CREATE TABLE IF NOT EXISTS `promo_rule` ( `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `deleted_at` DATETIME DEFAULT NULL COMMENT '软删除时间', PRIMARY KEY (`id`), - KEY `idx_enabled_priority` (`enabled`, `priority` DESC), - KEY `idx_deleted_at` (`deleted_at`) + KEY `idx_enabled_priority_deleted` (`enabled`, `deleted_at`, `priority` DESC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='促销规则表'; +SET @index_exists = ( + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'promo_rule' + AND INDEX_NAME = 'idx_enabled_priority' +); + +SET @sql = IF( + @index_exists = 1, + 'ALTER TABLE `promo_rule` DROP INDEX `idx_enabled_priority`', + 'SELECT ''Index idx_enabled_priority does not exist on promo_rule 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 = 'promo_rule' + AND INDEX_NAME = 'idx_deleted_at' +); + +SET @sql = IF( + @index_exists = 1, + 'ALTER TABLE `promo_rule` DROP INDEX `idx_deleted_at`', + 'SELECT ''Index idx_deleted_at does not exist on promo_rule 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 = 'promo_rule' + AND INDEX_NAME = 'idx_enabled_priority_deleted' +); + +SET @sql = IF( + @index_exists = 0, + 'ALTER TABLE `promo_rule` ADD KEY `idx_enabled_priority_deleted` (`enabled`, `deleted_at`, `priority` DESC)', + 'SELECT ''Index idx_enabled_priority_deleted already exists on promo_rule table''' +); + +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + CREATE TABLE IF NOT EXISTS `subscribe_promo` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `subscribe_id` BIGINT UNSIGNED NOT NULL COMMENT '套餐规格 ID', diff --git a/internal/logic/public/order/preCreateOrderLogic.go b/internal/logic/public/order/preCreateOrderLogic.go index c4ee0a4..1759d53 100644 --- a/internal/logic/public/order/preCreateOrderLogic.go +++ b/internal/logic/public/order/preCreateOrderLogic.go @@ -47,6 +47,10 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r l.Debugf("[PreCreateOrder] Quantity is less than or equal to 0, setting to 1") req.Quantity = 1 } + entitlement, entErr := commonLogic.ResolveEntitlementUser(l.ctx, l.svcCtx.DB, u.Id) + if entErr != nil { + return nil, entErr + } targetSubscribeID := req.SubscribeId orderType := uint8(1) @@ -54,7 +58,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r decision, routeErr := commonLogic.ResolvePurchaseRoute( l.ctx, l.svcCtx.Config.Subscribe.SingleModel, - u.Id, + entitlement.EffectiveUserID, req.SubscribeId, l.svcCtx.UserModel.FindSingleModeAnchorSubscribe, ) @@ -75,6 +79,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r logger.Field("route", "purchase_to_renewal"), logger.Field("anchor_user_subscribe_id", decision.Anchor.Id), logger.Field("user_id", u.Id), + logger.Field("effective_user_id", entitlement.EffectiveUserID), ) } } @@ -85,7 +90,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r 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). + Where("user_id = ? AND token != '' AND (order_id > 0 OR token LIKE 'iap:%')", entitlement.EffectiveUserID). Order("expire_time DESC"). Order("updated_at DESC"). Order("id DESC"). @@ -97,6 +102,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r logger.Field("existing_subscribe_id", existSub.Id), logger.Field("existing_status", existSub.Status), logger.Field("user_id", u.Id), + logger.Field("effective_user_id", entitlement.EffectiveUserID), logger.Field("resolved_subscribe_id", targetSubscribeID), ) } else if e != nil && !errors.Is(e, gorm.ErrRecordNotFound) { @@ -114,7 +120,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r // check subscribe plan quota limit for new purchase flow only if !isSingleModeRenewal && sub.Quota > 0 { - userSub, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, u.Id) + userSub, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, entitlement.EffectiveUserID) if err != nil { l.Errorw("[PreCreateOrder] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find user subscription error: %v", err.Error()) @@ -130,7 +136,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r } } - newUserDiscount, err := resolveNewUserDiscountEligibility(l.ctx, l.svcCtx.DB, u.Id, targetSubscribeID, req.Quantity, sub.Discount) + newUserDiscount, err := resolveNewUserDiscountEligibility(l.ctx, l.svcCtx.DB, entitlement.EffectiveUserID, targetSubscribeID, req.Quantity, sub.Discount) if err != nil { l.Errorw("[PreCreateOrder] Database query error resolving new user eligibility", logger.Field("error", err.Error()), @@ -145,7 +151,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r priceResult, err := calculatePurchasePrice( l.ctx, l.svcCtx, - u.Id, + entitlement.EffectiveUserID, targetSubscribeID, sub.UnitPrice, req.Quantity, diff --git a/node.json b/node.json index 65f3765..e03f593 100644 --- a/node.json +++ b/node.json @@ -3688,8 +3688,7 @@ "title": "SubscribeDiscount", "required": [ "quantity", - "discount", - "promo" + "discount" ] }, "SubscribeGroup": { diff --git a/queue/logic/order/activateOrderLogic.go b/queue/logic/order/activateOrderLogic.go index a2525b3..6bd964e 100644 --- a/queue/logic/order/activateOrderLogic.go +++ b/queue/logic/order/activateOrderLogic.go @@ -150,6 +150,12 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) } if err = l.recordPromoUsage(ctx, orderInfo); err != nil { + if releaseErr := l.releaseClaim(ctx, orderInfo.OrderNo); releaseErr != nil { + logger.WithContext(ctx).Error("[ActivateOrderLogic] releaseClaim also failed, stuck recovery will handle", + logger.Field("order_no", orderInfo.OrderNo), + logger.Field("release_error", releaseErr.Error()), + ) + } logger.WithContext(ctx).Error("[ActivateOrderLogic] 促销使用记录写入失败,将重试", logger.Field("order_no", orderInfo.OrderNo), logger.Field("promo_rule_id", orderInfo.PromoRuleId), diff --git a/user.json b/user.json index e99b819..a026dfb 100644 --- a/user.json +++ b/user.json @@ -5908,8 +5908,7 @@ "title": "SubscribeDiscount", "required": [ "quantity", - "discount", - "promo" + "discount" ] }, "SubscribeGroup": {