214 lines
6.6 KiB
Go
214 lines
6.6 KiB
Go
package iot
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
|
)
|
|
|
|
func TestAddRenewDurationByUnitKeepsSameCalendarDate(t *testing.T) {
|
|
begin := time.Date(2026, time.September, 1, 0, 0, 0, 0, time.Local)
|
|
got := addRenewDurationByUnit(begin, "year", 1)
|
|
want := time.Date(2027, time.September, 1, 23, 59, 59, 0, time.Local)
|
|
if !got.Equal(want) {
|
|
t.Fatalf(
|
|
"addRenewDurationByUnit() = %s, want %s",
|
|
got.Format(time.RFC3339),
|
|
want.Format(time.RFC3339),
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestValidateRenewConfirmContract(t *testing.T) {
|
|
snapshot := &model.TSimCardRenewPriceSnapshot{
|
|
RenewableDurationOptions: []int{12, 24, 36},
|
|
}
|
|
if err := validateRenewConfirmContract(snapshot, 24); err != nil {
|
|
t.Fatalf("valid renew contract rejected: %v", err)
|
|
}
|
|
if err := validateRenewConfirmContract(snapshot, 6); err == nil {
|
|
t.Fatal("renew duration outside prepare contract was accepted")
|
|
}
|
|
if err := validateRenewConfirmContract(nil, 12); err == nil {
|
|
t.Fatal("missing renew contract was accepted")
|
|
}
|
|
}
|
|
|
|
func TestValidateChangeConfirmContract(t *testing.T) {
|
|
prepareSnapshot := &model.TSimCardChangePrepareSnapshot{
|
|
OldPackageCode: "PKG-OLD",
|
|
}
|
|
priceSnapshot := &model.TSimCardChangePriceSnapshot{
|
|
NewPackageCode: "PKG-NEW",
|
|
RenewableDurationOptions: []int{12, 24},
|
|
}
|
|
valid := &model.TSimCardChangeBatchSubmitParam{
|
|
NewPackageCode: "PKG-NEW",
|
|
DurationMonths: 12,
|
|
EffectiveMode: cardChangeEffectiveNextMonth,
|
|
}
|
|
if err := validateChangeConfirmContract(prepareSnapshot, priceSnapshot, cardChangeEffectiveNextMonth, valid); err != nil {
|
|
t.Fatalf("valid change contract rejected: %v", err)
|
|
}
|
|
if err := validateChangeConfirmContract(prepareSnapshot, priceSnapshot, "", valid); err != nil {
|
|
t.Fatalf("legacy change contract without effective mode rejected: %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
in model.TSimCardChangeBatchSubmitParam
|
|
}{
|
|
{
|
|
name: "current package selected",
|
|
in: model.TSimCardChangeBatchSubmitParam{
|
|
NewPackageCode: "PKG-OLD",
|
|
DurationMonths: 12,
|
|
EffectiveMode: cardChangeEffectiveNextMonth,
|
|
},
|
|
},
|
|
{
|
|
name: "target package changed",
|
|
in: model.TSimCardChangeBatchSubmitParam{
|
|
NewPackageCode: "PKG-OTHER",
|
|
DurationMonths: 12,
|
|
EffectiveMode: cardChangeEffectiveNextMonth,
|
|
},
|
|
},
|
|
{
|
|
name: "duration outside contract",
|
|
in: model.TSimCardChangeBatchSubmitParam{
|
|
NewPackageCode: "PKG-NEW",
|
|
DurationMonths: 6,
|
|
EffectiveMode: cardChangeEffectiveNextMonth,
|
|
},
|
|
},
|
|
{
|
|
name: "effective mode changed",
|
|
in: model.TSimCardChangeBatchSubmitParam{
|
|
NewPackageCode: "PKG-NEW",
|
|
DurationMonths: 12,
|
|
EffectiveMode: cardChangeEffectiveImmediate,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if err := validateChangeConfirmContract(prepareSnapshot, priceSnapshot, cardChangeEffectiveNextMonth, &tt.in); err == nil {
|
|
t.Fatal("invalid change contract was accepted")
|
|
}
|
|
})
|
|
}
|
|
|
|
if err := validateChangeConfirmContract(nil, priceSnapshot, cardChangeEffectiveNextMonth, valid); err == nil {
|
|
t.Fatal("missing change contract was accepted")
|
|
}
|
|
}
|
|
|
|
func TestNormalizeAddPackagePaymentIntent(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
mode string
|
|
confirmed bool
|
|
isTopDept bool
|
|
wantMode string
|
|
wantConfirm bool
|
|
wantErr string
|
|
}{
|
|
{name: "child default uses balance", wantMode: "balance"},
|
|
{name: "top default uses balance", isTopDept: true, wantMode: "balance"},
|
|
{name: "balance clears offline confirmation", mode: "balance", confirmed: true, isTopDept: true, wantMode: "balance"},
|
|
{name: "child cannot use offline", mode: "offline", confirmed: true, wantErr: "必须使用余额支付"},
|
|
{name: "top offline requires confirmation", mode: "offline", isTopDept: true, wantErr: "请确认线下合同"},
|
|
{name: "top offline keeps confirmation", mode: "offline", confirmed: true, isTopDept: true, wantMode: "offline", wantConfirm: true},
|
|
{name: "invalid payment mode", mode: "cash", isTopDept: true, wantErr: "付款方式不正确"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotMode, gotConfirm, err := normalizeAddPackagePaymentIntent(tt.mode, tt.confirmed, tt.isTopDept)
|
|
if tt.wantErr != "" {
|
|
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Fatalf("error = %v, want substring %q", err, tt.wantErr)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("normalizeAddPackagePaymentIntent() error = %v", err)
|
|
}
|
|
if gotMode != tt.wantMode {
|
|
t.Fatalf("payment mode = %q, want %q", gotMode, tt.wantMode)
|
|
}
|
|
if gotConfirm != tt.wantConfirm {
|
|
t.Fatalf("offline confirmation = %v, want %v", gotConfirm, tt.wantConfirm)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizedChangePrepareSourceBatchNo(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
sourceType int
|
|
mainSource string
|
|
snapshot string
|
|
want string
|
|
}{
|
|
{
|
|
name: "input ignores self reference",
|
|
sourceType: consts.BatchSourceTypeBatchInput,
|
|
mainSource: "CHG20260803170000INPUT",
|
|
snapshot: "CHG20260803170000INPUT",
|
|
},
|
|
{
|
|
name: "file ignores stale source",
|
|
sourceType: consts.BatchSourceTypeFile,
|
|
mainSource: "CHG20260803170000FILE",
|
|
snapshot: "OUT20260803STALE",
|
|
},
|
|
{
|
|
name: "batch selection keeps snapshot source",
|
|
sourceType: consts.BatchSourceTypeBatchSelect,
|
|
mainSource: "OUT20260803MAIN",
|
|
snapshot: "OUT20260803CONFIRMED",
|
|
want: "OUT20260803CONFIRMED",
|
|
},
|
|
{
|
|
name: "batch selection repairs worker self reference",
|
|
sourceType: consts.BatchSourceTypeBatchSelect,
|
|
mainSource: "OUT20260803MAIN",
|
|
snapshot: "CHG20260803170000BATCH",
|
|
want: "OUT20260803MAIN",
|
|
},
|
|
{
|
|
name: "legacy self reference without real source becomes empty",
|
|
sourceType: consts.BatchSourceTypeBatchSelect,
|
|
mainSource: "CHG20260803170000BATCH",
|
|
snapshot: "CHG20260803170000BATCH",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
batchNo := "CHG20260803170000BATCH"
|
|
if tt.sourceType == consts.BatchSourceTypeBatchInput {
|
|
batchNo = "CHG20260803170000INPUT"
|
|
}
|
|
if tt.sourceType == consts.BatchSourceTypeFile {
|
|
batchNo = "CHG20260803170000FILE"
|
|
}
|
|
batch := &entity.BatchMain{
|
|
BatchNo: batchNo,
|
|
SourceType: tt.sourceType,
|
|
SourceBatchNo: tt.mainSource,
|
|
}
|
|
if got := normalizedChangePrepareSourceBatchNo(batch, tt.snapshot); got != tt.want {
|
|
t.Fatalf("sourceBatchNo = %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|