不允许购买第二个主套餐
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m50s

This commit is contained in:
Break
2026-06-10 15:24:26 +08:00
parent 32c9859b38
commit 5c779cb6e0
7 changed files with 314 additions and 108 deletions

View File

@@ -2,8 +2,10 @@ package purchase_validation
import (
"context"
"time"
"github.com/break/junhong_cmp_fiber/internal/model"
packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
"github.com/break/junhong_cmp_fiber/internal/service/packageprice"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
@@ -82,6 +84,10 @@ func (s *Service) ValidateCardPurchase(ctx context.Context, cardID uint, package
return nil, err
}
if err := s.validatePackageUsageRules(ctx, constants.AssetWalletResourceTypeIotCard, card.ID, packages); err != nil {
return nil, err
}
return &PurchaseValidationResult{
Card: card,
Packages: packages,
@@ -113,6 +119,10 @@ func (s *Service) ValidateDevicePurchase(ctx context.Context, deviceID uint, pac
return nil, err
}
if err := s.validatePackageUsageRules(ctx, constants.AssetWalletResourceTypeDevice, device.ID, packages); err != nil {
return nil, err
}
return &PurchaseValidationResult{
Device: device,
Packages: packages,
@@ -179,6 +189,61 @@ func (s *Service) validatePackages(ctx context.Context, packageIDs []uint, serie
return packages, totalPrice, nil
}
// validatePackageUsageRules 校验主套餐和加油包的购买前置条件。
func (s *Service) validatePackageUsageRules(ctx context.Context, carrierType string, carrierID uint, packages []*model.Package) error {
formalCount := 0
hasAddon := false
for _, pkg := range packages {
if pkg == nil {
continue
}
switch pkg.PackageType {
case constants.PackageTypeFormal:
formalCount++
case constants.PackageTypeAddon:
hasAddon = true
}
if formalCount > 0 && hasAddon {
return errors.New(errors.CodeMixedOrderForbidden)
}
}
if formalCount > 1 {
return errors.New(errors.CodeMainPackageExists, "一次只能购买一个主套餐")
}
if formalCount == 1 {
hasBlockingMain, err := packagepkg.HasBlockingMainPackageForFormal(
s.db.WithContext(ctx),
carrierType,
carrierID,
time.Now(),
)
if err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
}
if hasBlockingMain {
return errors.New(errors.CodeMainPackageExists)
}
}
if hasAddon {
if _, err := packagepkg.FindAttachableMainPackageForAddon(
s.db.WithContext(ctx),
carrierType,
carrierID,
time.Now(),
); err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeNoMainPackage)
}
return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
}
}
return nil
}
// validateAgentAllocation 校验卖家代理的分配记录上架状态,并返回分配记录
func (s *Service) validateAgentAllocation(ctx context.Context, sellerShopID, packageID uint) (*model.ShopPackageAllocation, error) {
allocation, err := s.packageAllocationStore.GetByShopAndPackageForSystem(ctx, sellerShopID, packageID)
@@ -252,6 +317,10 @@ func (s *Service) ValidateAdminOfflineCardPurchase(ctx context.Context, cardID u
return nil, err
}
if err := s.validatePackageUsageRules(ctx, constants.AssetWalletResourceTypeIotCard, card.ID, packages); err != nil {
return nil, err
}
return &PurchaseValidationResult{
Card: card,
Packages: packages,
@@ -279,6 +348,10 @@ func (s *Service) ValidateAdminOfflineDevicePurchase(ctx context.Context, device
return nil, err
}
if err := s.validatePackageUsageRules(ctx, constants.AssetWalletResourceTypeDevice, device.ID, packages); err != nil {
return nil, err
}
return &PurchaseValidationResult{
Device: device,
Packages: packages,