307 lines
12 KiB
Go
307 lines
12 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/dao"
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/do"
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
)
|
|
|
|
type appRenewExecutionContext struct {
|
|
CardPeriods []map[string]any
|
|
LatestBindsByIccid map[string]*entity.TSimCardBindPkg
|
|
NewBindsByIccid map[string]*entity.TSimCardBindPkg
|
|
BeginAtByIccid map[string]*gtime.Time
|
|
EndAtByIccid map[string]*gtime.Time
|
|
MinBeginAt *gtime.Time
|
|
MaxEndAt *gtime.Time
|
|
}
|
|
|
|
func (s *sAppCard) prepareAppRenewExecution(ctx context.Context, tx gdb.TX, batch *appRenewBatchContext, durationMonths int) (*appRenewExecutionContext, error) {
|
|
if batch == nil || len(batch.Items) == 0 {
|
|
return nil, gerror.New("续费卡不能为空")
|
|
}
|
|
if durationMonths <= 0 {
|
|
return nil, gerror.New("续费时长必须大于0")
|
|
}
|
|
|
|
exec := &appRenewExecutionContext{
|
|
CardPeriods: make([]map[string]any, 0, len(batch.Items)),
|
|
LatestBindsByIccid: make(map[string]*entity.TSimCardBindPkg, len(batch.Items)),
|
|
NewBindsByIccid: make(map[string]*entity.TSimCardBindPkg, len(batch.Items)),
|
|
BeginAtByIccid: make(map[string]*gtime.Time, len(batch.Items)),
|
|
EndAtByIccid: make(map[string]*gtime.Time, len(batch.Items)),
|
|
}
|
|
for index, item := range batch.Items {
|
|
if item == nil || item.Card == nil {
|
|
return nil, gerror.New("续费卡信息不完整")
|
|
}
|
|
lockedCard, err := s.lockRenewCardForSubmit(ctx, tx, item.Card, item.ExpectedCurrentPackageCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
latestBind, err := s.lockLatestRenewBindForSubmit(ctx, tx, lockedCard, item)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
baseExpireAt := appRenewBaseExpireTimeFromEntity(lockedCard, latestBind)
|
|
if baseExpireAt == nil || baseExpireAt.IsZero() {
|
|
return nil, gerror.Newf("ICCID最新订购记录没有预计到期时间,不能续费:%s", lockedCard.Iccid)
|
|
}
|
|
if appRenewExpireAfterAllowedWindow(baseExpireAt) {
|
|
return nil, gerror.New("距离到期超过6个月,不能续费")
|
|
}
|
|
beginAt := appRenewBeginDateFromExpire(baseExpireAt)
|
|
endAt := beginAt.AddDate(0, durationMonths, 0)
|
|
exec.MinBeginAt = appEarlierTime(exec.MinBeginAt, beginAt)
|
|
exec.MaxEndAt = appLaterTime(exec.MaxEndAt, endAt)
|
|
exec.LatestBindsByIccid[item.Card.Iccid] = latestBind
|
|
exec.BeginAtByIccid[item.Card.Iccid] = beginAt
|
|
exec.EndAtByIccid[item.Card.Iccid] = endAt
|
|
item.LatestBind = latestBind
|
|
exec.CardPeriods = append(exec.CardPeriods, map[string]any{
|
|
"rowNo": appRenewBatchSourceRowNo(index),
|
|
"cardId": item.Card.Id,
|
|
"iccid": item.Card.Iccid,
|
|
"msisdn": item.Card.Msisdn,
|
|
"oldSubscriptionNo": latestBind.SubscriptionNo,
|
|
"serviceBeginAt": appRenewFormatTime(beginAt),
|
|
"serviceEndAt": appRenewFormatTime(endAt),
|
|
"oldExpectedExpireTime": appRenewFormatTime(latestBind.ExpectedExpireTime),
|
|
})
|
|
}
|
|
return exec, nil
|
|
}
|
|
|
|
func (s *sAppCard) lockLatestRenewBindForSubmit(ctx context.Context, tx gdb.TX, lockedCard *entity.TSimCardInfo, item *appRenewPackageContext) (*entity.TSimCardBindPkg, error) {
|
|
if lockedCard == nil || item == nil || item.Card == nil {
|
|
return nil, gerror.New("续费卡信息不完整")
|
|
}
|
|
expectedPackageCode := strings.TrimSpace(item.ExpectedCurrentPackageCode)
|
|
if expectedPackageCode == "" {
|
|
return nil, gerror.New("ICCID没有当前套餐,不能续费")
|
|
}
|
|
|
|
var bind *entity.TSimCardBindPkg
|
|
err := dao.TSimCardBindPkg.Ctx(ctx).TX(tx).
|
|
Where(dao.TSimCardBindPkg.Columns().Iccid, lockedCard.Iccid).
|
|
OrderDesc(dao.TSimCardBindPkg.Columns().ExpectedExpireTime).
|
|
OrderDesc(dao.TSimCardBindPkg.Columns().Id).
|
|
LockUpdate().
|
|
Limit(1).
|
|
Scan(&bind)
|
|
if err != nil {
|
|
return nil, gerror.Wrap(err, "锁定最新订购记录失败")
|
|
}
|
|
if bind == nil || bind.Id == 0 {
|
|
return nil, gerror.Newf("ICCID没有订购记录,不能续费:%s", lockedCard.Iccid)
|
|
}
|
|
if strings.TrimSpace(bind.PackageCode) != expectedPackageCode {
|
|
return nil, gerror.Newf("ICCID当前套餐与最新订购记录不一致,不能续费:%s", lockedCard.Iccid)
|
|
}
|
|
return bind, nil
|
|
}
|
|
|
|
func (s *sAppCard) insertAppRenewSubscriptionBinds(ctx context.Context, tx gdb.TX, user *entity.SysUser, batch *appRenewBatchContext, exec *appRenewExecutionContext, batchNo string, orderSn string, durationMonths int, now *gtime.Time) error {
|
|
if user == nil || batch == nil || batch.Package == nil || batch.Party == nil || exec == nil {
|
|
return gerror.New("续费订购记录信息不完整")
|
|
}
|
|
batchNo = strings.TrimSpace(batchNo)
|
|
orderSn = strings.TrimSpace(orderSn)
|
|
if batchNo == "" || orderSn == "" {
|
|
return gerror.New("续费批次号或订单号不能为空")
|
|
}
|
|
|
|
periodByIccid := make(map[string]map[string]any, len(exec.CardPeriods))
|
|
for _, period := range exec.CardPeriods {
|
|
iccid := strings.TrimSpace(fmt.Sprint(period["iccid"]))
|
|
if iccid != "" {
|
|
periodByIccid[iccid] = period
|
|
}
|
|
}
|
|
|
|
rows := make([]do.TSimCardBindPkg, 0, len(batch.Items))
|
|
for _, item := range batch.Items {
|
|
card := item.Card
|
|
if card == nil {
|
|
return gerror.New("续费卡信息不完整")
|
|
}
|
|
latestBind := exec.LatestBindsByIccid[card.Iccid]
|
|
if latestBind == nil {
|
|
return gerror.Newf("ICCID最新订购记录不完整:%s", card.Iccid)
|
|
}
|
|
periodBegin := exec.BeginAtByIccid[card.Iccid]
|
|
periodEnd := exec.EndAtByIccid[card.Iccid]
|
|
if periodBegin == nil || periodBegin.IsZero() || periodEnd == nil || periodEnd.IsZero() {
|
|
return gerror.Newf("ICCID续费服务周期不完整:%s", card.Iccid)
|
|
}
|
|
subscriptionNo := appOrderNo("SUB", user.UserId, now)
|
|
row := do.TSimCardBindPkg{
|
|
SubscriptionNo: subscriptionNo,
|
|
BatchNo: batchNo,
|
|
Iccid: card.Iccid,
|
|
Msisdn: strings.TrimSpace(card.Msisdn),
|
|
DeptId: fmt.Sprintf("%d", batch.Party.CustomerAgentId),
|
|
PackageType: batch.Package.PackageType,
|
|
PackageCode: batch.Package.PackageCode,
|
|
PreviousPackageCode: item.ExpectedCurrentPackageCode,
|
|
BusinessType: consts.PackageBusinessTypeRenew,
|
|
EffectiveStatus: consts.EffectiveStatusPending,
|
|
HandleTime: now,
|
|
EffectiveTime: periodBegin,
|
|
ExpectedExpireTime: periodEnd,
|
|
DurationMonths: durationMonths,
|
|
GiftDurationMonths: 0,
|
|
OrderCode: orderSn,
|
|
Remark: batchNo,
|
|
TenantId: user.TenantId,
|
|
CreatedDept: batch.Party.CreatedDept,
|
|
CreatedBy: user.UserId,
|
|
CreatedAt: now,
|
|
UpdatedBy: user.UserId,
|
|
UpdatedAt: now,
|
|
}
|
|
rows = append(rows, row)
|
|
newBind := &entity.TSimCardBindPkg{
|
|
SubscriptionNo: subscriptionNo,
|
|
BatchNo: batchNo,
|
|
Iccid: card.Iccid,
|
|
Msisdn: strings.TrimSpace(card.Msisdn),
|
|
DeptId: fmt.Sprintf("%d", batch.Party.CustomerAgentId),
|
|
PackageType: batch.Package.PackageType,
|
|
PackageCode: batch.Package.PackageCode,
|
|
PreviousPackageCode: item.ExpectedCurrentPackageCode,
|
|
BusinessType: consts.PackageBusinessTypeRenew,
|
|
EffectiveStatus: consts.EffectiveStatusPending,
|
|
HandleTime: now,
|
|
EffectiveTime: periodBegin,
|
|
ExpectedExpireTime: periodEnd,
|
|
DurationMonths: durationMonths,
|
|
GiftDurationMonths: 0,
|
|
OrderCode: orderSn,
|
|
Remark: batchNo,
|
|
TenantId: user.TenantId,
|
|
CreatedDept: batch.Party.CreatedDept,
|
|
CreatedBy: user.UserId,
|
|
CreatedAt: now,
|
|
UpdatedBy: user.UserId,
|
|
UpdatedAt: now,
|
|
}
|
|
exec.NewBindsByIccid[card.Iccid] = newBind
|
|
if period := periodByIccid[card.Iccid]; period != nil {
|
|
period["newSubscriptionNo"] = subscriptionNo
|
|
period["renewEffectiveTime"] = appRenewFormatTime(periodBegin)
|
|
period["renewExpectedExpireTime"] = appRenewFormatTime(periodEnd)
|
|
period["cardFlowPkgEndAt"] = appRenewFormatTime(periodEnd)
|
|
}
|
|
}
|
|
if len(rows) > 0 {
|
|
if _, err := dao.TSimCardBindPkg.Ctx(ctx).TX(tx).Data(rows).Insert(); err != nil {
|
|
return gerror.Wrap(err, "写入续费订购记录失败")
|
|
}
|
|
}
|
|
return s.updateCardsAfterAppRenew(ctx, tx, user, batch, exec, now)
|
|
}
|
|
|
|
func (s *sAppCard) updateCardsAfterAppRenew(ctx context.Context, tx gdb.TX, user *entity.SysUser, batch *appRenewBatchContext, exec *appRenewExecutionContext, now *gtime.Time) error {
|
|
for _, item := range batch.Items {
|
|
if item == nil || item.Card == nil {
|
|
return gerror.New("续费卡信息不完整")
|
|
}
|
|
newBind := exec.NewBindsByIccid[item.Card.Iccid]
|
|
if newBind == nil || newBind.ExpectedExpireTime == nil {
|
|
return gerror.Newf("ICCID续费订购记录不完整:%s", item.Card.Iccid)
|
|
}
|
|
packageStatus := appCalcPackageStatus(now, item.Card.FlowPkgBeginAt, newBind.ExpectedExpireTime)
|
|
result, err := dao.TSimCardInfo.Ctx(ctx).TX(tx).
|
|
Where(dao.TSimCardInfo.Columns().TenantId, item.Card.TenantId).
|
|
Where(dao.TSimCardInfo.Columns().Iccid, item.Card.Iccid).
|
|
Data(do.TSimCardInfo{
|
|
CurrentPackageCode: batch.Package.PackageCode,
|
|
FlowPkgEndAt: newBind.ExpectedExpireTime,
|
|
PackageStatus: packageStatus,
|
|
UpdatedBy: user.UserId,
|
|
UpdatedAt: now,
|
|
}).
|
|
Update()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "更新续费后卡套餐到期时间失败")
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "读取续费后卡信息更新数量失败")
|
|
}
|
|
if affected != 1 {
|
|
return gerror.Newf("ICCID卡信息已变化,请刷新后重试:%s", item.Card.Iccid)
|
|
}
|
|
item.Card.FlowPkgEndAt = newBind.ExpectedExpireTime
|
|
item.Card.PackageStatus = packageStatus
|
|
item.Card.CurrentPackageCode = batch.Package.PackageCode
|
|
if err = s.updateTerminalBindAfterAppRenew(ctx, tx, user, batch, item, now); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *sAppCard) updateTerminalBindAfterAppRenew(ctx context.Context, tx gdb.TX, user *entity.SysUser, batch *appRenewBatchContext, item *appRenewPackageContext, now *gtime.Time) error {
|
|
if item == nil || item.Card == nil || batch == nil || batch.Party == nil || !s.isTerminalUser(ctx, user) {
|
|
return nil
|
|
}
|
|
card := item.Card
|
|
if card.TerminalBindId <= 0 && card.TerminalUserId <= 0 {
|
|
return nil
|
|
}
|
|
|
|
mod := dao.TSimTerminal.Ctx(ctx).TX(tx).
|
|
Where(dao.TSimTerminal.Columns().TenantId, card.TenantId).
|
|
Where(dao.TSimTerminal.Columns().Iccid, card.Iccid)
|
|
if card.TerminalBindId > 0 {
|
|
mod = mod.Where(dao.TSimTerminal.Columns().Id, card.TerminalBindId)
|
|
} else {
|
|
mod = mod.Where(dao.TSimTerminal.Columns().TerminalId, user.UserId)
|
|
}
|
|
|
|
result, err := mod.Data(do.TSimTerminal{
|
|
DeptId: batch.Party.CustomerAgentId,
|
|
CurrentPackageCode: strings.TrimSpace(batch.Package.PackageCode),
|
|
UpdatedBy: user.UserId,
|
|
UpdatedAt: now,
|
|
}).Update()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "更新续费后的终端卡关联信息失败")
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return gerror.Wrap(err, "读取续费后的终端卡关联更新数量失败")
|
|
}
|
|
if affected != 1 {
|
|
return gerror.Newf("ICCID终端卡关联已变化,请刷新后重试:%s", card.Iccid)
|
|
}
|
|
card.TerminalDeptId = batch.Party.CustomerAgentId
|
|
card.TerminalCurrentPackageCode = strings.TrimSpace(batch.Package.PackageCode)
|
|
return nil
|
|
}
|
|
|
|
func appCalcPackageStatus(now, beginAt, endAt *gtime.Time) int {
|
|
if now == nil {
|
|
now = gtime.Now()
|
|
}
|
|
if beginAt != nil && beginAt.After(now) {
|
|
return consts.PackageStatusPending
|
|
}
|
|
if endAt != nil && !endAt.After(now) {
|
|
return consts.PackageStatusExpired
|
|
}
|
|
return consts.PackageStatusEffective
|
|
}
|