chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
package renew
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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/library/batchimport"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type Processor struct {
|
||||
repo *Repository
|
||||
config batchimport.ProcessorConfig
|
||||
}
|
||||
|
||||
func NewProcessor() *Processor {
|
||||
return &Processor{
|
||||
repo: NewRepository(),
|
||||
config: batchimport.ProcessorConfig{
|
||||
Code: "sim_card_renew",
|
||||
BatchType: consts.BatchTypeRenew,
|
||||
BatchNoPrefix: consts.BatchNoPrefixRenew,
|
||||
TaskName: consts.ResourceBatchDownloadTaskSimCardRenew,
|
||||
ExportScene: consts.ResourceExportSceneRenew,
|
||||
ImportDir: consts.SimCardRenewSubDirImportExcel,
|
||||
ResultDir: consts.SimCardRenewSubDirResultExcel,
|
||||
MaxFileSize: consts.SimCardRenewMaxFileSize,
|
||||
TemplateHeaders: ExcelTemplateHeaders(),
|
||||
RequiredHeaders: []string{"ICCID"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Processor) Config() batchimport.ProcessorConfig {
|
||||
return p.config
|
||||
}
|
||||
|
||||
func (p *Processor) ParseRows(ctx context.Context, filePath string) ([]batchimport.Row, error) {
|
||||
return nil, gerror.New("卡续费不支持文件导入")
|
||||
}
|
||||
|
||||
func (p *Processor) ValidateRows(ctx context.Context, rows []batchimport.Row) error {
|
||||
renewRows := make([]*Row, 0, len(rows))
|
||||
for _, item := range rows {
|
||||
row, ok := item.(*Row)
|
||||
if !ok {
|
||||
item.AddErrorReason("续费行类型错误")
|
||||
continue
|
||||
}
|
||||
renewRows = append(renewRows, row)
|
||||
}
|
||||
if err := normalizeRenewIdentityRows(ctx, renewRows); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateRows(renewRows)
|
||||
}
|
||||
|
||||
func (p *Processor) Execute(ctx context.Context, tx gdb.TX, req *batchimport.SubmitRequest, rows []batchimport.Row) error {
|
||||
if req == nil {
|
||||
return gerror.New("续费请求不能为空")
|
||||
}
|
||||
in, ok := req.BizParams.(*model.TSimCardRenewBatchSubmitParam)
|
||||
if !ok || in == nil {
|
||||
return gerror.New("续费参数类型错误")
|
||||
}
|
||||
|
||||
renewRows := make([]*Row, 0, len(rows))
|
||||
for _, item := range rows {
|
||||
row, ok := item.(*Row)
|
||||
if !ok {
|
||||
return gerror.New("续费行类型错误")
|
||||
}
|
||||
renewRows = append(renewRows, row)
|
||||
}
|
||||
options, err := loadExecutionOptions(ctx, tx, req.BatchNo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applyExecutionOptions(in, options)
|
||||
|
||||
prepared, err := p.validateRenewContext(ctx, tx, in, req.Operator, renewRows, req.BatchNo, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
priceSnapshot, err := ensurePriceSnapshot(ctx, tx, req.Operator, prepared, options.PriceSnapshot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
durationValue := renewDisplayDurationValue(in)
|
||||
if durationValue <= 0 {
|
||||
return gerror.New("续费时长必须大于0")
|
||||
}
|
||||
if !containsRenewDurationOption(priceSnapshot.RenewableDurationOptions, durationValue) {
|
||||
return gerror.New("续费时长不在当前套餐可续费范围内")
|
||||
}
|
||||
|
||||
output, err := p.Complete(ctx, tx, &CompleteInput{
|
||||
SubmitParam: in,
|
||||
BatchNo: req.BatchNo,
|
||||
Rows: renewRows,
|
||||
Operator: req.Operator,
|
||||
PriceSnapshot: priceSnapshot,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.ExecutionResult = output
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Processor) BuildBatchInfo(ctx context.Context, req batchimport.SubmitRequest, result *batchimport.Result, importOss *model.SysOssSaveContentModel, resultOss *model.SysOssSaveContentModel, downloadId int64) *gjson.Json {
|
||||
info := g.Map{}
|
||||
if result != nil && result.ImportFileOssId > 0 {
|
||||
info["importFileOssId"] = result.ImportFileOssId
|
||||
} else if importOss != nil && importOss.OssId > 0 {
|
||||
info["importFileOssId"] = importOss.OssId
|
||||
}
|
||||
if resultOss != nil {
|
||||
info["resultFileOssId"] = resultOss.OssId
|
||||
}
|
||||
if downloadId > 0 {
|
||||
info["resultDownloadId"] = downloadId
|
||||
}
|
||||
if in, ok := req.BizParams.(*model.TSimCardRenewBatchSubmitParam); ok && in != nil {
|
||||
durationValue := renewDisplayDurationValue(in)
|
||||
if durationValue > 0 {
|
||||
actualDurationMonths := renewActualDurationMonths(nil, durationValue)
|
||||
info["durationYears"] = durationValue
|
||||
info["durationMonths"] = actualDurationMonths
|
||||
info["durationValue"] = durationValue
|
||||
info["actualDurationMonths"] = actualDurationMonths
|
||||
}
|
||||
info["giftDurationMonths"] = in.GiftDurationMonths
|
||||
info["amount"] = strings.TrimSpace(in.Amount)
|
||||
if in.PaymentSnapshot != nil {
|
||||
appendRenewPaymentSnapshot(info, in.PaymentSnapshot)
|
||||
} else if paymentMode := strings.TrimSpace(in.PaymentMode); paymentMode != "" {
|
||||
info["paymentMode"] = paymentMode
|
||||
}
|
||||
if packageCode := strings.TrimSpace(in.PackageCode); packageCode != "" {
|
||||
info["packageCode"] = packageCode
|
||||
}
|
||||
info["offlineContractCompleted"] = in.OfflineContractCompleted
|
||||
if sourceBatchNo := strings.TrimSpace(in.SourceBatchNo); sourceBatchNo != "" {
|
||||
info["sourceBatchNo"] = sourceBatchNo
|
||||
}
|
||||
if buyerNote := strings.TrimSpace(in.BuyerNote); buyerNote != "" {
|
||||
info["buyerNote"] = buyerNote
|
||||
}
|
||||
if adminNote := strings.TrimSpace(in.AdminNote); adminNote != "" {
|
||||
info["adminNote"] = adminNote
|
||||
}
|
||||
if remark := strings.TrimSpace(in.Remark); remark != "" {
|
||||
info["remark"] = remark
|
||||
}
|
||||
}
|
||||
if snapshot, ok := req.ExecutionResult.(*model.TSimCardRenewPriceSnapshot); ok && snapshot != nil {
|
||||
if result != nil && result.BatchType == consts.BatchTypePrepare {
|
||||
info["targetBatchType"] = consts.BatchTypeRenew
|
||||
info["targetBatchName"] = "卡续费"
|
||||
}
|
||||
info["customerAgentId"] = snapshot.CustomerAgentId
|
||||
info["packageCode"] = snapshot.PackageCode
|
||||
info["packageName"] = snapshot.PackageName
|
||||
info["billingMethod"] = snapshot.BillingMethod
|
||||
info["renewDurationUnit"] = snapshot.RenewDurationUnit
|
||||
info["renewDurationUnitText"] = snapshot.RenewDurationUnitText
|
||||
if durationValue := gconv.Int(info["durationValue"]); durationValue > 0 {
|
||||
actualDurationMonths := renewActualDurationMonths(snapshot, durationValue)
|
||||
info["durationMonths"] = actualDurationMonths
|
||||
info["actualDurationMonths"] = actualDurationMonths
|
||||
}
|
||||
info["quantity"] = result.ValidRows
|
||||
info["priceSource"] = snapshot.PriceSource
|
||||
info["priceOwnerDeptId"] = snapshot.PriceOwnerDeptId
|
||||
info["agentDefaultPriceId"] = snapshot.AgentDefaultPriceId
|
||||
info["targetPriceId"] = snapshot.TargetPriceId
|
||||
info["renewUnitPrice"] = snapshot.RenewUnitPrice
|
||||
info["renewableDurationOptions"] = snapshot.RenewableDurationOptions
|
||||
info["renewablePackageCodes"] = snapshot.RenewablePackageCodes
|
||||
info["renewablePackages"] = snapshot.RenewablePackages
|
||||
info["renewBeginDate"] = snapshot.RenewBeginDate
|
||||
info["renewBeginDateMin"] = snapshot.RenewBeginDateMin
|
||||
info["renewBeginDateMax"] = snapshot.RenewBeginDateMax
|
||||
info["sameRenewBeginDate"] = snapshot.SameRenewBeginDate
|
||||
}
|
||||
if output, ok := req.ExecutionResult.(*CompleteOutput); ok && output != nil {
|
||||
info["quantity"] = output.Quantity
|
||||
info["packageCode"] = output.PackageCode
|
||||
info["orderSn"] = output.OrderSn
|
||||
info["renewTime"] = output.RenewTime
|
||||
if sourceBatchNo := strings.TrimSpace(output.SourceBatchNo); sourceBatchNo != "" {
|
||||
info["sourceBatchNo"] = sourceBatchNo
|
||||
}
|
||||
}
|
||||
return gjson.New(info)
|
||||
}
|
||||
|
||||
func appendRenewPaymentSnapshot(info g.Map, snapshot *model.TSimCardRenewPaymentSnapshot) {
|
||||
if info == nil || snapshot == nil {
|
||||
return
|
||||
}
|
||||
info["paymentMode"] = strings.TrimSpace(snapshot.PaymentMode)
|
||||
info["payType"] = snapshot.PayType
|
||||
info["payStatus"] = snapshot.PayStatus
|
||||
info["payAmount"] = snapshot.PayAmount
|
||||
info["balanceAmount"] = snapshot.BalanceAmount
|
||||
info["offlinePaidAmount"] = snapshot.OfflinePaidAmount
|
||||
info["balanceBefore"] = snapshot.BalanceBefore
|
||||
info["balanceAfter"] = snapshot.BalanceAfter
|
||||
info["balanceDetailSerialNo"] = strings.TrimSpace(snapshot.BalanceDetailSerialNo)
|
||||
info["payerDeptId"] = snapshot.PayerDeptId
|
||||
info["payerUserId"] = snapshot.PayerUserId
|
||||
info["isTopDept"] = snapshot.IsTopDept
|
||||
if snapshot.PaymentTime != nil {
|
||||
info["paymentTime"] = snapshot.PaymentTime.Format("Y-m-d H:i:s")
|
||||
}
|
||||
info["paymentSnapshot"] = snapshot
|
||||
}
|
||||
|
||||
func (p *Processor) ValidatePrepareContext(ctx context.Context, tx gdb.TX, in *model.TSimCardRenewBatchSubmitParam, operator batchimport.OperatorContext, rows []*Row) (*PrepareContext, error) {
|
||||
return p.validateRenewContext(ctx, tx, in, operator, rows, "", false)
|
||||
}
|
||||
|
||||
func (p *Processor) RevalidatePrepareContext(ctx context.Context, tx gdb.TX, in *model.TSimCardRenewBatchSubmitParam, operator batchimport.OperatorContext, rows []*Row, currentBatchNo string) (*PrepareContext, bool, error) {
|
||||
prepared, err := p.validateRenewContext(ctx, tx, in, operator, rows, currentBatchNo, true)
|
||||
return prepared, hasInvalidRows(rows), err
|
||||
}
|
||||
|
||||
func (p *Processor) validateRenewContext(ctx context.Context, tx gdb.TX, in *model.TSimCardRenewBatchSubmitParam, operator batchimport.OperatorContext, rows []*Row, currentBatchNo string, allowPartial bool) (*PrepareContext, error) {
|
||||
iccids := rowsToIccids(rows)
|
||||
cardsByIccid, err := p.repo.LockCardsByIccids(ctx, tx, iccids)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "校验续费卡信息失败")
|
||||
}
|
||||
bindsByIccid, err := p.repo.LockLatestBindsByIccids(ctx, tx, iccids)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "校验续费订购记录失败")
|
||||
}
|
||||
conflictingBatches, err := p.repo.UnfinishedRenewBatchNosByIccids(
|
||||
ctx,
|
||||
tx,
|
||||
operator.TenantId,
|
||||
iccids,
|
||||
currentBatchNo,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "校验未完成续费批次失败")
|
||||
}
|
||||
|
||||
sourceBatchNo := strings.TrimSpace(in.SourceBatchNo)
|
||||
packageCodes := make(map[string]struct{})
|
||||
customerAgentIds := make(map[int64]struct{})
|
||||
currentPackagePeriods := make(map[string]struct{})
|
||||
renewBeginDates := make([]string, 0, len(rows))
|
||||
packageCode := ""
|
||||
customerAgentId := int64(0)
|
||||
for _, row := range rows {
|
||||
if row == nil || row.Reason != "" {
|
||||
continue
|
||||
}
|
||||
card := cardsByIccid[row.Iccid]
|
||||
bind := bindsByIccid[row.Iccid]
|
||||
if strings.TrimSpace(conflictingBatches[row.Iccid]) != "" {
|
||||
row.AddReason("存在未完成续费批次,不能重复续费")
|
||||
continue
|
||||
}
|
||||
reason := validateRenewRow(sourceBatchNo, operator, card, bind)
|
||||
if reason != "" {
|
||||
row.AddReason(reason)
|
||||
continue
|
||||
}
|
||||
baseExpireAt := renewBaseExpireTime(card, bind)
|
||||
|
||||
periodKey := currentPackagePeriodKeyWithExpire(bind, baseExpireAt)
|
||||
if periodKey == "" {
|
||||
row.AddReason("不是统一批次")
|
||||
continue
|
||||
}
|
||||
currentPackageCode := strings.TrimSpace(card.CurrentPackageCode)
|
||||
packageCodes[currentPackageCode] = struct{}{}
|
||||
customerAgentIds[card.DeptId] = struct{}{}
|
||||
currentPackagePeriods[periodKey] = struct{}{}
|
||||
packageCode = currentPackageCode
|
||||
customerAgentId = card.DeptId
|
||||
renewBeginAt := renewBeginDateFromExpire(baseExpireAt)
|
||||
if renewBeginAt != nil {
|
||||
renewBeginDates = append(renewBeginDates, renewBeginAt.Format("Y-m-d"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(packageCodes) > 1 {
|
||||
markRowsWithoutReason(rows, "当前批次下存在多个套餐,不能统一续费")
|
||||
}
|
||||
if len(customerAgentIds) > 1 {
|
||||
markRowsWithoutReason(rows, "当前批次下存在多个客户,不能统一续费")
|
||||
}
|
||||
if len(currentPackagePeriods) > 1 {
|
||||
markRowsWithoutReason(rows, "不是统一批次")
|
||||
}
|
||||
if len(customerAgentIds) == 1 && customerAgentId > 0 {
|
||||
if err := validateRenewCustomerDeptScope(ctx, tx, operator, customerAgentId); err != nil {
|
||||
markRowsWithoutReason(rows, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if hasInvalidRows(rows) && !allowPartial {
|
||||
markRemainingRowsSkipped(rows)
|
||||
return nil, gerror.New("存在不满足续费条件的卡,本次未执行")
|
||||
}
|
||||
validCount := countValidRows(rows)
|
||||
if validCount == 0 {
|
||||
return &PrepareContext{}, nil
|
||||
}
|
||||
renewBeginDate, renewBeginDateMin, renewBeginDateMax, sameRenewBeginDate := summarizeRenewBeginDates(renewBeginDates)
|
||||
return &PrepareContext{
|
||||
CustomerAgentId: customerAgentId,
|
||||
PackageCode: packageCode,
|
||||
Quantity: validCount,
|
||||
RenewBeginDate: renewBeginDate,
|
||||
RenewBeginDateMin: renewBeginDateMin,
|
||||
RenewBeginDateMax: renewBeginDateMax,
|
||||
SameRenewBeginDate: sameRenewBeginDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func currentPackagePeriodKey(bind *entity.TSimCardBindPkg) string {
|
||||
if bind == nil {
|
||||
return ""
|
||||
}
|
||||
return currentPackagePeriodKeyWithExpire(bind, bind.ExpectedExpireTime)
|
||||
}
|
||||
|
||||
func currentPackagePeriodKeyWithExpire(bind *entity.TSimCardBindPkg, expireAt *gtime.Time) string {
|
||||
if bind == nil || bind.EffectiveTime == nil {
|
||||
return ""
|
||||
}
|
||||
if expireAt == nil {
|
||||
expireAt = bind.ExpectedExpireTime
|
||||
}
|
||||
if expireAt == nil {
|
||||
return ""
|
||||
}
|
||||
return bind.EffectiveTime.Format("Y-m-d") + "|" + expireAt.Format("Y-m-d")
|
||||
}
|
||||
|
||||
func summarizeRenewBeginDates(dates []string) (sameDate string, minDate string, maxDate string, same bool) {
|
||||
cleaned := make([]string, 0, len(dates))
|
||||
for _, date := range dates {
|
||||
date = strings.TrimSpace(date)
|
||||
if date != "" {
|
||||
cleaned = append(cleaned, date)
|
||||
}
|
||||
}
|
||||
if len(cleaned) == 0 {
|
||||
return "", "", "", false
|
||||
}
|
||||
sort.Strings(cleaned)
|
||||
minDate = cleaned[0]
|
||||
maxDate = cleaned[len(cleaned)-1]
|
||||
same = minDate == maxDate
|
||||
if same {
|
||||
sameDate = minDate
|
||||
}
|
||||
return sameDate, minDate, maxDate, same
|
||||
}
|
||||
|
||||
func renewBeginDateFromExpire(expireAt *gtime.Time) *gtime.Time {
|
||||
if expireAt == nil {
|
||||
return nil
|
||||
}
|
||||
return normalizeRenewDateAtDayEnd(expireAt)
|
||||
}
|
||||
|
||||
func normalizeRenewDateAtDayEnd(expireAt *gtime.Time) *gtime.Time {
|
||||
if expireAt == nil || expireAt.IsZero() {
|
||||
return nil
|
||||
}
|
||||
t := expireAt.Time
|
||||
return gtime.NewFromTime(
|
||||
time.Date(
|
||||
t.Year(),
|
||||
t.Month(),
|
||||
t.Day(),
|
||||
23,
|
||||
59,
|
||||
59,
|
||||
0,
|
||||
t.Location(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func validateRenewRow(sourceBatchNo string, operator batchimport.OperatorContext, card *entity.TSimCardInfo, bind *entity.TSimCardBindPkg) string {
|
||||
if card == nil {
|
||||
return "ICCID不存在正式卡记录,不能续费"
|
||||
}
|
||||
if card.BossCardStatus == consts.V3ApiSimBossCardStatusStopped {
|
||||
return "ICCID当前为停机状态,不能续费"
|
||||
}
|
||||
if bind == nil {
|
||||
return "ICCID没有订购记录,不能续费"
|
||||
}
|
||||
if strings.TrimSpace(card.CurrentPackageCode) == "" || card.PackageStatus == consts.PackageStatusNone {
|
||||
return "ICCID没有当前套餐,不能续费"
|
||||
}
|
||||
if strings.TrimSpace(card.CurrentPackageCode) != strings.TrimSpace(bind.PackageCode) {
|
||||
return "ICCID当前套餐与最新订购记录不一致,不能续费"
|
||||
}
|
||||
baseExpireAt := renewBaseExpireTime(card, bind)
|
||||
if baseExpireAt == nil {
|
||||
return "ICCID最新订购没有预计到期时间,不能续费"
|
||||
}
|
||||
if renewExpireAfterAllowedWindow(baseExpireAt) {
|
||||
return "距离到期超过6个月,不能续费"
|
||||
}
|
||||
if sourceBatchNo != "" && strings.TrimSpace(card.OutboundBatchNo) != sourceBatchNo {
|
||||
return "ICCID不属于来源出库批次,不能续费"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func renewBaseExpireTime(card *entity.TSimCardInfo, bind *entity.TSimCardBindPkg) *gtime.Time {
|
||||
var expireAt *gtime.Time
|
||||
if bind != nil {
|
||||
expireAt = laterRenewExpireTime(expireAt, bind.ExpectedExpireTime)
|
||||
}
|
||||
if card != nil {
|
||||
expireAt = laterRenewExpireTime(expireAt, card.FlowPkgEndAt)
|
||||
expireAt = laterRenewExpireTime(expireAt, card.FlowPkgPresentAt)
|
||||
expireAt = laterRenewExpireTime(expireAt, card.FlowPkgRealPresentAt)
|
||||
}
|
||||
return expireAt
|
||||
}
|
||||
|
||||
func laterRenewExpireTime(current, candidate *gtime.Time) *gtime.Time {
|
||||
if candidate == nil || candidate.IsZero() {
|
||||
return current
|
||||
}
|
||||
if current == nil || current.IsZero() || candidate.After(current) {
|
||||
return candidate
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func renewExpireAfterAllowedWindow(expireAt *gtime.Time) bool {
|
||||
if expireAt == nil {
|
||||
return false
|
||||
}
|
||||
return expireAt.After(gtime.Now().AddDate(0, 6, 0))
|
||||
}
|
||||
|
||||
func validateRenewCustomerDeptScope(ctx context.Context, tx gdb.TX, operator batchimport.OperatorContext, customerDeptID int64) error {
|
||||
if operator.DeptId <= 0 || operator.TenantId == "" {
|
||||
return gerror.New("当前用户未绑定组织或租户")
|
||||
}
|
||||
if customerDeptID <= 0 {
|
||||
return gerror.New("ICCID不属于当前机构,不能续费")
|
||||
}
|
||||
if customerDeptID == operator.DeptId {
|
||||
return nil
|
||||
}
|
||||
dept := &entity.SysDept{}
|
||||
if err := tx.Ctx(ctx).Model(dao.SysDept.Table()).
|
||||
Fields(dao.SysDept.Columns().DeptId, dao.SysDept.Columns().ParentId, dao.SysDept.Columns().Ancestors).
|
||||
Where(dao.SysDept.Columns().TenantId, operator.TenantId).
|
||||
Where(dao.SysDept.Columns().DeptId, customerDeptID).
|
||||
WhereNull(dao.SysDept.Columns().DeletedAt).
|
||||
Scan(dept); err != nil {
|
||||
return gerror.Wrap(err, "校验ICCID归属失败")
|
||||
}
|
||||
if dept.DeptId == 0 {
|
||||
return gerror.New("ICCID不属于当前机构,不能续费")
|
||||
}
|
||||
if dept.ParentId == operator.DeptId || renewDeptAncestorsContain(dept.Ancestors, operator.DeptId) {
|
||||
return nil
|
||||
}
|
||||
return gerror.New("ICCID不属于当前机构,不能续费")
|
||||
}
|
||||
|
||||
func renewDeptAncestorsContain(ancestors string, deptID int64) bool {
|
||||
if deptID <= 0 {
|
||||
return false
|
||||
}
|
||||
target := strconv.FormatInt(deptID, 10)
|
||||
for _, item := range strings.Split(strings.Trim(ancestors, ","), ",") {
|
||||
if strings.TrimSpace(item) == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasInvalidRows(rows []*Row) bool {
|
||||
for _, row := range rows {
|
||||
if row != nil && row.Reason != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func countValidRows(rows []*Row) int {
|
||||
count := 0
|
||||
for _, row := range rows {
|
||||
if row != nil && row.Valid() {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func markRowsWithoutReason(rows []*Row, reason string) {
|
||||
for _, row := range rows {
|
||||
if row != nil && row.Reason == "" {
|
||||
row.AddReason(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func markRemainingRowsSkipped(rows []*Row) {
|
||||
for _, row := range rows {
|
||||
if row != nil && row.Reason == "" {
|
||||
row.AddReason("同批存在不满足续费条件的卡,本行未执行")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateRows(rows []*Row) error {
|
||||
firstByIccid := make(map[string]*Row, len(rows))
|
||||
for _, row := range rows {
|
||||
row.Iccid = strings.TrimSpace(row.Iccid)
|
||||
if row.Iccid == "" {
|
||||
row.AddReason("ICCID不能为空")
|
||||
continue
|
||||
}
|
||||
if first, ok := firstByIccid[row.Iccid]; ok {
|
||||
row.AddReason("ICCID重复")
|
||||
first.AddReason("ICCID重复")
|
||||
continue
|
||||
}
|
||||
firstByIccid[row.Iccid] = row
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user