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/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 DurationYears int DurationMonths int GiftDurationMonths int RenewDate string PackageBeginTime string PackageEndTime string OfflineContract bool BuyerNote string AdminNote string Remark string PriceSnapshot *model.TSimCardRenewPriceSnapshot PaymentSnapshot *model.TSimCardRenewPaymentSnapshot SourceBatchNo 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=101 的待处理续费批次:重置主表正式执行相关字段并把明细的 BatchType 切换到 101、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.BatchTypeRenew } 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 } durationValue := in.DurationYears if durationValue <= 0 { durationValue = renewDurationYearsFromLegacy(in.DurationMonths, 0, in.PriceSnapshot) } if durationValue > 0 { data["durationValue"] = durationValue data["durationYears"] = durationValue actualDurationMonths := renewActualDurationMonths(in.PriceSnapshot, durationValue) data["durationMonths"] = actualDurationMonths data["actualDurationMonths"] = actualDurationMonths } if in.GiftDurationMonths >= 0 { data["giftDurationMonths"] = in.GiftDurationMonths } if strings.TrimSpace(in.RenewDate) != "" { data["renewDate"] = strings.TrimSpace(in.RenewDate) } if strings.TrimSpace(in.PackageBeginTime) != "" { data["packageBeginTime"] = strings.TrimSpace(in.PackageBeginTime) } if strings.TrimSpace(in.PackageEndTime) != "" { data["packageEndTime"] = strings.TrimSpace(in.PackageEndTime) } 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["priceSnapshot"] = in.PriceSnapshot data["packageCode"] = in.PriceSnapshot.PackageCode data["packageName"] = in.PriceSnapshot.PackageName data["renewUnitPrice"] = in.PriceSnapshot.RenewUnitPrice data["billingMethod"] = in.PriceSnapshot.BillingMethod data["renewDurationUnit"] = in.PriceSnapshot.RenewDurationUnit data["renewDurationUnitText"] = in.PriceSnapshot.RenewDurationUnitText data["priceSource"] = in.PriceSnapshot.PriceSource data["priceOwnerDeptId"] = in.PriceSnapshot.PriceOwnerDeptId data["agentDefaultPriceId"] = in.PriceSnapshot.AgentDefaultPriceId data["targetPriceId"] = in.PriceSnapshot.TargetPriceId data["renewableDurationOptions"] = in.PriceSnapshot.RenewableDurationOptions data["renewablePackageCodes"] = in.PriceSnapshot.RenewablePackageCodes data["renewablePackages"] = in.PriceSnapshot.RenewablePackages if durationValue > 0 { data["actualDurationMonths"] = renewActualDurationMonths(in.PriceSnapshot, durationValue) } } if in.PaymentSnapshot != nil { data["paymentMode"] = strings.TrimSpace(in.PaymentSnapshot.PaymentMode) data["payType"] = in.PaymentSnapshot.PayType data["payStatus"] = in.PaymentSnapshot.PayStatus data["payAmount"] = in.PaymentSnapshot.PayAmount data["balanceAmount"] = in.PaymentSnapshot.BalanceAmount data["offlinePaidAmount"] = in.PaymentSnapshot.OfflinePaidAmount data["balanceBefore"] = in.PaymentSnapshot.BalanceBefore data["balanceAfter"] = in.PaymentSnapshot.BalanceAfter data["balanceDetailSerialNo"] = strings.TrimSpace(in.PaymentSnapshot.BalanceDetailSerialNo) data["payerDeptId"] = in.PaymentSnapshot.PayerDeptId data["payerUserId"] = in.PaymentSnapshot.PayerUserId data["isTopDept"] = in.PaymentSnapshot.IsTopDept if in.PaymentSnapshot.PaymentTime != nil { data["paymentTime"] = in.PaymentSnapshot.PaymentTime.Format("Y-m-d H:i:s") } data["paymentSnapshot"] = in.PaymentSnapshot } if strings.TrimSpace(in.SourceBatchNo) != "" { data["sourceBatchNo"] = strings.TrimSpace(in.SourceBatchNo) } return data }