integrate global logistics staff user into seeder

refactor pricing data seeder to fold surcharge types into rates
update route meta subtitle to remove surcharge types
enhance RuleEngineFormDialog to support conditional field visibility
 remove surcharge types from URL constants and related services
add cargo leaf options query for bulk cargo type selection
update RuleEngineResourcePage to utilize cargo leaf options
modify resources configuration to remove surcharge types
implement migration to fold surcharge types into rates
create utility to derive legacy rate types from new rate structure
This commit is contained in:
Marshal
2026-06-23 23:15:32 +00:00
parent 2b4dfc6490
commit 9d81a2e1ee
30 changed files with 642 additions and 632 deletions

View File

@@ -0,0 +1,187 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Fold the `surcharge_types` table into self-describing rates.
*
* Previously a surcharge was a separate row {trigger_condition, rate_id}. Now
* each rate carries its own `applies_to` (friendly category) and `trigger`
* (ALWAYS = base freight, otherwise a surcharge condition), plus an optional
* `cargo_type_id` for bulk leaf commodities. The rule engine reads triggers
* directly off LIVE rates, so the join table is no longer needed.
*
* This migration:
* 1. adds applies_to / trigger / cargo_type_id to rates and backfills them
* from the existing rate_type matrix,
* 2. repoints booking_cargo_modifier from surcharge_type_id → rate_id
* (backfilled via surcharge_types.rate_id),
* 3. drops surcharge_types and its FK.
*/
export class FoldSurchargeTypesIntoRates1820000000004 implements MigrationInterface {
name = 'FoldSurchargeTypesIntoRates1820000000004';
public async up(queryRunner: QueryRunner): Promise<void> {
// ── 1. New rate columns ────────────────────────────────────────────────
await queryRunner.query(`
ALTER TABLE freight.rates
ADD COLUMN IF NOT EXISTS applies_to varchar(20) NOT NULL DEFAULT 'OTHER',
ADD COLUMN IF NOT EXISTS "trigger" varchar(20) NOT NULL DEFAULT 'ALWAYS',
ADD COLUMN IF NOT EXISTS cargo_type_id uuid NULL;
`);
await queryRunner.query(`
ALTER TABLE freight.rates
ADD CONSTRAINT "FK_rates_cargo_type_id"
FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id)
ON DELETE SET NULL;
`);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_rates_trigger" ON freight.rates ("trigger");`,
);
// ── 1a. Backfill applies_to from the legacy rate_type matrix ────────────
await queryRunner.query(`
UPDATE freight.rates SET applies_to = CASE
WHEN rate_type IN ('CONTAINER_IMPORT','CONTAINER_EXPORT','CONTAINER_WITH_RETURN') THEN 'CONTAINER'
WHEN rate_type IN ('BULK_IMPORT','BULK_EXPORT') THEN 'BULK'
WHEN rate_type IN ('INTERCITY_CONTAINER','INTERCITY_BULK') THEN 'INTERCITY'
WHEN rate_type = 'FIRST_MILE' THEN 'FIRST_MILE'
WHEN rate_type = 'LAST_MILE' THEN 'LAST_MILE'
ELSE 'OTHER'
END;
`);
// ── 1b. Backfill trigger from the legacy rate_type matrix ───────────────
await queryRunner.query(`
UPDATE freight.rates SET "trigger" = CASE
WHEN rate_type = 'HAZARD_SURCHARGE' THEN 'HAZARDOUS'
WHEN rate_type = 'REEFER_SURCHARGE' THEN 'REEFER'
WHEN rate_type = 'OVERWEIGHT_PER_TON' THEN 'OVERWEIGHT'
WHEN rate_type = 'DOUBLE_HANDLING' THEN 'SHIPPING_LINE'
WHEN rate_type = 'LASHING' THEN 'CONSOLIDATION'
WHEN rate_type = 'CANCELLATION_FEE' THEN 'CANCELLATION'
WHEN rate_type = 'DEMURRAGE' THEN 'DEMURRAGE'
WHEN rate_type = 'PIL_EXTRA_FEE' THEN 'PIL_EXTRA_FEE'
ELSE 'ALWAYS'
END;
`);
// Align the trigger to the actual surcharge_types mapping where one exists
// (covers any rate wired as a surcharge with a non-obvious rate_type).
await queryRunner.query(`
UPDATE freight.rates r SET "trigger" = m.trig
FROM (
SELECT st.rate_id, CASE st.trigger_condition
WHEN 'CARGO_FLAG_HAZARDOUS' THEN 'HAZARDOUS'
WHEN 'CARGO_FLAG_REEFER' THEN 'REEFER'
WHEN 'VGM_EXCEEDS_LIMIT' THEN 'OVERWEIGHT'
WHEN 'SHIPPING_LINE_MAPPED' THEN 'SHIPPING_LINE'
WHEN 'CONSOLIDATION_ENABLED' THEN 'CONSOLIDATION'
ELSE 'ALWAYS'
END AS trig
FROM freight.surcharge_types st
WHERE st.rate_id IS NOT NULL AND st.deleted_at IS NULL
) m
WHERE r.id = m.rate_id AND m.trig <> 'ALWAYS';
`);
// ── 2. Repoint booking_cargo_modifier to rate_id ────────────────────────
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
ADD COLUMN IF NOT EXISTS rate_id uuid NULL;
`);
await queryRunner.query(`
UPDATE freight.booking_cargo_modifier bcm
SET rate_id = st.rate_id
FROM freight.surcharge_types st
WHERE bcm.surcharge_type_id = st.id AND st.rate_id IS NOT NULL;
`);
// Rows whose surcharge lost its rate can't be repointed — they reference a
// now-defunct surcharge. Remove them so the NOT NULL + FK can be enforced.
await queryRunner.query(`
DELETE FROM freight.booking_cargo_modifier WHERE rate_id IS NULL;
`);
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
ALTER COLUMN rate_id SET NOT NULL;
`);
// Drop the old FK + column + index for surcharge_type_id.
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_surcharge_type_id";
`);
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_booking_cargo_modifier_surcharge_type_id";`,
);
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
DROP COLUMN IF EXISTS surcharge_type_id;
`);
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
ADD CONSTRAINT "FK_booking_cargo_modifier_rate_id"
FOREIGN KEY (rate_id) REFERENCES freight.rates(id);
`);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_booking_cargo_modifier_rate_id" ON freight.booking_cargo_modifier (rate_id);`,
);
// ── 3. Drop the surcharge_types table ───────────────────────────────────
await queryRunner.query(`DROP TABLE IF EXISTS freight.surcharge_types;`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Recreate surcharge_types (structure only — data is not restored).
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS freight.surcharge_types (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
code varchar(40) NOT NULL,
label varchar(100),
trigger_condition varchar(50),
rate_id uuid,
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz
);
`);
await queryRunner.query(
`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_surcharge_types_code" ON freight.surcharge_types (code);`,
);
// Restore booking_cargo_modifier.surcharge_type_id (nullable; not backfilled).
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_rate_id";
`);
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_booking_cargo_modifier_rate_id";`,
);
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier
ADD COLUMN IF NOT EXISTS surcharge_type_id uuid NULL;
`);
await queryRunner.query(`
ALTER TABLE freight.booking_cargo_modifier DROP COLUMN IF EXISTS rate_id;
`);
// Drop the new rate columns.
await queryRunner.query(
`DROP INDEX IF EXISTS freight."IDX_rates_trigger";`,
);
await queryRunner.query(`
ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "FK_rates_cargo_type_id";
`);
await queryRunner.query(`
ALTER TABLE freight.rates
DROP COLUMN IF EXISTS cargo_type_id,
DROP COLUMN IF EXISTS "trigger",
DROP COLUMN IF EXISTS applies_to;
`);
}
}