Files
iotlcm/worker-svr/internal/service/renewchange/subscription_validation.go
T

210 lines
6.2 KiB
Go

package renewchange
import (
"strings"
"github.com/gogf/gf/v2/errors/gerror"
"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"
)
type subscriptionValidation struct {
ICCID string
MSISDN string
IMSI string
TenantID string
CustomerDeptID int64
PackageCode string
SourceBatchNo string
}
// resolveCurrentSubscriptions selects the current package fact per ICCID.
// It keeps future pending subscriptions for change-package cleanup, while
// allowing renew to append after the farthest pending subscription.
func resolveCurrentSubscriptions(rows []*rc.SimCardBindPkg, iccids []string) (map[string]*rc.SimCardBindPkg, map[string][]*rc.SimCardBindPkg, error) {
grouped := make(map[string][]*rc.SimCardBindPkg, len(iccids))
for _, row := range rows {
if row == nil {
continue
}
iccid := strings.TrimSpace(row.Iccid)
if iccid == "" {
continue
}
grouped[iccid] = append(grouped[iccid], row)
}
current := make(map[string]*rc.SimCardBindPkg, len(iccids))
future := make(map[string][]*rc.SimCardBindPkg, len(iccids))
for _, rawICCID := range iccids {
iccid := strings.TrimSpace(rawICCID)
selected, pending, err := selectCurrentSubscription(grouped[iccid], iccid)
if err != nil {
return nil, nil, err
}
current[iccid] = selected
future[iccid] = pending
}
return current, future, nil
}
func selectCurrentSubscription(rows []*rc.SimCardBindPkg, iccid string) (*rc.SimCardBindPkg, []*rc.SimCardBindPkg, error) {
var (
effective *rc.SimCardBindPkg
pending []*rc.SimCardBindPkg
expired []*rc.SimCardBindPkg
)
for _, row := range rows {
if row == nil || strings.TrimSpace(row.Iccid) != strings.TrimSpace(iccid) {
continue
}
if consts.IsAddPackageType(row.PackageType) {
continue
}
switch row.EffectiveStatus {
case consts.EffectiveStatusEffective:
if effective != nil {
return nil, nil, gerror.Newf("同一张卡存在多个生效中的套餐订购记录:%s", iccid)
}
effective = row
case consts.EffectiveStatusPending:
pending = append(pending, row)
case consts.EffectiveStatusExpired:
expired = append(expired, row)
}
}
sortPendingSubscriptions(pending)
if effective != nil {
return effective, pending, nil
}
if len(pending) > 0 {
return pending[0], pending[1:], nil
}
if latest := latestExpiredSubscription(expired); latest != nil {
return latest, nil, nil
}
return nil, nil, gerror.Newf("ICCID没有当前套餐订购记录:%s", iccid)
}
func latestExpiredSubscription(rows []*rc.SimCardBindPkg) *rc.SimCardBindPkg {
var latest *rc.SimCardBindPkg
for _, row := range rows {
if row == nil {
continue
}
if latest == nil || subscriptionAfter(row, latest) {
latest = row
}
}
return latest
}
func sortPendingSubscriptions(rows []*rc.SimCardBindPkg) {
if len(rows) <= 1 {
return
}
for i := 1; i < len(rows); i++ {
current := rows[i]
j := i - 1
for j >= 0 && subscriptionAfter(rows[j], current) {
rows[j+1] = rows[j]
j--
}
rows[j+1] = current
}
}
func subscriptionAfter(left, right *rc.SimCardBindPkg) bool {
if compareTime(expectedExpireTime(left), expectedExpireTime(right)) != 0 {
return compareTime(expectedExpireTime(left), expectedExpireTime(right)) > 0
}
if compareTime(effectiveTime(left), effectiveTime(right)) != 0 {
return compareTime(effectiveTime(left), effectiveTime(right)) > 0
}
return strings.TrimSpace(subscriptionNo(left)) > strings.TrimSpace(subscriptionNo(right))
}
func expectedExpireTime(row *rc.SimCardBindPkg) *gtime.Time {
if row == nil {
return nil
}
return row.ExpectedExpireTime
}
func effectiveTime(row *rc.SimCardBindPkg) *gtime.Time {
if row == nil {
return nil
}
return row.EffectiveTime
}
func subscriptionNo(row *rc.SimCardBindPkg) string {
if row == nil {
return ""
}
return row.SubscriptionNo
}
func compareTime(left, right *gtime.Time) int {
switch {
case left == nil && right == nil:
return 0
case left == nil:
return -1
case right == nil:
return 1
case left.Before(right):
return -1
case left.After(right):
return 1
default:
return 0
}
}
func validateCurrentSubscription(card *rc.SimCardInfo, bind *rc.SimCardBindPkg, expected subscriptionValidation) error {
if card == nil || bind == nil {
return gerror.New("卡信息或当前订购记录缺失")
}
iccid := strings.TrimSpace(expected.ICCID)
if iccid == "" || strings.TrimSpace(card.Iccid) != iccid || strings.TrimSpace(bind.Iccid) != iccid {
return gerror.New("ICCID不一致")
}
if strings.TrimSpace(expected.TenantID) != "" &&
(strings.TrimSpace(card.TenantId) != expected.TenantID || strings.TrimSpace(bind.TenantId) != expected.TenantID) {
return gerror.New("租户不一致")
}
// t_sim_card_info.dept_id is the current card owner. A card allocation
// changes that field, while the historical bind row keeps the department
// that originally purchased the subscription.
if expected.CustomerDeptID <= 0 || card.DeptId != expected.CustomerDeptID {
return gerror.New("客户部门不一致")
}
packageCode := strings.TrimSpace(expected.PackageCode)
if packageCode == "" || strings.TrimSpace(card.CurrentPackageCode) != packageCode || strings.TrimSpace(bind.PackageCode) != packageCode {
return gerror.New("当前套餐不一致")
}
if card.PackageStatus == consts.PackageStatusNone {
return gerror.New("卡没有当前套餐")
}
if msisdn := strings.TrimSpace(expected.MSISDN); msisdn != "" && strings.TrimSpace(card.Msisdn) != msisdn {
return gerror.New("MSISDN不一致")
}
if bindMSISDN := strings.TrimSpace(bind.Msisdn); bindMSISDN != "" && strings.TrimSpace(card.Msisdn) != bindMSISDN {
return gerror.New("订购记录MSISDN不一致")
}
if imsi := strings.TrimSpace(expected.IMSI); imsi != "" && strings.TrimSpace(card.Imsi) != imsi {
return gerror.New("IMSI不一致")
}
if sourceBatchNo := strings.TrimSpace(expected.SourceBatchNo); sourceBatchNo != "" {
bindBatchNo := strings.TrimSpace(bind.BatchNo)
outboundBatchNo := strings.TrimSpace(card.OutboundBatchNo)
if bindBatchNo != sourceBatchNo && outboundBatchNo != sourceBatchNo {
return gerror.New("当前订购来源批次不一致")
}
}
return nil
}