package change 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/library/batchimport" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "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/encoding/gjson" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) type AsyncConfirmInput struct { BatchNo string TargetBatchType int NewPackageCode string DurationMonths int GiftDurationMonths int EffectiveMode string OfflineContract bool BuyerNote string AdminNote string Remark string PriceSnapshot *model.TSimCardChangePriceSnapshot SourceBatchNo string PackageBeginTimeStr string Operator batchimport.OperatorContext } type AsyncConfirmResult struct { BatchNo string BatchType int BatchAsyncStatus int } // ConvertPrepareToAsync 以 CAS 方式把 batch_type=4 + batch_async_status=Success + run_result=Success 的预处理批次 // 转换为 batch_type=102 的待处理变更批次:重置主表正式执行相关字段并把明细的 BatchType 切换到 102、DetailStatus 重置为 Pending。 func ConvertPrepareToAsync(ctx context.Context, tx gdb.TX, in *AsyncConfirmInput) (*AsyncConfirmResult, error) { if in == nil { return nil, gerror.New("变更确认参数不能为空") } batchNo := strings.TrimSpace(in.BatchNo) if batchNo == "" { return nil, gerror.New("变更批次号不能为空") } targetBatchType := in.TargetBatchType if targetBatchType == 0 { targetBatchType = consts.BatchTypeChange } columns := dao.BatchMain.Columns() main := &entity.BatchMain{} err := tx.Ctx(ctx).Model(dao.BatchMain.Table()). Where(columns.BatchNo, batchNo). Where(columns.TenantId, contexts.GetTenantId(ctx)). Where(columns.CreatedDept, contexts.GetDeptId(ctx)). LockUpdate(). Scan(main) if err != nil { return nil, gerror.Wrap(err, "查询变更预处理批次失败") } if main.Id == 0 { return nil, gerror.New("变更预处理批次不存在") } if main.BatchType != consts.BatchTypePrepare { return nil, gerror.New("变更批次不是预处理类型") } if main.BatchAsyncStatus != consts.BatchAsyncStatusSuccess { return nil, gerror.New("变更预处理批次尚未完成") } if main.RunResult != consts.BatchRunResultSuccess { return nil, gerror.New("变更预处理批次未成功") } if main.BatchInfo == nil { return nil, gerror.New("变更预处理批次缺少快照") } if main.BatchInfo.Get("targetBatchType").Int() != targetBatchType { return nil, gerror.New("变更预处理批次类型不匹配") } now := gtime.Now() info := mergeConfirmBatchInfo(main.BatchInfo, in) data := do.BatchMain{ BatchType: targetBatchType, BatchAsyncStatus: consts.BatchAsyncStatusPending, RunResult: consts.BatchRunResultPending, StartTime: nil, EndTime: nil, FailReason: "", SuccessCount: 0, FailCount: 0, BatchInfo: gjson.New(info), UpdatedBy: in.Operator.UserId, UpdatedAt: now, } res, err := tx.Ctx(ctx).Model(dao.BatchMain.Table()). Where(columns.Id, main.Id). Where(columns.BatchType, consts.BatchTypePrepare). Where(columns.BatchAsyncStatus, consts.BatchAsyncStatusSuccess). Where(columns.RunResult, consts.BatchRunResultSuccess). Data(data). Update() if err != nil { return nil, gerror.Wrap(err, "更新变更批次状态失败") } affected, err := res.RowsAffected() if err != nil { return nil, gerror.Wrap(err, "读取变更批次更新结果失败") } if affected != 1 { return nil, gerror.New("变更批次状态已变化,请重试") } detailColumns := dao.BatchDetail.Columns() if _, err = tx.Ctx(ctx).Model(dao.BatchDetail.Table()). Where(detailColumns.BatchNo, batchNo). Where(detailColumns.BatchType, consts.BatchTypePrepare). Data(do.BatchDetail{ BatchType: targetBatchType, DetailStatus: consts.BatchDetailStatusPending, ErrorCode: "", ErrorReason: "", UpdatedBy: in.Operator.UserId, UpdatedAt: now, }). Update(); err != nil { return nil, gerror.Wrap(err, "更新变更批次明细类型失败") } return &AsyncConfirmResult{ BatchNo: batchNo, BatchType: targetBatchType, BatchAsyncStatus: consts.BatchAsyncStatusPending, }, nil } func mergeConfirmBatchInfo(base *gjson.Json, in *AsyncConfirmInput) g.Map { data := g.Map{} if base != nil { for key, value := range base.Map() { data[key] = value } } if in == nil { return data } if newPackageCode := strings.TrimSpace(in.NewPackageCode); newPackageCode != "" { data["newPackageCode"] = newPackageCode } if in.DurationMonths > 0 { data["durationMonths"] = in.DurationMonths } if in.GiftDurationMonths >= 0 { data["giftDurationMonths"] = in.GiftDurationMonths } if effectiveMode := strings.TrimSpace(in.EffectiveMode); effectiveMode != "" { data["effectiveMode"] = effectiveMode } if strings.TrimSpace(in.PackageBeginTimeStr) != "" { data["packageBeginTime"] = strings.TrimSpace(in.PackageBeginTimeStr) } data["offlineContractCompleted"] = in.OfflineContract if note := strings.TrimSpace(in.BuyerNote); note != "" { data["buyerNote"] = note } if note := strings.TrimSpace(in.AdminNote); note != "" { data["adminNote"] = note } if note := strings.TrimSpace(in.Remark); note != "" { data["remark"] = note } if in.PriceSnapshot != nil { data["changeUnitPrice"] = in.PriceSnapshot.ChangeUnitPrice } if strings.TrimSpace(in.SourceBatchNo) != "" { data["sourceBatchNo"] = strings.TrimSpace(in.SourceBatchNo) } return data }