feat(代理分销提现): 落地扫码注册、提现资料资格与企微终审提现
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

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
配置启用场景与模板控件映射;未配置时相应提交失败关闭。
This commit is contained in:
2026-09-14 09:45:13 +08:00
parent 315a7de3e4
commit 575d056f54
68 changed files with 5759 additions and 309 deletions

View File

@@ -0,0 +1,21 @@
-- 回滚代理分销码与公开扫码注册 Schema。
-- 已产生注册事实、已生成分销码或已存在新业务类型审批场景配置时禁止破坏性回滚:
-- 注册记录无法通过重建 Schema 恢复,分销码一旦清除将导致既有二维码失效。
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM tb_agent_distribution_registration) THEN
RAISE EXCEPTION '存在代理扫码注册记录,禁止回滚代理分销码迁移';
END IF;
IF EXISTS (SELECT 1 FROM tb_shop WHERE distribution_code <> '') THEN
RAISE EXCEPTION '存在已生成的分销码,禁止回滚代理分销码迁移';
END IF;
END $$;
DROP INDEX IF EXISTS uk_agent_distribution_registration_instance;
DROP INDEX IF EXISTS idx_agent_distribution_registration_phone;
DROP INDEX IF EXISTS idx_agent_distribution_registration_parent;
DROP TABLE IF EXISTS tb_agent_distribution_registration;
DROP INDEX IF EXISTS uk_shop_distribution_code;
ALTER TABLE tb_shop DROP COLUMN IF EXISTS distribution_code;

View File

