import { MigrationInterface, QueryRunner } from 'typeorm'; /** * Intercity (DOMESTIC) cargo is loaded at its origin yard and unloaded at its * destination yard, but only some yards have the equipment to do it. EDR's * load/unload facilities are Indode, Sebeta, Modjo, Adama, Dire Dawa and Negad — * and the set grows, so it must be data, not a constant. * * `yards.has_facility` marks a yard as a load/unload point; `yard_facilities` * holds what that facility can do. Only a facility with `has_warehouse` (Indode * today) stores cargo, and therefore accrues storage/demurrage — the rest just * move it on and off the train. * * `facility_handling_events` records each load/unload and carries its GRN. * warehouse_inventory can't do that job: its warehouse/yard/zone are NOT NULL, so * a facility with no warehouse could never have a row. `inventory_id` links to the * storage record when the facility does have a warehouse. */ export class YardFacilities2290000000000 implements MigrationInterface { name = 'YardFacilities2290000000000'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.yards ADD COLUMN IF NOT EXISTS has_facility boolean NOT NULL DEFAULT false `); await queryRunner.query(` CREATE TABLE IF NOT EXISTS freight.yard_facilities ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), yard_id uuid NOT NULL REFERENCES freight.yards(id) ON DELETE CASCADE, has_warehouse boolean NOT NULL DEFAULT false, equipment_notes text NULL, is_active boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz NULL ) `); // One facility record per yard. await queryRunner.query(` CREATE UNIQUE INDEX IF NOT EXISTS "UQ_yard_facility_yard" ON freight.yard_facilities (yard_id) WHERE deleted_at IS NULL `); await queryRunner.query(` CREATE TABLE IF NOT EXISTS freight.facility_handling_events ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), booking_id uuid NOT NULL REFERENCES freight.bookings(id), yard_id uuid NOT NULL REFERENCES freight.yards(id), train_schedule_id uuid NULL REFERENCES freight.train_schedules(id), event_type varchar(10) NOT NULL, grn_number varchar(60) NULL, quantity numeric(14, 3) NULL, weight_tons numeric(14, 3) NULL, inventory_id uuid NULL REFERENCES freight.warehouse_inventory(id), performed_by varchar(120) NULL, occurred_at timestamptz NOT NULL DEFAULT now(), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz NULL ) `); await queryRunner.query(` CREATE INDEX IF NOT EXISTS "IDX_facility_handling_events_booking" ON freight.facility_handling_events (booking_id) `); await queryRunner.query(` CREATE INDEX IF NOT EXISTS "IDX_facility_handling_events_yard" ON freight.facility_handling_events (yard_id) `); await queryRunner.query(` CREATE INDEX IF NOT EXISTS "IDX_facility_handling_events_grn" ON freight.facility_handling_events (grn_number) WHERE grn_number IS NOT NULL `); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(`DROP TABLE IF EXISTS freight.facility_handling_events`); await queryRunner.query(`DROP TABLE IF EXISTS freight.yard_facilities`); await queryRunner.query(` ALTER TABLE freight.yards DROP COLUMN IF EXISTS has_facility `); } }