错误的套餐购买限制
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m48s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m48s
This commit is contained in:
@@ -63,15 +63,15 @@ func NewClientAssetHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type resolvedAssetContext struct {
|
type resolvedAssetContext struct {
|
||||||
CustomerID uint
|
CustomerID uint
|
||||||
Identifier string
|
Identifier string
|
||||||
Asset *dto.AssetResolveResponse
|
Asset *dto.AssetResolveResponse
|
||||||
Generation int
|
Generation int
|
||||||
WalletBalance int64
|
WalletBalance int64
|
||||||
SkipPermissionCtx context.Context
|
SkipPermissionCtx context.Context
|
||||||
IsAgentChannel bool
|
IsAgentChannel bool
|
||||||
SellerShopID uint
|
SellerShopID uint
|
||||||
MainPackageActived bool
|
HasAddonMainPackage bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveAssetFromIdentifier 统一执行资产解析与归属校验
|
// resolveAssetFromIdentifier 统一执行资产解析与归属校验
|
||||||
@@ -232,11 +232,16 @@ func (h *ClientAssetHandler) GetAvailablePackages(c *fiber.Ctx) error {
|
|||||||
return errors.New(errors.CodeNoAvailablePackage, "当前无可购买套餐")
|
return errors.New(errors.CodeNoAvailablePackage, "当前无可购买套餐")
|
||||||
}
|
}
|
||||||
|
|
||||||
packagesResult, err := h.assetService.GetPackages(resolved.SkipPermissionCtx, resolved.Asset.AssetType, resolved.Asset.AssetID, 1, 50, nil)
|
if _, err := packagepkg.FindAttachableMainPackageForAddon(
|
||||||
if err != nil {
|
h.db.WithContext(resolved.SkipPermissionCtx),
|
||||||
return err
|
resolved.Asset.AssetType,
|
||||||
|
resolved.Asset.AssetID,
|
||||||
|
time.Now(),
|
||||||
|
); err == nil {
|
||||||
|
resolved.HasAddonMainPackage = true
|
||||||
|
} else if err != gorm.ErrRecordNotFound {
|
||||||
|
return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
|
||||||
}
|
}
|
||||||
resolved.MainPackageActived = hasActiveMainPackage(packagesResult.Items)
|
|
||||||
|
|
||||||
listCtx := resolved.SkipPermissionCtx
|
listCtx := resolved.SkipPermissionCtx
|
||||||
if resolved.IsAgentChannel {
|
if resolved.IsAgentChannel {
|
||||||
@@ -512,18 +517,6 @@ func collectPackageIDs(pkgs []*model.Package) []uint {
|
|||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasActiveMainPackage(usages []*dto.AssetPackageResponse) bool {
|
|
||||||
for _, usage := range usages {
|
|
||||||
if usage == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if usage.PackageType == constants.PackageTypeFormal && usage.Status == constants.PackageUsageStatusActive {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildClientPackageItem(
|
func buildClientPackageItem(
|
||||||
pkg *model.Package,
|
pkg *model.Package,
|
||||||
resolved *resolvedAssetContext,
|
resolved *resolvedAssetContext,
|
||||||
@@ -537,7 +530,7 @@ func buildClientPackageItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAddon := pkg.PackageType == constants.PackageTypeAddon
|
isAddon := pkg.PackageType == constants.PackageTypeAddon
|
||||||
if isAddon && !resolved.MainPackageActived {
|
if isAddon && !resolved.HasAddonMainPackage {
|
||||||
return dto.ClientPackageItem{}, false
|
return dto.ClientPackageItem{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2297,14 +2297,8 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
|||||||
|
|
||||||
// activateAddonPackage 任务 8.5-8.7: 加油包激活逻辑
|
// 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 {
|
func (s *Service) activateAddonPackage(ctx context.Context, tx *gorm.DB, order *model.Order, pkg *model.Package, carrierType string, carrierID uint, now time.Time) error {
|
||||||
// 任务 8.5-8.6: 检查是否有主套餐(status IN (0,1))
|
// 任务 8.5-8.6: 检查是否有可挂靠主套餐(待生效、未过期的生效中或已用完)
|
||||||
var mainPackage model.PackageUsage
|
mainPackage, err := packagepkg.FindAttachableMainPackageForAddon(tx, carrierType, carrierID, now)
|
||||||
err := tx.Where("status IN ?", []int{constants.PackageUsageStatusPending, constants.PackageUsageStatusActive}).
|
|
||||||
Where("master_usage_id IS NULL").
|
|
||||||
Where(carrierType+"_id = ?", carrierID).
|
|
||||||
Order("priority ASC").
|
|
||||||
First(&mainPackage).Error
|
|
||||||
|
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return errors.New(errors.CodeInvalidParam, "必须有主套餐才能购买加油包")
|
return errors.New(errors.CodeInvalidParam, "必须有主套餐才能购买加油包")
|
||||||
}
|
}
|
||||||
|
|||||||
41
internal/service/package/addon_main_package.go
Normal file
41
internal/service/package/addon_main_package.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package packagepkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||||
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindAttachableMainPackageForAddon 查询加油包可挂靠的主套餐。
|
||||||
|
// 已用完但未过期的主套餐仍可挂靠;已过期、已失效的主套餐不可挂靠。
|
||||||
|
func FindAttachableMainPackageForAddon(tx *gorm.DB, carrierType string, carrierID uint, now time.Time) (*model.PackageUsage, error) {
|
||||||
|
var mainPackage model.PackageUsage
|
||||||
|
query := tx.Model(&model.PackageUsage{}).
|
||||||
|
Where("master_usage_id IS NULL").
|
||||||
|
Where(
|
||||||
|
"(status = ? OR (status IN ? AND (expires_at IS NULL OR expires_at > ?)))",
|
||||||
|
constants.PackageUsageStatusPending,
|
||||||
|
[]int{
|
||||||
|
constants.PackageUsageStatusActive,
|
||||||
|
constants.PackageUsageStatusDepleted,
|
||||||
|
},
|
||||||
|
now,
|
||||||
|
).
|
||||||
|
Order("priority ASC")
|
||||||
|
|
||||||
|
switch carrierType {
|
||||||
|
case constants.AssetWalletResourceTypeIotCard, "card":
|
||||||
|
query = query.Where("iot_card_id = ?", carrierID)
|
||||||
|
case constants.AssetWalletResourceTypeDevice:
|
||||||
|
query = query.Where("device_id = ?", carrierID)
|
||||||
|
default:
|
||||||
|
return nil, gorm.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := query.First(&mainPackage).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mainPackage, nil
|
||||||
|
}
|
||||||
@@ -588,12 +588,7 @@ func (h *AutoPurchaseHandler) activateAddonPackage(
|
|||||||
now time.Time,
|
now time.Time,
|
||||||
) error {
|
) error {
|
||||||
_ = ctx
|
_ = ctx
|
||||||
var mainPackage model.PackageUsage
|
mainPackage, err := packagepkg.FindAttachableMainPackageForAddon(tx, carrierType, carrierID, now)
|
||||||
err := tx.Where("status IN ?", []int{constants.PackageUsageStatusPending, constants.PackageUsageStatusActive}).
|
|
||||||
Where("master_usage_id IS NULL").
|
|
||||||
Where(carrierType+"_id = ?", carrierID).
|
|
||||||
Order("priority ASC").
|
|
||||||
First(&mainPackage).Error
|
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return errors.New("必须有主套餐才能购买加油包")
|
return errors.New("必须有主套餐才能购买加油包")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user