From b1c829bbf8feb69af310e7365b66f6c3577bb9ca Mon Sep 17 00:00:00 2001 From: "Hafizh A. Y" Date: Sun, 8 Mar 2026 19:01:09 +0700 Subject: [PATCH] fix: migration fifo v2 --- ...strap_fifo_stock_v2_core_pre_seed.down.sql | 24 +++ ...otstrap_fifo_stock_v2_core_pre_seed.up.sql | 154 ++++++++++++++++++ ...8090010_seed_fifo_stock_v2_config.down.sql | 81 +++++---- ..._disable_chickin_fifo_consumption.down.sql | 21 ++- 4 files changed, 244 insertions(+), 36 deletions(-) create mode 100644 internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.down.sql create mode 100644 internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.up.sql diff --git a/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.down.sql b/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.down.sql new file mode 100644 index 00000000..0aee55e2 --- /dev/null +++ b/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.down.sql @@ -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; diff --git a/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.up.sql b/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.up.sql new file mode 100644 index 00000000..8723e831 --- /dev/null +++ b/internal/database/migrations/20260217000000_bootstrap_fifo_stock_v2_core_pre_seed.up.sql @@ -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; diff --git a/internal/database/migrations/20260218090010_seed_fifo_stock_v2_config.down.sql b/internal/database/migrations/20260218090010_seed_fifo_stock_v2_config.down.sql index 05786a61..b91a563c 100644 --- a/internal/database/migrations/20260218090010_seed_fifo_stock_v2_config.down.sql +++ b/internal/database/migrations/20260218090010_seed_fifo_stock_v2_config.down.sql @@ -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; diff --git a/internal/database/migrations/20260228143207_disable_chickin_fifo_consumption.down.sql b/internal/database/migrations/20260228143207_disable_chickin_fifo_consumption.down.sql index ee662a07..ebc94e91 100644 --- a/internal/database/migrations/20260228143207_disable_chickin_fifo_consumption.down.sql +++ b/internal/database/migrations/20260228143207_disable_chickin_fifo_consumption.down.sql @@ -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, - updated_at = NOW() -WHERE flag_group_code = 'AYAM' - AND lane = 'USABLE' - AND function_code = 'CHICKIN_OUT' - AND source_table = 'project_chickins'; +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'' + '; + END IF; +END $$; COMMIT;