diff --git a/db_migrations/phase14_defective_goods_location_snapshot.sql b/db_migrations/phase14_defective_goods_location_snapshot.sql new file mode 100644 index 0000000..4b431b2 --- /dev/null +++ b/db_migrations/phase14_defective_goods_location_snapshot.sql @@ -0,0 +1,108 @@ +-- ============================================================================= +-- 不良品在管台账:补「原库位 / 批次(序列号)」快照列 +-- +-- 背景 +-- 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;