Files
KCGL/db_migrations/phase4c_borrow_transfer_handshake.sql
yueli b271ca3a49 feat(borrow): 转交流水表补 borrow_no 与 status(双向握手数据层)
背景
----
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(应用层强制),避免两个接收人争抢同一批实物。
2026-09-17 10:04:05 +08:00

94 lines
4.5 KiB
PL/PgSQL
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.

-- =============================================================================
-- 借库转交 · 双向握手 + 整单覆盖
--
-- 本次解决两个已发生的问题:
-- 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
'发起转交时的代表明细IDtrans_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;