背景
----
原单退回只做两件事:良品加回库存 / 不良品转在管台账。但**申请人的需求并没有
被满足** —— 东西交回来了(甚至还是坏的),系统却不提醒任何人、无单据承载
「我要重新领一份」,退回与后续再出库之间也毫无关联。现场只能靠人记住再手建
一张出库申请,而那张单与原单看不出任何关系。
改动
----
· outbound_approval 新增 source_return_id(非空 = 补发单),把「退回 → 补发」
串成闭环。
· POST /inbound/stock/return-from-outbound 新增 need_reissue / reissue_qty:
勾选即自动生成一张**免审批**出库单(status=1,直接进入待执行),
沿用原单出库类型,并关联回本笔退回。
★ 为什么只存退回单 ID,不加 is_reissue 布尔列
「是不是补发」完全由来源是否存在决定,再加一列就是同一事实的两处存储,
必然有不同步的一天。也不冗余存原出库单 ID:trans_return 已有 outbound_id。
★ 库存不足 → 整笔回滚(关键取舍)
补发走 reserve_for_items(strict=True),与出库申请同一口径。不足时抛错,
退回也一并回滚 —— 若只让补发静默失败,「需要补发」的意图就丢了,
那正是本功能要解决的问题。库管看到提示后取消勾选即可只做退回过账。
★ 一个被发现的数据约束(改变了原设计)
原打算把补发单的申请人设为「原出库单的申请人」,但 **trans_outbound 既没有
申请人字段,也没有指回原审批单的关联**(扫码出库时只把审批单状态置为 3)。
按 consumer_name 反查会重蹈「重名错绑」的覆辙。故申请人取**当前操作人**,
原领用人写入备注供人工追溯。
⚠ 若业务要求补发单挂在原领用人名下,需要前端在退回弹窗里加一个「补发给谁」
的人员选择 —— 请确认是否需要。
验证(打桩 JWT 直连真实接口,22 项断言全通过)
勾选补发 → 免审批单生成、关联退回、预占库存、原领用人入备注;
不勾选 → 不生成补发单、良品正常回库;
★ 库存不足 → 接口拒绝且**退回流水/补发单/退回额度全部未落库**(整笔回滚);
补发量 > 退回量被拒;库存与数据零残留。
66 lines
3.1 KiB
PL/PgSQL
66 lines
3.1 KiB
PL/PgSQL
-- =============================================================================
|
||
-- 出库 · 原单退回后的「补发单」关联
|
||
--
|
||
-- 背景
|
||
-- 原单退回目前只做两件事:良品加回库存 / 不良品转在管台账。
|
||
-- 但**申请人的需求并没有被满足** —— 东西交回来了(甚至还是坏的),
|
||
-- 系统却:不提醒任何人、无单据承载「我要重新领一份」、退回与后续再出库
|
||
-- 之间毫无关联。现场只能靠人记住再手动新建一张出库申请,且那张单与原单
|
||
-- 看不出任何关系。
|
||
--
|
||
-- 本次改动
|
||
-- outbound_approval 新增 source_return_id:非空即表示这是一张由「原单退回」
|
||
-- 自动生成的**补发单**,从而把「退回 → 补发」串成闭环,出库记录里也能
|
||
-- 一眼看出哪张单是补发的。
|
||
--
|
||
-- ---------------------------------------------------------------------------
|
||
-- ★ 为什么不加 is_reissue 布尔列
|
||
-- 「是不是补发」完全由「来源退回单是否存在」决定,再加一个布尔列就是
|
||
-- 同一事实的两处存储,必然有不同步的一天(改了 A 忘了 B)。
|
||
-- 单列既表达事实,又能直接 join 回原单。
|
||
--
|
||
-- ★ 为什么只存退回单 ID,不另存原出库单 ID
|
||
-- trans_return 本身已有 outbound_id,顺着 source_return_id 一跳即可拿到
|
||
-- 原出库明细。冗余存储只会带来「两张单对不上」的风险。
|
||
--
|
||
-- 幂等:带 IF NOT EXISTS,可重复执行。不含 psql 元命令,DataGrip 可直接执行。
|
||
-- =============================================================================
|
||
|
||
BEGIN;
|
||
|
||
ALTER TABLE outbound_approval
|
||
ADD COLUMN IF NOT EXISTS source_return_id integer;
|
||
|
||
COMMENT ON COLUMN outbound_approval.source_return_id IS
|
||
'补发单来源:trans_return.id。非空即表示本单是由「原单退回」自动生成的补发单';
|
||
|
||
-- 支撑「这批补发是从哪张退回单来的」与列表标识
|
||
CREATE INDEX IF NOT EXISTS ix_outbound_approval_source_return
|
||
ON outbound_approval (source_return_id);
|
||
|
||
COMMIT;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 执行后核对
|
||
-- =============================================================================
|
||
SELECT '=== 1) 新列已就位 ===' AS "核对项";
|
||
SELECT column_name, data_type FROM information_schema.columns
|
||
WHERE table_name = 'outbound_approval' AND column_name = 'source_return_id';
|
||
|
||
SELECT '=== 2) 索引已就位 ===' AS "核对项";
|
||
SELECT indexname FROM pg_indexes
|
||
WHERE tablename = 'outbound_approval' AND indexname = 'ix_outbound_approval_source_return';
|
||
|
||
SELECT '=== 3) 存量补发单(新功能上线前应为 0)===' AS "核对项";
|
||
SELECT count(*) AS 补发单数 FROM outbound_approval WHERE source_return_id IS NOT NULL;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 回滚段
|
||
-- =============================================================================
|
||
-- BEGIN;
|
||
-- DROP INDEX IF EXISTS ix_outbound_approval_source_return;
|
||
-- ALTER TABLE outbound_approval DROP COLUMN IF EXISTS source_return_id;
|
||
-- COMMIT;
|