实现套餐生效条件覆盖与购买快照
This commit is contained in:
65
internal/domain/package/terms.go
Normal file
65
internal/domain/package/terms.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Package package 提供套餐生命周期领域规则。
|
||||
package packagedomain
|
||||
|
||||
import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
)
|
||||
|
||||
// TermsSnapshot 套餐购买时不可变计时条款。
|
||||
type TermsSnapshot struct {
|
||||
ExpiryBase string
|
||||
CalendarType string
|
||||
DurationMonths int
|
||||
DurationDays int
|
||||
}
|
||||
|
||||
// ResolveTermsSnapshot 解析并校验套餐购买时计时条款。
|
||||
func ResolveTermsSnapshot(pkg *model.Package, allocation *model.ShopPackageAllocation) (TermsSnapshot, error) {
|
||||
if pkg == nil {
|
||||
return TermsSnapshot{}, errors.New(errors.CodeInvalidParam, "套餐计时条款缺失")
|
||||
}
|
||||
expiryBase := pkg.ExpiryBase
|
||||
if allocation != nil && allocation.ExpiryBaseOverride != nil {
|
||||
expiryBase = *allocation.ExpiryBaseOverride
|
||||
}
|
||||
if expiryBase != constants.PackageExpiryBaseFromActivation && expiryBase != constants.PackageExpiryBaseFromPurchase {
|
||||
return TermsSnapshot{}, errors.New(errors.CodeInvalidParam, "套餐生效条件无效")
|
||||
}
|
||||
if pkg.CalendarType == constants.PackageCalendarTypeNaturalMonth {
|
||||
if pkg.DurationMonths <= 0 {
|
||||
return TermsSnapshot{}, errors.New(errors.CodeInvalidParam, "套餐自然月时长无效")
|
||||
}
|
||||
return TermsSnapshot{ExpiryBase: expiryBase, CalendarType: pkg.CalendarType, DurationMonths: pkg.DurationMonths}, nil
|
||||
}
|
||||
if pkg.CalendarType == constants.PackageCalendarTypeByDay && pkg.DurationDays > 0 {
|
||||
return TermsSnapshot{ExpiryBase: expiryBase, CalendarType: pkg.CalendarType, DurationDays: pkg.DurationDays}, nil
|
||||
}
|
||||
return TermsSnapshot{}, errors.New(errors.CodeInvalidParam, "套餐按天时长无效")
|
||||
}
|
||||
|
||||
// Apply 将计时条款写入套餐使用记录。
|
||||
func (s TermsSnapshot) Apply(usage *model.PackageUsage) {
|
||||
usage.ExpiryBaseSnapshot = s.ExpiryBase
|
||||
usage.CalendarTypeSnapshot = s.CalendarType
|
||||
usage.DurationMonthsSnapshot = s.DurationMonths
|
||||
usage.DurationDaysSnapshot = s.DurationDays
|
||||
}
|
||||
|
||||
// IsValid 判断快照是否完整有效。
|
||||
func (s TermsSnapshot) IsValid() bool {
|
||||
if s.ExpiryBase != constants.PackageExpiryBaseFromActivation && s.ExpiryBase != constants.PackageExpiryBaseFromPurchase {
|
||||
return false
|
||||
}
|
||||
return (s.CalendarType == constants.PackageCalendarTypeNaturalMonth && s.DurationMonths > 0) ||
|
||||
(s.CalendarType == constants.PackageCalendarTypeByDay && s.DurationDays > 0)
|
||||
}
|
||||
|
||||
// TermsSnapshotFromUsage 从使用记录读取计时条款。
|
||||
func TermsSnapshotFromUsage(usage *model.PackageUsage) TermsSnapshot {
|
||||
return TermsSnapshot{
|
||||
ExpiryBase: usage.ExpiryBaseSnapshot, CalendarType: usage.CalendarTypeSnapshot,
|
||||
DurationMonths: usage.DurationMonthsSnapshot, DurationDays: usage.DurationDaysSnapshot,
|
||||
}
|
||||
}
|
||||
35
internal/domain/package/terms_test.go
Normal file
35
internal/domain/package/terms_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package packagedomain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
)
|
||||
|
||||
// TestResolveTermsSnapshot 验证默认、覆盖及两种周期规则。
|
||||
func TestResolveTermsSnapshot(t *testing.T) {
|
||||
override := constants.PackageExpiryBaseFromPurchase
|
||||
tests := []struct {
|
||||
name string
|
||||
pkg model.Package
|
||||
allocation *model.ShopPackageAllocation
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "自然月默认", pkg: model.Package{ExpiryBase: constants.PackageExpiryBaseFromActivation, CalendarType: constants.PackageCalendarTypeNaturalMonth, DurationMonths: 12}},
|
||||
{name: "按天覆盖", pkg: model.Package{ExpiryBase: constants.PackageExpiryBaseFromActivation, CalendarType: constants.PackageCalendarTypeByDay, DurationDays: 30}, allocation: &model.ShopPackageAllocation{ExpiryBaseOverride: &override}},
|
||||
{name: "非法生效条件", pkg: model.Package{ExpiryBase: "invalid", CalendarType: constants.PackageCalendarTypeByDay, DurationDays: 30}, wantErr: true},
|
||||
{name: "非法按天时长", pkg: model.Package{ExpiryBase: constants.PackageExpiryBaseFromPurchase, CalendarType: constants.PackageCalendarTypeByDay}, wantErr: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, err := ResolveTermsSnapshot(&test.pkg, test.allocation)
|
||||
if (err != nil) != test.wantErr {
|
||||
t.Fatalf("错误状态不符合预期:%v", err)
|
||||
}
|
||||
if !test.wantErr && !got.IsValid() {
|
||||
t.Fatalf("快照应有效:%+v", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user