Merge branch 'fix/migration-fifo-v2' into 'dev/fifo-v2'

fix: migration fifo v2

See merge request mbugroup/lti-api!360
This commit is contained in:
Hafizh A. Y.
2026-03-08 12:02:11 +00:00
4 changed files with 244 additions and 36 deletions
@@ -0,0 +1,24 @@
BEGIN;
DROP INDEX IF EXISTS idx_stock_allocations_idempotency;
DROP INDEX IF EXISTS idx_stock_allocations_flag_group;
DROP INDEX IF EXISTS idx_stock_allocations_engine_version;
ALTER TABLE stock_allocations
DROP COLUMN IF EXISTS idempotency_key,
DROP COLUMN IF EXISTS reflow_run_id,
DROP COLUMN IF EXISTS function_code,
DROP COLUMN IF EXISTS flag_group_code,
DROP COLUMN IF EXISTS engine_version;
DROP TABLE IF EXISTS fifo_stock_v2_shadow_allocations;
DROP TABLE IF EXISTS fifo_stock_v2_reflow_checkpoints;
DROP TABLE IF EXISTS fifo_stock_v2_reflow_runs;
DROP TABLE IF EXISTS fifo_stock_v2_operation_log;
DROP TABLE IF EXISTS fifo_stock_v2_overconsume_rules;
DROP TABLE IF EXISTS fifo_stock_v2_route_rules;
DROP TABLE IF EXISTS fifo_stock_v2_traits;
DROP TABLE IF EXISTS fifo_stock_v2_flag_members;
DROP TABLE IF EXISTS fifo_stock_v2_flag_groups;
COMMIT;
@@ -0,0 +1,154 @@
BEGIN;
-- Bootstrap FIFO v2 core tables before seed migration (20260218090010).
-- Keep definitions aligned with 20260304033546_create_fifo_stock_v2_core.
CREATE TABLE IF NOT EXISTS fifo_stock_v2_flag_groups (
code VARCHAR(64) PRIMARY KEY,
name VARCHAR(128) NOT NULL,
priority INT NOT NULL DEFAULT 100,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_flag_members (
flag_name VARCHAR(64) PRIMARY KEY,
flag_group_code VARCHAR(64) NOT NULL REFERENCES fifo_stock_v2_flag_groups(code),
priority INT NOT NULL DEFAULT 100,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_traits (
id BIGSERIAL PRIMARY KEY,
source_table VARCHAR(64) NOT NULL,
lane VARCHAR(16) NOT NULL CHECK (lane IN ('STOCKABLE', 'USABLE')),
date_table VARCHAR(64) NULL,
date_join_left_col VARCHAR(64) NULL,
date_join_right_col VARCHAR(64) NULL,
date_column VARCHAR(64) NOT NULL,
fallback_date_column VARCHAR(64) NULL,
sort_priority INT NOT NULL DEFAULT 100,
id_column VARCHAR(64) NOT NULL DEFAULT 'id',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
UNIQUE (source_table, lane)
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_route_rules (
id BIGSERIAL PRIMARY KEY,
flag_group_code VARCHAR(64) NOT NULL REFERENCES fifo_stock_v2_flag_groups(code),
lane VARCHAR(16) NOT NULL CHECK (lane IN ('STOCKABLE', 'USABLE')),
function_code VARCHAR(64) NOT NULL,
source_table VARCHAR(64) NOT NULL,
source_id_column VARCHAR(64) NOT NULL DEFAULT 'id',
product_warehouse_col VARCHAR(64) NOT NULL,
quantity_col VARCHAR(64) NOT NULL,
used_quantity_col VARCHAR(64) NULL,
pending_quantity_col VARCHAR(64) NULL,
scope_sql TEXT NULL,
legacy_type_key VARCHAR(100) NOT NULL,
allow_pending_default BOOLEAN NOT NULL DEFAULT TRUE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (flag_group_code, lane, function_code, source_table)
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_overconsume_rules (
id BIGSERIAL PRIMARY KEY,
flag_group_code VARCHAR(64) NULL REFERENCES fifo_stock_v2_flag_groups(code),
function_code VARCHAR(64) NULL,
lane VARCHAR(16) NOT NULL DEFAULT 'USABLE' CHECK (lane IN ('STOCKABLE', 'USABLE')),
allow_overconsume BOOLEAN NOT NULL,
priority INT NOT NULL DEFAULT 100,
reason TEXT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_operation_log (
id BIGSERIAL PRIMARY KEY,
idempotency_key VARCHAR(128) NOT NULL,
operation VARCHAR(16) NOT NULL CHECK (operation IN ('ALLOCATE', 'ROLLBACK', 'REFLOW', 'RECALCULATE')),
product_warehouse_id BIGINT NOT NULL,
flag_group_code VARCHAR(64) NOT NULL,
usable_type VARCHAR(100) NULL,
usable_id BIGINT NULL,
request_hash VARCHAR(64) NOT NULL,
status VARCHAR(16) NOT NULL CHECK (status IN ('RUNNING', 'DONE', 'FAILED')),
result_payload JSONB NULL,
error_text TEXT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
finished_at TIMESTAMPTZ NULL,
UNIQUE (idempotency_key, operation)
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_reflow_runs (
id BIGSERIAL PRIMARY KEY,
mode VARCHAR(16) NOT NULL CHECK (mode IN ('DRY_RUN', 'APPLY')),
status VARCHAR(16) NOT NULL CHECK (status IN ('RUNNING', 'PAUSED', 'DONE', 'FAILED', 'CANCELLED')),
as_of TIMESTAMPTZ NULL,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
finished_at TIMESTAMPTZ NULL,
total_shards INT NOT NULL DEFAULT 0,
processed_shards INT NOT NULL DEFAULT 0,
processed_rows BIGINT NOT NULL DEFAULT 0,
mismatch_rows BIGINT NOT NULL DEFAULT 0,
created_by BIGINT NULL,
note TEXT NULL
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_reflow_checkpoints (
id BIGSERIAL PRIMARY KEY,
run_id BIGINT NOT NULL REFERENCES fifo_stock_v2_reflow_runs(id) ON DELETE CASCADE,
flag_group_code VARCHAR(64) NOT NULL,
product_warehouse_id BIGINT NOT NULL,
last_sort_at TIMESTAMPTZ NULL,
last_source_table VARCHAR(64) NULL,
last_source_id BIGINT NULL,
status VARCHAR(16) NOT NULL CHECK (status IN ('PENDING', 'RUNNING', 'DONE', 'FAILED')) DEFAULT 'PENDING',
retry_count INT NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (run_id, flag_group_code, product_warehouse_id)
);
CREATE TABLE IF NOT EXISTS fifo_stock_v2_shadow_allocations (
id BIGSERIAL PRIMARY KEY,
run_id BIGINT NOT NULL REFERENCES fifo_stock_v2_reflow_runs(id) ON DELETE CASCADE,
product_warehouse_id BIGINT NOT NULL,
stockable_type VARCHAR(100) NOT NULL,
stockable_id BIGINT NOT NULL,
usable_type VARCHAR(100) NOT NULL,
usable_id BIGINT NOT NULL,
qty NUMERIC(15,3) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
sort_at TIMESTAMPTZ NULL,
source_table VARCHAR(64) NULL,
source_id BIGINT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_fifo_v2_shadow_run_usable
ON fifo_stock_v2_shadow_allocations(run_id, usable_type, usable_id);
CREATE INDEX IF NOT EXISTS idx_fifo_v2_shadow_run_stockable
ON fifo_stock_v2_shadow_allocations(run_id, stockable_type, stockable_id);
ALTER TABLE stock_allocations
ADD COLUMN IF NOT EXISTS engine_version VARCHAR(8) NOT NULL DEFAULT 'v1',
ADD COLUMN IF NOT EXISTS flag_group_code VARCHAR(64) NULL,
ADD COLUMN IF NOT EXISTS function_code VARCHAR(64) NULL,
ADD COLUMN IF NOT EXISTS reflow_run_id BIGINT NULL,
ADD COLUMN IF NOT EXISTS idempotency_key VARCHAR(128) NULL;
CREATE INDEX IF NOT EXISTS idx_stock_allocations_engine_version
ON stock_allocations(engine_version);
CREATE INDEX IF NOT EXISTS idx_stock_allocations_flag_group
ON stock_allocations(flag_group_code);
CREATE INDEX IF NOT EXISTS idx_stock_allocations_idempotency
ON stock_allocations(idempotency_key);
COMMIT;
@@ -1,37 +1,60 @@
BEGIN;
DELETE FROM fifo_stock_v2_overconsume_rules
WHERE reason IN (
'fifo_v2_default_allow',
'fifo_v2_exception_ayam_depletion_block',
'fifo_v2_exception_marketing_block',
'fifo_v2_exception_transfer_block',
'fifo_v2_exception_adjustment_block',
'fifo_v2_exception_transfer_laying_block'
);
DO $$
BEGIN
IF to_regclass('public.fifo_stock_v2_overconsume_rules') IS NOT NULL THEN
EXECUTE '
DELETE FROM fifo_stock_v2_overconsume_rules
WHERE reason IN (
''fifo_v2_default_allow'',
''fifo_v2_exception_ayam_depletion_block'',
''fifo_v2_exception_marketing_block'',
''fifo_v2_exception_transfer_block'',
''fifo_v2_exception_adjustment_block'',
''fifo_v2_exception_transfer_laying_block''
)
';
END IF;
DELETE FROM fifo_stock_v2_route_rules
WHERE flag_group_code IN ('AYAM', 'AFKIR_CULLING_MATI', 'PAKAN', 'OVK', 'TELUR', 'TELUR_GRADE');
IF to_regclass('public.fifo_stock_v2_route_rules') IS NOT NULL THEN
EXECUTE '
DELETE FROM fifo_stock_v2_route_rules
WHERE flag_group_code IN (''AYAM'', ''AFKIR_CULLING_MATI'', ''PAKAN'', ''OVK'', ''TELUR'', ''TELUR_GRADE'')
';
END IF;
DELETE FROM fifo_stock_v2_traits
WHERE source_table IN (
'purchase_items',
'stock_transfer_details',
'laying_transfer_targets',
'laying_transfer_sources',
'adjustment_stocks',
'recording_stocks',
'recording_depletions',
'recording_eggs',
'marketing_delivery_products',
'project_chickins',
'project_flock_populations'
);
IF to_regclass('public.fifo_stock_v2_traits') IS NOT NULL THEN
EXECUTE '
DELETE FROM fifo_stock_v2_traits
WHERE source_table IN (
''purchase_items'',
''stock_transfer_details'',
''laying_transfer_targets'',
''laying_transfer_sources'',
''adjustment_stocks'',
''recording_stocks'',
''recording_depletions'',
''recording_eggs'',
''marketing_delivery_products'',
''project_chickins'',
''project_flock_populations''
)
';
END IF;
DELETE FROM fifo_stock_v2_flag_members
WHERE flag_group_code IN ('AYAM', 'AFKIR_CULLING_MATI', 'PAKAN', 'OVK', 'TELUR', 'TELUR_GRADE');
IF to_regclass('public.fifo_stock_v2_flag_members') IS NOT NULL THEN
EXECUTE '
DELETE FROM fifo_stock_v2_flag_members
WHERE flag_group_code IN (''AYAM'', ''AFKIR_CULLING_MATI'', ''PAKAN'', ''OVK'', ''TELUR'', ''TELUR_GRADE'')
';
END IF;
DELETE FROM fifo_stock_v2_flag_groups
WHERE code IN ('AYAM', 'AFKIR_CULLING_MATI', 'PAKAN', 'OVK', 'TELUR', 'TELUR_GRADE');
IF to_regclass('public.fifo_stock_v2_flag_groups') IS NOT NULL THEN
EXECUTE '
DELETE FROM fifo_stock_v2_flag_groups
WHERE code IN (''AYAM'', ''AFKIR_CULLING_MATI'', ''PAKAN'', ''OVK'', ''TELUR'', ''TELUR_GRADE'')
';
END IF;
END $$;
COMMIT;
@@ -2,12 +2,19 @@ BEGIN;
-- Restore CHICKIN route if rollback is required.
-- NOTE: released PROJECT_CHICKIN allocations are not restored by this down migration.
UPDATE fifo_stock_v2_route_rules
SET is_active = TRUE,
DO $$
BEGIN
IF to_regclass('public.fifo_stock_v2_route_rules') IS NOT NULL THEN
EXECUTE '
UPDATE fifo_stock_v2_route_rules
SET is_active = TRUE,
updated_at = NOW()
WHERE flag_group_code = 'AYAM'
AND lane = 'USABLE'
AND function_code = 'CHICKIN_OUT'
AND source_table = 'project_chickins';
WHERE flag_group_code = ''AYAM''
AND lane = ''USABLE''
AND function_code = ''CHICKIN_OUT''
AND source_table = ''project_chickins''
';
END IF;
END $$;
COMMIT;