Files
iotlcm/internal/repository/renewchange/tables.go
T
MiFaZhan 2bec257289 chore: 初始开源发布
iotlcm-worker-svr:异步执行中枢(RabbitMQ 消费者 + 全量同步编排)。

- Go module:iotlcm-worker-svr → git.5iot.com/iotlcm-public/iotlcm-worker-svr(214 文件)
- 凭据与内部标识脱敏:MySQL/Redis 凭据、私网与生产 IP、内网域名、
  库名 xiujie_admin → iotlcm、哨兵名占位
- 159 处真实手机号 → 合法 11 位编造号(保留号段与后 4 位,维持互异,
  不破坏「校验 MSISDN 格式」等测试断言)
- 移除内部资产:CI 触发器、Jenkins 触发测试文档、预演门禁与镜像
  digest 记录
- Dockerfile 改用公共基础镜像(golang:1.25-alpine → alpine:3.23),
  移除写死的 git 凭据
- README 重写(架构/全量同步模型/配置/已知失败),补 Apache-2.0
  LICENSE,LF 行尾 + .gitattributes

已知:3 个测试包在源仓同一提交上同样失败(client/upstream、
service/allocate、service/inbound),属既有缺陷,本仓未引入亦未修复。
2026-10-22 16:37:56 +08:00

393 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}