背景 ---- 1) **单内撕裂**:原 /transfer 收的是**明细行 ID**,只更新那一行。一张单有 2 条明细时,转交后一条归接收人、另一条仍是原借用人 —— 前端按 borrow_no 聚合便同时显示两个名字(实测 BOR-20260917-0001:108→测试 / 109→杜邢宸)。 2) **单向强塞**:原实现发起即生效,接收人在毫不知情的情况下背上资产责任。 本次改动 ---- · 新增 borrow_no —— 单据身份。一次转交要覆盖该单**多行**,单行 ID 表达不了 覆盖范围;accept 时据此批量更新。borrow_id 保留为「发起时的代表明细」供追溯。 · 新增 status —— PENDING / ACCEPTED / REJECTED 状态机。 · 存量 1 行按旧语义(发起即生效)标记为 ACCEPTED 并回填 borrow_no: 它事实上已经生效,若标 PENDING,接收人会收到一条早已生效的待办。 · 建 borrow_no / status / (to_user_id,status) 索引,后者支撑「待我接收」查询。 同单号同一时刻只允许一条 PENDING(应用层强制),避免两个接收人争抢同一批实物。
94 lines
4.5 KiB
PL/PgSQL
94 lines
4.5 KiB
PL/PgSQL
-- =============================================================================
|
||
-- 借库转交 · 双向握手 + 整单覆盖
|
||
--
|
||
-- 本次解决两个已发生的问题:
|
||
-- 1) **单内撕裂**:原 /transfer 收的是**明细行 ID**,只更新那一行。
|
||
-- 一张单有 2 条明细时,转交后 108 归属接收人、109 仍是原借用人 ——
|
||
-- 前端按 borrow_no 聚合,两个名字同时出现(实测 BOR-20260917-0001)。
|
||
-- 修复方向:转交必须按 **borrow_no** 覆盖该单全部未还明细。
|
||
-- 2) **单向强塞**:原实现发起即生效,接收人「被通知式」地背上资产责任。
|
||
-- 改为双向握手:发起只落 PENDING,接收人 accept 后才真正转移责任。
|
||
--
|
||
-- ---------------------------------------------------------------------------
|
||
-- 1) 为什么新增 borrow_no 而不是复用 borrow_id
|
||
-- borrow_id 是**明细行**主键,一条转交要覆盖该单多行,用单行 ID 无法表达
|
||
-- 「本次转交覆盖了哪些行」。borrow_no 是单据身份,accept 时据此批量更新。
|
||
-- borrow_id 保留为「发起时的代表明细」,供追溯与旧前端兼容。
|
||
--
|
||
-- 2) 为什么存量行标记为 ACCEPTED
|
||
-- 旧语义是「发起即生效」—— 写流水的同时就改了主表 current_holder。
|
||
-- 本表现有 1 行(BOR-20260917-0001)已是生效状态,标为 ACCEPTED 才符合
|
||
-- 事实;若标 PENDING,接收人会收到一条早已生效的待办。
|
||
--
|
||
-- 3) 状态机
|
||
-- PENDING ──accept──> ACCEPTED (主表 current_holder 正式转移)
|
||
-- └────reject──> REJECTED (主表不动,责任仍在原持有人)
|
||
-- 同一单号同一时刻只允许一条 PENDING(应用层强制),避免两个接收人
|
||
-- 争抢同一批实物。
|
||
--
|
||
-- 幂等:带 IF NOT EXISTS,可重复执行。
|
||
-- 执行:docker exec -i inventory_db psql -U test -d inventory_system < 本文件
|
||
-- =============================================================================
|
||
|
||
BEGIN;
|
||
|
||
ALTER TABLE trans_borrow_transfer
|
||
ADD COLUMN IF NOT EXISTS borrow_no varchar(100),
|
||
ADD COLUMN IF NOT EXISTS status varchar(20) NOT NULL DEFAULT 'PENDING';
|
||
|
||
COMMENT ON COLUMN trans_borrow_transfer.borrow_no IS
|
||
'借用单号(单据身份)。一次转交覆盖该单号下全部未还明细,accept 时据此批量更新';
|
||
COMMENT ON COLUMN trans_borrow_transfer.status IS
|
||
'PENDING 待接收 / ACCEPTED 已接收(主表已转移)/ REJECTED 已拒绝(主表未动)';
|
||
COMMENT ON COLUMN trans_borrow_transfer.borrow_id IS
|
||
'发起转交时的代表明细ID(trans_borrow.id),仅供追溯;覆盖范围以 borrow_no 为准';
|
||
|
||
-- 存量行:按旧语义(发起即生效)回填单号并标记为已接收
|
||
UPDATE trans_borrow_transfer t
|
||
SET borrow_no = tb.borrow_no,
|
||
status = 'ACCEPTED'
|
||
FROM trans_borrow tb
|
||
WHERE t.borrow_id = tb.id
|
||
AND t.status = 'PENDING';
|
||
|
||
CREATE INDEX IF NOT EXISTS ix_trans_borrow_transfer_no
|
||
ON trans_borrow_transfer (borrow_no);
|
||
CREATE INDEX IF NOT EXISTS ix_trans_borrow_transfer_status
|
||
ON trans_borrow_transfer (status);
|
||
-- 支撑「待我接收」的可见性与列表查询
|
||
CREATE INDEX IF NOT EXISTS ix_trans_borrow_transfer_to_user
|
||
ON trans_borrow_transfer (to_user_id, status);
|
||
|
||
COMMIT;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 执行后核对
|
||
-- =============================================================================
|
||
\echo '--- 1) 新列已就位 ---'
|
||
SELECT column_name, data_type, column_default
|
||
FROM information_schema.columns
|
||
WHERE table_name = 'trans_borrow_transfer'
|
||
AND column_name IN ('borrow_no', 'status')
|
||
ORDER BY column_name;
|
||
|
||
\echo '--- 2) 存量行状态(应为 ACCEPTED 且 borrow_no 已回填)---'
|
||
SELECT id, borrow_id, borrow_no, status, from_user_name, to_user_name
|
||
FROM trans_borrow_transfer ORDER BY id;
|
||
|
||
\echo '--- 3) 不应存在无单号的流水(应为 0)---'
|
||
SELECT count(*) AS 缺单号 FROM trans_borrow_transfer WHERE borrow_no IS NULL;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 回滚段
|
||
-- =============================================================================
|
||
-- BEGIN;
|
||
-- DROP INDEX IF EXISTS ix_trans_borrow_transfer_no;
|
||
-- DROP INDEX IF EXISTS ix_trans_borrow_transfer_status;
|
||
-- DROP INDEX IF EXISTS ix_trans_borrow_transfer_to_user;
|
||
-- ALTER TABLE trans_borrow_transfer
|
||
-- DROP COLUMN IF EXISTS borrow_no,
|
||
-- DROP COLUMN IF EXISTS status;
|
||
-- COMMIT;
|