mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 05:21:57 +00:00
401 lines
12 KiB
SQL
401 lines
12 KiB
SQL
-- Legacy Egg Cutover Verification Checklist
|
|
-- Usage:
|
|
-- 1. Replace the values below before executing.
|
|
-- 2. Run section BEFORE before --apply.
|
|
-- 3. Run section AFTER after --apply.
|
|
-- 4. Run rollback checks if needed.
|
|
|
|
-- =====================================================================
|
|
-- PARAMETERS
|
|
-- =====================================================================
|
|
|
|
-- Replace manually before running.
|
|
-- Example:
|
|
-- location_name = Jamali
|
|
-- cutover_date = 2026-04-07
|
|
-- run_id = egg-cutover-20260407T130344.220407000Z
|
|
|
|
-- =====================================================================
|
|
-- BEFORE APPLY
|
|
-- =====================================================================
|
|
|
|
-- [BEFORE-01] Identify target location and farm warehouse
|
|
SELECT
|
|
l.id AS location_id,
|
|
l.name AS location_name,
|
|
fw.id AS farm_warehouse_id,
|
|
fw.name AS farm_warehouse_name
|
|
FROM locations l
|
|
LEFT JOIN warehouses fw
|
|
ON fw.location_id = l.id
|
|
AND fw.type = 'LOKASI'
|
|
AND fw.deleted_at IS NULL
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
ORDER BY fw.id ASC;
|
|
|
|
-- Expectation:
|
|
-- - exactly one target location
|
|
-- - at least one farm warehouse exists
|
|
|
|
-- [BEFORE-02] Verify location timing status (must be CLEAN_CUTOVER for phase 1)
|
|
WITH timing AS (
|
|
SELECT
|
|
pf.location_id AS location_id,
|
|
l.name AS location_name,
|
|
MIN(CASE WHEN w.type = 'KANDANG' THEN DATE(r.record_datetime) END) AS first_kandang_date,
|
|
MAX(CASE WHEN w.type = 'KANDANG' THEN DATE(r.record_datetime) END) AS last_kandang_date,
|
|
MIN(CASE WHEN w.type = 'LOKASI' THEN DATE(r.record_datetime) END) AS first_farm_date,
|
|
MAX(CASE WHEN w.type = 'LOKASI' THEN DATE(r.record_datetime) END) AS last_farm_date
|
|
FROM recording_eggs re
|
|
JOIN recordings r ON r.id = re.recording_id
|
|
JOIN project_flock_kandangs pk ON pk.id = COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id)
|
|
JOIN project_flocks pf ON pf.id = pk.project_flock_id
|
|
JOIN locations l ON l.id = pf.location_id
|
|
JOIN product_warehouses pw ON pw.id = re.product_warehouse_id
|
|
JOIN warehouses w ON w.id = pw.warehouse_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
GROUP BY pf.location_id, l.name
|
|
)
|
|
SELECT
|
|
location_id,
|
|
location_name,
|
|
first_kandang_date,
|
|
last_kandang_date,
|
|
first_farm_date,
|
|
last_farm_date,
|
|
CASE
|
|
WHEN first_farm_date IS NULL THEN 'KANDANG_ONLY'
|
|
WHEN last_kandang_date IS NULL OR first_farm_date > last_kandang_date THEN 'CLEAN_CUTOVER'
|
|
ELSE 'OVERLAP'
|
|
END AS location_status
|
|
FROM timing;
|
|
|
|
-- Expectation:
|
|
-- - phase 1 location must be CLEAN_CUTOVER
|
|
|
|
-- [BEFORE-03] Candidate source rows that should be migrated
|
|
WITH first_farm AS (
|
|
SELECT location_id, MIN(id) AS farm_warehouse_id
|
|
FROM warehouses
|
|
WHERE type = 'LOKASI'
|
|
AND deleted_at IS NULL
|
|
GROUP BY location_id
|
|
)
|
|
SELECT
|
|
l.id AS location_id,
|
|
l.name AS location_name,
|
|
kw.id AS source_warehouse_id,
|
|
kw.name AS source_warehouse_name,
|
|
fw.id AS farm_warehouse_id,
|
|
fw.name AS farm_warehouse_name,
|
|
pw.id AS product_warehouse_id,
|
|
p.id AS product_id,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS on_hand_qty
|
|
FROM product_warehouses pw
|
|
JOIN warehouses kw
|
|
ON kw.id = pw.warehouse_id
|
|
AND kw.type = 'KANDANG'
|
|
AND kw.deleted_at IS NULL
|
|
JOIN locations l ON l.id = kw.location_id
|
|
JOIN products p ON p.id = pw.product_id
|
|
LEFT JOIN product_categories pc ON pc.id = p.product_category_id
|
|
LEFT JOIN first_farm ff ON ff.location_id = kw.location_id
|
|
LEFT JOIN warehouses fw ON fw.id = ff.farm_warehouse_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM recording_eggs re
|
|
WHERE re.product_warehouse_id = pw.id
|
|
)
|
|
AND (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM flags f
|
|
WHERE f.flagable_type = 'products'
|
|
AND f.flagable_id = p.id
|
|
AND (UPPER(f.name) = 'TELUR' OR UPPER(f.name) LIKE 'TELUR-%')
|
|
)
|
|
OR (
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM flags f_any
|
|
WHERE f_any.flagable_type = 'products'
|
|
AND f_any.flagable_id = p.id
|
|
)
|
|
AND UPPER(COALESCE(pc.code, '')) = 'EGG'
|
|
)
|
|
)
|
|
AND COALESCE(pw.qty, 0) > 0
|
|
ORDER BY kw.name, p.name;
|
|
|
|
-- Expectation:
|
|
-- - every row here should match dry-run eligible rows
|
|
|
|
-- [BEFORE-04] Totals per source warehouse and product
|
|
WITH candidates AS (
|
|
SELECT
|
|
kw.name AS source_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS on_hand_qty
|
|
FROM product_warehouses pw
|
|
JOIN warehouses kw
|
|
ON kw.id = pw.warehouse_id
|
|
AND kw.type = 'KANDANG'
|
|
AND kw.deleted_at IS NULL
|
|
JOIN locations l ON l.id = kw.location_id
|
|
JOIN products p ON p.id = pw.product_id
|
|
LEFT JOIN product_categories pc ON pc.id = p.product_category_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND EXISTS (
|
|
SELECT 1 FROM recording_eggs re WHERE re.product_warehouse_id = pw.id
|
|
)
|
|
AND (
|
|
EXISTS (
|
|
SELECT 1 FROM flags f
|
|
WHERE f.flagable_type = 'products'
|
|
AND f.flagable_id = p.id
|
|
AND (UPPER(f.name) = 'TELUR' OR UPPER(f.name) LIKE 'TELUR-%')
|
|
)
|
|
OR (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM flags f_any
|
|
WHERE f_any.flagable_type = 'products'
|
|
AND f_any.flagable_id = p.id
|
|
)
|
|
AND UPPER(COALESCE(pc.code, '')) = 'EGG'
|
|
)
|
|
)
|
|
AND COALESCE(pw.qty, 0) > 0
|
|
)
|
|
SELECT
|
|
source_warehouse_name,
|
|
product_name,
|
|
SUM(on_hand_qty) AS total_qty
|
|
FROM candidates
|
|
GROUP BY source_warehouse_name, product_name
|
|
ORDER BY source_warehouse_name, product_name;
|
|
|
|
-- [BEFORE-05] Current farm egg stock before cutover
|
|
SELECT
|
|
fw.name AS farm_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS farm_on_hand_qty
|
|
FROM warehouses fw
|
|
JOIN locations l ON l.id = fw.location_id
|
|
JOIN product_warehouses pw ON pw.warehouse_id = fw.id
|
|
JOIN products p ON p.id = pw.product_id
|
|
LEFT JOIN product_categories pc ON pc.id = p.product_category_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND fw.type = 'LOKASI'
|
|
AND fw.deleted_at IS NULL
|
|
AND (
|
|
EXISTS (
|
|
SELECT 1 FROM flags f
|
|
WHERE f.flagable_type = 'products'
|
|
AND f.flagable_id = p.id
|
|
AND (UPPER(f.name) = 'TELUR' OR UPPER(f.name) LIKE 'TELUR-%')
|
|
)
|
|
OR (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM flags f_any
|
|
WHERE f_any.flagable_type = 'products'
|
|
AND f_any.flagable_id = p.id
|
|
)
|
|
AND UPPER(COALESCE(pc.code, '')) = 'EGG'
|
|
)
|
|
)
|
|
ORDER BY p.name;
|
|
|
|
-- [BEFORE-06] Existing cutover transfers for this location
|
|
SELECT
|
|
st.id,
|
|
st.movement_number,
|
|
st.transfer_date,
|
|
st.reason,
|
|
ws.name AS source_warehouse_name,
|
|
wd.name AS farm_warehouse_name,
|
|
st.deleted_at
|
|
FROM stock_transfers st
|
|
JOIN warehouses ws ON ws.id = st.from_warehouse_id
|
|
JOIN warehouses wd ON wd.id = st.to_warehouse_id
|
|
LEFT JOIN locations l ON l.id = COALESCE(ws.location_id, wd.location_id)
|
|
WHERE LOWER(COALESCE(l.name, '')) = LOWER('<location_name>')
|
|
AND st.reason LIKE 'EGG_FARM_CUTOVER|%'
|
|
ORDER BY st.id DESC;
|
|
|
|
-- Expectation:
|
|
-- - no unexpected older active cutover transfers for the same location
|
|
|
|
-- =====================================================================
|
|
-- AFTER APPLY
|
|
-- =====================================================================
|
|
|
|
-- [AFTER-01] Transfer headers created by run_id
|
|
SELECT
|
|
st.id,
|
|
st.movement_number,
|
|
st.transfer_date,
|
|
st.reason,
|
|
ws.name AS source_warehouse_name,
|
|
wd.name AS farm_warehouse_name,
|
|
st.deleted_at
|
|
FROM stock_transfers st
|
|
JOIN warehouses ws ON ws.id = st.from_warehouse_id
|
|
JOIN warehouses wd ON wd.id = st.to_warehouse_id
|
|
WHERE st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
ORDER BY st.id ASC;
|
|
|
|
-- [AFTER-02] Transfer detail rows created by run_id
|
|
SELECT
|
|
st.id AS transfer_id,
|
|
st.movement_number,
|
|
ws.name AS source_warehouse_name,
|
|
wd.name AS farm_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(std.total_qty, std.usage_qty, 0) AS moved_qty,
|
|
std.source_product_warehouse_id,
|
|
std.dest_product_warehouse_id
|
|
FROM stock_transfers st
|
|
JOIN stock_transfer_details std
|
|
ON std.stock_transfer_id = st.id
|
|
AND std.deleted_at IS NULL
|
|
JOIN products p ON p.id = std.product_id
|
|
JOIN warehouses ws ON ws.id = st.from_warehouse_id
|
|
JOIN warehouses wd ON wd.id = st.to_warehouse_id
|
|
WHERE st.deleted_at IS NULL
|
|
AND st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
ORDER BY st.id, p.name;
|
|
|
|
-- [AFTER-03] Stock logs created by run_id transfer details
|
|
SELECT
|
|
st.id AS transfer_id,
|
|
st.movement_number,
|
|
p.name AS product_name,
|
|
sl.product_warehouse_id,
|
|
sl.increase,
|
|
sl.decrease,
|
|
sl.stock,
|
|
sl.created_at
|
|
FROM stock_transfers st
|
|
JOIN stock_transfer_details std
|
|
ON std.stock_transfer_id = st.id
|
|
AND std.deleted_at IS NULL
|
|
JOIN products p ON p.id = std.product_id
|
|
JOIN stock_logs sl
|
|
ON sl.loggable_type = 'TRANSFER'
|
|
AND sl.loggable_id = std.id
|
|
WHERE st.deleted_at IS NULL
|
|
AND st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
ORDER BY st.id, p.name, sl.id;
|
|
|
|
-- Expectation:
|
|
-- - every detail has one stock log decrease from source and one stock log increase to destination
|
|
|
|
-- [AFTER-04] Source rows after cutover
|
|
SELECT
|
|
kw.name AS source_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS source_qty_after
|
|
FROM product_warehouses pw
|
|
JOIN warehouses kw ON kw.id = pw.warehouse_id
|
|
JOIN locations l ON l.id = kw.location_id
|
|
JOIN products p ON p.id = pw.product_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND kw.type = 'KANDANG'
|
|
AND EXISTS (
|
|
SELECT 1 FROM recording_eggs re WHERE re.product_warehouse_id = pw.id
|
|
)
|
|
ORDER BY kw.name, p.name;
|
|
|
|
-- Expectation:
|
|
-- - rows that were transferred should now be 0 or no longer available for use
|
|
|
|
-- [AFTER-05] Farm rows after cutover
|
|
SELECT
|
|
fw.name AS farm_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS farm_qty_after
|
|
FROM product_warehouses pw
|
|
JOIN warehouses fw ON fw.id = pw.warehouse_id
|
|
JOIN locations l ON l.id = fw.location_id
|
|
JOIN products p ON p.id = pw.product_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND fw.type = 'LOKASI'
|
|
ORDER BY fw.name, p.name;
|
|
|
|
-- Expectation:
|
|
-- - farm qty increases by the moved amount
|
|
|
|
-- [AFTER-06] Reconciliation: total moved by run
|
|
SELECT
|
|
p.name AS product_name,
|
|
SUM(COALESCE(std.total_qty, std.usage_qty, 0)) AS total_moved_qty
|
|
FROM stock_transfers st
|
|
JOIN stock_transfer_details std
|
|
ON std.stock_transfer_id = st.id
|
|
AND std.deleted_at IS NULL
|
|
JOIN products p ON p.id = std.product_id
|
|
WHERE st.deleted_at IS NULL
|
|
AND st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
GROUP BY p.name
|
|
ORDER BY p.name;
|
|
|
|
-- [AFTER-07] Farm stock available for SO after cutover
|
|
SELECT
|
|
fw.name AS farm_warehouse_name,
|
|
p.name AS product_name,
|
|
COALESCE(pw.qty, 0) AS available_qty
|
|
FROM product_warehouses pw
|
|
JOIN warehouses fw ON fw.id = pw.warehouse_id
|
|
JOIN locations l ON l.id = fw.location_id
|
|
JOIN products p ON p.id = pw.product_id
|
|
WHERE LOWER(l.name) = LOWER('<location_name>')
|
|
AND fw.type = 'LOKASI'
|
|
AND COALESCE(pw.qty, 0) > 0
|
|
ORDER BY p.name;
|
|
|
|
-- =====================================================================
|
|
-- ROLLBACK CHECKS
|
|
-- =====================================================================
|
|
|
|
-- [ROLLBACK-01] Check downstream consumption guard before rollback
|
|
SELECT
|
|
st.id AS transfer_id,
|
|
st.movement_number,
|
|
p.name AS product_name,
|
|
sa.usable_type,
|
|
sa.usable_id,
|
|
sa.qty,
|
|
sa.function_code,
|
|
sa.flag_group_code
|
|
FROM stock_transfers st
|
|
JOIN stock_transfer_details std
|
|
ON std.stock_transfer_id = st.id
|
|
AND std.deleted_at IS NULL
|
|
JOIN products p ON p.id = std.product_id
|
|
JOIN stock_allocations sa
|
|
ON sa.stockable_type = 'STOCK_TRANSFER_IN'
|
|
AND sa.stockable_id = std.id
|
|
AND sa.status = 'ACTIVE'
|
|
AND sa.allocation_purpose = 'CONSUME'
|
|
AND sa.deleted_at IS NULL
|
|
WHERE st.deleted_at IS NULL
|
|
AND st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
ORDER BY st.id, p.name, sa.usable_type, sa.usable_id;
|
|
|
|
-- Expectation:
|
|
-- - rollback only safe if this query returns 0 rows
|
|
|
|
-- [ROLLBACK-02] Verify run is fully rolled back
|
|
SELECT
|
|
st.id,
|
|
st.movement_number,
|
|
st.deleted_at
|
|
FROM stock_transfers st
|
|
WHERE st.reason LIKE 'EGG_FARM_CUTOVER|run_id=<run_id>|%'
|
|
ORDER BY st.id;
|
|
|
|
-- Expectation:
|
|
-- - after rollback, deleted_at should be filled for all transfers in the run
|