- 提取 ResolveTermsFromTx 到 service/package,消除 order 和 auto_purchase 中的重复实现 - 补全 domain 测试:新增 from_activation 覆盖用例,现覆盖两种覆盖值 - 补全激活集成测试:新增 from_purchase 立即激活场景、历史记录兼容回退计数器验证 - 补全自动购包集成测试:新增购买后修改套餐配置不影响已有快照的验证 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
2.7 KiB
Go
68 lines
2.7 KiB
Go
package packagepkg
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
|
|
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/store/postgres"
|
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
"go.uber.org/zap"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var historicalTermsFallbackCount atomic.Uint64
|
|
|
|
// ResolveUsageTerms 优先读取使用记录快照,仅对完整空快照的历史记录显式回退。
|
|
func ResolveUsageTerms(usage *model.PackageUsage, pkg *model.Package, logger *zap.Logger) (packagedomain.TermsSnapshot, error) {
|
|
terms := packagedomain.TermsSnapshotFromUsage(usage)
|
|
if terms.IsValid() {
|
|
return terms, nil
|
|
}
|
|
if !isEmptyHistoricalTerms(usage) {
|
|
if logger != nil {
|
|
logger.Error("套餐使用记录计时快照异常", zap.Uint("package_usage_id", usage.ID), zap.Uint("package_id", usage.PackageID))
|
|
}
|
|
return packagedomain.TermsSnapshot{}, errors.New(errors.CodeInternalError, "套餐使用记录计时快照异常")
|
|
}
|
|
fallback, err := packagedomain.ResolveTermsSnapshot(pkg, nil)
|
|
if err != nil {
|
|
return packagedomain.TermsSnapshot{}, err
|
|
}
|
|
historicalTermsFallbackCount.Add(1)
|
|
if logger != nil {
|
|
logger.Warn("历史套餐使用记录缺少计时快照,回退套餐当前配置",
|
|
zap.Uint("package_usage_id", usage.ID), zap.Uint("package_id", usage.PackageID),
|
|
zap.Uint64("historical_terms_fallback_count", historicalTermsFallbackCount.Load()))
|
|
}
|
|
return fallback, nil
|
|
}
|
|
|
|
// HistoricalTermsFallbackCount 返回历史计时条款回退累计次数。
|
|
func HistoricalTermsFallbackCount() uint64 {
|
|
return historicalTermsFallbackCount.Load()
|
|
}
|
|
|
|
// ResolveTermsFromTx 在给定事务内查询分配覆盖并解析计时条款快照。
|
|
// 必须在事务内调用,确保分配读取与 PackageUsage 写入在同一连接,避免快照与提交值不一致。
|
|
func ResolveTermsFromTx(ctx context.Context, tx *gorm.DB, pkg *model.Package, sellerShopID *uint) (packagedomain.TermsSnapshot, error) {
|
|
var allocation *model.ShopPackageAllocation
|
|
if sellerShopID != nil && *sellerShopID > 0 {
|
|
store := postgres.NewShopPackageAllocationStore(tx)
|
|
found, err := store.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 isEmptyHistoricalTerms(usage *model.PackageUsage) bool {
|
|
return usage.ExpiryBaseSnapshot == "" && usage.CalendarTypeSnapshot == "" &&
|
|
usage.DurationMonthsSnapshot == 0 && usage.DurationDaysSnapshot == 0
|
|
}
|