Files
junhong_cmp_fiber/internal/model/financial.go
break 575d056f54
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
feat(代理分销提现): 落地扫码注册、提现资料资格与企微终审提现
AUG26-008。

- 迁移 000214–000217:tb_shop 全局唯一且不可修改的随机分销码(含存量回填)、
  tb_agent_distribution_registration 待审批注册记录、tb_withdrawal_qualification 资料版本、
  tb_commission_withdrawal_request_attempt 审批尝试记录,以及提现申请的 latest_*/异常标记列;
  不修改既有迁移,down 在存在本 Change 业务事实或新类型场景行时拒绝破坏性回滚。
- 公开接口 POST /api/c/v1/agent-distribution-registrations:无认证,复用既有短信验证码校验、
  消费与限流;无效分销码、停用上级、验证码无效或已消费统一返回「分销码不可用」且不落库,
  审批通过前不创建店铺、账号或钱包。
- 审批通过才在同一事务内建启用店铺、代理主账号、钱包、上级层级与业务员快照,驳回不建实体,
  重复回调不重复建实体,提交后清理上级下级缓存。
- 提现资料资格按不可变版本保存,替换合同或法人身份证即新增版本并同事务失效旧有效版本;
  超管作废原因必填;代理停用与店铺删除联动失效。
- 提现每次提交或重提新增不可变审批尝试记录并冻结金额;企业微信通过仅一次从冻结扣减、
  保持状态 2 并写 paid_at(不使用状态 4),驳回/cancelled/deleted 仅一次释放,
  通过后撤销不回滚、不重新冻结、只写正交异常标记;加锁顺序统一为申请→尝试→钱包。
- 本地人工终审对已关联审批实例的申请返回状态冲突,approval_instance_id 为空的存量申请保持既有行为,
  不新增任何配置开关。
- 补齐审批业务类型注册点全集:业务类型与场景字段常量、场景 DTO 两处枚举与中文描述、
  场景字段白名单/合法类型/中文名、数据库 CHECK、Worker 决策消费者与装配、审批审计资源映射,
  以及三个新审计资源与 13 个审计动作;失败/拒绝审计改为必达。
- 新增后台路由与 OpenAPI:资格提交/查询/作废、提现申请/重提/详情、店铺详情返回只读分销码。
- 归档本 Change:主 Spec 新增 agent-distribution-withdrawal 能力(5 个 Requirement)。

验证(junhong_cmp_test + Redis DB 6,显式 DB_*,未重置整库):
- 迁移 up → version 217 且 dirty=false → down 3 → up 回 217,fixture 复核残留为 0。
- 受控状态机脚手架 227 项通过 / 0 项失败,覆盖 18 组场景(幂等与乱序回调、资金冻结/释放/重提、
  退款回扣 × 在途提现并发、负向场景拒绝审计与 14 个动作码审计真实落库)。
- gofmt 空、go build/go vet 通过、gendocs 与工作区逐字节一致、context-health 通过、
  openspec validate --strict 通过、doctor healthy;自动化测试按项目决策为 N/A。

运行期前置(未完成,非代码交付物):由超管经 PUT /api/admin/wecom/scenes/{business_type} 为
agent_distribution_approval、withdrawal_qualification_approval、commission_withdrawal_approval
配置启用场景与模板控件映射;未配置时相应提交失败关闭。
2026-09-14 09:45:13 +08:00

