Files
junhong_cmp_fiber/pkg/constants/iot.go
break 1aa4eacee2
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m26s
feat(退款分佣): 佣金回溯明细替换全额失效并补齐读侧与导出
用 PRD 2.14 语义整体替换退款佣金「整单全额失效」实现:原佣金保持已发放不变,
回溯事实落在新表 tb_commission_clawback_record 的负数、不可提现明细上。

- 新增成对迁移 000220 建 tb_commission_clawback_record,唯一约束
  (refund_id, original_commission_id) 为权威幂等键,附店铺+时间/原佣金/订单索引。
- 回溯用例(internal/service/refund/clawback.go):准入仅由退款申请状态、审批异常
  标记与退款方式决定;金额按分整数计算,分母取冻结实收(缺失回落审批尝试)、
  分子原路取渠道成功金额,乘法用 math/big 中间量,舍入差自末条起向前补差;
  终态判据要求订单佣金已离开待计算且不存在 status IN (1,2,99) 的记录。
- 三层幂等:唯一约束兜底、佣金行行锁 + 钱包乐观锁、commission_deducted 仅作投影
  并带 WHERE commission_deducted = false 条件置位;闭合三结果为已回溯、无需回溯、
  审批异常转人工。
- 事务内顺序固定:锁提现申请行 → 锁尝试行 → 解冻冻结 → 置驳回 → 插回溯明细 →
  扣 balance(允许为负)→ 写负数流水 → 审计;删除旧全额失效写入与其两个审计调用点,
  refund.invalidate_commission 仅保留常量与注册供历史审计读取。
- 读侧:佣金明细列表 status 筛选透传,两表 UNION ALL 合并分页并以 source ASC 作
  末位次序键;新增佣金明细详情接口并同步路由与 OpenAPI 装配。
- 导出:新增 commission_record 场景(白名单、exporter 注册、DTO oneof、DataSource
  与列定义),粒度为佣金记录,原佣金与回溯各一行,金额保持分且可为负。
- 新增退款佣金回溯周期补偿任务(@every 1m / MaxRetry(3) / Timeout(10m) /
  Unique(10m),独立队列),保留启动时补偿扫描,判据与既有实现一致。

Refs: AUG26-012
2026-09-14 13:40:34 +08:00

