Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕 - 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败 - 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影 - 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序 - 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列 - 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名 - 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
137 lines
11 KiB
Go
137 lines
11 KiB
Go
package model
|
||
|
||
import (
|
||
"time"
|
||
|
||
"gorm.io/datatypes"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// RefundRequest 退款申请模型
|
||
// 记录退款申请的完整生命周期,包含退款单号、关联订单、金额、状态流转、审批信息等
|
||
// 状态流转:1(待审批) → 2(已通过)/3(已拒绝)/4(已退回),4(已退回) → 1(待审批)
|
||
type RefundRequest struct {
|
||
gorm.Model
|
||
BaseModel `gorm:"embedded"`
|
||
|
||
// 退款单基础信息
|
||
RefundNo string `gorm:"column:refund_no;type:varchar(50);uniqueIndex:idx_refund_request_refund_no,where:deleted_at IS NULL;not null;comment:退款单号(RF+日期时间+6位随机数)" json:"refund_no"`
|
||
OrderID uint `gorm:"column:order_id;index;not null;comment:关联订单ID" json:"order_id"`
|
||
OrderNo string `gorm:"column:order_no;type:varchar(30);not null;default:'';comment:关联订单号快照" json:"order_no"`
|
||
OrderType string `gorm:"column:order_type;type:varchar(20);not null;default:'';comment:订单类型快照(single_card/device)" json:"order_type,omitempty"`
|
||
AssetIdentifier string `gorm:"column:asset_identifier;type:varchar(100);not null;default:'';comment:下单时资产标识符快照(卡为ICCID,设备优先VirtualNo、其次IMEI)" json:"asset_identifier,omitempty"`
|
||
IotCardID *uint `gorm:"column:iot_card_id;comment:下单时IoT卡ID快照" json:"iot_card_id,omitempty"`
|
||
DeviceID *uint `gorm:"column:device_id;comment:下单时设备ID快照" json:"device_id,omitempty"`
|
||
PackageUsageID *uint `gorm:"column:package_usage_id;comment:关联套餐使用记录ID(可选)" json:"package_usage_id,omitempty"`
|
||
ShopID *uint `gorm:"column:shop_id;index;comment:店铺ID(从订单获取,用于数据权限过滤)" json:"shop_id,omitempty"`
|
||
ShopName string `gorm:"column:shop_name;->" json:"shop_name,omitempty"`
|
||
|
||
// 金额信息
|
||
ActualReceivedAmount int64 `gorm:"column:actual_received_amount;type:bigint;not null;comment:实收金额(分)" json:"actual_received_amount"`
|
||
RequestedRefundAmount int64 `gorm:"column:requested_refund_amount;type:bigint;not null;comment:申请退款金额(分)" json:"requested_refund_amount"`
|
||
ApprovedRefundAmount *int64 `gorm:"column:approved_refund_amount;type:bigint;comment:审批实际退款金额(分)" json:"approved_refund_amount,omitempty"`
|
||
|
||
// 退款凭证、原因和状态
|
||
RefundVoucherKey StringJSONBArray `gorm:"column:refund_voucher_key;type:jsonb;not null;comment:退款凭证对象存储file_key列表(jsonb存储[]string)" json:"refund_voucher_key"`
|
||
RefundReason string `gorm:"column:refund_reason;type:text;comment:退款原因" json:"refund_reason"`
|
||
Status int `gorm:"column:status;type:int;not null;default:1;index;comment:状态 1-待审批 2-已通过 3-已拒绝 4-已退回" json:"status"`
|
||
|
||
// 审批信息
|
||
ApprovalInstanceID *uint `gorm:"column:approval_instance_id;comment:关联的唯一通用审批实例ID" json:"approval_instance_id,omitempty"`
|
||
ProcessorID *uint `gorm:"column:processor_id;comment:审批人ID" json:"processor_id,omitempty"`
|
||
ProcessedAt *time.Time `gorm:"column:processed_at;comment:审批时间" json:"processed_at,omitempty"`
|
||
RejectReason string `gorm:"column:reject_reason;type:text;comment:拒绝原因" json:"reject_reason,omitempty"`
|
||
Remark string `gorm:"column:remark;type:text;comment:审批备注" json:"remark,omitempty"`
|
||
|
||
// 退款方式、冻结实收与当前材料快照
|
||
Method string `gorm:"column:method;type:varchar(20);not null;default:'';comment:退款方式,空表示未接入方式的存量申请" json:"method"`
|
||
FrozenActualReceivedAmount int64 `gorm:"column:frozen_actual_received_amount;type:bigint;not null;default:0;comment:冻结的权威实收金额(分)" json:"frozen_actual_received_amount"`
|
||
CustomerAccountInfo string `gorm:"column:customer_account_info;type:text;not null;default:'';comment:客户收款信息自由文本快照" json:"customer_account_info"`
|
||
|
||
// 结算标识:来源支付事实在创建或重提时冻结,线下处理流水号由财务补录(写审计),二者语义不同。
|
||
SourcePaymentNo string `gorm:"column:source_payment_no;type:varchar(64);not null;default:'';comment:冻结的来源支付单号,线下订单为空" json:"source_payment_no"`
|
||
OriginalChannelTradeNo string `gorm:"column:original_channel_trade_no;type:varchar(100);not null;default:'';comment:冻结的原支付渠道交易流水号(列宽与 tb_payment.third_party_trade_no 一致),线下订单为空" json:"original_channel_trade_no"`
|
||
OfflineSettlementNo string `gorm:"column:offline_settlement_no;type:varchar(128);not null;default:'';comment:线下退款处理流水号或凭证编号,由授权账号补录或更正" json:"offline_settlement_no"`
|
||
OfflineSettledAt *time.Time `gorm:"column:offline_settled_at;comment:线下退款处理流水号最近登记或更正时间" json:"offline_settled_at,omitempty"`
|
||
OfflineSettledBy uint `gorm:"column:offline_settled_by;not null;default:0;comment:线下退款处理流水号最近登记或更正的操作账号ID,0-未登记" json:"offline_settled_by"`
|
||
|
||
// 审批尝试引用,仅用于列表与详情展示
|
||
LatestAttemptID uint `gorm:"column:latest_attempt_id;type:bigint;not null;default:0;comment:最新审批尝试记录ID,仅用于展示" json:"latest_attempt_id"`
|
||
LatestApprovalInstanceID uint `gorm:"column:latest_approval_instance_id;type:bigint;not null;default:0;comment:最新通用审批实例ID,仅用于展示" json:"latest_approval_instance_id"`
|
||
|
||
// 渠道原路退款结果与结构化失败分类
|
||
ChannelRefundStatus int `gorm:"column:channel_refund_status;type:smallint;not null;default:0;comment:渠道退款状态 0-未发起或不适用 1-处理中 2-明确成功 3-明确失败" json:"channel_refund_status"`
|
||
ChannelRefundNo string `gorm:"column:channel_refund_no;type:varchar(64);not null;default:'';comment:渠道退款流水号" json:"channel_refund_no"`
|
||
ChannelRefundRequestNo string `gorm:"column:channel_refund_request_no;type:varchar(64);not null;default:'';comment:渠道退款请求号快照" json:"channel_refund_request_no"`
|
||
ChannelRefundAmount int64 `gorm:"column:channel_refund_amount;type:bigint;not null;default:0;comment:渠道退款金额快照(分)" json:"channel_refund_amount"`
|
||
ChannelRefundedAt *time.Time `gorm:"column:channel_refunded_at;comment:渠道明确退款成功时间" json:"channel_refunded_at,omitempty"`
|
||
// ChannelSubmittedAt 非空表示该尝试已向渠道提交过退款请求;重投只允许查询,不得再次提交。
|
||
ChannelSubmittedAt *time.Time `gorm:"column:channel_submitted_at;comment:渠道退款请求提交认领时间" json:"channel_submitted_at,omitempty"`
|
||
FailureReason string `gorm:"column:failure_reason;type:varchar(32);not null;default:'';comment:结构化失败分类稳定编码" json:"failure_reason"`
|
||
FailureMessage string `gorm:"column:failure_message;type:varchar(500);not null;default:'';comment:失败安全摘要" json:"failure_message"`
|
||
|
||
// 正交异常标记:企业微信通过后撤销、渠道结果永久未知等情况转人工处理
|
||
AnomalyFlag int `gorm:"column:anomaly_flag;type:smallint;not null;default:0;comment:异常标记 0-无异常 1-有异常" json:"anomaly_flag"`
|
||
AnomalyReason string `gorm:"column:anomaly_reason;type:varchar(500);not null;default:'';comment:异常原因" json:"anomaly_reason"`
|
||
|
||
// 后处理标记
|
||
CommissionDeducted bool `gorm:"column:commission_deducted;not null;default:false;comment:佣金是否已回扣" json:"commission_deducted"`
|
||
AssetReset bool `gorm:"column:asset_reset;not null;default:false;comment:退款后资产处理是否完成" json:"asset_reset"`
|
||
}
|
||
|
||
// TableName 指定表名
|
||
func (RefundRequest) TableName() string {
|
||
return "tb_refund_request"
|
||
}
|
||
|
||
// RefundRequestAttempt 退款审批尝试记录。
|
||
// 每次提交或重提新增一条不可变记录,冻结当次方式、金额、冻结实收、原因、客户收款信息、
|
||
// 凭证与套餐使用快照;主键同时作为通用审批业务标识,使同一退款单每次提交持有独立审批实例。
|
||
type RefundRequestAttempt struct {
|
||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||
RefundID uint `gorm:"column:refund_id;not null;index" json:"refund_id"`
|
||
AttemptNo int `gorm:"column:attempt_no;type:int;not null" json:"attempt_no"`
|
||
Method string `gorm:"column:method;type:varchar(20);not null" json:"method"`
|
||
RefundAmount int64 `gorm:"column:refund_amount;type:bigint;not null" json:"refund_amount"`
|
||
FrozenActualReceivedAmount int64 `gorm:"column:frozen_actual_received_amount;type:bigint;not null" json:"frozen_actual_received_amount"`
|
||
RefundReason string `gorm:"column:refund_reason;type:text;not null;default:''" json:"refund_reason"`
|
||
// Remark 是本次提交的申请人备注,逐次冻结;与退款主表 remark(审批备注)语义不同,不得复用。
|
||
Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"`
|
||
CustomerAccountInfo string `gorm:"column:customer_account_info;type:text;not null;default:''" json:"customer_account_info"`
|
||
CustomerVoucherKeys StringJSONBArray `gorm:"column:customer_voucher_keys;type:jsonb;not null" json:"customer_voucher_keys"`
|
||
PackageUsageSnapshot datatypes.JSON `gorm:"column:package_usage_snapshot;type:jsonb;not null" json:"package_usage_snapshot"`
|
||
ChannelRefundRequestNo string `gorm:"column:channel_refund_request_no;type:varchar(64);not null;default:''" json:"channel_refund_request_no"`
|
||
SubmittedByAccountID uint `gorm:"column:submitted_by_account_id;not null" json:"submitted_by_account_id"`
|
||
ApprovalInstanceID *uint `gorm:"column:approval_instance_id" json:"approval_instance_id,omitempty"`
|
||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||
}
|
||
|
||
// TableName 指定审批尝试记录表名。
|
||
func (RefundRequestAttempt) TableName() string {
|
||
return "tb_refund_request_attempt"
|
||
}
|
||
|
||
// 退款状态常量
|
||
const (
|
||
RefundStatusPending = 1 // 待审批
|
||
RefundStatusApproved = 2 // 已通过(退款已完成)
|
||
RefundStatusRejected = 3 // 已拒绝
|
||
RefundStatusReturned = 4 // 已退回
|
||
|
||
// RefundStatusChannelProcessing 表示企业微信已通过、原路渠道结果尚未确认。
|
||
RefundStatusChannelProcessing = 5
|
||
// RefundStatusChannelFailed 表示原路渠道明确失败或超时可恢复失败。
|
||
RefundStatusChannelFailed = 6
|
||
)
|
||
|
||
// RefundActiveStatuses 返回会阻止同一订单创建新退款申请的状态集合。
|
||
// 该集合必须与迁移中 uk_refund_request_active_order 的谓词保持一致。
|
||
func RefundActiveStatuses() []int {
|
||
return []int{RefundStatusPending, RefundStatusChannelProcessing, RefundStatusChannelFailed}
|
||
}
|
||
|
||
// RefundResubmittableStatuses 返回允许修改材料并重提的状态集合。
|
||
func RefundResubmittableStatuses() []int {
|
||
return []int{RefundStatusRejected, RefundStatusReturned, RefundStatusChannelFailed}
|
||
}
|