Files
KCGL/db_migrations/phase4d_borrow_transfer_item_level.sql
yueli 7d9cdeb297 feat(borrow): 转交粒度下沉到明细行,支持部分转交
背景(业务方推翻上一轮约束)
----
上一轮按「一张单同时只能有一个持有人」实现了**整单转交**,并把「单内出现多个
持有人」当作 bug 去修。业务方验收后明确纠正:

    物理现场经常只转交部分工具(借了 2 件、只把 1 件转给别人),
    单内多持有人才是符合现实的正常状态。

故转交粒度从 borrow_no 下沉回 trans_borrow.id(明细行)。

改动
----
· transfer_borrow:只操作传入的那**一行**明细,不再按单号整批覆盖。
  转出方 = 该行当前持有人;数量 = 该行待还量。
· accept_transfer:只转移 transfer.borrow_id 指向的那一行 ——
  整批改写会把别人手上的东西一并抢过来(部分转交下同单明细分属不同人)。
· 唯一性约束从「单号至多一条 PENDING」下沉为「明细行至多一条」:
  同单的其他明细可以同时各自挂着待接收,互不阻塞 —— 这正是部分转交的语义。
· get_records 的 pending_transfer 改按 borrow_id 关联(原按 borrow_no),
  否则同单多项待接收会互相覆盖。
· 删除已无用的 _load_slip_for_update。

★ 数量粒度:一行只支持**整行转交**。一行只能有一个 current_holder_id,
  「同一行只转一部分」需要把这行拆成两行 —— 经业务确认,现场场景中
  「借 2 件转 1 件」的两件本就是两条明细行,故该限制不影响实际使用;
  接口对传入的非整行数量会明确提示「应另立一条明细行」。

数据层
----
无需改表结构:borrow_id 本就是流水的关联列,borrow_no 退化为单据归属与
分组展示用。仅补 (borrow_id, status) 复合索引支撑新的查询路径。
存量撕裂数据(BOR-20260917-0001 的「测试 / 杜邢宸」)按业务方选择**保留不动**
—— 它现在不再是 bug,而是部分转交的正常形态。

验证(合成 2 明细单,21 项断言全通过)
----
· 只转工具A:工具B 完全不受影响
· 同一张单可同时挂两条待接收,互不阻塞;同一明细重复发起被拒
· accept 工具A 后:A→测试,B 仍是杜邢宸(单内两个持有人)
· 两个持有人、以及待接收人,三方各自都能在列表中看到该单
· pending_transfer 挂在正确的明细行上,is_mine 判定正确
· reject 后主表持有人不变;非整行数量被拒并提示拆行
· 全程 available_quantity 无变化,库存精确还原、零残留数据
2026-09-17 10:12:31 +08:00

75 lines
3.8 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.

-- =============================================================================
-- 借库转交 · 粒度下沉到明细行(部分转交)
--
-- 背景(业务方推翻上一轮约束)
-- 上一轮按「一张单同时只能有一个持有人」实现了**整单转交**,并把「单内出现
-- 多个持有人」当作 bug 去修。业务方验收后明确纠正:
-- 物理现场经常只转交部分工具(借了 2 件,只把 1 件转给别人),
-- **单内多持有人才是符合现实的正常状态**。
-- 故转交粒度从 borrow_no 下沉回 trans_borrow.id明细行
--
-- ---------------------------------------------------------------------------
-- 本次改动的实质
-- 代码层transfer_borrow / accept_transfer 只操作**一行**明细,
-- 唯一性约束从「单号最多一条 PENDING」改为「明细行最多一条 PENDING」。
-- 数据层:**无需改动任何表结构** —— borrow_id明细行本就是流水的主键
-- 关联列borrow_no 继续保留作单据归属与展示分组用。
-- 仅补一个复合索引,支撑「按明细行查待接收流水」这一新查询路径。
--
-- ★ 为什么不需要新的列
-- 转交粒度既然回到明细行,覆盖范围就是 borrow_id 指向的那一行本身 ——
-- 不需要额外的「覆盖清单」来表达范围borrow_no 退化为分组/展示用途。
--
-- ★ 存量数据不动(业务方选择)
-- BOR-20260917-0001 的「测试 / 杜邢宸」双持有人状态予以保留:
-- 它现在不再是 bug而是「部分转交」的正常业务形态。
--
-- 幂等:带 IF NOT EXISTS可重复执行。
-- 执行docker exec -i inventory_db psql -U test -d inventory_system < 本文件
-- =============================================================================
BEGIN;
-- 支撑「该明细行是否已有待接收流水」的唯一性检查,以及按明细行批量取待接收
CREATE INDEX IF NOT EXISTS ix_trans_borrow_transfer_borrow_status
ON trans_borrow_transfer (borrow_id, status);
COMMENT ON COLUMN trans_borrow_transfer.borrow_no IS
'借用单号。仅用于单据归属与列表分组展示;转交的**覆盖范围**是 borrow_id 指向的单个明细行';
COMMENT ON COLUMN trans_borrow_transfer.borrow_id IS
'转交目标明细行IDtrans_borrow.id。转交粒度 = 明细行,一行最多一条待接收流水';
COMMIT;
-- =============================================================================
-- 执行后核对
-- =============================================================================
\echo '--- 1) 复合索引已就位 ---'
SELECT indexname FROM pg_indexes
WHERE tablename = 'trans_borrow_transfer'
AND indexname = 'ix_trans_borrow_transfer_borrow_status';
\echo '--- 2) 存量流水borrow_id / borrow_no / status---'
SELECT id, borrow_id, borrow_no, status, from_user_name, to_user_name
FROM trans_borrow_transfer ORDER BY id;
\echo '--- 3) 各明细行的待接收流水数(应全部 <= 1---'
SELECT borrow_id, count(*) AS
FROM trans_borrow_transfer WHERE status = 'PENDING'
GROUP BY borrow_id HAVING count(*) > 1;
\echo '--- 4) 单内多持有人的单号(现在属正常业务形态,不再视为异常)---'
SELECT borrow_no, count(DISTINCT current_holder_id) AS ,
string_agg(DISTINCT coalesce(current_holder_name,'NULL'), ', ') AS
FROM trans_borrow WHERE is_returned = FALSE
GROUP BY borrow_no HAVING count(DISTINCT current_holder_id) > 1;
-- =============================================================================
-- 回滚段
-- =============================================================================
-- BEGIN;
-- DROP INDEX IF EXISTS ix_trans_borrow_transfer_borrow_status;
-- COMMIT;