Files

300 lines
9.0 KiB
Go

package renew
import (
"context"
"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/entity"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
)
type Repository struct{}
func NewRepository() *Repository {
return &Repository{}
}
func (r *Repository) GetSourceBatch(ctx context.Context, batchNo string) (*entity.BatchMain, error) {
batch := &entity.BatchMain{}
columns := dao.BatchMain.Columns()
err := dao.BatchMain.Ctx(ctx).
Fields(
columns.Id,
columns.BatchNo,
columns.BatchType,
columns.BatchStatus,
columns.RunResult,
columns.TenantId,
columns.DeptId,
columns.CreatedDept,
columns.CreatedBy,
).
Where(columns.BatchNo, strings.TrimSpace(batchNo)).
Scan(batch)
if err != nil {
return nil, err
}
if batch.Id == 0 {
return nil, nil
}
return batch, nil
}
func (r *Repository) GetRenewBatchRows(ctx context.Context, batchNo string, batchType int) ([]*Row, error) {
return r.getRenewBatchRows(ctx, nil, batchNo, batchType)
}
func (r *Repository) GetRenewBatchRowsTx(ctx context.Context, tx gdb.TX, batchNo string, batchType int) ([]*Row, error) {
return r.getRenewBatchRows(ctx, tx, batchNo, batchType)
}
func (r *Repository) getRenewBatchRows(ctx context.Context, tx gdb.TX, batchNo string, batchType int) ([]*Row, error) {
var details []*entity.BatchDetail
columns := dao.BatchDetail.Columns()
if batchType == 0 {
batchType = consts.BatchTypeRenew
}
model := dao.BatchDetail.Ctx(ctx)
if tx != nil {
model = tx.Ctx(ctx).Model(dao.BatchDetail.Table())
}
err := model.
Fields(columns.RowNo, columns.ItemId, columns.Snapshot).
Where(columns.BatchNo, strings.TrimSpace(batchNo)).
Where(columns.BatchType, batchType).
Where(columns.DetailStatus, consts.BatchDetailStatusSuccess).
OrderAsc(columns.RowNo).
Scan(&details)
if err != nil {
return nil, err
}
return detailsToRows(details), nil
}
func (r *Repository) GetSourceBatchRows(ctx context.Context, batchNo string) ([]*Row, error) {
var details []*entity.BatchDetail
columns := dao.BatchDetail.Columns()
err := dao.BatchDetail.Ctx(ctx).
Fields(columns.RowNo, columns.ItemId, columns.Snapshot).
Where(columns.BatchNo, strings.TrimSpace(batchNo)).
Where(columns.BatchType, consts.BatchTypeOutbound).
WhereIn(columns.DetailStatus, []int{consts.BatchDetailStatusSuccess, consts.BatchAsyncStatusSuccess}).
OrderAsc(columns.RowNo).
Scan(&details)
if err != nil {
return nil, err
}
return detailsToRows(details), nil
}
func (r *Repository) BatchDetailItemIDs(ctx context.Context, tx gdb.TX, batchNo string, batchType int, statuses []int) ([]string, error) {
batchNo = strings.TrimSpace(batchNo)
if batchNo == "" {
return nil, nil
}
var details []*entity.BatchDetail
model := tx.Ctx(ctx).Model(dao.BatchDetail.Table()).
Fields(dao.BatchDetail.Columns().ItemId).
Where(dao.BatchDetail.Columns().BatchNo, batchNo)
if batchType > 0 {
model = model.Where(dao.BatchDetail.Columns().BatchType, batchType)
}
if len(statuses) > 0 {
model = model.WhereIn(dao.BatchDetail.Columns().DetailStatus, statuses)
}
if err := model.Scan(&details); err != nil {
return nil, err
}
ids := make([]string, 0, len(details))
for _, detail := range details {
if detail == nil {
continue
}
if itemID := strings.TrimSpace(detail.ItemId); itemID != "" {
ids = append(ids, itemID)
}
}
return uniqueStrings(ids), nil
}
func (r *Repository) UnfinishedRenewBatchNosByIccids(ctx context.Context, tx gdb.TX, tenantID string, iccids []string, currentBatchNo string) (map[string]string, error) {
result := make(map[string]string)
iccids = uniqueStrings(iccids)
if len(iccids) == 0 {
return result, nil
}
currentBatchID, err := r.batchIDByNo(ctx, tx, currentBatchNo)
if err != nil {
return nil, err
}
type conflictRow struct {
ItemId string `orm:"item_id"`
BatchNo string `orm:"batch_no"`
}
bd := "bd"
bm := "bm"
detailColumns := dao.BatchDetail.Columns()
mainColumns := dao.BatchMain.Columns()
model := tx.Ctx(ctx).Model(dao.BatchDetail.Table()+" "+bd).
InnerJoin(dao.BatchMain.Table()+" "+bm, bm+"."+mainColumns.BatchNo+" = "+bd+"."+detailColumns.BatchNo).
Fields(bd+"."+detailColumns.ItemId, bm+"."+mainColumns.BatchNo).
Where(bd+"."+detailColumns.BatchType, consts.BatchTypeRenew).
Where(bm+"."+mainColumns.BatchType, consts.BatchTypeRenew).
Where(bm+"."+mainColumns.BatchStatus, consts.BatchStatusNormal).
WhereIn(bm+"."+mainColumns.BatchAsyncStatus, []int{
consts.BatchAsyncStatusCreated,
consts.BatchAsyncStatusPending,
consts.BatchAsyncStatusProcessing,
}).
WhereIn(bm+"."+mainColumns.RunResult, []int{
consts.BatchRunResultPending,
consts.BatchRunResultRunning,
}).
WhereIn(bd+"."+detailColumns.DetailStatus, []int{
consts.BatchDetailStatusPending,
consts.BatchDetailStatusRunning,
}).
WhereIn(bd+"."+detailColumns.ItemId, iccids).
OrderAsc(bm + "." + mainColumns.Id)
if strings.TrimSpace(tenantID) != "" {
model = model.Where(bm+"."+mainColumns.TenantId, strings.TrimSpace(tenantID))
}
if currentBatchID > 0 {
// When duplicate formal renew batches already exist, the earliest batch
// wins and later batches fail. This prevents two batches from blocking
// each other forever.
model = model.Where(bm+"."+mainColumns.Id+" < ?", currentBatchID)
} else if currentBatchNo = strings.TrimSpace(currentBatchNo); currentBatchNo != "" {
model = model.Where(bm+"."+mainColumns.BatchNo+" <> ?", currentBatchNo)
}
var rows []conflictRow
if err := model.Scan(&rows); err != nil {
return nil, err
}
for _, row := range rows {
itemID := strings.TrimSpace(row.ItemId)
if itemID == "" {
continue
}
if _, exists := result[itemID]; !exists {
result[itemID] = strings.TrimSpace(row.BatchNo)
}
}
return result, nil
}
func (r *Repository) batchIDByNo(ctx context.Context, tx gdb.TX, batchNo string) (int64, error) {
batchNo = strings.TrimSpace(batchNo)
if batchNo == "" {
return 0, nil
}
batch := &entity.BatchMain{}
if err := tx.Ctx(ctx).Model(dao.BatchMain.Table()).
Fields(dao.BatchMain.Columns().Id).
Where(dao.BatchMain.Columns().BatchNo, batchNo).
Limit(1).
Scan(batch); err != nil {
return 0, err
}
return batch.Id, nil
}
func detailsToRows(details []*entity.BatchDetail) []*Row {
rows := make([]*Row, 0, len(details))
for _, detail := range details {
if detail == nil {
continue
}
row := &Row{RowNo: detail.RowNo, Iccid: strings.TrimSpace(detail.ItemId)}
if detail.Snapshot != nil {
if row.Iccid == "" {
row.Iccid = strings.TrimSpace(detail.Snapshot.Get("iccid").String())
}
if row.Iccid == "" {
row.Iccid = strings.TrimSpace(detail.Snapshot.Get("ICCID").String())
}
row.Msisdn = strings.TrimSpace(detail.Snapshot.Get("msisdn").String())
if row.Msisdn == "" {
row.Msisdn = strings.TrimSpace(detail.Snapshot.Get("MSISDN").String())
}
row.Imsi = strings.TrimSpace(detail.Snapshot.Get("imsi").String())
if row.Imsi == "" {
row.Imsi = strings.TrimSpace(detail.Snapshot.Get("IMSI").String())
}
}
rows = append(rows, row)
}
return rows
}
func (r *Repository) LockCardsByIccids(ctx context.Context, tx gdb.TX, iccids []string) (map[string]*entity.TSimCardInfo, error) {
result := make(map[string]*entity.TSimCardInfo)
if len(iccids) == 0 {
return result, nil
}
var list []*entity.TSimCardInfo
if err := tx.Ctx(ctx).Model(dao.TSimCardInfo.Table()).
WhereIn(dao.TSimCardInfo.Columns().Iccid, uniqueStrings(iccids)).
LockUpdate().
Scan(&list); err != nil {
return nil, err
}
for _, item := range list {
if item != nil && strings.TrimSpace(item.Iccid) != "" {
result[strings.TrimSpace(item.Iccid)] = item
}
}
return result, nil
}
func (r *Repository) LockLatestBindsByIccids(ctx context.Context, tx gdb.TX, iccids []string) (map[string]*entity.TSimCardBindPkg, error) {
result := make(map[string]*entity.TSimCardBindPkg)
if len(iccids) == 0 {
return result, nil
}
var list []*entity.TSimCardBindPkg
if err := tx.Ctx(ctx).Model(dao.TSimCardBindPkg.Table()).
WhereIn(dao.TSimCardBindPkg.Columns().Iccid, uniqueStrings(iccids)).
WhereIn(dao.TSimCardBindPkg.Columns().PackageType, []int{101, 102}).
WhereIn(dao.TSimCardBindPkg.Columns().EffectiveStatus, []int{
consts.EffectiveStatusPending,
consts.EffectiveStatusEffective,
consts.EffectiveStatusExpired,
}).
OrderDesc(dao.TSimCardBindPkg.Columns().ExpectedExpireTime).
OrderDesc(dao.TSimCardBindPkg.Columns().Id).
LockUpdate().
Scan(&list); err != nil {
return nil, err
}
effectiveCount := make(map[string]int)
for _, item := range list {
if item == nil || strings.TrimSpace(item.Iccid) == "" {
continue
}
iccid := strings.TrimSpace(item.Iccid)
if item.EffectiveStatus == consts.EffectiveStatusEffective {
effectiveCount[iccid]++
if effectiveCount[iccid] > 1 {
return nil, gerror.Newf("同一张卡存在多个生效中的套餐订购记录:%s", iccid)
}
}
if _, exists := result[iccid]; exists {
continue
}
result[iccid] = item
}
return result, nil
}