erp_be/scripts/patch-unify-item-asset-categories.sql

235 lines
7.1 KiB
PL/PgSQL

-- Unify asset categories onto item_categories / item_subcategories
-- Run against PostgreSQL before deploying BE that expects item_* FKs on assets.
--
-- Pre-check (optional):
-- SELECT ac.code, ac.name AS asset_cat, ic.name AS item_cat
-- FROM asset_categories ac
-- JOIN item_categories ic ON UPPER(ac.code) = UPPER(ic.code)
-- AND ac.deleted_at IS NULL AND ic.deleted_at IS NULL;
BEGIN;
-- =========================================================
-- 1) Extend item_categories with asset defaults
-- =========================================================
ALTER TABLE item_categories
ADD COLUMN IF NOT EXISTS code_prefix VARCHAR(10),
ADD COLUMN IF NOT EXISTS default_useful_life_years INT,
ADD COLUMN IF NOT EXISTS default_depreciation_method VARCHAR(20);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'item_categories_code_prefix_key'
) THEN
ALTER TABLE item_categories
ADD CONSTRAINT item_categories_code_prefix_key UNIQUE (code_prefix);
END IF;
END $$;
-- =========================================================
-- 2) Mapping tables
-- =========================================================
CREATE TEMP TABLE map_asset_category (
old_asset_category_id BIGINT PRIMARY KEY,
new_item_category_id BIGINT NOT NULL
);
CREATE TEMP TABLE map_asset_subcategory (
old_asset_subcategory_id BIGINT PRIMARY KEY,
new_item_subcategory_id BIGINT NOT NULL
);
-- =========================================================
-- 3) Upsert asset_categories -> item_categories
-- =========================================================
WITH src AS (
SELECT *
FROM asset_categories
WHERE deleted_at IS NULL
),
matched AS (
SELECT s.id AS old_id, ic.id AS new_id
FROM src s
JOIN item_categories ic
ON UPPER(ic.code) = UPPER(s.code)
AND ic.deleted_at IS NULL
),
inserted AS (
INSERT INTO item_categories (
code, name, code_prefix,
default_useful_life_years, default_depreciation_method,
is_active, created_by, updated_by, created_at, updated_at
)
SELECT
s.code,
s.name,
s.code_prefix,
s.default_useful_life_years,
s.default_depreciation_method,
s.is_active,
s.created_by,
s.updated_by,
s.created_at,
s.updated_at
FROM src s
WHERE NOT EXISTS (
SELECT 1 FROM matched m WHERE m.old_id = s.id
)
RETURNING id, code
)
INSERT INTO map_asset_category (old_asset_category_id, new_item_category_id)
SELECT old_id, new_id FROM matched
UNION ALL
SELECT s.id, i.id
FROM src s
JOIN inserted i ON UPPER(i.code) = UPPER(s.code);
UPDATE item_categories ic
SET
code_prefix = COALESCE(ic.code_prefix, ac.code_prefix),
default_useful_life_years = COALESCE(ic.default_useful_life_years, ac.default_useful_life_years),
default_depreciation_method = COALESCE(ic.default_depreciation_method, ac.default_depreciation_method),
updated_at = NOW()
FROM asset_categories ac
JOIN map_asset_category m ON m.old_asset_category_id = ac.id
WHERE ic.id = m.new_item_category_id
AND ac.deleted_at IS NULL;
-- =========================================================
-- 4) Upsert asset_subcategories -> item_subcategories
-- =========================================================
WITH src AS (
SELECT asub.*, m.new_item_category_id
FROM asset_subcategories asub
JOIN map_asset_category m ON m.old_asset_category_id = asub.asset_category_id
WHERE asub.deleted_at IS NULL
),
matched AS (
SELECT s.id AS old_id, isub.id AS new_id
FROM src s
JOIN item_subcategories isub
ON UPPER(isub.code) = UPPER(s.code)
AND isub.deleted_at IS NULL
),
inserted AS (
INSERT INTO item_subcategories (
item_category_id, code, name,
is_active, created_by, updated_by, created_at, updated_at
)
SELECT
s.new_item_category_id,
s.code,
s.name,
s.is_active,
s.created_by,
s.updated_by,
s.created_at,
s.updated_at
FROM src s
WHERE NOT EXISTS (
SELECT 1 FROM matched m WHERE m.old_id = s.id
)
RETURNING id, code
)
INSERT INTO map_asset_subcategory (old_asset_subcategory_id, new_item_subcategory_id)
SELECT old_id, new_id FROM matched
UNION ALL
SELECT s.id, i.id
FROM src s
JOIN inserted i ON UPPER(i.code) = UPPER(s.code);
UPDATE item_subcategories isub
SET
item_category_id = mcat.new_item_category_id,
updated_at = NOW()
FROM map_asset_subcategory msub
JOIN asset_subcategories asub ON asub.id = msub.old_asset_subcategory_id
JOIN map_asset_category mcat ON mcat.old_asset_category_id = asub.asset_category_id
WHERE isub.id = msub.new_item_subcategory_id;
-- =========================================================
-- 5) Remap assets to item_* columns
-- =========================================================
ALTER TABLE assets
ADD COLUMN IF NOT EXISTS item_category_id BIGINT,
ADD COLUMN IF NOT EXISTS item_subcategory_id BIGINT;
UPDATE assets a
SET
item_category_id = mapped.new_item_category_id,
item_subcategory_id = mapped.new_item_subcategory_id,
updated_at = NOW()
FROM (
SELECT
a2.id AS asset_id,
mcat.new_item_category_id,
msub.new_item_subcategory_id
FROM assets a2
JOIN map_asset_category mcat
ON mcat.old_asset_category_id = a2.asset_category_id
LEFT JOIN map_asset_subcategory msub
ON msub.old_asset_subcategory_id = a2.asset_subcategory_id
) mapped
WHERE a.id = mapped.asset_id;
DO $$
DECLARE missing_count BIGINT;
BEGIN
SELECT COUNT(*) INTO missing_count
FROM assets
WHERE deleted_at IS NULL
AND item_category_id IS NULL;
IF missing_count > 0 THEN
RAISE EXCEPTION '% active assets could not be mapped to item_category_id', missing_count;
END IF;
END $$;
ALTER TABLE assets
ALTER COLUMN item_category_id SET NOT NULL;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'assets_item_category_id_fkey'
) THEN
ALTER TABLE assets
ADD CONSTRAINT assets_item_category_id_fkey
FOREIGN KEY (item_category_id) REFERENCES item_categories (id);
END IF;
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'assets_item_subcategory_id_fkey'
) THEN
ALTER TABLE assets
ADD CONSTRAINT assets_item_subcategory_id_fkey
FOREIGN KEY (item_subcategory_id) REFERENCES item_subcategories (id);
END IF;
END $$;
CREATE INDEX IF NOT EXISTS idx_assets_item_category_id ON assets (item_category_id);
CREATE INDEX IF NOT EXISTS idx_assets_item_subcategory_id ON assets (item_subcategory_id);
-- =========================================================
-- 6) Drop dependent views, then old asset category FKs / columns / tables
-- =========================================================
DROP VIEW IF EXISTS v_asset_expiry_alerts CASCADE;
DROP VIEW IF EXISTS v_asset_next_service CASCADE;
DROP VIEW IF EXISTS v_assets CASCADE;
ALTER TABLE assets DROP CONSTRAINT IF EXISTS assets_asset_category_id_fkey;
ALTER TABLE assets DROP CONSTRAINT IF EXISTS assets_asset_subcategory_id_fkey;
DROP INDEX IF EXISTS idx_assets_category_id;
DROP INDEX IF EXISTS idx_assets_subcategory_id;
ALTER TABLE assets DROP COLUMN IF EXISTS asset_category_id;
ALTER TABLE assets DROP COLUMN IF EXISTS asset_subcategory_id;
DROP TABLE IF EXISTS asset_subcategories;
DROP TABLE IF EXISTS asset_categories;
COMMIT;
-- Recreate reporting views after this script:
-- psql ... -f scripts/patch-assets-views.sql