@@ -0,0 +1,81 @@
-- 代理分销码与公开扫码注册:店铺全局唯一分销码、待审批注册记录。
-- 分销码由应用层随机生成且不可修改,条件唯一索引兜底;不提供人工指定或编辑入口。
-- 注册只落待审批记录,审批通过前不创建店铺、账号、钱包或上下级归属。
-- 不使用数据库外键,关联以 ID 保存并由应用层显式校验。
ALTER TABLE tb_shop
ADD COLUMN IF NOT EXISTS distribution_code VARCHAR(32) NOT NULL DEFAULT '';
COMMENT ON COLUMN tb_shop.distribution_code IS '全局唯一随机分销码,创建时生成且不可修改;空字符串表示历史数据未生成';
CREATE UNIQUE INDEX IF NOT EXISTS uk_shop_distribution_code
ON tb_shop (distribution_code)
WHERE distribution_code <> '' AND deleted_at IS NULL;
CREATE TABLE tb_agent_distribution_registration (
id BIGSERIAL PRIMARY KEY,
distribution_code VARCHAR(32) NOT NULL,
parent_shop_id BIGINT NOT NULL,
phone VARCHAR(20) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
shop_name VARCHAR(100) NOT NULL,
shop_code VARCHAR(50) NOT NULL,
username VARCHAR(50) NOT NULL,
contact_name VARCHAR(50) NOT NULL DEFAULT '',
province VARCHAR(50) NOT NULL DEFAULT '',
city VARCHAR(50) NOT NULL DEFAULT '',
district VARCHAR(50) NOT NULL DEFAULT '',
address VARCHAR(255) NOT NULL DEFAULT '',
status SMALLINT NOT NULL DEFAULT 0,
approval_instance_id BIGINT,
reject_reason VARCHAR(500) NOT NULL DEFAULT '',
decided_at TIMESTAMPTZ,
creator BIGINT NOT NULL DEFAULT 0,
updater BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_agent_distribution_registration_code CHECK (distribution_code <> ''),
CONSTRAINT chk_agent_distribution_registration_parent CHECK (parent_shop_id > 0),
CONSTRAINT chk_agent_distribution_registration_phone CHECK (phone <> ''),
CONSTRAINT chk_agent_distribution_registration_password CHECK (password_hash <> ''),
CONSTRAINT chk_agent_distribution_registration_shop CHECK (
shop_name <> '' AND shop_code <> '' AND username <> ''
),
CONSTRAINT chk_agent_distribution_registration_status CHECK (status IN (0, 1, 2)),
CONSTRAINT chk_agent_distribution_registration_instance CHECK (
approval_instance_id IS NULL OR approval_instance_id > 0
)
);
-- 同一手机号可存在多条记录:驳回后再次扫码是新记录、新审批实例。
CREATE INDEX idx_agent_distribution_registration_parent
ON tb_agent_distribution_registration (parent_shop_id, status, id);
CREATE INDEX idx_agent_distribution_registration_phone
ON tb_agent_distribution_registration (phone, id DESC);
CREATE UNIQUE INDEX uk_agent_distribution_registration_instance
ON tb_agent_distribution_registration (approval_instance_id)
WHERE approval_instance_id IS NOT NULL;
COMMENT ON TABLE tb_agent_distribution_registration IS '代理扫码注册待审批记录,审批通过后才创建店铺与账号';
COMMENT ON COLUMN tb_agent_distribution_registration.id IS '主键注册记录ID同时作为通用审批业务ID';
COMMENT ON COLUMN tb_agent_distribution_registration.distribution_code IS '提交时使用的上级店铺分销码快照,审批通过时校验其归属店铺仍启用';
COMMENT ON COLUMN tb_agent_distribution_registration.parent_shop_id IS '上级店铺ID审批通过后作为新店铺的直接上级';
COMMENT ON COLUMN tb_agent_distribution_registration.phone IS '注册手机号,审批通过时写入代理主账号;不在此记录明文密码';
COMMENT ON COLUMN tb_agent_distribution_registration.password_hash IS '注册时生成的 bcrypt 密码哈希,审批通过时直接写入新建账号';
COMMENT ON COLUMN tb_agent_distribution_registration.shop_name IS '申请店铺名称快照';
COMMENT ON COLUMN tb_agent_distribution_registration.shop_code IS '申请店铺编号快照,审批通过时按既有唯一约束校验';
COMMENT ON COLUMN tb_agent_distribution_registration.username IS '申请代理主账号用户名快照,审批通过时按既有唯一约束校验';
COMMENT ON COLUMN tb_agent_distribution_registration.contact_name IS '联系人姓名快照';
COMMENT ON COLUMN tb_agent_distribution_registration.province IS '省份快照';
COMMENT ON COLUMN tb_agent_distribution_registration.city IS '城市快照';
COMMENT ON COLUMN tb_agent_distribution_registration.district IS '区县快照';
COMMENT ON COLUMN tb_agent_distribution_registration.address IS '详细地址快照';
COMMENT ON COLUMN tb_agent_distribution_registration.status IS '状态0 待审批、1 已通过、2 已驳回';
COMMENT ON COLUMN tb_agent_distribution_registration.approval_instance_id IS '关联的通用审批实例ID创建后不可修改';
COMMENT ON COLUMN tb_agent_distribution_registration.reject_reason IS '企业微信最终驳回原因,通过时为空';
COMMENT ON COLUMN tb_agent_distribution_registration.decided_at IS '审批终态到达时间';
COMMENT ON COLUMN tb_agent_distribution_registration.creator IS '创建人用户ID0 表示系统';
COMMENT ON COLUMN tb_agent_distribution_registration.updater IS '最近更新人用户ID0 表示系统';
COMMENT ON COLUMN tb_agent_distribution_registration.created_at IS '创建时间';
COMMENT ON COLUMN tb_agent_distribution_registration.updated_at IS '最近更新时间';

View File

@@ -0,0 +1,39 @@
-- 回滚提现资格资料版本与提现审批尝试记录 Schema。
-- 任一本 Change 的业务事实存在时禁止破坏性回滚:资金冻结与资格审批事实无法通过重建 Schema 恢复。
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM tb_withdrawal_qualification) THEN
RAISE EXCEPTION '存在提现资格资料版本,禁止回滚提现资格与审批尝试迁移';
END IF;
IF EXISTS (SELECT 1 FROM tb_commission_withdrawal_request_attempt) THEN
RAISE EXCEPTION '存在提现审批尝试记录,禁止回滚提现资格与审批尝试迁移';
END IF;
IF EXISTS (
SELECT 1 FROM tb_commission_withdrawal_request
WHERE latest_attempt_id <> 0 OR latest_approval_instance_id <> 0
OR approval_instance_id IS NOT NULL OR anomaly_flag <> 0
) THEN
RAISE EXCEPTION '存在已接入企业微信终审的提现申请,禁止回滚提现资格与审批尝试迁移';
END IF;
END $$;
ALTER TABLE tb_commission_withdrawal_request DROP CONSTRAINT IF EXISTS chk_commission_withdrawal_request_anomaly;
ALTER TABLE tb_commission_withdrawal_request DROP CONSTRAINT IF EXISTS chk_commission_withdrawal_request_approval_instance;
ALTER TABLE tb_commission_withdrawal_request
DROP COLUMN IF EXISTS anomaly_reason,
DROP COLUMN IF EXISTS anomaly_flag,
DROP COLUMN IF EXISTS approval_instance_id,
DROP COLUMN IF EXISTS latest_approval_instance_id,
DROP COLUMN IF EXISTS latest_attempt_id;
DROP INDEX IF EXISTS idx_commission_withdrawal_attempt_unreleased;
DROP INDEX IF EXISTS idx_commission_withdrawal_attempt_request;
DROP INDEX IF EXISTS uk_commission_withdrawal_attempt_instance;
DROP TABLE IF EXISTS tb_commission_withdrawal_request_attempt;
DROP INDEX IF EXISTS uk_withdrawal_qualification_instance;
DROP INDEX IF EXISTS idx_withdrawal_qualification_shop;
DROP INDEX IF EXISTS uk_withdrawal_qualification_valid;
DROP TABLE IF EXISTS tb_withdrawal_qualification;

