import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; /** * Create freight.last_mile_requests — the pre-approval confirmation stage that * sits in front of freight.last_mile: a train departs Djibouti, the customer * confirms which containers go via EDR last-mile, and the Truck & Machinery * chief approves/rejects before a freight.last_mile execution record exists. */ export class CreateLastMileRequests3250000000000 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { const exists = await queryRunner.hasTable('freight.last_mile_requests'); if (exists) return; await queryRunner.createTable( new Table({ name: 'freight.last_mile_requests', columns: [ { name: 'id', type: 'uuid', isPrimary: true, default: 'gen_random_uuid()' }, { name: 'booking_id', type: 'uuid', isNullable: false }, { name: 'train_schedule_id', type: 'uuid', isNullable: false }, { name: 'status', type: 'varchar', length: '30', default: `'AWAITING_CONFIRMATION'`, isNullable: false, }, { name: 'requested_container_numbers', type: 'text', isArray: true, isNullable: true }, { name: 'reminder_sent_at', type: 'timestamptz', isNullable: true }, { name: 'submitted_by_user_id', type: 'uuid', isNullable: true }, { name: 'submitted_at', type: 'timestamptz', isNullable: true }, { name: 'reviewed_by_staff_id', type: 'uuid', isNullable: true }, { name: 'reviewed_at', type: 'timestamptz', isNullable: true }, { name: 'rejection_reason', type: 'text', isNullable: true }, { name: 'resulting_last_mile_id', type: 'uuid', isNullable: true }, { name: 'created_at', type: 'timestamptz', default: 'now()' }, { name: 'updated_at', type: 'timestamptz', default: 'now()' }, { name: 'deleted_at', type: 'timestamptz', isNullable: true }, ], }), true, ); await queryRunner.createForeignKey( 'freight.last_mile_requests', new TableForeignKey({ columnNames: ['booking_id'], referencedTableName: 'freight.bookings', referencedColumnNames: ['id'], onDelete: 'CASCADE', }), ); await queryRunner.createForeignKey( 'freight.last_mile_requests', new TableForeignKey({ columnNames: ['train_schedule_id'], referencedTableName: 'freight.train_schedules', referencedColumnNames: ['id'], onDelete: 'CASCADE', }), ); await queryRunner.createForeignKey( 'freight.last_mile_requests', new TableForeignKey({ columnNames: ['resulting_last_mile_id'], referencedTableName: 'freight.last_mile', referencedColumnNames: ['id'], onDelete: 'SET NULL', }), ); // One request per booking per departure — remind()/submit() are idempotent on this. await queryRunner.query( `CREATE UNIQUE INDEX IF NOT EXISTS "IDX_last_mile_requests_booking_schedule" ON "freight"."last_mile_requests" ("booking_id", "train_schedule_id") WHERE "deleted_at" IS NULL`, ); await queryRunner.query( `CREATE INDEX IF NOT EXISTS "IDX_last_mile_requests_status" ON "freight"."last_mile_requests" ("status")`, ); } public async down(queryRunner: QueryRunner): Promise { const exists = await queryRunner.hasTable('freight.last_mile_requests'); if (exists) { await queryRunner.dropTable('freight.last_mile_requests'); } } }