mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-06-09 15:07:49 +00:00
add migration for normalize jamali non aktif to gudang farm jamali
This commit is contained in:
+99
@@ -0,0 +1,99 @@
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================
|
||||
-- Rollback dynamic via audit snapshots di schema `migration_audit.jamali_w10_*`.
|
||||
-- Semua reverse dibaca dari snapshot yang dibuat oleh UP migration —
|
||||
-- tidak ada IDs/qty yang hardcode. Robust terhadap data drift antara
|
||||
-- dump time dan UP apply time (misalnya row baru warehouse_id=10
|
||||
-- yang muncul setelah dump diambil).
|
||||
--
|
||||
-- LIMITASI: FK relinks di stock_logs / stock_allocations / recording_eggs /
|
||||
-- marketing_products / dll. TIDAK direverse di sini (skip audit per-row
|
||||
-- untuk hemat storage ~40MB). Setelah down, 9 PW W10 yang di-restore
|
||||
-- akan kosong dari child rows (semua child masih pointing ke W25 PW
|
||||
-- yang sebelumnya menerima merge). Untuk rollback penuh, restore DB
|
||||
-- dari backup pre-migration.
|
||||
-- ============================================================
|
||||
|
||||
-- Guard: pastikan audit tables ada (kalau tidak, fail-loud)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'migration_audit'
|
||||
AND table_name = 'jamali_w10_pw_deleted_snapshot'
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Audit table migration_audit.jamali_w10_* tidak ditemukan. UP migration belum dijalankan atau audit sudah di-drop. Restore dari DB backup jika perlu.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 1. Un-soft-delete warehouse 10 (kalau memang di-softdelete oleh UP)
|
||||
UPDATE warehouses w
|
||||
SET deleted_at = NULL, updated_at = NOW()
|
||||
FROM migration_audit.jamali_w10_warehouse_softdeleted a
|
||||
WHERE w.id = a.id;
|
||||
|
||||
-- 2. Un-soft-delete stock_transfers self-loop yang disoft-delete UP step 7.1
|
||||
UPDATE stock_transfers st
|
||||
SET deleted_at = NULL, updated_at = NOW()
|
||||
FROM migration_audit.jamali_w10_st_softdeleted a
|
||||
WHERE st.id = a.id;
|
||||
|
||||
-- 3. Reverse stock_transfers redirect (CASE-based dari snapshot was_from_w10/was_to_w10)
|
||||
UPDATE stock_transfers st
|
||||
SET from_warehouse_id = CASE WHEN a.was_from_w10 THEN 10 ELSE st.from_warehouse_id END,
|
||||
to_warehouse_id = CASE WHEN a.was_to_w10 THEN 10 ELSE st.to_warehouse_id END,
|
||||
updated_at = NOW()
|
||||
FROM migration_audit.jamali_w10_st_redirected a
|
||||
WHERE st.id = a.id;
|
||||
|
||||
-- 3b. Self-loop transfers (W10<->W25 awal) juga punya from_warehouse_id=25 atau
|
||||
-- to_warehouse_id=25 setelah UP step 7.2. Karena snapshot jamali_w10_st_softdeleted
|
||||
-- punya kolom from_warehouse_id & to_warehouse_id asli, pakai itu untuk reverse.
|
||||
UPDATE stock_transfers st
|
||||
SET from_warehouse_id = 10, updated_at = NOW()
|
||||
FROM migration_audit.jamali_w10_st_softdeleted a
|
||||
WHERE st.id = a.id AND a.from_warehouse_id = 10;
|
||||
|
||||
UPDATE stock_transfers st
|
||||
SET to_warehouse_id = 10, updated_at = NOW()
|
||||
FROM migration_audit.jamali_w10_st_softdeleted a
|
||||
WHERE st.id = a.id AND a.to_warehouse_id = 10;
|
||||
|
||||
-- 4. Reverse purchase_items.warehouse_id 25 -> 10
|
||||
UPDATE purchase_items
|
||||
SET warehouse_id = 10
|
||||
WHERE id IN (SELECT id FROM migration_audit.jamali_w10_purchase_items);
|
||||
|
||||
-- 5. Reverse W10-only PW (warehouse_id 25 -> 10, restore pfk asli dari snapshot)
|
||||
UPDATE product_warehouses pw
|
||||
SET warehouse_id = 10, project_flock_kandang_id = a.original_pfk
|
||||
FROM migration_audit.jamali_w10_pw_w10only_snapshot a
|
||||
WHERE pw.id = a.id;
|
||||
|
||||
-- 6. Subtract qty dari W25 PW (reverse merge)
|
||||
-- WARNING: kalau W25 qty sudah dikonsumsi pasca-UP (sales/recording/dll),
|
||||
-- hasil bisa negatif. Tidak ada CHECK constraint di product_warehouses.qty,
|
||||
-- jadi silent. Operator harus verifikasi manual post-down:
|
||||
-- SELECT id, qty FROM product_warehouses WHERE qty < 0;
|
||||
UPDATE product_warehouses pw
|
||||
SET qty = pw.qty - a.merged_qty
|
||||
FROM migration_audit.jamali_w10_qty_merge a
|
||||
WHERE pw.id = a.target_pw_id;
|
||||
|
||||
-- 7. Re-INSERT 9 W10 PW rows yang di-DELETE oleh UP (PK asli + qty asli)
|
||||
INSERT INTO product_warehouses (id, product_id, warehouse_id, qty, project_flock_kandang_id)
|
||||
SELECT id, product_id, 10, qty, project_flock_kandang_id
|
||||
FROM migration_audit.jamali_w10_pw_deleted_snapshot;
|
||||
|
||||
-- 8. Cleanup audit tables (drop satu per satu, tidak wildcard untuk safety)
|
||||
DROP TABLE migration_audit.jamali_w10_pw_deleted_snapshot;
|
||||
DROP TABLE migration_audit.jamali_w10_qty_merge;
|
||||
DROP TABLE migration_audit.jamali_w10_pw_w10only_snapshot;
|
||||
DROP TABLE migration_audit.jamali_w10_st_softdeleted;
|
||||
DROP TABLE migration_audit.jamali_w10_st_redirected;
|
||||
DROP TABLE migration_audit.jamali_w10_purchase_items;
|
||||
DROP TABLE migration_audit.jamali_w10_warehouse_softdeleted;
|
||||
-- Schema migration_audit dipertahankan (bisa dipakai migration lain di masa depan)
|
||||
|
||||
COMMIT;
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================
|
||||
-- Normalisasi warehouse 10 (Jamali NON_AKTIF) -> 25 (Gudang Farm Jamali)
|
||||
-- Background: Dua warehouse LOKASI di area & lokasi sama (area_id=6,
|
||||
-- location_id=16). W10 sudah ditandai NON_AKTIF tapi masih punya 13
|
||||
-- product_warehouses, 3,590 stock_logs, ~790K stock_allocations,
|
||||
-- 332 marketing_products, 17 purchase_items, dan 14 stock_transfers.
|
||||
-- Migration ini konsolidasikan semua relasi ke W25 lalu soft-delete W10.
|
||||
--
|
||||
-- Klasifikasi data:
|
||||
-- A. 9 product_warehouses W10 overlap dengan W25 (sama product_id, pfk=NULL)
|
||||
-- -> merge qty ke W25, relink semua FK ke product_warehouses.id,
|
||||
-- lalu DELETE W10 PW rows.
|
||||
-- B. 4 product_warehouses W10-only -> UPDATE warehouse_id=25.
|
||||
-- Rows 1188/1189/1190 punya pfk=98 (anomali LOKASI, seharusnya NULL
|
||||
-- per aturan di CLAUDE.md [2026-05-06]) -> normalisasi sekalian.
|
||||
-- C. 17 purchase_items.warehouse_id=10 -> UPDATE 25 (no unique conflict).
|
||||
-- D. 3 stock_transfers W10<->W25 (PND-LTI-00107/00109/00119) akan jadi
|
||||
-- self-loop W25<->W25 setelah merge -> soft-delete.
|
||||
-- E. 12 stock_transfers EGG_FARM_CUTOVER to_warehouse_id=10 -> UPDATE 25.
|
||||
-- F. warehouse_id=10 sendiri -> soft-delete.
|
||||
--
|
||||
-- UP membuat 7 snapshot table di schema `migration_audit.jamali_w10_*`
|
||||
-- sebelum mutasi. DOWN baca snapshot itu untuk reverse dynamic (tidak
|
||||
-- hardcode IDs/qty), sehingga apapun yang ada di production saat UP
|
||||
-- dijalankan akan ter-audit dan ter-reverse. FK relinks
|
||||
-- (stock_logs/stock_allocations/dll) TIDAK di-audit (storage ~40MB)
|
||||
-- — limitation: tidak bisa di-reverse DOWN, full rollback = DB backup.
|
||||
-- ============================================================
|
||||
|
||||
-- STEP -1: Buat schema audit + snapshot tables (idempotent rerun via DROP IF EXISTS)
|
||||
CREATE SCHEMA IF NOT EXISTS migration_audit;
|
||||
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_pw_deleted_snapshot;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_qty_merge;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_pw_w10only_snapshot;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_st_softdeleted;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_st_redirected;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_purchase_items;
|
||||
DROP TABLE IF EXISTS migration_audit.jamali_w10_warehouse_softdeleted;
|
||||
|
||||
-- Snapshot 9 W10 PW yang akan di-DELETE (overlap dgn W25, pfk=NULL)
|
||||
CREATE TABLE migration_audit.jamali_w10_pw_deleted_snapshot AS
|
||||
SELECT pw10.id, pw10.product_id, pw10.qty, pw10.project_flock_kandang_id
|
||||
FROM product_warehouses pw10
|
||||
JOIN product_warehouses pw25
|
||||
ON pw25.product_id = pw10.product_id
|
||||
AND pw25.warehouse_id = 25
|
||||
AND pw25.project_flock_kandang_id IS NULL
|
||||
WHERE pw10.warehouse_id = 10 AND pw10.project_flock_kandang_id IS NULL;
|
||||
|
||||
-- Snapshot qty delta per W25 target (untuk reverse subtract)
|
||||
CREATE TABLE migration_audit.jamali_w10_qty_merge AS
|
||||
SELECT pw25.id AS target_pw_id, pw10.id AS source_pw_id, pw10.qty AS merged_qty
|
||||
FROM product_warehouses pw10
|
||||
JOIN product_warehouses pw25
|
||||
ON pw25.product_id = pw10.product_id
|
||||
AND pw25.warehouse_id = 25
|
||||
AND pw25.project_flock_kandang_id IS NULL
|
||||
WHERE pw10.warehouse_id = 10 AND pw10.project_flock_kandang_id IS NULL;
|
||||
|
||||
-- Snapshot W10-only PW (yang akan di-UPDATE warehouse_id 10->25)
|
||||
CREATE TABLE migration_audit.jamali_w10_pw_w10only_snapshot AS
|
||||
SELECT pw10.id, pw10.project_flock_kandang_id AS original_pfk
|
||||
FROM product_warehouses pw10
|
||||
WHERE pw10.warehouse_id = 10
|
||||
AND pw10.id NOT IN (SELECT id FROM migration_audit.jamali_w10_pw_deleted_snapshot);
|
||||
|
||||
-- Snapshot stock_transfers yang akan di-soft-delete (self-loop W10<->W25)
|
||||
-- Simpan from/to_warehouse_id asli supaya DOWN bisa reverse direction tepat
|
||||
CREATE TABLE migration_audit.jamali_w10_st_softdeleted AS
|
||||
SELECT id, movement_number, from_warehouse_id, to_warehouse_id
|
||||
FROM stock_transfers
|
||||
WHERE deleted_at IS NULL
|
||||
AND ((from_warehouse_id = 10 AND to_warehouse_id = 25)
|
||||
OR (from_warehouse_id = 25 AND to_warehouse_id = 10));
|
||||
|
||||
-- Snapshot stock_transfers yang akan di-UPDATE (W10<->other, bukan self-loop)
|
||||
CREATE TABLE migration_audit.jamali_w10_st_redirected AS
|
||||
SELECT id,
|
||||
(from_warehouse_id = 10) AS was_from_w10,
|
||||
(to_warehouse_id = 10) AS was_to_w10
|
||||
FROM stock_transfers
|
||||
WHERE deleted_at IS NULL
|
||||
AND (from_warehouse_id = 10 OR to_warehouse_id = 10)
|
||||
AND id NOT IN (SELECT id FROM migration_audit.jamali_w10_st_softdeleted);
|
||||
|
||||
-- Snapshot purchase_items IDs (cheap, ~17 rows)
|
||||
CREATE TABLE migration_audit.jamali_w10_purchase_items AS
|
||||
SELECT id FROM purchase_items WHERE warehouse_id = 10;
|
||||
|
||||
-- Snapshot warehouses soft-delete flag (1 row, kalau memang masih aktif)
|
||||
CREATE TABLE migration_audit.jamali_w10_warehouse_softdeleted AS
|
||||
SELECT id FROM warehouses WHERE id = 10 AND deleted_at IS NULL;
|
||||
|
||||
-- STEP 0: Pre-check sanity (idempotent guards)
|
||||
DO $$
|
||||
DECLARE v_count INT;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO v_count FROM warehouses
|
||||
WHERE id IN (10, 25) AND type = 'LOKASI' AND area_id = 6 AND location_id = 16;
|
||||
IF v_count <> 2 THEN
|
||||
RAISE EXCEPTION 'Pre-check: warehouse 10/25 schema mismatch (got % rows)', v_count;
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*) INTO v_count FROM purchase_items a
|
||||
JOIN purchase_items b ON a.purchase_id = b.purchase_id
|
||||
AND a.product_id = b.product_id
|
||||
AND a.id <> b.id
|
||||
WHERE a.warehouse_id = 10 AND b.warehouse_id = 25;
|
||||
IF v_count > 0 THEN
|
||||
RAISE EXCEPTION 'Pre-check: % purchase_items unique conflict (purchase_id,product_id)', v_count;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- STEP 1: Merge qty W10 -> W25 untuk overlap (pfk=NULL)
|
||||
UPDATE product_warehouses pw25
|
||||
SET qty = pw25.qty + pw10.qty
|
||||
FROM product_warehouses pw10
|
||||
WHERE pw10.warehouse_id = 10 AND pw10.project_flock_kandang_id IS NULL
|
||||
AND pw25.warehouse_id = 25 AND pw25.project_flock_kandang_id IS NULL
|
||||
AND pw25.product_id = pw10.product_id;
|
||||
|
||||
-- STEP 2: Build temp mapping (W10 PW id -> W25 PW id) untuk overlap saja
|
||||
CREATE TEMP TABLE _pw_map ON COMMIT DROP AS
|
||||
SELECT pw10.id AS old_id, pw25.id AS new_id
|
||||
FROM product_warehouses pw10
|
||||
JOIN product_warehouses pw25
|
||||
ON pw25.product_id = pw10.product_id
|
||||
AND pw25.warehouse_id = 25
|
||||
AND pw25.project_flock_kandang_id IS NULL
|
||||
WHERE pw10.warehouse_id = 10 AND pw10.project_flock_kandang_id IS NULL;
|
||||
|
||||
CREATE INDEX ON _pw_map(old_id);
|
||||
|
||||
-- STEP 3: Relink semua FK ke product_warehouses.id (hanya rows di _pw_map)
|
||||
UPDATE stock_logs SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE stock_logs.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE stock_allocations SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE stock_allocations.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE recording_eggs SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE recording_eggs.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE recording_stocks SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE recording_stocks.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE recording_depletions SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE recording_depletions.product_warehouse_id = m.old_id;
|
||||
UPDATE recording_depletions SET source_product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE recording_depletions.source_product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE adjustment_stocks SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE adjustment_stocks.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE marketing_products SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE marketing_products.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE marketing_delivery_products SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE marketing_delivery_products.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE project_chickins SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE project_chickins.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE project_chickin_details SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE project_chickin_details.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE project_flock_populations SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE project_flock_populations.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE laying_transfers SET source_product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE laying_transfers.source_product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE laying_transfer_sources SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE laying_transfer_sources.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE laying_transfer_targets SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE laying_transfer_targets.product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE stock_transfer_details SET source_product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE stock_transfer_details.source_product_warehouse_id = m.old_id;
|
||||
UPDATE stock_transfer_details SET dest_product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE stock_transfer_details.dest_product_warehouse_id = m.old_id;
|
||||
|
||||
UPDATE purchase_items SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE purchase_items.product_warehouse_id = m.old_id;
|
||||
|
||||
-- FIFO v2 tables (kosong di dump 2026-05-25, defensive)
|
||||
UPDATE fifo_stock_v2_operation_log SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE fifo_stock_v2_operation_log.product_warehouse_id = m.old_id;
|
||||
UPDATE fifo_stock_v2_reflow_checkpoints SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE fifo_stock_v2_reflow_checkpoints.product_warehouse_id = m.old_id;
|
||||
UPDATE fifo_stock_v2_shadow_allocations SET product_warehouse_id = m.new_id
|
||||
FROM _pw_map m WHERE fifo_stock_v2_shadow_allocations.product_warehouse_id = m.old_id;
|
||||
|
||||
-- STEP 4: Hard-delete W10 PW yang sudah merged (9 rows expected)
|
||||
DELETE FROM product_warehouses WHERE id IN (SELECT old_id FROM _pw_map);
|
||||
|
||||
-- STEP 5: Sisa W10 PW (4 rows: 1188/1189/1190/1196) -> warehouse_id=25,
|
||||
-- pfk dinormalisasi ke NULL sekalian (LOKASI rule)
|
||||
UPDATE product_warehouses
|
||||
SET warehouse_id = 25, project_flock_kandang_id = NULL
|
||||
WHERE warehouse_id = 10;
|
||||
|
||||
-- STEP 6: purchase_items.warehouse_id (17 rows)
|
||||
UPDATE purchase_items SET warehouse_id = 25 WHERE warehouse_id = 10;
|
||||
|
||||
-- STEP 7: stock_transfers
|
||||
-- 7.1 Soft-delete self-loop (W10<->W25 akan jadi W25<->W25)
|
||||
UPDATE stock_transfers
|
||||
SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE deleted_at IS NULL
|
||||
AND ((from_warehouse_id = 10 AND to_warehouse_id = 25)
|
||||
OR (from_warehouse_id = 25 AND to_warehouse_id = 10));
|
||||
|
||||
-- 7.2 Sisa W10<->other -> 25 (12 EGG_FARM_CUTOVER ke W10)
|
||||
UPDATE stock_transfers SET from_warehouse_id = 25, updated_at = NOW() WHERE from_warehouse_id = 10;
|
||||
UPDATE stock_transfers SET to_warehouse_id = 25, updated_at = NOW() WHERE to_warehouse_id = 10;
|
||||
|
||||
-- STEP 8: Soft-delete warehouse 10 sendiri
|
||||
UPDATE warehouses SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = 10 AND deleted_at IS NULL;
|
||||
|
||||
-- STEP 9: Post-check (fail-fast jika ada residu)
|
||||
DO $$
|
||||
DECLARE v_count INT;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO v_count FROM product_warehouses WHERE warehouse_id = 10;
|
||||
IF v_count <> 0 THEN RAISE EXCEPTION 'product_warehouses W10 residual %', v_count; END IF;
|
||||
|
||||
SELECT COUNT(*) INTO v_count FROM purchase_items WHERE warehouse_id = 10;
|
||||
IF v_count <> 0 THEN RAISE EXCEPTION 'purchase_items W10 residual %', v_count; END IF;
|
||||
|
||||
SELECT COUNT(*) INTO v_count FROM stock_transfers
|
||||
WHERE deleted_at IS NULL AND (from_warehouse_id = 10 OR to_warehouse_id = 10);
|
||||
IF v_count <> 0 THEN RAISE EXCEPTION 'stock_transfers W10 residual %', v_count; END IF;
|
||||
END $$;
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user