实现套餐生效条件覆盖与购买快照
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
packagedomain "github.com/break/junhong_cmp_fiber/internal/domain/package"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
|
||||
@@ -2222,6 +2223,11 @@ func (s *Service) markOrderCreated(ctx context.Context, idempotencyKey string, o
|
||||
|
||||
// activateMainPackage 任务 8.2-8.4: 主套餐激活逻辑
|
||||
func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *model.Order, pkg *model.Package, carrierType string, carrierID uint, now time.Time) error {
|
||||
terms, err := s.resolvePackageTerms(ctx, pkg, order.SellerShopID)
|
||||
if err != nil {
|
||||
s.logger.Error("生成套餐计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if err := s.lockPackageCarrier(ctx, tx, carrierType, carrierID); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2252,19 +2258,17 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
priority = 1
|
||||
activatedAt = now
|
||||
// 使用工具函数计算过期时间
|
||||
expiresAt = packagepkg.CalculateExpiryTime(pkg.CalendarType, activatedAt, pkg.DurationMonths, pkg.DurationDays)
|
||||
expiresAt = packagepkg.CalculateExpiryTime(terms.CalendarType, activatedAt, terms.DurationMonths, terms.DurationDays)
|
||||
// 计算下次重置时间(基于套餐周期类型)
|
||||
nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, pkg.CalendarType, now, activatedAt)
|
||||
nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, terms.CalendarType, now, activatedAt)
|
||||
|
||||
// REALNAME-02: 后台囤货场景三维决策(卡类型 + 购买路径 + expiry_base + 实名状态)
|
||||
// 查询卡类型(行业卡永远直接激活,不等实名)
|
||||
// 同时查询载体当前实名状态:已实名则跳过 pending,直接激活
|
||||
var cardCategory string
|
||||
var currentlyRealnamed bool
|
||||
if carrierType == "iot_card" {
|
||||
var card model.IotCard
|
||||
if err := tx.Select("card_category", "real_name_status").First(&card, carrierID).Error; err == nil {
|
||||
cardCategory = card.CardCategory
|
||||
if err := tx.Select("real_name_status").First(&card, carrierID).Error; err == nil {
|
||||
currentlyRealnamed = card.RealNameStatus == constants.RealNameStatusVerified
|
||||
}
|
||||
// err != nil 时 currentlyRealnamed 保守默认 false,不阻断购买流程
|
||||
@@ -2285,9 +2289,9 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
// 判断是否 C 端购买(C 端购买前已做实名前置检查,直接激活)
|
||||
isCEndPurchase := order.BuyerType == model.BuyerTypePersonal
|
||||
|
||||
if cardCategory != "industry" && !isCEndPurchase {
|
||||
if !isCEndPurchase {
|
||||
// 后台囤货路径:按 expiry_base 决定是否等实名
|
||||
if pkg.ExpiryBase != "from_purchase" {
|
||||
if terms.ExpiryBase != constants.PackageExpiryBaseFromPurchase {
|
||||
if currentlyRealnamed {
|
||||
s.logger.Info("购买时载体已实名,直接激活套餐",
|
||||
zap.String("carrier_type", carrierType),
|
||||
@@ -2303,7 +2307,7 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
}
|
||||
// from_purchase:立即激活,status 已为 Active,保持不变
|
||||
}
|
||||
// 行业卡或 C 端购买:直接激活,status 已为 Active,保持不变
|
||||
// C 端购买已完成实名前置校验,直接激活。
|
||||
}
|
||||
|
||||
// 创建套餐使用记录
|
||||
@@ -2332,6 +2336,7 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
PackagePriceConfigStatus: pkg.PriceConfigStatus,
|
||||
PackageIsGift: pkg.IsGift,
|
||||
}
|
||||
terms.Apply(usage)
|
||||
|
||||
if carrierType == "iot_card" {
|
||||
usage.IotCardID = carrierID
|
||||
@@ -2362,6 +2367,11 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
|
||||
// activateAddonPackage 任务 8.5-8.7: 加油包激活逻辑
|
||||
func (s *Service) activateAddonPackage(ctx context.Context, tx *gorm.DB, order *model.Order, pkg *model.Package, carrierType string, carrierID uint, now time.Time) error {
|
||||
terms, err := s.resolvePackageTerms(ctx, pkg, order.SellerShopID)
|
||||
if err != nil {
|
||||
s.logger.Error("生成加油包计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
// 任务 8.5-8.6: 检查是否有可挂靠主套餐(待生效、未过期的生效中或已用完)
|
||||
mainPackage, err := packagepkg.FindAttachableMainPackageForAddon(tx, carrierType, carrierID, now)
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
@@ -2421,6 +2431,7 @@ func (s *Service) activateAddonPackage(ctx context.Context, tx *gorm.DB, order *
|
||||
PackagePriceConfigStatus: pkg.PriceConfigStatus,
|
||||
PackageIsGift: pkg.IsGift,
|
||||
}
|
||||
terms.Apply(usage)
|
||||
|
||||
if carrierType == "iot_card" {
|
||||
usage.IotCardID = carrierID
|
||||
@@ -2436,6 +2447,20 @@ func (s *Service) activateAddonPackage(ctx context.Context, tx *gorm.DB, order *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) resolvePackageTerms(ctx context.Context, pkg *model.Package, sellerShopID *uint) (packagedomain.TermsSnapshot, error) {
|
||||
var allocation *model.ShopPackageAllocation
|
||||
if sellerShopID != nil && *sellerShopID > 0 {
|
||||
found, err := s.shopPackageAllocationStore.GetByShopAndPackageForSystem(ctx, *sellerShopID, pkg.ID)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return packagedomain.TermsSnapshot{}, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐分配失败")
|
||||
}
|
||||
if err == nil {
|
||||
allocation = found
|
||||
}
|
||||
}
|
||||
return packagedomain.ResolveTermsSnapshot(pkg, allocation)
|
||||
}
|
||||
|
||||
func (s *Service) enqueueCommissionCalculation(ctx context.Context, orderID uint) {
|
||||
if s.queueClient == nil {
|
||||
s.logger.Warn("队列客户端未初始化,跳过佣金计算任务入队", zap.Uint("order_id", orderID))
|
||||
|
||||
Reference in New Issue
Block a user