544 lines
20 KiB
Go
544 lines
20 KiB
Go
package renewchange
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gjson"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/consts"
|
|
rc "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/repository/renewchange"
|
|
)
|
|
|
|
func TestValidateRuntimeRenewDurationRejectsUnsupportedOption(t *testing.T) {
|
|
pkg := &rc.FlowPackageInfo{
|
|
PackageCode: "PKG001",
|
|
BillingMethod: consts.BillingMethodMonth,
|
|
PackageName: "测试套餐",
|
|
RenewableDurationConfig: gjson.New([]any{1, 2, 3}),
|
|
}
|
|
|
|
options, err := validateRuntimeRenewDuration(pkg, 1)
|
|
if err != nil {
|
|
t.Fatalf("validateRuntimeRenewDuration returned error: %v", err)
|
|
}
|
|
if len(options) != 3 {
|
|
t.Fatalf("options = %v, want 3 entries", options)
|
|
}
|
|
|
|
_, err = validateRuntimeRenewDuration(pkg, 4)
|
|
if err == nil {
|
|
t.Fatal("expected unsupported renew duration to be rejected")
|
|
}
|
|
if got := err.Error(); !strings.Contains(got, "4年") || !strings.Contains(got, "测试套餐(PKG001)") || !strings.Contains(got, "3年") {
|
|
t.Fatalf("error message %q does not include duration/package/options", got)
|
|
}
|
|
}
|
|
|
|
func TestValidateRuntimeRenewDurationNormalizesLegacyMonthOptions(t *testing.T) {
|
|
pkg := &rc.FlowPackageInfo{
|
|
PackageCode: "PKG001",
|
|
PackageName: "测试套餐",
|
|
RenewableDurationConfig: gjson.New([]any{12, 24, 36}),
|
|
}
|
|
|
|
options, err := validateRuntimeRenewDuration(pkg, 2)
|
|
if err != nil {
|
|
t.Fatalf("validateRuntimeRenewDuration returned error: %v", err)
|
|
}
|
|
if got := options; len(got) != 3 || got[0] != 1 || got[1] != 2 || got[2] != 3 {
|
|
t.Fatalf("options = %v, want [1 2 3]", got)
|
|
}
|
|
}
|
|
|
|
func TestAddMonthsClampsToTargetMonthEnd(t *testing.T) {
|
|
begin := time.Date(2027, time.January, 31, 0, 0, 0, 0, time.UTC)
|
|
want := time.Date(2027, time.February, 28, 0, 0, 0, 0, time.UTC)
|
|
if got := addMonths(begin, 1); !got.Equal(want) {
|
|
t.Fatalf("addMonths() = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestRenewBaseSubscriptionForCardPrefersLaterCardExpire(t *testing.T) {
|
|
card := &rc.SimCardInfo{
|
|
Iccid: "8986001",
|
|
CurrentPackageCode: "PKG001",
|
|
FlowPkgEndAt: gtime.NewFromStr("2026-08-31 00:00:00"),
|
|
FlowPkgPresentAt: gtime.NewFromStr("2026-09-30 00:00:00"),
|
|
FlowPkgRealPresent: gtime.NewFromStr("2026-10-31 00:00:00"),
|
|
}
|
|
bind := &rc.SimCardBindPkg{
|
|
Iccid: "8986001",
|
|
PackageCode: "PKG001",
|
|
ExpectedExpireTime: gtime.NewFromStr("2026-08-31 00:00:00"),
|
|
}
|
|
|
|
if got := renewBaseSubscriptionForCard(card, bind, nil); got == nil || got.ExpectedExpireTime.Format("Y-m-d") != "2026-10-31" {
|
|
t.Fatalf("renew base expire = %v, want 2026-10-31", got)
|
|
}
|
|
}
|
|
|
|
func TestParseExecutionContractConvertsYearDurationToActualMonths(t *testing.T) {
|
|
main := &rc.BatchMainRow{
|
|
BatchNo: "REN20260806000000TEST",
|
|
BatchType: consts.BatchTypeRenew,
|
|
TenantId: "000000",
|
|
DeptId: 1000,
|
|
CreatedDept: 1000,
|
|
CreatedBy: 1,
|
|
BatchInfo: gjson.New(map[string]any{
|
|
"customerAgentId": 1001,
|
|
"packageCode": "PKG001",
|
|
"packageName": "Test package",
|
|
"renewUnitPrice": 120,
|
|
"quantity": 2,
|
|
"billingMethod": consts.BillingMethodYear,
|
|
"renewDurationUnit": consts.RenewDurationUnitYear,
|
|
"durationValue": 1,
|
|
"durationMonths": 1,
|
|
"offlineContractCompleted": true,
|
|
"paymentMode": "offline",
|
|
}),
|
|
}
|
|
|
|
contract, err := ParseExecutionContract(main)
|
|
if err != nil {
|
|
t.Fatalf("ParseExecutionContract returned error: %v", err)
|
|
}
|
|
if contract.DurationDisplayValue != 1 {
|
|
t.Fatalf("display duration = %d, want 1", contract.DurationDisplayValue)
|
|
}
|
|
if contract.DurationMonths != 12 {
|
|
t.Fatalf("actual duration months = %d, want 12", contract.DurationMonths)
|
|
}
|
|
if got := contract.TotalAmount(); got != 240 {
|
|
t.Fatalf("total amount = %v, want 240", got)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeRenewFactsRequiresSameCurrentPeriod(t *testing.T) {
|
|
main := &rc.BatchMainRow{
|
|
BatchNo: "REN20260806000000TEST",
|
|
TenantId: "000000",
|
|
}
|
|
begin := gtime.NewFromStr("2026-01-01 00:00:00")
|
|
expire := gtime.NewFromStr("2026-12-31 23:59:59")
|
|
details := []*rc.BatchDetailRow{
|
|
{RowNo: 1, ItemId: "898600000000000001"},
|
|
{RowNo: 2, ItemId: "898600000000000002"},
|
|
}
|
|
cards := map[string]*rc.SimCardInfo{
|
|
details[0].ItemId: {
|
|
Iccid: details[0].ItemId,
|
|
DeptId: 117,
|
|
CurrentPackageCode: "PKG001",
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
TenantId: main.TenantId,
|
|
},
|
|
details[1].ItemId: {
|
|
Iccid: details[1].ItemId,
|
|
DeptId: 117,
|
|
CurrentPackageCode: "PKG001",
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
TenantId: main.TenantId,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
details[0].ItemId: {
|
|
Iccid: details[0].ItemId,
|
|
DeptId: 117,
|
|
PackageCode: "PKG001",
|
|
EffectiveTime: begin,
|
|
ExpectedExpireTime: expire,
|
|
TenantId: main.TenantId,
|
|
},
|
|
details[1].ItemId: {
|
|
Iccid: details[1].ItemId,
|
|
DeptId: 117,
|
|
PackageCode: "PKG001",
|
|
EffectiveTime: begin,
|
|
ExpectedExpireTime: expire,
|
|
TenantId: main.TenantId,
|
|
},
|
|
}
|
|
|
|
now := time.Date(2026, 8, 1, 0, 0, 0, 0, time.Local)
|
|
if _, _, _, err := runtimeRenewFacts(main, details, cards, binds, nil, now); err != nil {
|
|
t.Fatalf("runtimeRenewFacts() error = %v", err)
|
|
}
|
|
|
|
binds[details[1].ItemId].ExpectedExpireTime = gtime.NewFromStr("2027-01-31 23:59:59")
|
|
if _, _, _, err := runtimeRenewFacts(main, details, cards, binds, nil, now); err == nil {
|
|
t.Fatalf("runtimeRenewFacts() error = nil, want same period failure")
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsUsesConfirmedDuration(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
base := now.AddDate(0, 1, 0)
|
|
contract := testRenewContract(12, 2)
|
|
details := []*rc.BatchDetailRow{{RowNo: 1, ItemId: "8986000000000000001"}}
|
|
cards := map[string]*rc.SimCardInfo{
|
|
details[0].ItemId: {
|
|
Iccid: details[0].ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
FlowPkgBeginAt: gtime.NewFromTime(now.AddDate(0, -1, 0)),
|
|
FlowPkgEndAt: gtime.NewFromTime(base),
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
details[0].ItemId: {
|
|
Iccid: details[0].ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
Msisdn: cards[details[0].ItemId].Msisdn,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(base),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
|
|
got, err := validateRenewExecutions(contract, details, cards, binds, nil, now)
|
|
if err != nil {
|
|
t.Fatalf("validateRenewExecutions returned error: %v", err)
|
|
}
|
|
renewBegin := renewBeginDateFromExpire(gtime.NewFromTime(base))
|
|
wantEnd := addMonths(renewBegin.Time, 14)
|
|
if len(got) != 1 || !got[0].end.Equal(wantEnd) {
|
|
t.Fatalf("renew end = %v, want %v", got[0].end, wantEnd)
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsUsesLatestBindExpiration(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
contract := testRenewContract(12, 0)
|
|
detail := &rc.BatchDetailRow{RowNo: 1, ItemId: "8986000000000000002"}
|
|
cardEnd := gtime.NewFromTime(time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC))
|
|
cards := map[string]*rc.SimCardInfo{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
FlowPkgEndAt: cardEnd,
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
Msisdn: cards[detail.ItemId].Msisdn,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(cardEnd.Time.AddDate(0, 0, 1)),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
|
|
got, err := validateRenewExecutions(contract, []*rc.BatchDetailRow{detail}, cards, binds, nil, now)
|
|
if err != nil {
|
|
t.Fatalf("validateRenewExecutions returned error: %v", err)
|
|
}
|
|
renewBegin := renewBeginDateFromExpire(gtime.NewFromTime(cardEnd.Time.AddDate(0, 0, 1)))
|
|
wantEnd := addMonths(renewBegin.Time, contract.DurationMonths)
|
|
if len(got) != 1 || !got[0].end.Equal(wantEnd) {
|
|
t.Fatalf("renew end = %v, want %v", got[0].end, wantEnd)
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsAllowsRenewalFromExpiredSubscription(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
contract := testRenewContract(12, 0)
|
|
detail := &rc.BatchDetailRow{RowNo: 1, ItemId: "8986000000000000006"}
|
|
expiredAt := time.Date(2026, 7, 1, 0, 0, 0, 0, time.UTC)
|
|
cards := map[string]*rc.SimCardInfo{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusExpired,
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
EffectiveStatus: consts.EffectiveStatusExpired,
|
|
ExpectedExpireTime: gtime.NewFromTime(expiredAt),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
|
|
got, err := validateRenewExecutions(contract, []*rc.BatchDetailRow{detail}, cards, binds, nil, now)
|
|
if err != nil {
|
|
t.Fatalf("validateRenewExecutions returned error: %v", err)
|
|
}
|
|
renewBegin := renewBeginDateFromExpire(gtime.NewFromTime(expiredAt))
|
|
wantEnd := addMonths(renewBegin.Time, contract.DurationMonths)
|
|
if len(got) != 1 || !got[0].begin.Equal(renewBegin.Time) || !got[0].end.Equal(wantEnd) {
|
|
t.Fatalf("renew range = %v - %v, want %v - %v", got[0].begin, got[0].end, renewBegin.Time, wantEnd)
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsAppendsAfterFuturePendingExpiration(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
contract := testRenewContract(12, 0)
|
|
detail := &rc.BatchDetailRow{RowNo: 1, ItemId: "8986000000000000005"}
|
|
currentExpire := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
|
|
futureExpire := time.Date(2027, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
cards := map[string]*rc.SimCardInfo{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(currentExpire),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
futureBinds := map[string][]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
{
|
|
Iccid: detail.ItemId,
|
|
BatchNo: "REN-FUTURE",
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(futureExpire),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
},
|
|
}
|
|
|
|
got, err := validateRenewExecutions(contract, []*rc.BatchDetailRow{detail}, cards, binds, futureBinds, now)
|
|
if err != nil {
|
|
t.Fatalf("validateRenewExecutions returned error: %v", err)
|
|
}
|
|
renewBegin := renewBeginDateFromExpire(gtime.NewFromTime(futureExpire))
|
|
wantEnd := addMonths(renewBegin.Time, contract.DurationMonths)
|
|
if len(got) != 1 || !got[0].begin.Equal(renewBegin.Time) || !got[0].end.Equal(wantEnd) {
|
|
t.Fatalf("renew range = %v - %v, want %v - %v", got[0].begin, got[0].end, renewBegin.Time, wantEnd)
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsRejectsPendingExpirationBeyondWindow(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
contract := testRenewContract(12, 0)
|
|
detail := &rc.BatchDetailRow{RowNo: 1, ItemId: "8986000000000000007"}
|
|
currentExpire := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
|
|
futureExpire := time.Date(2027, 9, 1, 0, 0, 0, 0, time.UTC)
|
|
cards := map[string]*rc.SimCardInfo{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(currentExpire),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
futureBinds := map[string][]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
{
|
|
Iccid: detail.ItemId,
|
|
BatchNo: "REN-FUTURE",
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(futureExpire),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := validateRenewExecutions(contract, []*rc.BatchDetailRow{detail}, cards, binds, futureBinds, now)
|
|
if err == nil || !strings.Contains(err.Error(), renewExpireFailureReason) {
|
|
t.Fatalf("validateRenewExecutions error = %v, want renew window failure", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateRunningRenewDetailsRejectsChangedSnapshot(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
locked []*rc.BatchDetailRow
|
|
loaded []*rc.BatchDetailRow
|
|
}{
|
|
{
|
|
name: "count",
|
|
locked: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
loaded: nil,
|
|
},
|
|
{
|
|
name: "id",
|
|
locked: []*rc.BatchDetailRow{{Id: 2, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
loaded: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
},
|
|
{
|
|
name: "row number",
|
|
locked: []*rc.BatchDetailRow{{Id: 1, RowNo: 2, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
loaded: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
},
|
|
{
|
|
name: "iccid",
|
|
locked: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986002", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
loaded: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
},
|
|
{
|
|
name: "status",
|
|
locked: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusSuccess}},
|
|
loaded: []*rc.BatchDetailRow{{Id: 1, RowNo: 1, ItemId: "8986001", DetailStatus: consts.BatchDetailStatusRunning}},
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if err := validateRunningRenewDetails(tc.locked, tc.loaded); err == nil {
|
|
t.Fatal("expected changed renew details to be rejected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewExecutionsUsesConfirmedPackageBeginTime(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.Local)
|
|
contract := testRenewContract(12, 0)
|
|
confirmedBegin := time.Date(2026, 10, 1, 0, 0, 0, 0, time.Local)
|
|
contract.PackageBeginTime = gtime.NewFromTime(confirmedBegin)
|
|
detail := &rc.BatchDetailRow{RowNo: 1, ItemId: "8986000000000000004"}
|
|
latestExpire := time.Date(2026, 9, 1, 0, 0, 0, 0, time.Local)
|
|
cards := map[string]*rc.SimCardInfo{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
DeptId: contract.CustomerAgentID,
|
|
CurrentPackageCode: contract.PackageCode,
|
|
PackageStatus: consts.PackageStatusEffective,
|
|
OutboundBatchNo: contract.SourceBatchNo,
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
binds := map[string]*rc.SimCardBindPkg{
|
|
detail.ItemId: {
|
|
Iccid: detail.ItemId,
|
|
BatchNo: contract.SourceBatchNo,
|
|
DeptId: contract.CustomerAgentID,
|
|
PackageCode: contract.PackageCode,
|
|
ExpectedExpireTime: gtime.NewFromTime(latestExpire),
|
|
TenantId: contract.TenantID,
|
|
},
|
|
}
|
|
|
|
got, err := validateRenewExecutions(contract, []*rc.BatchDetailRow{detail}, cards, binds, nil, now)
|
|
if err != nil {
|
|
t.Fatalf("validateRenewExecutions returned error: %v", err)
|
|
}
|
|
wantEnd := addMonths(confirmedBegin, contract.DurationMonths)
|
|
if len(got) != 1 || !got[0].begin.Equal(confirmedBegin) || !got[0].end.Equal(wantEnd) {
|
|
t.Fatalf("renew range = %v - %v, want %v - %v", got[0].begin, got[0].end, confirmedBegin, wantEnd)
|
|
}
|
|
}
|
|
|
|
func TestBuildRenewBindUsesConfirmedContract(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
begin := now.AddDate(0, 1, 0)
|
|
contract := testRenewContract(12, 3)
|
|
pkg := &rc.FlowPackageInfo{PackageCode: contract.PackageCode, PackageType: 7}
|
|
execution := renewExecution{
|
|
card: &rc.SimCardInfo{Iccid: "8986000000000000003", Msisdn: "13800000000"},
|
|
bind: &rc.SimCardBindPkg{ExpectedExpireTime: gtime.NewFromTime(begin)},
|
|
begin: begin,
|
|
end: contract.ServiceEnd(begin),
|
|
}
|
|
|
|
bind := buildRenewBind(contract, pkg, execution, "SO20260803100000ABC", "SUB20260803100000ABC", now)
|
|
if bind.DurationMonths != 12 || bind.GiftDurationMonths != 3 {
|
|
t.Fatalf("duration = %d+%d, want 12+3", bind.DurationMonths, bind.GiftDurationMonths)
|
|
}
|
|
if bind.PackageType != 7 || bind.EffectiveTime.Time != begin {
|
|
t.Fatalf("bind contract fields were not preserved: %+v", bind)
|
|
}
|
|
}
|
|
|
|
func TestBuildRenewDetailSnapshotUsesConfirmedBatchAmount(t *testing.T) {
|
|
contract := testRenewContract(12, 0)
|
|
contract.Quantity = 2
|
|
execution := renewExecution{
|
|
detail: &rc.BatchDetailRow{RowNo: 1},
|
|
card: &rc.SimCardInfo{Iccid: "8986000000000000003"},
|
|
bind: &rc.SimCardBindPkg{},
|
|
begin: time.Date(2026, 8, 3, 0, 0, 0, 0, time.UTC),
|
|
end: time.Date(2027, 8, 3, 0, 0, 0, 0, time.UTC),
|
|
}
|
|
pkg := &rc.FlowPackageInfo{PackageCode: contract.PackageCode, PackageName: contract.PackageName}
|
|
|
|
snapshot := buildRenewDetailSnapshot(execution, contract, pkg, "SO-1", "SUB-1")
|
|
if got := snapshot.Get("amount").Float64(); got != 240 {
|
|
t.Fatalf("detail amount = %v, want confirmed batch amount 240", got)
|
|
}
|
|
}
|
|
|
|
func TestRenewPackageStatus(t *testing.T) {
|
|
now := time.Date(2026, 8, 3, 10, 0, 0, 0, time.UTC)
|
|
if got := renewPackageStatus(now, gtime.NewFromTime(now.AddDate(0, 1, 0)), gtime.NewFromTime(now.AddDate(0, 13, 0))); got != consts.PackageStatusPending {
|
|
t.Fatalf("future package status = %d, want pending", got)
|
|
}
|
|
if got := renewPackageStatus(now, gtime.NewFromTime(now.AddDate(0, -1, 0)), gtime.NewFromTime(now.AddDate(0, 1, 0))); got != consts.PackageStatusEffective {
|
|
t.Fatalf("active package status = %d, want effective", got)
|
|
}
|
|
if got := renewPackageStatus(now, gtime.NewFromTime(now.AddDate(0, -2, 0)), gtime.NewFromTime(now.AddDate(0, -1, 0))); got != consts.PackageStatusExpired {
|
|
t.Fatalf("expired package status = %d, want expired", got)
|
|
}
|
|
}
|
|
|
|
func testRenewContract(duration, gift int) *ExecutionContract {
|
|
return &ExecutionContract{
|
|
BatchNo: "REN20260803100000TEST",
|
|
BatchType: consts.BatchTypeRenew,
|
|
SourceBatchNo: "OUT20260801TEST",
|
|
TenantID: "000000",
|
|
CustomerAgentID: 1001,
|
|
SellerAgentID: 1000,
|
|
CreatedDeptID: 1000,
|
|
OperatorUserID: 1,
|
|
PackageCode: "PKG001",
|
|
PackageName: "Test package",
|
|
PriceSource: PriceSourceSystem,
|
|
UnitPrice: 10,
|
|
Quantity: 1,
|
|
DurationMonths: duration,
|
|
GiftDurationMonths: gift,
|
|
OfflineContractCompleted: true,
|
|
BuyerNote: "buyer",
|
|
AdminNote: "admin",
|
|
Remark: "renew test",
|
|
}
|
|
}
|