package renewchange import ( "encoding/json" "sort" "strings" "time" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) const ( TableSimCardInfo = "t_sim_card_info" TableSimCardBindPkg = "t_sim_card_bind_pkg" TableSimPoolBindPackage = "t_sim_pool_bind_package" TableSimBindPackageLogs = "t_sim_bind_package_logs" TableOrder = "t_order" TableOrderItem = "t_order_item" TableSimFlowPackageInfo = "t_sim_flow_package_info" TableSimFlowPackagePrice = "t_sim_flow_package_price" TableSysDept = "sys_dept" TableBatchMain = "batch_main" TableBatchDetail = "batch_detail" TableAgentBalance = "t_agent_balance" TableBalanceDetail = "t_balance_detail" TableSysOss = "sys_oss" TableTResourceBatchDl = "t_resource_batch_download" ) // typed row structs(worker 端未生成 DAO/DO/entity,故使用本地 typed struct)。 type SimCardInfo struct { Id int64 `orm:"id"` Iccid string `orm:"iccid"` Msisdn string `orm:"msisdn"` Imsi string `orm:"imsi"` RegionCode string `orm:"region_code"` DeptId int64 `orm:"dept_id"` AllocationBatchNo string `orm:"allocation_batch_no"` CurrentPackageCode string `orm:"current_package_code"` PackageStatus int `orm:"package_status"` ChanKey string `orm:"chan_key"` OutboundBatchNo string `orm:"outbound_batch_no"` InboundBatchNo string `orm:"inbound_batch_no"` FlowPkgBeginAt *gtime.Time `orm:"flow_pkg_begin_at"` FlowPkgPresentAt *gtime.Time `orm:"flow_pkg_present_at"` FlowPkgRealPresent *gtime.Time `orm:"flow_pkg_real_present_at"` FlowPkgEndAt *gtime.Time `orm:"flow_pkg_end_at"` DataServiceStatus int `orm:"data_service_status"` PackageTotalFlowMb float64 `orm:"package_total_flow_mb"` UsedFlowMb float64 `orm:"used_flow_mb"` TrafficCutoffEn int `orm:"traffic_cutoff_status"` TrafficCutoffThr float64 `orm:"traffic_cutoff_threshold"` SmsServiceStatus int `orm:"sms_service_status"` PackageTotalSms int `orm:"package_total_sms"` UsedSms int `orm:"used_sms"` VoiceServiceStatus int `orm:"voice_service_status"` PackageTotalVoice int `orm:"package_total_voice"` UsedVoice int `orm:"used_voice"` RoamServiceStatus int `orm:"roam_service_status"` PkgTotalRoamFlowMb float64 `orm:"package_total_roam_flow_mb"` UsedRoamFlowMb float64 `orm:"used_roam_flow_mb"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type SimCardBindPkg struct { Id int64 `orm:"id"` BatchNo string `orm:"batch_no"` Iccid string `orm:"iccid"` Msisdn string `orm:"msisdn"` DeptId int64 `orm:"dept_id"` PackageType int `orm:"package_type"` PackageCode string `orm:"package_code"` PreviousPackageCode string `orm:"previous_package_code"` BusinessType int `orm:"business_type"` EffectiveStatus int `orm:"effective_status"` HandleTime *gtime.Time `orm:"handle_time"` EffectiveTime *gtime.Time `orm:"effective_time"` ExpectedExpireTime *gtime.Time `orm:"expected_expire_time"` ActualExpireTime *gtime.Time `orm:"actual_expire_time"` DurationMonths int `orm:"duration_months"` GiftDurationMonths int `orm:"gift_duration_months"` OrderCode string `orm:"order_code"` SubscriptionNo string `orm:"subscription_no"` Remark string `orm:"remark"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` CreatedAt *gtime.Time `orm:"created_at"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type SimBindPackageLogs struct { Id int64 `orm:"id"` SubscriptionNo string `orm:"subscription_no"` BatchNo string `orm:"batch_no"` Iccid string `orm:"iccid"` Msisdn string `orm:"msisdn"` DeptId int64 `orm:"dept_id"` PackageType int `orm:"package_type"` PackageCode string `orm:"package_code"` PreviousPackageCod string `orm:"previous_package_code"` BusinessType int `orm:"business_type"` EffectiveStatus int `orm:"effective_status"` HandleTime *gtime.Time `orm:"handle_time"` EffectiveTime *gtime.Time `orm:"effective_time"` ExpectedExpireTime *gtime.Time `orm:"expected_expire_time"` ActualExpireTime *gtime.Time `orm:"actual_expire_time"` DurationMonths int `orm:"duration_months"` GiftDurationMonths int `orm:"gift_duration_months"` OrderCode string `orm:"order_code"` Remark string `orm:"remark"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` CreatedAt *gtime.Time `orm:"created_at"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type FlowPackageInfo struct { Id int64 `orm:"id"` PackageCode string `orm:"package_code"` PoolPackageCode int64 `orm:"pool_package_code"` PackageName string `orm:"package_name"` PackageType int `orm:"package_type"` BillingMethod int `orm:"billing_method"` FlowMb float64 `orm:"flow_mb"` CostPrice float64 `orm:"cost_price"` SysDefaultRatio float64 `orm:"sys_default_ratio"` SysDefaultProfit float64 `orm:"sys_default_profit"` RenewableDurationConfig *gjson.Json `orm:"renewable_duration_config"` RenewablePackageCodes *gjson.Json `orm:"renewable_package_codes"` ChangeablePackageCodes *gjson.Json `orm:"changeable_package_codes"` TopupPackageCodes *gjson.Json `orm:"topup_package_codes"` Enabled int `orm:"enabled"` TenantId string `orm:"tenant_id"` } type PoolBindPackageLogs struct { Id int64 `orm:"id"` SubscriptionNo string `orm:"subscription_no"` BatchNo string `orm:"batch_no"` PoolNo string `orm:"pool_no"` DeptId int64 `orm:"dept_id"` PackageType int `orm:"package_type"` PackageCode string `orm:"package_code"` PreviousPackageCode string `orm:"previous_package_code"` BusinessType int `orm:"business_type"` EffectiveStatus int `orm:"effective_status"` HandleTime *gtime.Time `orm:"handle_time"` EffectiveTime *gtime.Time `orm:"effective_time"` ExpectedExpireTime *gtime.Time `orm:"expected_expire_time"` ActualExpireTime *gtime.Time `orm:"actual_expire_time"` DurationMonths int `orm:"duration_months"` GiftDurationMonths int `orm:"gift_duration_months"` OrderCode string `orm:"order_code"` Remark string `orm:"remark"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` CreatedAt *gtime.Time `orm:"created_at"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type FlowPackagePrice struct { Id int64 `orm:"id"` TenantId string `orm:"tenant_id"` DeptId int64 `orm:"dept_id"` AgentScopeType int `orm:"agent_scope_type"` TargetAgentId int64 `orm:"target_agent_id"` PackageCode string `orm:"package_code"` AgentCostRatio float64 `orm:"agent_cost_ratio"` AgentCostProfit float64 `orm:"agent_cost_profit"` } type SysDeptRow struct { DeptId int64 `orm:"dept_id"` ParentId int64 `orm:"parent_id"` DeptName string `orm:"dept_name"` TenantId string `orm:"tenant_id"` } type BatchMainRow struct { Id int64 `orm:"id"` BatchNo string `orm:"batch_no"` OrderSn string `orm:"order_sn"` BatchType int `orm:"batch_type"` BatchStatus int `orm:"batch_status"` BatchAsyncStatus int `orm:"batch_async_status"` SourceType int `orm:"source_type"` SourceBatchNo string `orm:"source_batch_no"` IsCrossDept int `orm:"is_cross_dept"` TargetDeptId int64 `orm:"target_dept_id"` DeptId int64 `orm:"dept_id"` TotalCount int `orm:"total_count"` ValidCount int `orm:"valid_count"` SuccessCount int `orm:"success_count"` FailCount int `orm:"fail_count"` RunResult int `orm:"run_result"` FailReason string `orm:"fail_reason"` BatchInfo *gjson.Json `orm:"batch_info"` StartTime *gtime.Time `orm:"start_time"` EndTime *gtime.Time `orm:"end_time"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` CreatedAt *gtime.Time `orm:"created_at"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type BatchDetailRow struct { Id int64 `orm:"id"` BatchNo string `orm:"batch_no"` BatchType int `orm:"batch_type"` DetailStatus int `orm:"detail_status"` BlankOutStatus int `orm:"blank_out_status"` RowNo int `orm:"row_no"` ItemId string `orm:"item_id"` ErrorCode string `orm:"error_code"` ErrorReason string `orm:"error_reason"` Snapshot *gjson.Json `orm:"snapshot"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` CreatedAt *gtime.Time `orm:"created_at"` UpdatedBy int64 `orm:"updated_by"` UpdatedAt *gtime.Time `orm:"updated_at"` } type SysOssRow struct { Id int64 `orm:"id"` TenantId string `orm:"tenant_id"` FileName string `orm:"file_name"` OriginalName string `orm:"original_name"` FileSuffix string `orm:"file_suffix"` Path string `orm:"path"` Url string `orm:"url"` Service string `orm:"service"` Md5 string `orm:"md5"` FileSize int64 `orm:"file_size"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` UpdatedBy int64 `orm:"updated_by"` } type ResourceBatchDownloadRow struct { Id int64 `orm:"id"` BatchNo string `orm:"batch_no"` TaskName string `orm:"task_name"` ResourceType int `orm:"resource_type"` ExportScene int `orm:"export_scene"` TotalCount int `orm:"total_count"` SuccessCount int `orm:"success_count"` FailCount int `orm:"fail_count"` DownloadStatus int `orm:"download_status"` OssId int64 `orm:"oss_id"` FileName string `orm:"file_name"` FileExt string `orm:"file_ext"` FileUrl string `orm:"file_url"` FilePath string `orm:"file_path"` FileSize int64 `orm:"file_size"` FileMd5 string `orm:"file_md5"` DownloadCount int `orm:"download_count"` MaxDownloadCount int `orm:"max_download_count"` DeptId int64 `orm:"dept_id"` StartTime *gtime.Time `orm:"start_time"` FinishTime *gtime.Time `orm:"finish_time"` TenantId string `orm:"tenant_id"` CreatedDept int64 `orm:"created_dept"` CreatedBy int64 `orm:"created_by"` UpdatedBy int64 `orm:"updated_by"` } // DB 默认从 g.DB() 取,避免和现有 repository 紧耦合。 func DB() gdb.DB { return db() } func db() gdb.DB { return g.DB() } func uniqueStrings(in []string) []string { if len(in) == 0 { return nil } seen := make(map[string]struct{}, len(in)) out := make([]string, 0, len(in)) for _, v := range in { v = strings.TrimSpace(v) if v == "" { continue } if _, ok := seen[v]; ok { continue } seen[v] = struct{}{} out = append(out, v) } return out } // RoundAmount 四舍五入到分(导出以便 service 层复用)。 func RoundAmount(value float64) float64 { return roundAmount(value) } func roundAmount(value float64) float64 { if value < 0 { return 0 } return float64(int(value*100+0.5)) / 100 } // RenewableDurationOptions 解析套餐的可续费时长配置。 func RenewableDurationOptions(jsonValue *gjson.Json) ([]int, error) { return renewableDurationOptions(jsonValue) } func renewableDurationOptions(jsonValue *gjson.Json) ([]int, error) { if jsonValue == nil || jsonValue.IsNil() { return nil, errRenewDurationEmpty } values := jsonValue.Interfaces() out := make([]int, 0, len(values)) seen := make(map[int]struct{}, len(values)) for _, raw := range values { var month int switch v := raw.(type) { case int: month = v case int32: month = int(v) case int64: month = int(v) case float32: month = int(v) case float64: month = int(v) case json.Number: n, err := v.Int64() if err != nil { continue } month = int(n) case string: if t, err := time.Parse("2006-01-02", strings.TrimSpace(v)); err == nil { // tolerate date strings, fall back to ignoring _ = t } continue default: continue } if month <= 0 { continue } if _, ok := seen[month]; ok { continue } seen[month] = struct{}{} out = append(out, month) } sort.Ints(out) if len(out) == 0 { return nil, errRenewDurationEmpty } return out, nil } // ContainsInt 检查切片中是否包含目标值。 func ContainsInt(values []int, target int) bool { return containsInt(values, target) } func containsInt(values []int, target int) bool { for _, v := range values { if v == target { return true } } return false }