View File

@@ -0,0 +1,166 @@
-- 提现资格资料版本与提现审批尝试记录。
-- 资格事实按版本不可变保存:替换合同或法人身份证即新增版本,旧有效版本在同一事务内失效。
-- 提现每次提交或重提新增一条不可变审批尝试记录,冻结与释放金额一律取尝试记录事实。
-- 附件字段每个只保存单个对象存储 Key必填合同、法人身份证正反面共 3 项,可选营业执照、门头照、发票共 3 项,
-- 合计不超过企业微信单张审批单 6 个附件上限。
-- 不使用数据库外键,关联以 ID 保存并由应用层显式校验。
CREATE TABLE tb_withdrawal_qualification (
id BIGSERIAL PRIMARY KEY,
shop_id BIGINT NOT NULL,
subject_type VARCHAR(20) NOT NULL,
subject_code VARCHAR(64) NOT NULL,
legal_person_id_card VARCHAR(64) NOT NULL,
contract_file_key VARCHAR(255) NOT NULL,
id_card_front_file_key VARCHAR(255) NOT NULL,
id_card_back_file_key VARCHAR(255) NOT NULL,
business_license_file_key VARCHAR(255) NOT NULL DEFAULT '',
shop_front_file_key VARCHAR(255) NOT NULL DEFAULT '',
invoice_file_key VARCHAR(255) NOT NULL DEFAULT '',
invoice_title VARCHAR(200) NOT NULL DEFAULT '',
invoice_subject_code VARCHAR(64) NOT NULL DEFAULT '',
status SMALLINT NOT NULL DEFAULT 0,
invalid_reason VARCHAR(500) NOT NULL DEFAULT '',
invalidated_at TIMESTAMPTZ,
invalidated_by BIGINT NOT NULL DEFAULT 0,
approval_instance_id BIGINT,
decided_at TIMESTAMPTZ,
creator BIGINT NOT NULL DEFAULT 0,
updater BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_withdrawal_qualification_shop CHECK (shop_id > 0),
CONSTRAINT chk_withdrawal_qualification_subject CHECK (subject_type IN ('enterprise', 'personal')),
CONSTRAINT chk_withdrawal_qualification_subject_code CHECK (subject_code <> ''),
CONSTRAINT chk_withdrawal_qualification_legal_person CHECK (legal_person_id_card <> ''),
CONSTRAINT chk_withdrawal_qualification_attachments CHECK (
contract_file_key <> '' AND id_card_front_file_key <> '' AND id_card_back_file_key <> ''
),
CONSTRAINT chk_withdrawal_qualification_invoice CHECK (
invoice_file_key = '' OR (invoice_title <> '' AND invoice_subject_code <> '')
),
CONSTRAINT chk_withdrawal_qualification_status CHECK (status IN (0, 1, 2, 3)),
CONSTRAINT chk_withdrawal_qualification_invalidated CHECK ((status = 3) = (invalidated_at IS NOT NULL)),
CONSTRAINT chk_withdrawal_qualification_instance CHECK (
approval_instance_id IS NULL OR approval_instance_id > 0
)
);
-- 同一店铺至多一个有效版本;失效与新增在同一事务内完成,因此提交即可替换。
CREATE UNIQUE INDEX uk_withdrawal_qualification_valid
ON tb_withdrawal_qualification (shop_id)
WHERE status = 1;
CREATE INDEX idx_withdrawal_qualification_shop
ON tb_withdrawal_qualification (shop_id, status, id DESC);
CREATE UNIQUE INDEX uk_withdrawal_qualification_instance
ON tb_withdrawal_qualification (approval_instance_id)
WHERE approval_instance_id IS NOT NULL;
COMMENT ON TABLE tb_withdrawal_qualification IS '提现资料资格版本,不可变保存历史、附件引用与审批结果';
COMMENT ON COLUMN tb_withdrawal_qualification.id IS '主键资料版本ID同时作为通用审批业务ID';
COMMENT ON COLUMN tb_withdrawal_qualification.shop_id IS '所属代理店铺ID';
COMMENT ON COLUMN tb_withdrawal_qualification.subject_type IS '签约主体类型enterprise 企业、personal 个人';
COMMENT ON COLUMN tb_withdrawal_qualification.subject_code IS '签约主体代码:企业统一社会信用代码、个人身份证号(脱敏后对外展示)';
COMMENT ON COLUMN tb_withdrawal_qualification.legal_person_id_card IS '法人身份证号,个人代理与签约主体代码一致(脱敏后对外展示)';
COMMENT ON COLUMN tb_withdrawal_qualification.contract_file_key IS '合同附件对象存储 Key单个对象必填';
COMMENT ON COLUMN tb_withdrawal_qualification.id_card_front_file_key IS '法人身份证正面附件对象存储 Key单个对象必填';
COMMENT ON COLUMN tb_withdrawal_qualification.id_card_back_file_key IS '法人身份证反面附件对象存储 Key单个对象必填';
COMMENT ON COLUMN tb_withdrawal_qualification.business_license_file_key IS '营业执照附件对象存储 Key单个对象可选';
COMMENT ON COLUMN tb_withdrawal_qualification.shop_front_file_key IS '门头照附件对象存储 Key单个对象可选';
COMMENT ON COLUMN tb_withdrawal_qualification.invoice_file_key IS '发票附件对象存储 Key单个对象仅企业可选';
COMMENT ON COLUMN tb_withdrawal_qualification.invoice_title IS '发票抬头,仅企业填写,且必须与签约主体一致';
COMMENT ON COLUMN tb_withdrawal_qualification.invoice_subject_code IS '发票统一社会信用代码,必须与签约主体代码一致';
COMMENT ON COLUMN tb_withdrawal_qualification.status IS '状态0 待审批、1 已通过有效、2 已驳回、3 已失效或已作废';
COMMENT ON COLUMN tb_withdrawal_qualification.invalid_reason IS '失效原因,作废必填,代理停用联动失效时记录停用原因';
COMMENT ON COLUMN tb_withdrawal_qualification.invalidated_at IS '失效时间,状态为 3 时必填';
COMMENT ON COLUMN tb_withdrawal_qualification.invalidated_by IS '使资格失效的操作账号ID0 表示由店铺停用联动触发';
COMMENT ON COLUMN tb_withdrawal_qualification.approval_instance_id IS '关联的通用审批实例ID创建后不可修改';
COMMENT ON COLUMN tb_withdrawal_qualification.decided_at IS '审批终态到达时间';
COMMENT ON COLUMN tb_withdrawal_qualification.creator IS '创建人用户ID';
COMMENT ON COLUMN tb_withdrawal_qualification.updater IS '最近更新人用户ID';
COMMENT ON COLUMN tb_withdrawal_qualification.created_at IS '创建时间';
COMMENT ON COLUMN tb_withdrawal_qualification.updated_at IS '最近更新时间';
CREATE TABLE tb_commission_withdrawal_request_attempt (
id BIGSERIAL PRIMARY KEY,
request_id BIGINT NOT NULL,
attempt_no INTEGER NOT NULL,
amount BIGINT NOT NULL,
fee BIGINT NOT NULL DEFAULT 0,
fee_rate BIGINT NOT NULL DEFAULT 0,
actual_amount BIGINT NOT NULL DEFAULT 0,
withdrawal_method VARCHAR(20) NOT NULL,
account_info JSONB NOT NULL,
invoice_keys JSONB NOT NULL DEFAULT '[]'::jsonb,
submitted_by_account_id BIGINT NOT NULL,
approval_instance_id BIGINT,
released_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_commission_withdrawal_attempt_no UNIQUE (request_id, attempt_no),
CONSTRAINT chk_commission_withdrawal_attempt_ids CHECK (
request_id > 0 AND submitted_by_account_id > 0
),
CONSTRAINT chk_commission_withdrawal_attempt_no_positive CHECK (attempt_no >= 1),
CONSTRAINT chk_commission_withdrawal_attempt_amount CHECK (
amount > 0 AND fee >= 0 AND fee_rate >= 0 AND actual_amount >= 0
),
CONSTRAINT chk_commission_withdrawal_attempt_method CHECK (withdrawal_method <> ''),
CONSTRAINT chk_commission_withdrawal_attempt_account CHECK (jsonb_typeof(account_info) = 'object'),
CONSTRAINT chk_commission_withdrawal_attempt_invoice CHECK (jsonb_typeof(invoice_keys) = 'array'),
CONSTRAINT chk_commission_withdrawal_attempt_instance CHECK (
approval_instance_id IS NULL OR approval_instance_id > 0
)
);
CREATE UNIQUE INDEX uk_commission_withdrawal_attempt_instance
ON tb_commission_withdrawal_request_attempt (approval_instance_id)
WHERE approval_instance_id IS NOT NULL;
CREATE INDEX idx_commission_withdrawal_attempt_request
ON tb_commission_withdrawal_request_attempt (request_id, attempt_no DESC);
-- 未结算尝试是后续佣金回溯的释放接缝:按申请读取未释放尝试。
CREATE INDEX idx_commission_withdrawal_attempt_unreleased
ON tb_commission_withdrawal_request_attempt (request_id, id)
WHERE released_at IS NULL;
COMMENT ON TABLE tb_commission_withdrawal_request_attempt IS '提现审批尝试记录,每次提交或重提一条不可变材料与冻结事实';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.id IS '主键审批尝试记录ID同时作为通用审批业务ID';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.request_id IS '所属提现申请ID';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.attempt_no IS '第几次提交,从 1 递增,申请内唯一';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.amount IS '本次冻结的提现金额(单位:分),释放与扣减一律取该事实';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.fee IS '本次手续费快照(单位:分)';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.fee_rate IS '本次手续费率快照基点100=1%';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.actual_amount IS '本次实际到账金额快照(单位:分)';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.withdrawal_method IS '本次收款方式快照';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.account_info IS '本次收款账户信息快照jsonb 对象)';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.invoice_keys IS '本次申请级发票对象存储 Key 列表jsonb 数组)';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.submitted_by_account_id IS '本次实际提交账号ID';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.approval_instance_id IS '本次尝试关联的通用审批实例ID创建后不可修改';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.released_at IS '本次冻结释放时间,空表示冻结仍未结算;是回溯可重放的幂等依据';
COMMENT ON COLUMN tb_commission_withdrawal_request_attempt.created_at IS '创建时间';
ALTER TABLE tb_commission_withdrawal_request
ADD COLUMN IF NOT EXISTS latest_attempt_id BIGINT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS latest_approval_instance_id BIGINT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS approval_instance_id BIGINT,
ADD COLUMN IF NOT EXISTS anomaly_flag SMALLINT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS anomaly_reason VARCHAR(500) NOT NULL DEFAULT '';
ALTER TABLE tb_commission_withdrawal_request
DROP CONSTRAINT IF EXISTS chk_commission_withdrawal_request_approval_instance;
ALTER TABLE tb_commission_withdrawal_request
ADD CONSTRAINT chk_commission_withdrawal_request_approval_instance
CHECK (approval_instance_id IS NULL OR approval_instance_id > 0);
ALTER TABLE tb_commission_withdrawal_request
DROP CONSTRAINT IF EXISTS chk_commission_withdrawal_request_anomaly;
ALTER TABLE tb_commission_withdrawal_request
ADD CONSTRAINT chk_commission_withdrawal_request_anomaly
CHECK (anomaly_flag IN (0, 1));
COMMENT ON COLUMN tb_commission_withdrawal_request.latest_attempt_id IS '最新审批尝试记录ID仅用于列表投影与历史事实定位';
COMMENT ON COLUMN tb_commission_withdrawal_request.latest_approval_instance_id IS '最新通用审批实例ID仅用于列表投影';
COMMENT ON COLUMN tb_commission_withdrawal_request.approval_instance_id IS '首次接入企业微信审批时关联的审批实例ID为空表示从未关联审批实例的存量申请仍走本地人工终审';
COMMENT ON COLUMN tb_commission_withdrawal_request.anomaly_flag IS '正交异常标记0 无异常、1 企业微信通过后撤销';
COMMENT ON COLUMN tb_commission_withdrawal_request.anomaly_reason IS '异常原因,供提现详情展示与人工处理';

