Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕 - 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败 - 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影 - 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序 - 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列 - 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名 - 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
117 lines
7.8 KiB
SQL
117 lines
7.8 KiB
SQL
-- 卡轮询优先队列补齐事实字段与两个新终态。
|
||
-- 背景:111.md §23.4/§23.6/§23.7/§23.9/§23.10 要求优先项可追溯资产、设备号、店铺与代理归属、
|
||
-- 尝试上限、执行起止时间、下一次执行时间、出队时间、集成交互日志标识与有效期起算时间,并要求
|
||
-- 支持「有效期到期出队」与「人工关闭出队」两个出口。既有 tb_polling_priority_item 只有执行结果、
|
||
-- 失败原因与尝试次数,读侧无法解释「什么时候执行、下一次什么时候执行、为什么出队」,
|
||
-- 也没有承载已关闭与已过期两个终态的取值空间。
|
||
--
|
||
-- 设计选择:
|
||
-- 1. 只加列与重建受影响的 CHECK,不改活动项唯一键:活动集合仍是 pending/processing,
|
||
-- 部分唯一索引谓词 status IN ('pending','processing') 保持原样,两个新终态不占键位,
|
||
-- 同一卡同一任务类型出队后可再次入队或人工重触发。
|
||
-- 2. 资产列(asset_type/asset_id)按既有设备—卡绑定回填:卡已绑定设备时资产为该设备,
|
||
-- 独立卡回填为卡自身;设备号快照取绑定设备的虚拟号,未绑定设备时为空字符串。
|
||
-- 两列允许空值/空串(CHECK 兼容旧代码回滚期不写这两列的插入),新代码入队必写。
|
||
-- 3. priority_effective_from 是有效期起算时间:既有活动项在 up 中回填为迁移时刻,
|
||
-- 使上线后首轮到期扫描不会把既有未完成项批量判为已过期;终态行留空(已出队,不再计算有效期)。
|
||
-- 新增行取入队时间。有效期长度与尝试上限均为代码常量,本迁移不新增可维护配置项。
|
||
-- 4. attempt_limit 默认 3 与既有代码常量一致,既有行随默认值获得尝试上限。
|
||
-- 5. next_run_at 可空:既有行没有下次计划执行时间,读侧 MUST NOT 据此判定已过期。
|
||
-- 为它建部分索引以支撑到期扫描与读侧筛选。
|
||
-- 6. 状态 CHECK 重建并新增 closed-已关闭 expired-已过期 两个终态;终态与结果约束同步放宽,
|
||
-- 使两个新终态可以保留既有执行结果与失败原因而不被约束拒绝。
|
||
-- 7. 不使用数据库外键;新增列由应用层显式写入。
|
||
|
||
ALTER TABLE tb_polling_priority_item
|
||
ADD COLUMN asset_type VARCHAR(20) NOT NULL DEFAULT '',
|
||
ADD COLUMN asset_id BIGINT,
|
||
ADD COLUMN device_no_snapshot VARCHAR(100) NOT NULL DEFAULT '',
|
||
ADD COLUMN agent_shop_id_snapshot BIGINT,
|
||
ADD COLUMN attempt_limit INT NOT NULL DEFAULT 3,
|
||
ADD COLUMN started_at TIMESTAMPTZ,
|
||
ADD COLUMN finished_at TIMESTAMPTZ,
|
||
ADD COLUMN next_run_at TIMESTAMPTZ,
|
||
ADD COLUMN dequeued_at TIMESTAMPTZ,
|
||
ADD COLUMN integration_log_id VARCHAR(64) NOT NULL DEFAULT '',
|
||
ADD COLUMN priority_effective_from TIMESTAMPTZ;
|
||
|
||
-- 资产列回填:优先取该卡当前有效的设备绑定(同一卡存在多条绑定时取 is_current 优先、其次最新一条)。
|
||
UPDATE tb_polling_priority_item AS i
|
||
SET asset_type = 'device',
|
||
asset_id = b.device_id,
|
||
device_no_snapshot = COALESCE(d.virtual_no, '')
|
||
FROM (
|
||
SELECT DISTINCT ON (iot_card_id) iot_card_id, device_id
|
||
FROM tb_device_sim_binding
|
||
WHERE bind_status = 1 AND deleted_at IS NULL
|
||
ORDER BY iot_card_id, is_current DESC, id DESC
|
||
) AS b
|
||
LEFT JOIN tb_device AS d ON d.id = b.device_id AND d.deleted_at IS NULL
|
||
WHERE b.iot_card_id = i.card_id;
|
||
|
||
-- 未被上一步覆盖的行即独立卡:资产为卡自身。
|
||
UPDATE tb_polling_priority_item
|
||
SET asset_type = 'iot_card',
|
||
asset_id = card_id
|
||
WHERE asset_id IS NULL;
|
||
|
||
-- 代理归属回填:卡所属店铺的直接上级代理店铺(一级代理与平台卡为空)。
|
||
UPDATE tb_polling_priority_item AS i
|
||
SET agent_shop_id_snapshot = s.parent_id
|
||
FROM tb_iot_card AS c
|
||
JOIN tb_shop AS s ON s.id = c.shop_id AND s.deleted_at IS NULL
|
||
WHERE c.id = i.card_id
|
||
AND c.deleted_at IS NULL
|
||
AND s.parent_id IS NOT NULL;
|
||
|
||
-- 既有活动项的有效期自迁移时刻起算,避免上线后被首轮到期扫描批量过期。
|
||
UPDATE tb_polling_priority_item
|
||
SET priority_effective_from = NOW()
|
||
WHERE deleted_at IS NULL AND status IN ('pending', 'processing');
|
||
|
||
COMMENT ON COLUMN tb_polling_priority_item.asset_type IS '资产类型 iot_card-物联网卡 device-设备,与 pkg/constants.AssetTypeIotCard/AssetTypeDevice 一致;卡绑定设备时资产为设备,独立卡为卡自身';
|
||
COMMENT ON COLUMN tb_polling_priority_item.asset_id IS '资产ID,与 asset_type 共同构成资产身份;入队时按设备—卡绑定解析';
|
||
COMMENT ON COLUMN tb_polling_priority_item.device_no_snapshot IS '设备号快照(绑定设备的虚拟号),独立卡为空字符串';
|
||
COMMENT ON COLUMN tb_polling_priority_item.agent_shop_id_snapshot IS '代理归属快照-卡所属店铺的直接上级代理店铺ID,一级代理与平台卡为空';
|
||
COMMENT ON COLUMN tb_polling_priority_item.attempt_limit IS '尝试上限,入队时取代码常量(3),既有行随默认值获得上限;不新增可维护配置项';
|
||
COMMENT ON COLUMN tb_polling_priority_item.started_at IS '最近一次执行的开始时间,只在真正发起执行后写入';
|
||
COMMENT ON COLUMN tb_polling_priority_item.finished_at IS '最近一次执行的结束时间,与开始时间共同表达执行耗时';
|
||
COMMENT ON COLUMN tb_polling_priority_item.next_run_at IS '下一次计划执行时间,可空;为空表示未排期,读侧 MUST NOT 据此判定已过期';
|
||
COMMENT ON COLUMN tb_polling_priority_item.dequeued_at IS '出队时间,终态(已完成、失败出队、已关闭、已过期)写入';
|
||
COMMENT ON COLUMN tb_polling_priority_item.integration_log_id IS '最近一次上游交互的集成交互日志标识,不复制凭证或响应原文';
|
||
COMMENT ON COLUMN tb_polling_priority_item.priority_effective_from IS '有效期起算时间,新增行取入队时间;既有活动项在迁移时刻回填,终态行留空';
|
||
|
||
-- 取值域约束:允许空串/空值以兼容旧代码回滚期的插入(旧版本不写资产列);
|
||
-- 一旦写入则必须是合法资产类型与正数资产ID。
|
||
ALTER TABLE tb_polling_priority_item
|
||
ADD CONSTRAINT ck_polling_priority_item_asset_type CHECK (asset_type IN ('', 'iot_card', 'device')),
|
||
ADD CONSTRAINT ck_polling_priority_item_asset CHECK (asset_id IS NULL OR asset_id > 0),
|
||
ADD CONSTRAINT ck_polling_priority_item_attempt_limit CHECK (attempt_limit > 0);
|
||
|
||
-- 状态约束重建:新增 closed-已关闭 与 expired-已过期 两个终态。
|
||
ALTER TABLE tb_polling_priority_item
|
||
DROP CONSTRAINT ck_polling_priority_item_status;
|
||
|
||
ALTER TABLE tb_polling_priority_item
|
||
ADD CONSTRAINT ck_polling_priority_item_status CHECK (
|
||
status IN ('pending', 'processing', 'completed', 'failed', 'closed', 'expired')
|
||
);
|
||
|
||
-- 终态与结果的约束同步放宽:两个新终态保留既有执行结果与失败原因,不参与「必须带结果」的强约束。
|
||
ALTER TABLE tb_polling_priority_item
|
||
DROP CONSTRAINT ck_polling_priority_item_terminal_result;
|
||
|
||
ALTER TABLE tb_polling_priority_item
|
||
ADD CONSTRAINT ck_polling_priority_item_terminal_result CHECK (
|
||
(status = 'completed' AND result = 'success')
|
||
OR (status = 'failed' AND result = 'failed')
|
||
OR status IN ('pending', 'processing', 'closed', 'expired')
|
||
);
|
||
|
||
-- 到期扫描与读侧筛选按下一次计划执行时间取活动项。
|
||
CREATE INDEX idx_polling_priority_item_next_run
|
||
ON tb_polling_priority_item (next_run_at)
|
||
WHERE deleted_at IS NULL AND status IN ('pending', 'processing') AND next_run_at IS NOT NULL;
|
||
|
||
COMMENT ON INDEX idx_polling_priority_item_next_run IS '优先队列活动项的下一次计划执行时间部分索引,服务到期扫描与读侧筛选';
|