86 lines
7.0 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 model
import (
"time"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// CommissionWithdrawalRequest 佣金提现申请模型
// 代理佣金提现申请、审批流程、提现记录查询
type CommissionWithdrawalRequest struct {
gorm.Model
BaseModel `gorm:"embedded"`
WithdrawalNo string `gorm:"column:withdrawal_no;type:varchar(50);uniqueIndex:uk_commission_withdrawal_no,where:deleted_at IS NULL AND withdrawal_no IS NOT NULL;comment:提现单号唯一格式W + 时间戳 + 随机数)" json:"withdrawal_no"`
AgentID uint `gorm:"column:agent_id;index;not null;comment:代理用户ID" json:"agent_id"`
ApplicantID uint `gorm:"column:applicant_id;index;comment:申请人账号ID" json:"applicant_id"`
ShopID uint `gorm:"column:shop_id;index;comment:店铺ID冗余字段" json:"shop_id"`
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:提现金额(分为单位)" json:"amount"`
Fee int64 `gorm:"column:fee;type:bigint;default:0;comment:手续费(分为单位)" json:"fee"`
FeeRate int64 `gorm:"column:fee_rate;type:bigint;default:0;comment:手续费比率基点100=1%,快照)" json:"fee_rate"`
ActualAmount int64 `gorm:"column:actual_amount;type:bigint;comment:实际到账金额(分为单位)" json:"actual_amount"`
WithdrawalMethod string `gorm:"column:withdrawal_method;type:varchar(20);comment:提现方式 alipay-支付宝 wechat-微信 bank-银行卡" json:"withdrawal_method"`
PaymentType string `gorm:"column:payment_type;type:varchar(20);default:'manual';comment:放款类型manual=人工打款)" json:"payment_type"`
AccountInfo datatypes.JSON `gorm:"column:account_info;type:jsonb;comment:收款账户信息(姓名、账号等)" json:"account_info"`
Status int `gorm:"column:status;type:int;default:1;comment:状态 1-待审核 2-已通过 3-已拒绝 4-已到账" json:"status"`
ProcessorID uint `gorm:"column:processor_id;index;comment:处理人ID" json:"processor_id"`
ProcessedAt *time.Time `gorm:"column:processed_at;comment:处理时间" json:"processed_at"`
PaidAt *time.Time `gorm:"column:paid_at;comment:到账时间" json:"paid_at"`
RejectReason string `gorm:"column:reject_reason;type:text;comment:拒绝原因" json:"reject_reason"`
Remark string `gorm:"column:remark;type:text;comment:备注" json:"remark"`
// LatestAttemptID 与 LatestApprovalInstanceID 仅用于列表投影,不是历史事实来源。
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"`
// ApprovalInstanceID 为空表示从未关联审批实例的存量申请,仍走既有本地人工终审。
ApprovalInstanceID *uint `gorm:"column:approval_instance_id;type:bigint;comment:首次接入企业微信审批的审批实例ID" json:"approval_instance_id,omitempty"`
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"`
}
// TableName 指定表名
func (CommissionWithdrawalRequest) TableName() string {
return "tb_commission_withdrawal_request"
}
// CommissionWithdrawalRequestAttempt 是提现申请每次提交或重提对应的不可变审批材料与冻结事实。
// 冻结与释放金额一律取本记录事实released_at 是回溯可重放的幂等依据。
type CommissionWithdrawalRequestAttempt struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
RequestID uint `gorm:"column:request_id;type:bigint;not null;comment:所属提现申请ID" json:"request_id"`
AttemptNo int `gorm:"column:attempt_no;type:int;not null;comment:第几次提交,从 1 递增" json:"attempt_no"`
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:本次冻结提现金额(分)" json:"amount"`
Fee int64 `gorm:"column:fee;type:bigint;not null;default:0;comment:本次手续费(分)" json:"fee"`
FeeRate int64 `gorm:"column:fee_rate;type:bigint;not null;default:0;comment:本次手续费率(基点)" json:"fee_rate"`
ActualAmount int64 `gorm:"column:actual_amount;type:bigint;not null;default:0;comment:本次实际到账金额(分)" json:"actual_amount"`
WithdrawalMethod string `gorm:"column:withdrawal_method;type:varchar(20);not null;comment:本次收款方式快照" json:"withdrawal_method"`
AccountInfo datatypes.JSON `gorm:"column:account_info;type:jsonb;not null;comment:本次收款账户信息快照" json:"account_info"`
InvoiceKeys datatypes.JSON `gorm:"column:invoice_keys;type:jsonb;not null;default:'[]';comment:本次申请级发票对象存储Key列表" json:"invoice_keys"`
SubmittedByAccountID uint `gorm:"column:submitted_by_account_id;type:bigint;not null;comment:本次实际提交账号ID" json:"submitted_by_account_id"`
ApprovalInstanceID *uint `gorm:"column:approval_instance_id;type:bigint;comment:本次尝试关联的通用审批实例ID" json:"approval_instance_id,omitempty"`
ReleasedAt *time.Time `gorm:"column:released_at;comment:本次冻结释放时间,空表示未结算" json:"released_at,omitempty"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
}
// TableName 指定提现审批尝试记录表名。
func (CommissionWithdrawalRequestAttempt) TableName() string {
return "tb_commission_withdrawal_request_attempt"
}
// CommissionWithdrawalSetting 佣金提现设置模型
// 提现参数配置(最低金额、手续费率、到账时间等)
type CommissionWithdrawalSetting struct {
gorm.Model
BaseModel `gorm:"embedded"`
MinWithdrawalAmount int64 `gorm:"column:min_withdrawal_amount;type:bigint;comment:最低提现金额(分为单位)" json:"min_withdrawal_amount"`
FeeRate int64 `gorm:"column:fee_rate;type:bigint;comment:手续费率(万分比,如100表示1%)" json:"fee_rate"`
ArrivalDays int `gorm:"column:arrival_days;type:int;comment:到账天数" json:"arrival_days"`
DailyWithdrawalLimit int `gorm:"column:daily_withdrawal_limit;type:int;default:3;comment:每日提现次数限制" json:"daily_withdrawal_limit"`
IsActive bool `gorm:"column:is_active;type:boolean;default:true;comment:是否生效(最新一条)" json:"is_active"`
}
// TableName 指定表名
func (CommissionWithdrawalSetting) TableName() string {
return "tb_commission_withdrawal_setting"
}