View File

@@ -0,0 +1,24 @@
-- 回滚企业微信审批场景业务类型白名单扩展。
-- 存在本 Change 新增类型的场景配置时禁止破坏性回滚:删除场景行会丢失已配置的模板控件映射,
-- 且相应业务提交将失去渠道而失败关闭。
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM tb_wecom_approval_scene
WHERE business_type IN (
'agent_distribution_approval',
'withdrawal_qualification_approval',
'commission_withdrawal_approval'
)
) THEN
RAISE EXCEPTION '存在分销注册、提现资格或提现终审审批场景配置,禁止回滚审批场景业务类型扩展';
END IF;
END $$;
ALTER TABLE tb_wecom_approval_scene
DROP CONSTRAINT IF EXISTS chk_wecom_approval_scene_business;
ALTER TABLE tb_wecom_approval_scene
ADD CONSTRAINT chk_wecom_approval_scene_business
CHECK (business_type IN ('refund_approval', 'offline_recharge_approval', 'employee_collection_approval'));

View File

@@ -0,0 +1,16 @@
-- 扩展企业微信审批场景业务类型白名单,纳入分销注册、提现资格与提现终审三个场景。
-- 既有的退款、线下代充值、员工代收款核销三个场景语义不变。
ALTER TABLE tb_wecom_approval_scene
DROP CONSTRAINT IF EXISTS chk_wecom_approval_scene_business;
ALTER TABLE tb_wecom_approval_scene
ADD CONSTRAINT chk_wecom_approval_scene_business
CHECK (business_type IN (
'refund_approval',
'offline_recharge_approval',
'employee_collection_approval',
'agent_distribution_approval',
'withdrawal_qualification_approval',
'commission_withdrawal_approval'
));

