Files

245 lines
7.8 KiB
Go

package cardpackage
import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
func (s *Service) TerminateCurrentPackage(ctx context.Context, tx gdb.TX, in *TerminateCurrentPackageInput) (*TerminateCurrentPackageOutput, error) {
if in == nil || len(in.Iccids) == 0 {
return nil, gerror.New("退订卡不能为空")
}
iccids := uniqueStrings(in.Iccids)
cardsByIccid, err := s.repo.LockCardsByIccids(ctx, tx, iccids)
if err != nil {
return nil, gerror.Wrap(err, "锁定卡信息失败")
}
if len(cardsByIccid) != len(iccids) {
return nil, gerror.New("部分卡信息已变化,请刷新后重试")
}
bindsByIccid, err := s.repo.LockCurrentActiveBindsByIccids(ctx, tx, iccids)
if err != nil {
return nil, gerror.Wrap(err, "锁定当前订购失败")
}
if len(bindsByIccid) != len(iccids) {
return nil, gerror.New("部分卡没有当前订购,不能退订")
}
now := gtime.Now()
sourceBatchNo := strings.TrimSpace(in.SourceBatchNo)
packageCode := ""
orderCodeSet := make(map[string]struct{}, len(iccids))
orderUnsubCounts := make(map[string]int, len(iccids))
logRows := make([]do.TSimBindPackageLogs, 0, len(iccids))
subscriptionNos := make([]string, 0, len(iccids))
for _, iccid := range iccids {
card := cardsByIccid[iccid]
bind := bindsByIccid[iccid]
if card == nil {
return nil, gerror.Newf("ICCID不存在正式卡记录:%s", iccid)
}
if bind == nil {
return nil, gerror.Newf("ICCID当前订购数据异常或不存在:%s", iccid)
}
if card.DeptId != in.Operator.DeptId && card.CreatedDept != in.Operator.DeptId {
return nil, gerror.Newf("ICCID不属于当前机构:%s", iccid)
}
if strings.TrimSpace(card.CurrentPackageCode) == "" || card.PackageStatus == consts.PackageStatusNone {
return nil, gerror.Newf("ICCID没有可退订套餐:%s", iccid)
}
if packageCode == "" {
packageCode = strings.TrimSpace(bind.PackageCode)
}
if packageCode != strings.TrimSpace(bind.PackageCode) {
return nil, gerror.New("当前批次下存在多个套餐,不能统一退订")
}
if strings.TrimSpace(card.CurrentPackageCode) != strings.TrimSpace(bind.PackageCode) {
return nil, gerror.Newf("ICCID当前套餐与订购记录不一致:%s", iccid)
}
if sourceBatchNo != "" && strings.TrimSpace(bind.BatchNo) != sourceBatchNo {
return nil, gerror.Newf("ICCID当前订购不属于来源出库批次:%s", iccid)
}
orderCode := strings.TrimSpace(bind.OrderCode)
if orderCode != "" {
orderCodeSet[orderCode] = struct{}{}
orderUnsubCounts[orderCode]++
}
subscriptionNos = append(subscriptionNos, bind.SubscriptionNo)
logRows = append(logRows, bindToHistory(bind, now, in.BatchNo, in.Operator.UserId))
}
if len(logRows) > 0 {
if _, err = tx.Ctx(ctx).Model(dao.TSimBindPackageLogs.Table()).
Data(logRows).
OnConflict(dao.TSimBindPackageLogs.Columns().SubscriptionNo).
Save(); err != nil {
return nil, gerror.Wrap(err, "写入订购历史失败")
}
}
affected, err := s.repo.DeleteBindsBySubscriptionNos(ctx, tx, subscriptionNos)
if err != nil {
return nil, gerror.Wrap(err, "删除当前订购失败")
}
if int(affected) != len(iccids) {
return nil, gerror.New("部分当前订购已变化,请刷新后重试")
}
orderCodes := mapKeys(orderCodeSet)
if err = s.updateOrdersAfterUnsub(ctx, tx, orderCodes, orderUnsubCounts, in.BatchNo, now, in.Operator.UserId); err != nil {
return nil, err
}
return &TerminateCurrentPackageOutput{
Iccids: iccids,
CardsByIccid: cardsByIccid,
BindsByIccid: bindsByIccid,
PackageCode: packageCode,
OrderCodes: orderCodes,
UnsubTime: now,
}, nil
}
func bindToHistory(bind *entity.TSimCardBindPkg, actualExpireAt *gtime.Time, unsubBatchNo string, userId int64) do.TSimBindPackageLogs {
return do.TSimBindPackageLogs{
SubscriptionNo: bind.SubscriptionNo,
BatchNo: bind.BatchNo,
Iccid: bind.Iccid,
Msisdn: bind.Msisdn,
DeptId: bind.DeptId,
PackageType: bind.PackageType,
PackageCode: bind.PackageCode,
PreviousPackageCode: bind.PreviousPackageCode,
BusinessType: bind.BusinessType,
EffectiveStatus: consts.EffectiveStatusTerminated,
HandleTime: bind.HandleTime,
EffectiveTime: bind.EffectiveTime,
ExpectedExpireTime: bind.ExpectedExpireTime,
ActualExpireTime: actualExpireAt,
DurationMonths: bind.DurationMonths,
GiftDurationMonths: bind.GiftDurationMonths,
OrderCode: bind.OrderCode,
Remark: appendRemark(bind.Remark, fmt.Sprintf("unsubscribeBatchNo=%s", unsubBatchNo)),
TenantId: bind.TenantId,
CreatedDept: bind.CreatedDept,
CreatedBy: bind.CreatedBy,
CreatedAt: bind.CreatedAt,
UpdatedBy: userId,
UpdatedAt: actualExpireAt,
}
}
func (s *Service) updateOrdersAfterUnsub(ctx context.Context, tx gdb.TX, orderCodes []string, unsubCounts map[string]int, batchNo string, unsubTime *gtime.Time, userId int64) error {
if len(orderCodes) == 0 {
return nil
}
activeCounts, err := s.repo.ActiveBindCountsByOrderCodes(ctx, tx, orderCodes)
if err != nil {
return gerror.Wrap(err, "统计订单剩余订购失败")
}
for _, orderCode := range orderCodes {
returnStatus := consts.OrderReturnStatusSuccess
if activeCounts[orderCode] > 0 {
returnStatus = consts.OrderReturnStatusPartial
}
if _, err = tx.Ctx(ctx).Model(dao.TOrder.Table()).
Where(dao.TOrder.Columns().OrderSn, orderCode).
Data(do.TOrder{
ReturnStatus: returnStatus,
UpdatedBy: userId,
UpdatedAt: unsubTime,
}).
Update(); err != nil {
return gerror.Wrap(err, "更新订单退订状态失败")
}
if err = updateOrderItemExtra(ctx, tx, orderCode, batchNo, unsubCounts[orderCode], unsubTime, userId); err != nil {
return err
}
}
return nil
}
func updateOrderItemExtra(ctx context.Context, tx gdb.TX, orderCode, batchNo string, unsubQuantity int, unsubTime *gtime.Time, userId int64) error {
var item *entity.TOrderItem
if err := tx.Ctx(ctx).Model(dao.TOrderItem.Table()).
Where(dao.TOrderItem.Columns().OrderSn, orderCode).
Limit(1).
Scan(&item); err != nil {
return gerror.Wrap(err, "查询订单项失败")
}
if item == nil {
return nil
}
extra := g.Map{}
if strings.TrimSpace(item.ExtraSkuData) != "" {
_ = json.Unmarshal([]byte(item.ExtraSkuData), &extra)
}
extra["lastUnsubscribeBatchNo"] = batchNo
extra["lastUnsubscribeTime"] = formatTime(unsubTime)
extra["unsubscribedQuantity"] = unsubQuantity
data, err := json.Marshal(extra)
if err != nil {
return gerror.Wrap(err, "生成订单项退订扩展失败")
}
if _, err = tx.Ctx(ctx).Model(dao.TOrderItem.Table()).
Where(dao.TOrderItem.Columns().ItemId, item.ItemId).
Data(do.TOrderItem{
ExtraSkuData: string(data),
UpdatedBy: userId,
UpdatedAt: unsubTime,
}).
Update(); err != nil {
return gerror.Wrap(err, "更新订单项退订扩展失败")
}
return nil
}
func appendRemark(old, addition string) string {
old = strings.TrimSpace(old)
addition = strings.TrimSpace(addition)
if old == "" {
return addition
}
if addition == "" {
return old
}
return old + "; " + addition
}
func mapKeys(set map[string]struct{}) []string {
result := make([]string, 0, len(set))
for key := range set {
if strings.TrimSpace(key) != "" {
result = append(result, key)
}
}
sort.Strings(result)
return result
}
func formatTime(t *gtime.Time) string {
if t == nil {
return ""
}
return t.Format("Y-m-d H:i:s")
}