问题:前面几个报废提交里,inventory-backend/app/models/transaction.py 已经 引用了 db_migrations/phase14_defective_goods_location_snapshot.sql(两处注释 指向它),但**该文件本身没被提交** —— 代码与迁移对不上,别人拉下来跑不起来。 内容:为 trans_defective_goods 增加 warehouse_location / batch_number 两列, 并从源库存行回填存量。 为什么需要这两列:报废台账页与报废申请单明细上,凡是不良品来源的行,库位与 批次此前一律显示 "-" —— 因为应用层硬编码了空串,理由是「源库存行可能已被 物理删除」。该担忧对 material_name/spec_model 成立(所以它们有冗余快照), 但库位/批次当时**没有**快照列,一律置空等于放弃了「源行还在」这个绝大多数 情形。补上快照后,退回那一刻 stock_row 已 with_for_update() 锁在手里, 库位/批次随手可取,落库后即使源行日后被删除,报表依然有值。 口径:存「原库位」(这批货最初在哪),与三张库存表来源的报废记录一致; 不良品区的位置本系统未记录。batch_number 对 stock_product 来源存的是 serial_number(成品表无 batch_number 列),与 scrap.py 的 _from_stock 对齐。 安全性:纯追加式 DDL,无 NOT NULL、无 DEFAULT,幂等可重复执行。 已在本机执行验证:存量 1 行全部回填,源行已删取不到 0 行。
109 lines
5.6 KiB
PL/PgSQL
109 lines
5.6 KiB
PL/PgSQL
-- =============================================================================
|
||
-- 不良品在管台账:补「原库位 / 批次(序列号)」快照列
|
||
--
|
||
-- 背景
|
||
-- trans_defective_goods 只冗余了 material_name / spec_model,却没有存库位与
|
||
-- 批次。于是报废台账页、报废申请单明细上,凡是不良品来源的行,库位与
|
||
-- 批次一律显示 "-" —— 而它们的源库存行往往**还在**,本该取得到。
|
||
--
|
||
-- 应用层原先的处置是在 _resolve_materials 与 DefectiveScrapAdapter.snapshot
|
||
-- 里直接硬编码空串,注释理由是「源库存行可能已被物理删除」。这个担忧对
|
||
-- material_name/spec_model 成立(所以它们有冗余快照),但库位/批次**没有**
|
||
-- 快照列,一律置空等于放弃了「源行还在」这个绝大多数情形。
|
||
--
|
||
-- 本次改动(A+B)
|
||
-- A. 应用层改为「快照优先 + 回查源库存行兜底」(本次只加列,逻辑在代码侧)
|
||
-- B. 本文件补两列,把「源行可能被删」这个担忧真正解决掉:退回那一刻
|
||
-- stock_row 已 with_for_update() 锁在手里,库位/批次随手可取,
|
||
-- 落库后即使源行日后被物理删除,报表依然有值。
|
||
--
|
||
-- 口径(2026-09-23 与业务确认)
|
||
-- 存的是「**原库位**」—— 这批货最初在哪,而不是坏件当前所在的不良品区。
|
||
-- 与三张库存表来源的报废记录口径一致。不良品区的位置本系统未记录。
|
||
--
|
||
-- ★ batch_number 列对 stock_product 来源存的是 serial_number:
|
||
-- 成品表没有 batch_number 列(见 information_schema),取值口径沿用
|
||
-- 应用层的 COALESCE(batch_number, serial_number),与 _from_stock 一致。
|
||
-- 故本列语义为「批次或序列号」,与前端列名「批次/序列号」对齐。
|
||
--
|
||
-- 安全性:纯追加式 DDL,无 NOT NULL、无 DEFAULT,既有行取值 NULL。
|
||
-- 幂等:IF NOT EXISTS + 带 WHERE 的 UPDATE,可重复执行。
|
||
--
|
||
-- 执行
|
||
-- docker exec -i inventory_db psql -U test -d inventory_system < 本文件
|
||
-- =============================================================================
|
||
|
||
BEGIN;
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 1) 快照列(长度与三张库存表对齐,均为 varchar(100))
|
||
-- ---------------------------------------------------------------------------
|
||
ALTER TABLE trans_defective_goods
|
||
ADD COLUMN IF NOT EXISTS warehouse_location varchar(100),
|
||
ADD COLUMN IF NOT EXISTS batch_number varchar(100);
|
||
|
||
COMMENT ON COLUMN trans_defective_goods.warehouse_location IS
|
||
'原库位快照(退回时取自源库存行)。源行被物理删除时此处仍有值,故报表优先用它';
|
||
COMMENT ON COLUMN trans_defective_goods.batch_number IS
|
||
'批次/序列号快照(退回时取自源库存行的 batch_number,成品表缺失时取 serial_number)';
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 2) 存量回填:按 source_table + stock_id 回查源库存行
|
||
-- 三张表分别 UPDATE(多态关联,无法用一条语句表达)。
|
||
-- WHERE warehouse_location IS NULL 保证幂等,且不覆盖已回填过的值。
|
||
--
|
||
-- 回填不到的(源行已被物理删除)保持 NULL —— 刻意不写成空串,
|
||
-- 这样下面的核对能数出「真正取不到」的行数,与「已确认无库位」区分开。
|
||
-- ---------------------------------------------------------------------------
|
||
UPDATE trans_defective_goods g
|
||
SET warehouse_location = COALESCE(b.warehouse_location, ''),
|
||
batch_number = COALESCE(NULLIF(b.batch_number, ''), b.serial_number, '')
|
||
FROM stock_buy b
|
||
WHERE g.source_table = 'stock_buy'
|
||
AND g.stock_id = b.id
|
||
AND g.warehouse_location IS NULL;
|
||
|
||
UPDATE trans_defective_goods g
|
||
SET warehouse_location = COALESCE(s.warehouse_location, ''),
|
||
batch_number = COALESCE(NULLIF(s.batch_number, ''), s.serial_number, '')
|
||
FROM stock_semi s
|
||
WHERE g.source_table = 'stock_semi'
|
||
AND g.stock_id = s.id
|
||
AND g.warehouse_location IS NULL;
|
||
|
||
-- ★ 成品表无 batch_number 列,只取 serial_number
|
||
UPDATE trans_defective_goods g
|
||
SET warehouse_location = COALESCE(p.warehouse_location, ''),
|
||
batch_number = COALESCE(p.serial_number, '')
|
||
FROM stock_product p
|
||
WHERE g.source_table = 'stock_product'
|
||
AND g.stock_id = p.id
|
||
AND g.warehouse_location IS NULL;
|
||
|
||
COMMIT;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 执行后核对
|
||
-- =============================================================================
|
||
SELECT '=== 1) 回填结果:已回填 / 源行已删取不到 / 无需回填 ===' AS "核对项";
|
||
SELECT count(*) FILTER (WHERE warehouse_location IS NOT NULL) AS 已回填,
|
||
count(*) FILTER (WHERE warehouse_location IS NULL) AS 源行已删_取不到,
|
||
count(*) AS 台账总行数
|
||
FROM trans_defective_goods;
|
||
|
||
SELECT '=== 2) ★ 源行已删的明细(取不到库位属预期,应逐条确认是否为真)===' AS "核对项";
|
||
SELECT id, source_table, stock_id, sku, status
|
||
FROM trans_defective_goods
|
||
WHERE warehouse_location IS NULL
|
||
ORDER BY id;
|
||
|
||
|
||
-- =============================================================================
|
||
-- 回滚段(仅撤销本迁移;回填值与「原本就是空」无法区分)
|
||
-- =============================================================================
|
||
-- BEGIN;
|
||
-- ALTER TABLE trans_defective_goods DROP COLUMN IF EXISTS warehouse_location;
|
||
-- ALTER TABLE trans_defective_goods DROP COLUMN IF EXISTS batch_number;
|
||
-- COMMIT;
|