View File

@@ -0,0 +1,14 @@
-- 回滚存量店铺分销码回填。
-- 回填不可逆:分销码一旦生成并对外使用(二维码、上级归属),清空会使既有二维码失效
-- 并使已注册下级失去上级入口。因此存在任何注册记录时拒绝回滚,不做静默清空。
--
-- 注意:本回滚不改变 distribution_code 的数据,也不回滚列注释——分销码已生成并可能被
-- 二维码与注册事实依赖,清空会使既有二维码与下级注册入口失效。因此存在任何注册记录时拒绝回滚;
-- 若维护者确需清除分销码,必须先停止新入口并确认无依赖,另行人工处理。
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM tb_agent_distribution_registration) THEN
RAISE EXCEPTION '存在代理扫码注册记录,禁止回滚分销码回填迁移';
END IF;
END $$;

View File

@@ -0,0 +1,16 @@
-- 回填存量店铺分销码。
-- 000214 只建列与条件唯一索引,既有店铺的分销码为空字符串,因而无法作为上级被扫码注册,
-- 公开注册链路对存量代理恒返回「分销码不可用」。本迁移为每个空码店铺生成全局唯一随机分销码。
--
-- 生成方式md5(random()::text || clock_timestamp()::text || id::text),不依赖任何扩展;
-- id 参与输入保证同一语句内各行取值不同clock_timestamp() 逐行求值进一步降低碰撞概率。
-- 已非空的店铺(由应用层建店或批量导入生成)保持不变,不覆盖既有码。
-- 条件唯一索引 uk_shop_distribution_code 兜底;若出现碰撞,本迁移整体失败并由维护者重跑。
UPDATE tb_shop
SET distribution_code = md5(random()::text || clock_timestamp()::text || id::text),
updated_at = NOW()
WHERE distribution_code = '';
-- 回填后不存在空值:同步列注释,避免继续声明「空字符串表示历史数据未生成」。
COMMENT ON COLUMN tb_shop.distribution_code IS '全局唯一随机分销码,创建时生成且不可修改;回填后所有未删除店铺均有值';