import { MigrationInterface, QueryRunner } from "typeorm"; /** * Add the daily booking-desk close hour. * * The import booking window used to reopen only within the same EAT calendar day * as its close; a cycle whose reopen crossed midnight died at CLOSED_FOR_DAY with * capacity still free. The window now runs a daily office range [openHour, * closeHour): a not-yet-full train pauses at closeHour and resumes the next * morning at openHour, every day until it fills or departs. openHour === closeHour * means a 24-hour desk. * * `window_close_hour` on the global-rules singleton is the live config; the * matching `rule_window_close_hour` snapshot on each schedule freezes it at * creation so the batch board keeps drawing the window the customer was shown. * Both default/backfill to 17:00 (5 PM), the previous implicit office close. */ export class AddWindowCloseHour1950000000000 implements MigrationInterface { name = "AddWindowCloseHour1950000000000"; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.train_scheduling_global_rules ADD COLUMN IF NOT EXISTS window_close_hour integer NOT NULL DEFAULT 17; `); await queryRunner.query(` ALTER TABLE freight.train_schedules ADD COLUMN IF NOT EXISTS rule_window_close_hour integer; `); // Backfill the snapshot from the global-rules singleton so pre-existing // schedules keep projecting reopen cycles. await queryRunner.query(` UPDATE freight.train_schedules ts SET rule_window_close_hour = COALESCE(ts.rule_window_close_hour, r.window_close_hour) FROM freight.train_scheduling_global_rules r WHERE ts.rule_window_close_hour IS NULL; `); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS rule_window_close_hour; `); await queryRunner.query(` ALTER TABLE freight.train_scheduling_global_rules DROP COLUMN IF EXISTS window_close_hour; `); } }