451 lines
12 KiB
Go
Raw Permalink 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 constants
// ========================================
// IoT SIM 管理系统常量定义
// ========================================
// ========================================
// 1. 核心业务常量
// ========================================
// IoT 卡状态
const (
IotCardStatusInStock = 1 // 在库
IotCardStatusDistributed = 2 // 已分销
IotCardStatusActivated = 3 // 已激活
IotCardStatusSuspended = 4 // 已停用
)
// IoT 卡业务类型
const (
CardCategoryNormal = "normal" // 普通卡(需要实名认证)
CardCategoryIndustry = "industry" // 行业卡(无需实名认证)
)
// 设备状态
const (
DeviceStatusInStock = 1 // 在库
DeviceStatusDistributed = 2 // 已分销
)
// 号卡状态
const (
NumberCardStatusOnSale = 1 // 在售
NumberCardStatusOffSale = 2 // 下架
)
// IoT 卡激活状态
const (
ActivationStatusInactive = 0 // 未激活
ActivationStatusActive = 1 // 已激活
)
// IoT 卡实名状态
const (
RealNameStatusNotVerified = 0 // 未实名
RealNameStatusVerified = 1 // 已实名
)
// PollingRealnameReversalThreshold 实名逆转防抖阈值:连续 N 次检测到逆转才触发停机
const PollingRealnameReversalThreshold = 3
// IoT 卡网络状态
const (
NetworkStatusOffline = 0 // 停机
NetworkStatusOnline = 1 // 开机
)
// Gateway 卡状态
const (
GatewayCardStatusReady = "准备" // 网关卡状态:准备
GatewayCardStatusNormal = "正常" // 网关卡状态:正常
GatewayCardStatusStopped = "停机" // 网关卡状态:停机
GatewayCardExtendPendingActivation = "待激活" // 网关扩展状态:待激活
GatewayCardExtendMachineSeparated = "机卡分离停机" // 网关扩展状态:机卡分离停机
GatewayCardStartExtendMachineSeparated = "2" // 机卡分离复机时上传给运营商的 extend 值
GatewayCardExtendRiskStop = "风险停机" // 网关扩展状态:运营商风险停机(独立卡不允许复机)
GatewayCardExtendCancelled = "已销户" // 网关扩展状态:已销户(独立卡不允许复机)
)
// IoT 卡停机原因
const (
StopReasonTrafficExhausted = "traffic_exhausted" // 流量耗尽
StopReasonManual = "manual" // 手动停机
StopReasonArrears = "arrears" // 欠费
StopReasonProtectPeriod = "protect_period" // 保护期一致性检查自动停机
StopReasonNoPackage = "no_package" // 停机原因:无有效套餐
StopReasonNotRealname = "not_realname" // 停机原因:非行业卡且未完成实名认证
StopReasonCarrierStopped = "carrier_stopped" // 停机原因:运营商/Gateway 侧主动停机
)
// 套餐流量类型
const (
DataTypeReal = "real" // 真流量
DataTypeVirtual = "virtual" // 虚流量
)
// 套餐类型
const (
PackageTypeFormal = "formal" // 正式套餐
PackageTypeAddon = "addon" // 附加套餐
)
// 套餐价格配置状态
const (
PackagePriceConfigStatusUnconfigured = 0 // 未配置
PackagePriceConfigStatusGiftZero = 1 // 赠送 0 价
PackagePriceConfigStatusConfigured = 2 // 已配置非 0
)
// 订单类型
const (
OrderTypePackage = 1 // 套餐订单
OrderTypeNumberCard = 2 // 号卡订单
)
// 订单状态 (IoT 模块)
const (
IotOrderStatusPending = 1 // 待支付
IotOrderStatusPaid = 2 // 已支付
IotOrderStatusCompleted = 3 // 已完成
IotOrderStatusCancelled = 4 // 已取消
IotOrderStatusRefunded = 5 // 已退款
)
// 支付方式
const (
PaymentMethodWallet = "wallet" // 钱包
PaymentMethodOnline = "online" // 在线支付
PaymentMethodCarrier = "carrier" // 运营商支付
)
// 所有者类型(统一枚举,仅支持 platform 和 shop
const (
OwnerTypePlatform = "platform" // 平台
OwnerTypeShop = "shop" // 店铺(代理商)
)
// 企业卡授权状态
const (
EnterpriseCardAuthStatusValid = 1 // 有效
EnterpriseCardAuthStatusRevoked = 0 // 已回收
)
// 资产分配类型
const (
AssetAllocationTypeAllocate = "allocate" // 分配
AssetAllocationTypeRecall = "recall" // 回收
)
// 资产类型
const (
AssetTypeIotCard = "iot_card" // 物联网卡
AssetTypeDevice = "device" // 设备
)
// 实名认证策略
const (
RealnamePolicyNone = "none" // 无需实名
RealnamePolicyBeforeOrder = "before_order" // 先实名后充值/购买
RealnamePolicyAfterOrder = "after_order" // 先充值/购买后实名
)
// 放款类型
const (
PaymentTypeManual = "manual" // 人工打款
)
// 绑定状态
const (
BindStatusBound = 1 // 已绑定
BindStatusUnbound = 2 // 已解绑
)
// ========================================
// 2. 套餐和轮询相关常量
// ========================================
// 套餐使用类型
const (
PackageUsageTypeSingleCard = "single_card" // 单卡套餐
PackageUsageTypeDevice = "device" // 设备级套餐
)
// 注意:套餐使用状态常量已迁移至 constants.go扩展为 5 个状态0-4
// 轮询配置卡条件
const (
CardConditionNotRealName = "not_real_name" // 未实名
CardConditionRealName = "real_name" // 已实名
CardConditionActivated = "activated" // 已激活
CardConditionSuspended = "suspended" // 已停用
)
// 流量使用记录来源
const (
DataUsageSourcePolling = "polling" // 轮询
DataUsageSourceManual = "manual" // 手动
DataUsageSourceGateway = "gateway" // Gateway回调
)
// ========================================
// 3. 分佣相关常量
// ========================================
// 分佣类型
const (
CommissionTypeOneTime = "one_time" // 一次性分佣
CommissionTypeLongTerm = "long_term" // 长期分佣
CommissionTypeCombined = "combined" // 组合分佣
)
// 分佣模式
const (
CommissionModeFixed = "fixed" // 固定金额
CommissionModePercent = "percent" // 百分比
)
// 分佣状态
const (
CommissionStatusFrozen = 1 // 已冻结
CommissionStatusUnfreezing = 2 // 解冻中
CommissionStatusReleased = 3 // 已发放
CommissionStatusInvalid = 4 // 已失效
CommissionStatusClawback = 5 // 回溯(退款完成后的负数、不可提现回溯明细)
CommissionStatusPendingReview = 99 // 待人工修正(链路断裂,需平台处理)
)
// 阶梯类型([预留] 用于分佣阶梯功能,待产品规划)
const (
LadderTypeActivation = "activation" // 激活量([预留]
LadderTypePickup = "pickup" // 提货量([预留]
LadderTypeDeposit = "deposit" // 充值量([预留]
)
// 卡类型
const (
CardTypeNumberCard = "number_card" // 号卡
CardTypeIotCard = "iot_card" // IoT卡
)
// 审批类型([预留] 用于审批流程功能,待产品规划)
const (
ApprovalTypeAuto = "auto" // 自动([预留]
ApprovalTypeManual = "manual" // 人工([预留]
)
// ========================================
// 4. 财务管理常量
// ========================================
// 提现状态
const (
WithdrawalStatusPending = 1 // 待审核
WithdrawalStatusApproved = 2 // 已通过
WithdrawalStatusRejected = 3 // 已拒绝
WithdrawalStatusPaid = 4 // 已到账
)
// 提现方式
const (
WithdrawalMethodAlipay = "alipay" // 支付宝
WithdrawalMethodWechat = "wechat" // 微信
WithdrawalMethodBank = "bank" // 银行卡
)
// ========================================
// 5. 系统管理常量
// ========================================
// ========================================
// 运营商编码
// ========================================
const (
CarrierCodeCMCC = "CMCC" // 中国移动
CarrierCodeCUCC = "CUCC" // 中国联通
CarrierCodeCTCC = "CTCC" // 中国电信
CarrierCodeCBN = "CBN" // 广电
)
// ========================================
// 状态名称映射函数
// ========================================
// GetIotCardStatusName 获取 IoT 卡业务状态名称
// 对应 IotCardStatus* 常量1=在库, 2=已分销, 3=已激活, 4=已停用
func GetIotCardStatusName(status int) string {
switch status {
case IotCardStatusInStock:
return "在库"
case IotCardStatusDistributed:
return "已分销"
case IotCardStatusActivated:
return "已激活"
case IotCardStatusSuspended:
return "已停用"
default:
return "未知"
}
}
// GetDeviceStatusName 获取设备归属状态名称
// 对应 DeviceStatus* 常量1=在库, 2=已分销
func GetDeviceStatusName(status int) string {
switch status {
case DeviceStatusInStock:
return "在库"
case DeviceStatusDistributed:
return "已分销"
default:
return "未知"
}
}
// GetActivationStatusName 获取激活状态名称
// 对应 ActivationStatus* 常量0=未激活, 1=已激活
func GetActivationStatusName(status int) string {
switch status {
case ActivationStatusInactive:
return "未激活"
case ActivationStatusActive:
return "已激活"
default:
return "未知"
}
}
// GetRealNameStatusName 获取实名状态名称
// 对应 RealNameStatus* 常量0=未实名, 1=已实名
func GetRealNameStatusName(status int) string {
switch status {
case RealNameStatusNotVerified:
return "未实名"
case RealNameStatusVerified:
return "已实名"
default:
return "未知"
}
}
// GetNetworkStatusName 获取网络状态名称
// 对应 NetworkStatus* 常量0=停机, 1=开机
func GetNetworkStatusName(status int) string {
switch status {
case NetworkStatusOffline:
return "停机"
case NetworkStatusOnline:
return "开机"
default:
return "未知"
}
}
// GetCommissionRecordStatusName 获取佣金记录状态名称
// 对应 CommissionStatus* 常量1=已冻结, 2=解冻中, 3=已发放, 4=已失效, 5=回溯, 99=待人工修正
func GetCommissionRecordStatusName(status int) string {
switch status {
case CommissionStatusFrozen:
return "已冻结"
case CommissionStatusUnfreezing:
return "解冻中"
case CommissionStatusReleased:
return "已发放"
case CommissionStatusInvalid:
return "已失效"
case CommissionStatusClawback:
return "回溯"
case CommissionStatusPendingReview:
return "待人工修正"
default:
return "未知"
}
}
// GetOrderPaymentStatusName 获取订单支付状态名称
// 1=待支付, 2=已支付, 3=已取消, 4=已退款
func GetOrderPaymentStatusName(status int) string {
switch status {
case 1:
return "待支付"
case 2:
return "已支付"
case 3:
return "已取消"
case 4:
return "已退款"
default:
return "未知"
}
}
// GetOrderCommissionStatusName 获取订单佣金流程状态名称
// 1=待计算, 2=已完成, 3=待人工处理
func GetOrderCommissionStatusName(status int) string {
switch status {
case 1:
return "待计算"
case 2:
return "已完成"
case 3:
return "待人工处理"
default:
return "未知"
}
}
// GetOrderCommissionResultName 获取订单佣金业务结果名称
// 0=未知, 1=有佣金, 2=无佣金, 3=链路异常
func GetOrderCommissionResultName(result int) string {
switch result {
case 0:
return "未知"
case 1:
return "有佣金"
case 2:
return "无佣金"
case 3:
return "链路异常"
default:
return "未知"
}
}
// GetRefundStatusName 获取退款申请状态名称
// 1=待审批, 2=已通过, 3=已拒绝, 4=已退回, 5=原路退款处理中, 6=原路退款失败
func GetRefundStatusName(status int) string {
switch status {
case 1:
return "待审批"
case 2:
return "已通过"
case 3:
return "已拒绝"
case 4:
return "已退回"
case 5:
return "原路退款处理中"
case 6:
return "原路退款失败"
default:
return "未知"
}
}
// GetWithdrawalStatusName 获取提现申请状态名称
// 对应 WithdrawalStatus* 常量1=待审核, 2=已通过, 3=已拒绝, 4=已到账
func GetWithdrawalStatusName(status int) string {
switch status {
case WithdrawalStatusPending:
return "待审核"
case WithdrawalStatusApproved:
return "已通过"
case WithdrawalStatusRejected:
return "已拒绝"
case WithdrawalStatusPaid:
return "已到账"
default:
return "未知"
}
}