import { MigrationInterface, QueryRunner } from "typeorm"; /** * Snapshot the booking-window rule onto each train schedule. * * A schedule's window (open time + reopen cycles) must be frozen to the rule it * was created with: a later global-rules edit applies only to FUTURE schedules, * while an already-open schedule keeps its base rule. Previously the batch board * recomputed windows from the LIVE global config, so editing the rule redrew the * board for open schedules (a synthetic grid that no longer matched the window * the customer was shown). These columns give the board a per-schedule rule to * derive its display windows from. * * Existing rows are backfilled from the current global-rules singleton — the best * available base, since they never stored one. Their stamped windowOpensAt/ * windowClosesAt are still real, so only projected reopen cycles rely on the * backfill. */ export class AddScheduleWindowRuleSnapshot1920000000000 implements MigrationInterface { name = "AddScheduleWindowRuleSnapshot1920000000000"; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.train_schedules ADD COLUMN IF NOT EXISTS rule_window_open_hour integer, ADD COLUMN IF NOT EXISTS rule_window_duration_hours numeric(6, 4), ADD COLUMN IF NOT EXISTS rule_reopen_delay_minutes integer, ADD COLUMN IF NOT EXISTS rule_import_window_lead_days integer, ADD COLUMN IF NOT EXISTS rule_export_booking_lead_hours integer; `); // Backfill from the global-rules singleton so pre-existing schedules render. await queryRunner.query(` UPDATE freight.train_schedules ts SET rule_window_open_hour = COALESCE(ts.rule_window_open_hour, r.window_open_hour), rule_window_duration_hours = COALESCE(ts.rule_window_duration_hours, r.window_duration_hours), rule_reopen_delay_minutes = COALESCE(ts.rule_reopen_delay_minutes, r.reopen_delay_minutes), rule_import_window_lead_days = COALESCE(ts.rule_import_window_lead_days, r.import_window_lead_days), rule_export_booking_lead_hours = COALESCE(ts.rule_export_booking_lead_hours, r.export_booking_lead_hours) FROM freight.train_scheduling_global_rules r WHERE ts.rule_window_open_hour IS NULL; `); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS rule_window_open_hour, DROP COLUMN IF EXISTS rule_window_duration_hours, DROP COLUMN IF EXISTS rule_reopen_delay_minutes, DROP COLUMN IF EXISTS rule_import_window_lead_days, DROP COLUMN IF EXISTS rule_export_booking_lead_hours; `); } }