diff --git a/.claude/skills/edr-db/SKILL.md b/.claude/skills/edr-db/SKILL.md index 47333128d..dde5f4b8a 100644 --- a/.claude/skills/edr-db/SKILL.md +++ b/.claude/skills/edr-db/SKILL.md @@ -11,7 +11,7 @@ One script, runs from anywhere in the repo (resolves `pg` from `apps/edr-freight node .claude/skills/edr-db/query.cjs "SELECT ... " # run SQL, console.table output node .claude/skills/edr-db/query.cjs explain "SELECT ..." # EXPLAIN-validate only (no rows touched) node .claude/skills/edr-db/query.cjs columns # freight.
column list -node .claude/skills/edr-db/query.cjs migrations [like] # public.migrations rows (newest first) +node .claude/skills/edr-db/query.cjs migrations [like] # migration rows, newest first (freight.migrations + iam.typeorm_migrations) node .claude/skills/edr-db/query.cjs drift
# bare column names, for diffing vs the entity ``` @@ -31,7 +31,11 @@ defaulting to the shared dev database (`edr_dev`). (`WHERE NOT EXISTS` guards) — watch-mode API instances race `migrationsRun`, and non-idempotent statements have double-run here before. - Timestamps for new migrations: must be unique across `src/migrations/` AND - higher than `SELECT max(timestamp) FROM public.migrations`. + higher than `SELECT max(timestamp) FROM freight.migrations`. +- Freight and IAM keep separate histories: `freight.migrations` for + `apps/edr-freight-api/src/migrations/*`, `iam.typeorm_migrations` for the + `@tria-plc/iamapi-common` migrations. `public.migrations` is the pre-split + table, left in place for rollback — never write to it. ## Diagnosing a pasted 400/500 (the recurring loop) diff --git a/.claude/skills/edr-db/query.cjs b/.claude/skills/edr-db/query.cjs index b4797bd45..6f41f555b 100644 --- a/.claude/skills/edr-db/query.cjs +++ b/.claude/skills/edr-db/query.cjs @@ -8,7 +8,7 @@ * node .claude/skills/edr-db/query.cjs "SELECT ... " run SQL (console.table) * node .claude/skills/edr-db/query.cjs explain "SELECT..." EXPLAIN-validate only * node .claude/skills/edr-db/query.cjs columns
list freight.
columns - * node .claude/skills/edr-db/query.cjs migrations [like] public.migrations rows + * node .claude/skills/edr-db/query.cjs migrations [like] freight/iam migration rows * node .claude/skills/edr-db/query.cjs drift
columns vs entity check helper * * Connection: DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME env vars, falling @@ -52,12 +52,27 @@ async function main() { console.table(r.rows); } else if (first === 'migrations') { const like = rest[0] ? `%${rest[0]}%` : '%'; - const r = await c.query( - `SELECT id, timestamp, name FROM public.migrations - WHERE name ILIKE $1 ORDER BY id DESC LIMIT 40`, - [like], - ); - console.table(r.rows); + // Histories are split per owner: freight.migrations (this app) and + // iam.typeorm_migrations (@tria-plc/iamapi-common). public.migrations is the + // pre-split table, kept for rollback — read it only if the split has not + // been applied to this DB yet. + const sources = [ + ['freight', 'freight.migrations'], + ['iam', 'iam.typeorm_migrations'], + ['legacy', 'public.migrations'], + ]; + const rows = []; + for (const [owner, table] of sources) { + const present = await c.query(`SELECT to_regclass($1) IS NOT NULL AS ok`, [table]); + if (!present.rows[0].ok) continue; + const r = await c.query( + `SELECT id, timestamp, name FROM ${table} + WHERE name ILIKE $1 ORDER BY id DESC LIMIT 40`, + [like], + ); + rows.push(...r.rows.map((row) => ({ owner, ...row }))); + } + console.table(rows); } else if (first === 'drift') { // Quick drift signal: DB columns for the table. Compare by eye against // the entity's @Column names; a recorded-but-absent column = drift. diff --git a/apps/edr-freight-api/src/config/database.config.ts b/apps/edr-freight-api/src/config/database.config.ts index 0591cd0b1..f699b193d 100644 --- a/apps/edr-freight-api/src/config/database.config.ts +++ b/apps/edr-freight-api/src/config/database.config.ts @@ -118,30 +118,91 @@ const iamMigrationsGlob = join( ); const freightMigrationsGlob = join(__dirname, "../migrations/*.js"); -export function buildDataSourceOptions(): DataSourceOptions { +/** + * Migration history is split per owner instead of sharing one `public.migrations` + * table: + * + * - IAM migrations ship with `@tria-plc/iamapi-common`, target the `iam` schema + * and are recorded in `iam.typeorm_migrations` — the same table the package's + * own CLI (`pnpm iam:migration:run|show|revert`) uses, so both paths agree on + * what has been applied. + * - Freight migrations are recorded in `freight.migrations`. + * + * `public.migrations` is the pre-split table; `src/scripts/migrate.ts` adopts its + * rows into the two tables above on first run and then leaves it untouched. + */ +export const IAM_MIGRATIONS = { + schema: "iam", + table: "typeorm_migrations", +} as const; + +export const FREIGHT_MIGRATIONS = { + schema: "freight", + table: "migrations", +} as const; + +export const LEGACY_MIGRATIONS = { + schema: "public", + table: "migrations", +} as const; + +function buildConnectionOptions() { return { - type: "postgres", + type: "postgres" as const, host: process.env.DB_HOST ?? "localhost", port: parseInt(process.env.DB_PORT ?? "5433", 10), username: process.env.DB_USER ?? "postgres", password: process.env.DB_PASSWORD ?? "", database: process.env.DB_NAME ?? "edr_freight", - schema: "public", // NOTE: do NOT pass `extra.options: '-c search_path=...'`. That sends the // Postgres startup `options` parameter, which connection poolers (PgBouncer / // proxies fronting the remote edr_dev DB) reject with // `08P01 unsupported startup parameter in options: search_path`. // The search_path is instead applied per-connection via a pool `connect` - // handler in app.module.ts (see setPoolSearchPath). - entities: [__dirname + "/../**/*.entity.{ts,js}", ...iamEntities], - migrations: [ - iamMigrationsGlob, - freightMigrationsGlob, - ], - migrationsTransactionMode: "each", + // handler (app.module.ts `setPoolSearchPath`, migrate.ts `applySearchPath`). synchronize: false, logging: - process.env.TYPEORM_LOGGING === "true" ? true : ["error", "warn"], + process.env.TYPEORM_LOGGING === "true" + ? true + : (["error", "warn"] as DataSourceOptions["logging"]), + }; +} + +/** + * Runtime options for the API (and the seed scripts using `AppDataSource`). + * Carries no migrations: migrations run only through `src/scripts/migrate.ts`, + * which uses the two dedicated DataSources below. + */ +export function buildDataSourceOptions(): DataSourceOptions { + return { + ...buildConnectionOptions(), + schema: "public", + entities: [__dirname + "/../**/*.entity.{ts,js}", ...iamEntities], + migrations: [], + }; +} + +/** IAM migrations only, recorded in `iam.typeorm_migrations`. */ +export function buildIamMigrationDataSourceOptions(): DataSourceOptions { + return { + ...buildConnectionOptions(), + schema: IAM_MIGRATIONS.schema, + entities: [], + migrations: [iamMigrationsGlob], + migrationsTableName: IAM_MIGRATIONS.table, + migrationsTransactionMode: "each", + }; +} + +/** Freight migrations only, recorded in `freight.migrations`. */ +export function buildFreightMigrationDataSourceOptions(): DataSourceOptions { + return { + ...buildConnectionOptions(), + schema: FREIGHT_MIGRATIONS.schema, + entities: [], + migrations: [freightMigrationsGlob], + migrationsTableName: FREIGHT_MIGRATIONS.table, + migrationsTransactionMode: "each", }; } diff --git a/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts b/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts index 99fbcab61..0f359a942 100644 --- a/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts +++ b/apps/edr-freight-api/src/config/ensure-postgres-schemas.ts @@ -10,6 +10,13 @@ export const APPLICATION_SCHEMAS = [ export const APPLICATION_SEARCH_PATH = APPLICATION_SCHEMAS.join(","); +/** + * Extensions the migrations call into but never create themselves — both the IAM + * package's migrations and the freight baseline default columns to + * `uuid_generate_v4()` / `gen_random_uuid()`. + */ +export const APPLICATION_EXTENSIONS = ["uuid-ossp", "pgcrypto"] as const; + /** * TypeORM creates the migrations table before any migration runs. If `public` was * dropped, current_schema() is null and CREATE TABLE migrations fails. @@ -42,6 +49,20 @@ export async function ensurePostgresSchemas( } } + // Best effort: creating an extension needs elevated rights the app user may not + // have. On an established database they are already installed and this is a + // no-op, so a failure here is only fatal for a brand-new database — where the + // first migration will fail loudly on the missing function anyway. + for (const extension of APPLICATION_EXTENSIONS) { + try { + await bootstrap.query(`CREATE EXTENSION IF NOT EXISTS "${extension}"`); + } catch (err) { + console.warn( + `could not ensure extension "${extension}": ${(err as Error).message}`, + ); + } + } + await bootstrap.query( `SET search_path TO ${APPLICATION_SEARCH_PATH}`, ); diff --git a/apps/edr-freight-api/src/migrations/1748427600000-AddServiceTypesAndCargoTypes.ts b/apps/edr-freight-api/src/migrations/1748427600000-AddServiceTypesAndCargoTypes.ts deleted file mode 100644 index 08ce634eb..000000000 --- a/apps/edr-freight-api/src/migrations/1748427600000-AddServiceTypesAndCargoTypes.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex, TableForeignKey } from "typeorm"; - -export class AddServiceTypesAndCargoTypes1748427600000 implements MigrationInterface { - name = "AddServiceTypesAndCargoTypes1748427600000"; - - public async up(queryRunner: QueryRunner): Promise { - // Create service_types table - if (!(await queryRunner.hasTable("freight.service_types"))) await queryRunner.createTable( - new Table({ - name: "service_types", - schema: "freight", - columns: [ - { - name: "id", - type: "uuid", - isPrimary: true, - generationStrategy: "uuid", - default: "uuid_generate_v4()", - }, - { - name: "service_name", - type: "varchar", - length: "255", - isNullable: false, - }, - { - name: "description", - type: "text", - isNullable: true, - }, - { - name: "can_be_booked_alone", - type: "boolean", - default: true, - isNullable: false, - }, - { - name: "includes_first_mile", - type: "boolean", - default: false, - isNullable: false, - }, - { - name: "includes_last_mile", - type: "boolean", - default: false, - isNullable: false, - }, - { - name: "includes_customs", - type: "boolean", - default: false, - isNullable: false, - }, - { - name: "priority_bonus_points", - type: "int", - default: 0, - isNullable: false, - }, - { - name: "is_active", - type: "boolean", - default: true, - isNullable: false, - }, - { - name: "display_order", - type: "int", - default: 1, - isNullable: false, - }, - { - name: "created_at", - type: "timestamptz", - default: "now()", - isNullable: false, - }, - { - name: "updated_at", - type: "timestamptz", - default: "now()", - isNullable: false, - }, - { - name: "deleted_at", - type: "timestamptz", - isNullable: true, - }, - ], - }), - true, - ); - - // Create indexes for service_types - const table = await queryRunner.getTable("freight.service_types"); - if (table && !table.indices.some((idx) => idx.name === "IDX_SERVICE_TYPES_IS_ACTIVE")) { - await queryRunner.createIndex( - "freight.service_types", - new TableIndex({ - name: "IDX_SERVICE_TYPES_IS_ACTIVE", - columnNames: ["is_active"], - }), - ); - } - if (table && !table.indices.some((idx) => idx.name === "IDX_SERVICE_TYPES_DISPLAY_ORDER")) { - await queryRunner.createIndex( - "freight.service_types", - new TableIndex({ - name: "IDX_SERVICE_TYPES_DISPLAY_ORDER", - columnNames: ["display_order"], - }), - ); - } - - // Create cargo_types table - if (!(await queryRunner.hasTable("freight.cargo_types"))) await queryRunner.createTable( - new Table({ - name: "cargo_types", - schema: "freight", - columns: [ - { - name: "id", - type: "uuid", - isPrimary: true, - generationStrategy: "uuid", - default: "uuid_generate_v4()", - }, - { - name: "cargo_type_name", - type: "varchar", - length: "255", - isNullable: false, - }, - { - name: "parent_group_id", - type: "uuid", - isNullable: true, - }, - { - name: "show_free_text_box", - type: "boolean", - default: false, - isNullable: false, - }, - { - name: "requires_director_approval", - type: "boolean", - default: false, - isNullable: false, - }, - { - name: "is_active", - type: "boolean", - default: true, - isNullable: false, - }, - { - name: "display_order", - type: "int", - default: 1, - isNullable: false, - }, - { - name: "created_at", - type: "timestamptz", - default: "now()", - isNullable: false, - }, - { - name: "updated_at", - type: "timestamptz", - default: "now()", - isNullable: false, - }, - { - name: "deleted_at", - type: "timestamptz", - isNullable: true, - }, - ], - }), - true, - ); - - // Create indexes for cargo_types - await queryRunner.createIndex( - "freight.cargo_types", - new TableIndex({ - name: "IDX_CARGO_TYPES_IS_ACTIVE", - columnNames: ["is_active"], - }), - ); - await queryRunner.createIndex( - "freight.cargo_types", - new TableIndex({ - name: "IDX_CARGO_TYPES_DISPLAY_ORDER", - columnNames: ["display_order"], - }), - ); - await queryRunner.createIndex( - "freight.cargo_types", - new TableIndex({ - name: "IDX_CARGO_TYPES_PARENT_GROUP_ID", - columnNames: ["parent_group_id"], - }), - ); - - // Create self-referencing foreign key for cargo_types - await queryRunner.createForeignKey( - "freight.cargo_types", - new TableForeignKey({ - name: "FK_CARGO_TYPES_PARENT_GROUP", - columnNames: ["parent_group_id"], - referencedSchema: "freight", - referencedTableName: "cargo_types", - referencedColumnNames: ["id"], - onDelete: "SET NULL", - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - // Drop foreign key first - await queryRunner.dropForeignKey("freight.cargo_types", "FK_CARGO_TYPES_PARENT_GROUP"); - - // Drop cargo_types table - await queryRunner.dropTable("freight.cargo_types", true); - - // Drop service_types table - await queryRunner.dropTable("freight.service_types", true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748514000000-AddRuleEngineTablesAndCodes.ts b/apps/edr-freight-api/src/migrations/1748514000000-AddRuleEngineTablesAndCodes.ts deleted file mode 100644 index e1a9f6aeb..000000000 --- a/apps/edr-freight-api/src/migrations/1748514000000-AddRuleEngineTablesAndCodes.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { - MigrationInterface, - QueryRunner, - Table, - TableIndex, - TableForeignKey, - TableColumn, -} from 'typeorm'; - -export class AddRuleEngineTablesAndCodes1748514000000 implements MigrationInterface { - name = 'AddRuleEngineTablesAndCodes1748514000000'; - - public async up(queryRunner: QueryRunner): Promise { - // ── 1. Add `code` column to existing tables ─────────────────────────── - - if (!(await queryRunner.hasColumn('freight.service_types', 'code'))) { - await queryRunner.addColumn( - 'freight.service_types', - new TableColumn({ - name: 'code', - type: 'varchar', - length: '50', - isNullable: true, - }), - ); - } - await queryRunner.query( - `UPDATE freight.service_types SET code = upper(replace(service_name, ' ', '_')) WHERE code IS NULL OR code = ''`, - ); - await queryRunner.query( - `UPDATE freight.service_types SET code = 'SERVICE_' || substring(id::text, 1, 8) WHERE code IS NULL`, - ); - await queryRunner.query( - `ALTER TABLE freight.service_types ALTER COLUMN code SET NOT NULL`, - ); - const serviceTypesCodeIdx = await queryRunner.query( - `SELECT 1 FROM pg_indexes WHERE schemaname = 'freight' AND indexname = 'idx_service_types_code' LIMIT 1`, - ); - if (serviceTypesCodeIdx.length === 0) { - await queryRunner.createIndex( - 'freight.service_types', - new TableIndex({ name: 'IDX_service_types_code', columnNames: ['code'], isUnique: true }), - ); - } - - if (!(await queryRunner.hasColumn('freight.cargo_types', 'code'))) { - await queryRunner.addColumn( - 'freight.cargo_types', - new TableColumn({ - name: 'code', - type: 'varchar', - length: '50', - isNullable: true, - }), - ); - } - await queryRunner.query( - `UPDATE freight.cargo_types SET code = upper(replace(cargo_type_name, ' ', '_')) WHERE code IS NULL OR code = ''`, - ); - await queryRunner.query( - `UPDATE freight.cargo_types SET code = 'CARGO_' || substring(id::text, 1, 8) WHERE code IS NULL`, - ); - await queryRunner.query( - `ALTER TABLE freight.cargo_types ALTER COLUMN code SET NOT NULL`, - ); - const cargoTypesCodeIdx = await queryRunner.query( - `SELECT 1 FROM pg_indexes WHERE schemaname = 'freight' AND indexname = 'idx_cargo_types_code' LIMIT 1`, - ); - if (cargoTypesCodeIdx.length === 0) { - await queryRunner.createIndex( - 'freight.cargo_types', - new TableIndex({ name: 'IDX_cargo_types_code', columnNames: ['code'], isUnique: true }), - ); - } - - // ── 2. surcharge_types ──────────────────────────────────────────────── - - if (!(await queryRunner.hasTable('freight.surcharge_types'))) await queryRunner.createTable( - new Table({ - name: 'surcharge_types', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'code', type: 'varchar', length: '50', isNullable: false }, - { name: 'name', type: 'varchar', length: '100', isNullable: false }, - { name: 'description', type: 'text', isNullable: true }, - { name: 'is_active', type: 'boolean', default: 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.createIndex( - 'freight.surcharge_types', - new TableIndex({ name: 'IDX_surcharge_types_code', columnNames: ['code'], isUnique: true }), - ); - await queryRunner.createIndex( - 'freight.surcharge_types', - new TableIndex({ name: 'IDX_surcharge_types_is_active', columnNames: ['is_active'] }), - ); - - // ── 3. surcharges ───────────────────────────────────────────────────── - - if (!(await queryRunner.hasTable('freight.surcharges'))) await queryRunner.createTable( - new Table({ - name: 'surcharges', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'surcharge_type_id', type: 'uuid', isNullable: false }, - { name: 'fee_name', type: 'varchar', length: '255', isNullable: false }, - { name: 'trigger_description', type: 'text', isNullable: true }, - { - name: 'calculation_method', - type: 'enum', - enum: ['PER_TON', 'FLAT_FEE', 'PERCENTAGE'], - default: `'PER_TON'`, - }, - { name: 'rate', type: 'numeric', precision: 10, scale: 2, isNullable: false }, - { name: 'currency', type: 'char', length: '3', default: `'USD'` }, - { name: 'apply_to_rail', type: 'boolean', default: false }, - { name: 'apply_to_first_mile', type: 'boolean', default: false }, - { name: 'apply_to_last_mile', type: 'boolean', default: false }, - { name: 'is_active', type: 'boolean', default: 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.surcharges', - new TableForeignKey({ - name: 'FK_surcharges_surcharge_type', - columnNames: ['surcharge_type_id'], - referencedTableName: 'freight.surcharge_types', - referencedColumnNames: ['id'], - onDelete: 'RESTRICT', - }), - ); - await queryRunner.createIndex( - 'freight.surcharges', - new TableIndex({ name: 'IDX_surcharges_surcharge_type_id', columnNames: ['surcharge_type_id'] }), - ); - await queryRunner.createIndex( - 'freight.surcharges', - new TableIndex({ name: 'IDX_surcharges_is_active', columnNames: ['is_active'] }), - ); - - // ── 4. container_types ──────────────────────────────────────────────── - - if (!(await queryRunner.hasTable('freight.container_types'))) await queryRunner.createTable( - new Table({ - name: 'container_types', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'size_code', type: 'varchar', length: '20', isNullable: false }, - { name: 'description', type: 'varchar', length: '100', isNullable: true }, - { name: 'containers_per_wagon', type: 'int', isNullable: false }, - { name: 'is_active', type: 'boolean', default: 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.createIndex( - 'freight.container_types', - new TableIndex({ name: 'IDX_container_types_size_code', columnNames: ['size_code'], isUnique: true }), - ); - await queryRunner.createIndex( - 'freight.container_types', - new TableIndex({ name: 'IDX_container_types_is_active', columnNames: ['is_active'] }), - ); - - // ── 5. weight_limit_rules ───────────────────────────────────────────── - - if (!(await queryRunner.hasTable('freight.weight_limit_rules'))) await queryRunner.createTable( - new Table({ - name: 'weight_limit_rules', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'container_type_id', type: 'uuid', isNullable: false }, - { - name: 'trade_direction', - type: 'enum', - enum: ['IMPORT', 'EXPORT', 'BOTH'], - isNullable: false, - }, - { name: 'max_weight_tons', type: 'numeric', precision: 10, scale: 2, isNullable: false }, - { name: 'warning_threshold_tons', type: 'numeric', precision: 10, scale: 2, isNullable: false }, - { - name: 'exceeded_action', - type: 'enum', - enum: ['WARNING_ONLY', 'HARD_BLOCK'], - default: `'WARNING_ONLY'`, - }, - { name: 'surcharge_id', type: 'uuid', isNullable: true }, - { name: 'is_active', type: 'boolean', default: 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.weight_limit_rules', - new TableForeignKey({ - name: 'FK_weight_limit_rules_container_type', - columnNames: ['container_type_id'], - referencedTableName: 'freight.container_types', - referencedColumnNames: ['id'], - onDelete: 'RESTRICT', - }), - ); - await queryRunner.createForeignKey( - 'freight.weight_limit_rules', - new TableForeignKey({ - name: 'FK_weight_limit_rules_surcharge', - columnNames: ['surcharge_id'], - referencedTableName: 'freight.surcharges', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - await queryRunner.createIndex( - 'freight.weight_limit_rules', - new TableIndex({ name: 'IDX_weight_limit_rules_container_type_id', columnNames: ['container_type_id'] }), - ); - await queryRunner.createIndex( - 'freight.weight_limit_rules', - new TableIndex({ name: 'IDX_weight_limit_rules_surcharge_id', columnNames: ['surcharge_id'] }), - ); - await queryRunner.createIndex( - 'freight.weight_limit_rules', - new TableIndex({ name: 'IDX_weight_limit_rules_is_active', columnNames: ['is_active'] }), - ); - - // ── 6. priority_rules ───────────────────────────────────────────────── - - if (!(await queryRunner.hasTable('freight.priority_rules'))) await queryRunner.createTable( - new Table({ - name: 'priority_rules', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { - name: 'priority_type', - type: 'enum', - enum: ['USD_PAYER', 'RAIL_AND_FORWARDING', 'GOVERNMENT_ACCOUNT', 'HIGH_VOLUME_SHIPMENT'], - isNullable: false, - }, - { name: 'rule_name', type: 'varchar', length: '255', isNullable: false }, - { name: 'description', type: 'text', isNullable: true }, - { name: 'activation_condition', type: 'text', isNullable: true }, - { name: 'bonus_points', type: 'int', default: 0 }, - { name: 'is_active', type: 'boolean', default: false }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - await queryRunner.createIndex( - 'freight.priority_rules', - new TableIndex({ name: 'IDX_priority_rules_priority_type', columnNames: ['priority_type'], isUnique: true }), - ); - await queryRunner.createIndex( - 'freight.priority_rules', - new TableIndex({ name: 'IDX_priority_rules_is_active', columnNames: ['is_active'] }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.priority_rules', true); - await queryRunner.dropTable('freight.weight_limit_rules', true); - await queryRunner.dropTable('freight.container_types', true); - await queryRunner.dropTable('freight.surcharges', true); - await queryRunner.dropTable('freight.surcharge_types', true); - await queryRunner.dropIndex('freight.cargo_types', 'IDX_cargo_types_code'); - await queryRunner.dropColumn('freight.cargo_types', 'code'); - await queryRunner.dropIndex('freight.service_types', 'IDX_service_types_code'); - await queryRunner.dropColumn('freight.service_types', 'code'); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748550000000-CreateFreightLegacyBaseline.ts b/apps/edr-freight-api/src/migrations/1748550000000-CreateFreightLegacyBaseline.ts deleted file mode 100644 index 2455727bf..000000000 --- a/apps/edr-freight-api/src/migrations/1748550000000-CreateFreightLegacyBaseline.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Pre-ITMLS baseline for fresh databases. Older environments created `freight.bookings` - * via synchronize or manual SQL; ItmlsFullSchemaRewrite only ALTERs that table. - */ -export class CreateFreightLegacyBaseline1748550000000 implements MigrationInterface { - name = 'CreateFreightLegacyBaseline1748550000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE SCHEMA IF NOT EXISTS freight`); - - await queryRunner.query(` - DO $$ BEGIN - CREATE TYPE freight.train_status AS ENUM ( - 'AVAILABLE', 'SCHEDULED', 'IN_SERVICE', 'UNDER_MAINTENANCE', 'OUT_OF_SERVICE' - ); - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.trains ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - code VARCHAR(32) NOT NULL UNIQUE, - capacity_tons NUMERIC(10, 2) NOT NULL DEFAULT 0, - status freight.train_status NOT NULL DEFAULT 'AVAILABLE', - notes TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.bookings ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - reference VARCHAR(64) NOT NULL UNIQUE, - customer_id UUID NOT NULL, - train_id UUID, - status VARCHAR(40) NOT NULL DEFAULT 'DRAFT', - scheduled_date TIMESTAMPTZ NOT NULL DEFAULT now(), - total_amount NUMERIC(14, 2) NOT NULL DEFAULT 0, - payment_status VARCHAR(20) NOT NULL DEFAULT 'PENDING', - contract_type VARCHAR(20) NOT NULL DEFAULT 'SPOT', - previous_contract_id UUID, - trade_direction VARCHAR(10) NOT NULL DEFAULT 'IMPORT', - equipment_return VARCHAR(20) NOT NULL DEFAULT 'RETURN', - first_mile_pickup_address TEXT, - last_mile_delivery_address TEXT, - cargo_total_weight_vgm NUMERIC(12, 3) NOT NULL DEFAULT 0, - is_hazardous BOOLEAN NOT NULL DEFAULT false, - payment_currency VARCHAR(5) NOT NULL DEFAULT 'USD', - start_date DATE, - end_date DATE, - financial_terms TEXT, - version_number INT NOT NULL DEFAULT 1, - approved_by_staff_id UUID, - approved_by_staff_at TIMESTAMPTZ, - signed_by_director_id UUID, - signed_by_director_at TIMESTAMPTZ, - signed_by_ceo_id UUID, - signed_by_ceo_at TIMESTAMPTZ, - priority_score INT NOT NULL DEFAULT 0, - allow_consolidation BOOLEAN NOT NULL DEFAULT false, - consolidation_partner_id UUID, - origin_station VARCHAR(255), - destination_station VARCHAR(255), - service_type VARCHAR(100), - freight_type VARCHAR(100), - freight_subtype VARCHAR(255), - containers JSONB, - first_mile_enabled BOOLEAN DEFAULT false, - last_mile_enabled BOOLEAN DEFAULT false, - is_refrigerated BOOLEAN DEFAULT false, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.bookings CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.trains CASCADE`); - await queryRunner.query(`DROP TYPE IF EXISTS freight.train_status`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748600000000-ItmlsFullSchemaRewrite.ts b/apps/edr-freight-api/src/migrations/1748600000000-ItmlsFullSchemaRewrite.ts deleted file mode 100644 index ce5b38c15..000000000 --- a/apps/edr-freight-api/src/migrations/1748600000000-ItmlsFullSchemaRewrite.ts +++ /dev/null @@ -1,544 +0,0 @@ -import { - MigrationInterface, - QueryRunner, - Table, - TableForeignKey, - TableIndex, - TableUnique, -} from 'typeorm'; - -export class ItmlsFullSchemaRewrite1748600000000 implements MigrationInterface { - name = 'ItmlsFullSchemaRewrite1748600000000'; - - public async up(queryRunner: QueryRunner): Promise { - // ── container_types ─────────────────────────────────────────────────── - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.container_types RENAME COLUMN size_code TO code; - EXCEPTION WHEN undefined_column THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.container_types RENAME COLUMN description TO label; - EXCEPTION WHEN undefined_column THEN NULL; - END $$; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - ADD COLUMN IF NOT EXISTS size_ft SMALLINT, - ADD COLUMN IF NOT EXISTS is_reefer BOOLEAN NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS is_open_top BOOLEAN NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS display_order INT NOT NULL DEFAULT 1; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - ADD COLUMN IF NOT EXISTS wagons_per_unit NUMERIC(4,2); - `); - await queryRunner.query(` - UPDATE freight.container_types - SET wagons_per_unit = CASE - WHEN containers_per_wagon > 0 THEN ROUND(1.0 / containers_per_wagon, 2) - ELSE 1.00 - END - WHERE wagons_per_unit IS NULL; - `); - await queryRunner.query(` - UPDATE freight.container_types - SET size_ft = CASE WHEN code LIKE '40%' OR code LIKE '%40%' THEN 40 ELSE 20 END - WHERE size_ft IS NULL; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - ALTER COLUMN wagons_per_unit SET NOT NULL, - DROP COLUMN IF EXISTS containers_per_wagon; - `); - - // ── weight_limit_rules ────────────────────────────────────────────────── - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.weight_limit_rules RENAME COLUMN max_weight_tons TO max_vgm_tons; - EXCEPTION WHEN undefined_column THEN NULL; - END $$; - `); - await queryRunner.query(` - ALTER TABLE freight.weight_limit_rules - ALTER COLUMN max_vgm_tons TYPE NUMERIC(8,3); - `); - await queryRunner.query(` - ALTER TABLE freight.weight_limit_rules - ADD COLUMN IF NOT EXISTS effective_from DATE NOT NULL DEFAULT CURRENT_DATE, - ADD COLUMN IF NOT EXISTS effective_to DATE; - `); - await queryRunner.query(` - ALTER TABLE freight.weight_limit_rules - DROP COLUMN IF EXISTS warning_threshold_tons, - DROP COLUMN IF EXISTS exceeded_action, - DROP COLUMN IF EXISTS surcharge_id, - DROP COLUMN IF EXISTS is_active; - `); - - // ── priority_rules ──────────────────────────────────────────────────── - await queryRunner.query(` - ALTER TABLE freight.priority_rules - ADD COLUMN IF NOT EXISTS code VARCHAR(40), - ADD COLUMN IF NOT EXISTS label VARCHAR(100), - ADD COLUMN IF NOT EXISTS score INT NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS condition_currency VARCHAR(5); - `); - await queryRunner.query(` - UPDATE freight.priority_rules - SET code = COALESCE(code, upper(priority_type::text)), - label = COALESCE(label, rule_name), - score = COALESCE(score, bonus_points) - WHERE code IS NULL OR label IS NULL; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_rules - DROP COLUMN IF EXISTS priority_type, - DROP COLUMN IF EXISTS rule_name, - DROP COLUMN IF EXISTS bonus_points, - DROP COLUMN IF EXISTS activation_condition, - DROP COLUMN IF EXISTS description; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_rules - ALTER COLUMN code SET NOT NULL, - ALTER COLUMN label SET NOT NULL; - `); - await queryRunner.createIndex( - 'freight.priority_rules', - new TableIndex({ name: 'UQ_priority_rules_code', columnNames: ['code'], isUnique: true }), - ); - - // ── rates (before surcharge_types.rate_id) ──────────────────────────── - await queryRunner.createTable( - new Table({ - name: 'rates', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'rate_type', type: 'varchar', length: '50' }, - { name: 'container_type_id', type: 'uuid', isNullable: true }, - { name: 'trade_direction', type: 'varchar', length: '10', isNullable: true }, - { name: 'currency', type: 'varchar', length: '5' }, - { name: 'rate_value', type: 'numeric', precision: 14, scale: 4 }, - { name: 'rate_unit', type: 'varchar', length: '30' }, - { name: 'status', type: 'varchar', length: '20', default: "'DRAFT'" }, - { name: 'proposed_by_staff_id', type: 'uuid' }, - { name: 'approved_by_ceo_id', type: 'uuid', isNullable: true }, - { name: 'approved_at', type: 'timestamptz', isNullable: true }, - { name: 'effective_from', type: 'date' }, - { name: 'effective_to', type: 'date', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - - // ── surcharge_types ─────────────────────────────────────────────────── - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.surcharge_types RENAME COLUMN name TO label; - EXCEPTION WHEN undefined_column THEN NULL; - END $$; - `); - await queryRunner.query(` - ALTER TABLE freight.surcharge_types - ADD COLUMN IF NOT EXISTS trigger_condition VARCHAR(50), - ADD COLUMN IF NOT EXISTS rate_id UUID; - `); - await queryRunner.query(`ALTER TABLE freight.surcharge_types DROP COLUMN IF EXISTS description`); - - await queryRunner.query(`DROP TABLE IF EXISTS freight.surcharges CASCADE`); - - // ── yards ───────────────────────────────────────────────────────────── - await queryRunner.createTable( - new Table({ - name: 'yards', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'code', type: 'varchar', length: '20' }, - { name: 'label', type: 'varchar', length: '100' }, - { name: 'country', type: 'varchar', length: '50' }, - { name: 'is_active', type: 'boolean', default: true }, - { name: 'display_order', type: 'int', default: 1 }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - await queryRunner.createIndex( - 'freight.yards', - new TableIndex({ name: 'UQ_yards_code', columnNames: ['code'], isUnique: true }), - ); - - // ── shipping_lines ──────────────────────────────────────────────────── - await queryRunner.createTable( - new Table({ - name: 'shipping_lines', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'code', type: 'varchar', length: '20' }, - { name: 'label', type: 'varchar', length: '100' }, - { name: 'mapped_to_code', type: 'varchar', length: '20', isNullable: true }, - { name: 'show_extra_fee_notice', type: 'boolean', default: false }, - { name: 'is_active', type: 'boolean', default: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - - // ── approval_rules ──────────────────────────────────────────────────── - await queryRunner.createTable( - new Table({ - name: 'approval_rules', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'requires_director_approval', type: 'boolean' }, - { name: 'step_order', type: 'smallint' }, - { name: 'required_role', type: 'varchar', length: '30' }, - { name: 'action_label', type: 'varchar', length: '50' }, - { name: 'blocks_role', type: 'varchar', length: '30', 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.createUniqueConstraint( - 'freight.approval_rules', - new TableUnique({ - name: 'UQ_approval_rules_chain_step', - columnNames: ['requires_director_approval', 'step_order'], - }), - ); - - // ── bookings ──────────────────────────────────────────────────────── - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS origin_yard_id UUID, - ADD COLUMN IF NOT EXISTS destination_yard_id UUID, - ADD COLUMN IF NOT EXISTS service_type_id UUID, - ADD COLUMN IF NOT EXISTS cargo_type_id UUID, - ADD COLUMN IF NOT EXISTS cargo_free_text VARCHAR(200), - ADD COLUMN IF NOT EXISTS shipping_line_id UUID, - ADD COLUMN IF NOT EXISTS pnr_code VARCHAR(50), - ADD COLUMN IF NOT EXISTS customer_signed_at TIMESTAMPTZ, - ADD COLUMN IF NOT EXISTS fully_executed_at TIMESTAMPTZ; - `); - - await queryRunner.query(` - INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at) - VALUES - (uuid_generate_v4(), 'KALITY', 'Kality Rail Terminal', 'Ethiopia', true, 1, now(), now()), - (uuid_generate_v4(), 'MOJO', 'Mojo Dry Port', 'Ethiopia', true, 2, now(), now()), - (uuid_generate_v4(), 'DIRE_DAWA', 'Dire Dawa Yard', 'Ethiopia', true, 3, now(), now()), - (uuid_generate_v4(), 'DJIB_PORT', 'Djibouti Port Terminal', 'Djibouti', true, 4, now(), now()), - (uuid_generate_v4(), 'NAGAD', 'Nagad Terminal, Djibouti', 'Djibouti', true, 5, now(), now()), - (uuid_generate_v4(), 'LEGACY_ORIGIN', 'Legacy Origin', 'Ethiopia', true, 99, now(), now()), - (uuid_generate_v4(), 'LEGACY_DEST', 'Legacy Destination', 'Ethiopia', true, 100, now(), now()) - ON CONFLICT (code) DO NOTHING; - `); - - await queryRunner.query(` - INSERT INTO freight.service_types (id, code, service_name, can_be_booked_alone, includes_first_mile, includes_last_mile, includes_customs, priority_bonus_points, is_active, display_order, created_at, updated_at) - SELECT uuid_generate_v4(), 'RAIL', 'Rail Transport Only', true, false, false, false, 0, true, 1, now(), now() - WHERE NOT EXISTS (SELECT 1 FROM freight.service_types LIMIT 1); - `); - await queryRunner.query(` - INSERT INTO freight.cargo_types (id, code, cargo_type_name, requires_director_approval, show_free_text_box, is_active, display_order, created_at, updated_at) - SELECT uuid_generate_v4(), 'GENERAL', 'General Cargo', false, false, true, 1, now(), now() - WHERE NOT EXISTS (SELECT 1 FROM freight.cargo_types LIMIT 1); - `); - - const hasServiceTypeCol = await queryRunner.query(` - SELECT 1 FROM information_schema.columns - WHERE table_schema = 'freight' AND table_name = 'bookings' AND column_name = 'service_type' - LIMIT 1; - `); - - if (hasServiceTypeCol.length > 0) { - await queryRunner.query(` - UPDATE freight.bookings b - SET service_type_id = st.id - FROM freight.service_types st - WHERE b.service_type_id IS NULL - AND ( - st.code = b.service_type - OR upper(replace(st.service_name, ' ', '_')) = upper(b.service_type) - OR st.code = upper(replace(b.service_type, ' ', '_')) - ); - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET cargo_type_id = ct.id - FROM freight.cargo_types ct - WHERE b.cargo_type_id IS NULL - AND ( - ct.code = upper(b.freight_type) - OR ct.code = upper(concat(b.freight_type, '_', coalesce(b.freight_subtype, ''))) - ); - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET cargo_free_text = b.freight_subtype - WHERE b.cargo_free_text IS NULL AND b.freight_subtype IS NOT NULL; - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET origin_yard_id = y.id - FROM freight.yards y - WHERE b.origin_yard_id IS NULL - AND (y.label ILIKE b.origin_station OR y.code = upper(replace(b.origin_station, ' ', '_'))); - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET destination_yard_id = y.id - FROM freight.yards y - WHERE b.destination_yard_id IS NULL - AND (y.label ILIKE b.destination_station OR y.code = upper(replace(b.destination_station, ' ', '_'))); - `); - } - - const defaultServiceTypeId = await queryRunner.query( - `SELECT id FROM freight.service_types ORDER BY display_order LIMIT 1`, - ); - const defaultCargoTypeId = await queryRunner.query( - `SELECT id FROM freight.cargo_types ORDER BY display_order LIMIT 1`, - ); - const legacyOriginId = await queryRunner.query( - `SELECT id FROM freight.yards WHERE code = 'LEGACY_ORIGIN' LIMIT 1`, - ); - const legacyDestId = await queryRunner.query( - `SELECT id FROM freight.yards WHERE code = 'LEGACY_DEST' LIMIT 1`, - ); - - if (defaultServiceTypeId[0]?.id) { - await queryRunner.query( - `UPDATE freight.bookings SET service_type_id = $1 WHERE service_type_id IS NULL`, - [defaultServiceTypeId[0].id], - ); - } - if (defaultCargoTypeId[0]?.id) { - await queryRunner.query( - `UPDATE freight.bookings SET cargo_type_id = $1 WHERE cargo_type_id IS NULL`, - [defaultCargoTypeId[0].id], - ); - } - if (legacyOriginId[0]?.id) { - await queryRunner.query( - `UPDATE freight.bookings SET origin_yard_id = $1 WHERE origin_yard_id IS NULL`, - [legacyOriginId[0].id], - ); - } - if (legacyDestId[0]?.id) { - await queryRunner.query( - `UPDATE freight.bookings SET destination_yard_id = $1 WHERE destination_yard_id IS NULL`, - [legacyDestId[0].id], - ); - } - - const nullBookings = await queryRunner.query( - `SELECT COUNT(*)::int AS cnt FROM freight.bookings WHERE service_type_id IS NULL OR cargo_type_id IS NULL OR origin_yard_id IS NULL OR destination_yard_id IS NULL`, - ); - if (nullBookings[0]?.cnt > 0) { - await queryRunner.query(`DELETE FROM freight.bookings WHERE service_type_id IS NULL OR cargo_type_id IS NULL OR origin_yard_id IS NULL OR destination_yard_id IS NULL`); - } - - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN service_type_id SET NOT NULL, - ALTER COLUMN cargo_type_id SET NOT NULL, - ALTER COLUMN origin_yard_id SET NOT NULL, - ALTER COLUMN destination_yard_id SET NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS origin_station, - DROP COLUMN IF EXISTS destination_station, - DROP COLUMN IF EXISTS service_type, - DROP COLUMN IF EXISTS freight_type, - DROP COLUMN IF EXISTS freight_subtype, - DROP COLUMN IF EXISTS containers, - DROP COLUMN IF EXISTS first_mile_enabled, - DROP COLUMN IF EXISTS last_mile_enabled, - DROP COLUMN IF EXISTS is_refrigerated; - `); - - // ── booking_container ───────────────────────────────────────────────── - await queryRunner.createTable( - new Table({ - name: 'booking_container', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'container_type_id', type: 'uuid' }, - { name: 'quantity', type: 'smallint' }, - { name: 'vgm_per_unit_tons', type: 'numeric', precision: 10, scale: 3 }, - { name: 'total_vgm_tons', type: 'numeric', precision: 12, scale: 3 }, - { name: 'wagons_required', type: 'numeric', precision: 6, scale: 2 }, - { name: 'weight_limit_rule_id', type: 'uuid', isNullable: true }, - { name: 'is_overweight', type: 'boolean', default: false }, - { name: 'overweight_excess_tons', type: 'numeric', precision: 10, scale: 3, 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.createTable( - new Table({ - name: 'booking_rate_snapshot', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'rate_id', type: 'uuid' }, - { name: 'rate_type', type: 'varchar', length: '50' }, - { name: 'rate_value', type: 'numeric', precision: 14, scale: 4 }, - { name: 'rate_unit', type: 'varchar', length: '30' }, - { name: 'currency', type: 'varchar', length: '5' }, - { name: 'snapshotted_at', type: 'timestamptz' }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - name: 'booking_cargo_modifier', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'surcharge_type_id', type: 'uuid' }, - { name: 'trigger_value', type: 'numeric', precision: 14, scale: 4, isNullable: true }, - { name: 'calculated_amount', type: 'numeric', precision: 14, scale: 2 }, - { name: 'rate_snapshot_id', type: 'uuid' }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - name: 'booking_approval_step', - schema: 'freight', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'approval_rule_id', type: 'uuid' }, - { name: 'step_order', type: 'smallint' }, - { name: 'required_role', type: 'varchar', length: '30' }, - { name: 'status', type: 'varchar', length: '20', default: "'PENDING'" }, - { name: 'actioned_by_staff_id', type: 'uuid', isNullable: true }, - { name: 'actioned_at', type: 'timestamptz', isNullable: true }, - { name: 'remarks', type: 'text', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - - // Foreign keys - await queryRunner.createForeignKey( - 'freight.surcharge_types', - new TableForeignKey({ - name: 'FK_surcharge_types_rate_id', - columnNames: ['rate_id'], - referencedTableName: 'rates', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }), - ); - await queryRunner.createForeignKey( - 'freight.booking_container', - new TableForeignKey({ - columnNames: ['booking_id'], - referencedTableName: 'bookings', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - await queryRunner.createForeignKey( - 'freight.bookings', - new TableForeignKey({ - columnNames: ['origin_yard_id'], - referencedTableName: 'yards', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }), - ); - await queryRunner.createForeignKey( - 'freight.bookings', - new TableForeignKey({ - columnNames: ['destination_yard_id'], - referencedTableName: 'yards', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.booking_approval_step', true); - await queryRunner.dropTable('freight.booking_cargo_modifier', true); - await queryRunner.dropTable('freight.booking_rate_snapshot', true); - await queryRunner.dropTable('freight.booking_container', true); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS origin_station VARCHAR(255), - ADD COLUMN IF NOT EXISTS destination_station VARCHAR(255), - ADD COLUMN IF NOT EXISTS service_type VARCHAR(30), - ADD COLUMN IF NOT EXISTS freight_type VARCHAR(20), - ADD COLUMN IF NOT EXISTS freight_subtype VARCHAR(100), - ADD COLUMN IF NOT EXISTS containers JSONB, - ADD COLUMN IF NOT EXISTS first_mile_enabled BOOLEAN DEFAULT false, - ADD COLUMN IF NOT EXISTS last_mile_enabled BOOLEAN DEFAULT false, - ADD COLUMN IF NOT EXISTS is_refrigerated BOOLEAN DEFAULT false; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS origin_yard_id, - DROP COLUMN IF EXISTS destination_yard_id, - DROP COLUMN IF EXISTS service_type_id, - DROP COLUMN IF EXISTS cargo_type_id, - DROP COLUMN IF EXISTS cargo_free_text, - DROP COLUMN IF EXISTS shipping_line_id, - DROP COLUMN IF EXISTS pnr_code, - DROP COLUMN IF EXISTS customer_signed_at, - DROP COLUMN IF EXISTS fully_executed_at; - `); - - await queryRunner.dropTable('freight.approval_rules', true); - await queryRunner.dropTable('freight.shipping_lines', true); - await queryRunner.dropTable('freight.yards', true); - await queryRunner.dropTable('freight.rates', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748700000000-AddBookingsConfigForeignKeys.ts b/apps/edr-freight-api/src/migrations/1748700000000-AddBookingsConfigForeignKeys.ts deleted file mode 100644 index 79f3cfb94..000000000 --- a/apps/edr-freight-api/src/migrations/1748700000000-AddBookingsConfigForeignKeys.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBookingsConfigForeignKeys1748700000000 implements MigrationInterface { - name = 'AddBookingsConfigForeignKeys1748700000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Ensure parent config rows exist for backfill - await queryRunner.query(` - INSERT INTO freight.service_types (id, code, service_name, can_be_booked_alone, includes_first_mile, includes_last_mile, includes_customs, priority_bonus_points, is_active, display_order, created_at, updated_at) - SELECT uuid_generate_v4(), 'RAIL', 'Rail Transport Only', true, false, false, false, 0, true, 1, now(), now() - WHERE NOT EXISTS (SELECT 1 FROM freight.service_types LIMIT 1); - `); - await queryRunner.query(` - INSERT INTO freight.cargo_types (id, code, cargo_type_name, requires_director_approval, show_free_text_box, is_active, display_order, created_at, updated_at) - SELECT uuid_generate_v4(), 'GENERAL', 'General Cargo', false, false, true, 1, now(), now() - WHERE NOT EXISTS (SELECT 1 FROM freight.cargo_types LIMIT 1); - `); - - // Clear orphan shipping_line references (nullable FK) - await queryRunner.query(` - UPDATE freight.bookings b - SET shipping_line_id = NULL - WHERE b.shipping_line_id IS NOT NULL - AND NOT EXISTS ( - SELECT 1 FROM freight.shipping_lines sl WHERE sl.id = b.shipping_line_id - ); - `); - - // Backfill required FK columns - await queryRunner.query(` - UPDATE freight.bookings - SET service_type_id = (SELECT id FROM freight.service_types ORDER BY display_order LIMIT 1) - WHERE service_type_id IS NULL - OR NOT EXISTS (SELECT 1 FROM freight.service_types st WHERE st.id = service_type_id); - `); - await queryRunner.query(` - UPDATE freight.bookings - SET cargo_type_id = (SELECT id FROM freight.cargo_types ORDER BY display_order LIMIT 1) - WHERE cargo_type_id IS NULL - OR NOT EXISTS (SELECT 1 FROM freight.cargo_types ct WHERE ct.id = cargo_type_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_service_type_id" - FOREIGN KEY (service_type_id) - REFERENCES freight.service_types(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_cargo_type_id" - FOREIGN KEY (cargo_type_id) - REFERENCES freight.cargo_types(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_shipping_line_id" - FOREIGN KEY (shipping_line_id) - REFERENCES freight.shipping_lines(id) - ON DELETE SET NULL; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_shipping_line_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_cargo_type_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_service_type_id"; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748800000000-AddBookingsRemainingForeignKeys.ts b/apps/edr-freight-api/src/migrations/1748800000000-AddBookingsRemainingForeignKeys.ts deleted file mode 100644 index 50d052a24..000000000 --- a/apps/edr-freight-api/src/migrations/1748800000000-AddBookingsRemainingForeignKeys.ts +++ /dev/null @@ -1,331 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBookingsRemainingForeignKeys1748800000000 implements MigrationInterface { - name = 'AddBookingsRemainingForeignKeys1748800000000'; - - public async up(queryRunner: QueryRunner): Promise { - const publicCustomersExists = await queryRunner.query(` - SELECT EXISTS ( - SELECT 1 FROM information_schema.tables - WHERE table_schema = 'public' AND table_name = 'customers' - ) AS exists - `); - const hasPublicCustomers = Boolean(publicCustomersExists[0]?.exists); - - // ── freight.bookings: nullable FK cleanup ───────────────────────────── - await queryRunner.query(` - UPDATE freight.bookings b - SET train_id = NULL - WHERE b.train_id IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM freight.trains t WHERE t.id = b.train_id); - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET previous_contract_id = NULL - WHERE b.previous_contract_id IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM freight.bookings pb WHERE pb.id = b.previous_contract_id); - `); - await queryRunner.query(` - UPDATE freight.bookings b - SET consolidation_partner_id = NULL - WHERE b.consolidation_partner_id IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM freight.bookings pb WHERE pb.id = b.consolidation_partner_id); - `); - - // Legacy DBs only: public.customers is created/moved in MoveCustomersToFreightSchema (174890). - if (hasPublicCustomers) { - await queryRunner.query(` - DELETE FROM freight.booking_cargo_modifier bcm - USING freight.bookings b - WHERE bcm.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_approval_step bas - USING freight.bookings b - WHERE bas.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_rate_snapshot brs - USING freight.bookings b - WHERE brs.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_container bc - USING freight.bookings b - WHERE bc.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.bookings b - WHERE NOT EXISTS (SELECT 1 FROM public.customers c WHERE c.id = b.customer_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_customer_id" - FOREIGN KEY (customer_id) - REFERENCES public.customers(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - } - - // ── freight.bookings FKs ──────────────────────────────────────────── - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_train_id" - FOREIGN KEY (train_id) - REFERENCES freight.trains(id) - ON DELETE SET NULL; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_previous_contract_id" - FOREIGN KEY (previous_contract_id) - REFERENCES freight.bookings(id) - ON DELETE SET NULL; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_consolidation_partner_id" - FOREIGN KEY (consolidation_partner_id) - REFERENCES freight.bookings(id) - ON DELETE SET NULL; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - // ── freight.booking_container ───────────────────────────────────────── - await queryRunner.query(` - UPDATE freight.booking_container bc - SET weight_limit_rule_id = NULL - WHERE bc.weight_limit_rule_id IS NOT NULL - AND NOT EXISTS ( - SELECT 1 FROM freight.weight_limit_rules wlr WHERE wlr.id = bc.weight_limit_rule_id - ); - `); - - await queryRunner.query(` - DELETE FROM freight.booking_container bc - WHERE NOT EXISTS (SELECT 1 FROM freight.container_types ct WHERE ct.id = bc.container_type_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_container - ADD CONSTRAINT "FK_booking_container_container_type_id" - FOREIGN KEY (container_type_id) - REFERENCES freight.container_types(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_container - ADD CONSTRAINT "FK_booking_container_weight_limit_rule_id" - FOREIGN KEY (weight_limit_rule_id) - REFERENCES freight.weight_limit_rules(id) - ON DELETE SET NULL; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - // ── freight.booking_rate_snapshot ───────────────────────────────────── - await queryRunner.query(` - DELETE FROM freight.booking_cargo_modifier bcm - USING freight.booking_rate_snapshot brs - WHERE bcm.rate_snapshot_id = brs.id - AND ( - NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = brs.booking_id) - OR NOT EXISTS (SELECT 1 FROM freight.rates r WHERE r.id = brs.rate_id) - ); - `); - await queryRunner.query(` - DELETE FROM freight.booking_rate_snapshot brs - WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = brs.booking_id) - OR NOT EXISTS (SELECT 1 FROM freight.rates r WHERE r.id = brs.rate_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_rate_snapshot - ADD CONSTRAINT "FK_booking_rate_snapshot_booking_id" - FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id) - ON DELETE CASCADE; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_rate_snapshot - ADD CONSTRAINT "FK_booking_rate_snapshot_rate_id" - FOREIGN KEY (rate_id) - REFERENCES freight.rates(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - // ── freight.booking_approval_step ───────────────────────────────────── - await queryRunner.query(` - DELETE FROM freight.booking_approval_step bas - WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = bas.booking_id) - OR NOT EXISTS (SELECT 1 FROM freight.approval_rules ar WHERE ar.id = bas.approval_rule_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_approval_step - ADD CONSTRAINT "FK_booking_approval_step_booking_id" - FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id) - ON DELETE CASCADE; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_approval_step - ADD CONSTRAINT "FK_booking_approval_step_approval_rule_id" - FOREIGN KEY (approval_rule_id) - REFERENCES freight.approval_rules(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - // ── freight.booking_cargo_modifier ──────────────────────────────────── - await queryRunner.query(` - DELETE FROM freight.booking_cargo_modifier bcm - WHERE NOT EXISTS (SELECT 1 FROM freight.bookings b WHERE b.id = bcm.booking_id) - OR NOT EXISTS (SELECT 1 FROM freight.surcharge_types st WHERE st.id = bcm.surcharge_type_id) - OR NOT EXISTS ( - SELECT 1 FROM freight.booking_rate_snapshot brs WHERE brs.id = bcm.rate_snapshot_id - ); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_cargo_modifier - ADD CONSTRAINT "FK_booking_cargo_modifier_booking_id" - FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id) - ON DELETE CASCADE; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_cargo_modifier - ADD CONSTRAINT "FK_booking_cargo_modifier_surcharge_type_id" - FOREIGN KEY (surcharge_type_id) - REFERENCES freight.surcharge_types(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.booking_cargo_modifier - ADD CONSTRAINT "FK_booking_cargo_modifier_rate_snapshot_id" - FOREIGN KEY (rate_snapshot_id) - REFERENCES freight.booking_rate_snapshot(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_cargo_modifier - DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_rate_snapshot_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.booking_cargo_modifier - DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_surcharge_type_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.booking_cargo_modifier - DROP CONSTRAINT IF EXISTS "FK_booking_cargo_modifier_booking_id"; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_approval_step - DROP CONSTRAINT IF EXISTS "FK_booking_approval_step_approval_rule_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.booking_approval_step - DROP CONSTRAINT IF EXISTS "FK_booking_approval_step_booking_id"; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_rate_snapshot - DROP CONSTRAINT IF EXISTS "FK_booking_rate_snapshot_rate_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.booking_rate_snapshot - DROP CONSTRAINT IF EXISTS "FK_booking_rate_snapshot_booking_id"; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_container - DROP CONSTRAINT IF EXISTS "FK_booking_container_weight_limit_rule_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.booking_container - DROP CONSTRAINT IF EXISTS "FK_booking_container_container_type_id"; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_consolidation_partner_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_previous_contract_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_train_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_customer_id"; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1748900000000-MoveCustomersToFreightSchema.ts b/apps/edr-freight-api/src/migrations/1748900000000-MoveCustomersToFreightSchema.ts deleted file mode 100644 index 36e848e64..000000000 --- a/apps/edr-freight-api/src/migrations/1748900000000-MoveCustomersToFreightSchema.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MoveCustomersToFreightSchema1748900000000 implements MigrationInterface { - name = 'MoveCustomersToFreightSchema1748900000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.customers ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID NOT NULL, - first_name VARCHAR(100) NOT NULL, - last_name VARCHAR(100) NOT NULL, - email VARCHAR(150) NOT NULL UNIQUE, - phone VARCHAR(20) NOT NULL, - company_name VARCHAR(200) NOT NULL, - company_email VARCHAR(150) NOT NULL, - company_phone VARCHAR(20) NOT NULL, - company_location VARCHAR(100) NOT NULL, - company_address TEXT NOT NULL, - customer_type VARCHAR(32), - status VARCHAR(32), - contact_person_name VARCHAR(100) NOT NULL, - contact_person_phone VARCHAR(20) NOT NULL, - tin_number VARCHAR(10) NOT NULL UNIQUE, - vat_number VARCHAR(50), - fan_number VARCHAR(16) NOT NULL UNIQUE, - general_manager_name VARCHAR(100) NOT NULL, - general_manager_email VARCHAR(150) NOT NULL, - general_manager_phone VARCHAR(20) NOT NULL, - poa_name VARCHAR(100), - poa_phone VARCHAR(20), - poa_address TEXT, - poa_email VARCHAR(150), - poa_location VARCHAR(100), - notes TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_freight_customers_email" - ON freight.customers (email); - `); - // await queryRunner.query(` - // CREATE INDEX IF NOT EXISTS "IDX_freight_customers_user_id" - // ON freight.customers (user_id); - //`); - - // Copy rows from public.customers when that legacy table exists - await queryRunner.query(` - DO $$ - DECLARE - has_public boolean; - has_user_id boolean; - has_userid boolean; - BEGIN - SELECT EXISTS ( - SELECT 1 FROM information_schema.tables - WHERE table_schema = 'public' AND table_name = 'customers' - ) INTO has_public; - - IF NOT has_public THEN - RETURN; - END IF; - - SELECT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_schema = 'public' AND table_name = 'customers' AND column_name = 'user_id' - ) INTO has_user_id; - - SELECT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_schema = 'public' AND table_name = 'customers' AND column_name = 'userid' - ) INTO has_userid; - - IF has_user_id THEN - INSERT INTO freight.customers ( - id, user_id, first_name, last_name, email, phone, - company_name, company_email, company_phone, company_location, company_address, - contact_person_name, contact_person_phone, tin_number, vat_number, fan_number, - general_manager_name, general_manager_email, general_manager_phone, - poa_name, poa_phone, poa_address, poa_email, poa_location, notes, - created_at, updated_at - ) - SELECT - id, user_id, first_name, last_name, email, phone, - company_name, company_email, company_phone, company_location, company_address, - contact_person_name, contact_person_phone, tin_number, vat_number, fan_number, - general_manager_name, general_manager_email, general_manager_phone, - poa_name, poa_phone, poa_address, poa_email, poa_location, notes, - COALESCE(created_at, now()), COALESCE(updated_at, now()) - FROM public.customers - ON CONFLICT (id) DO NOTHING; - ELSIF has_userid THEN - INSERT INTO freight.customers ( - id, user_id, first_name, last_name, email, phone, - company_name, company_email, company_phone, company_location, company_address, - contact_person_name, contact_person_phone, tin_number, vat_number, fan_number, - general_manager_name, general_manager_email, general_manager_phone, - poa_name, poa_phone, poa_address, poa_email, poa_location, notes, - created_at, updated_at - ) - SELECT - id, userid, firstname, lastname, email, phone, - companyname, companyemail, companyphone, companylocation, companyaddress, - contactpersonname, contactpersonphone, tinnumber, vatnumber, fannumber, - generalmanagername, generalmanageremail, generalmanagerphone, - poaname, poaphone, poaaddress, poaemail, poalocation, notes, - COALESCE("createdAt", now()), COALESCE("updatedAt", now()) - FROM public.customers - ON CONFLICT (id) DO NOTHING; - END IF; - END $$; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_customer_id"; - `); - - await queryRunner.query(` - DELETE FROM freight.booking_cargo_modifier bcm - USING freight.bookings b - WHERE bcm.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM freight.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_approval_step bas - USING freight.bookings b - WHERE bas.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM freight.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_rate_snapshot brs - USING freight.bookings b - WHERE brs.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM freight.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.booking_container bc - USING freight.bookings b - WHERE bc.booking_id = b.id - AND NOT EXISTS (SELECT 1 FROM freight.customers c WHERE c.id = b.customer_id); - `); - await queryRunner.query(` - DELETE FROM freight.bookings b - WHERE NOT EXISTS (SELECT 1 FROM freight.customers c WHERE c.id = b.customer_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_customer_id" - FOREIGN KEY (customer_id) - REFERENCES freight.customers(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_customer_id"; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_customer_id" - FOREIGN KEY (customer_id) - REFERENCES public.customers(id) - ON DELETE RESTRICT; - EXCEPTION - WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(`DROP TABLE IF EXISTS freight.customers CASCADE;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749000000000-NormalizeWeightLimitTradeDirectionBoth.ts b/apps/edr-freight-api/src/migrations/1749000000000-NormalizeWeightLimitTradeDirectionBoth.ts deleted file mode 100644 index 5dc1d6315..000000000 --- a/apps/edr-freight-api/src/migrations/1749000000000-NormalizeWeightLimitTradeDirectionBoth.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Align weight_limit_rules.trade_direction with app code: IMPORT, EXPORT, BOTH (not ANY). - */ -export class NormalizeWeightLimitTradeDirectionBoth1749000000000 - implements MigrationInterface -{ - name = 'NormalizeWeightLimitTradeDirectionBoth1749000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ BEGIN - UPDATE freight.weight_limit_rules - SET trade_direction = 'BOTH' - WHERE trade_direction::text = 'ANY'; - - UPDATE freight.weight_limit_rules - SET trade_direction = 'IMPORT' - WHERE trade_direction IS NULL; - EXCEPTION WHEN undefined_table OR undefined_column THEN NULL; - END $$; - `); - } - - public async down(_queryRunner: QueryRunner): Promise { - // No-op: ANY is not a valid enum value in PostgreSQL. - } -} diff --git a/apps/edr-freight-api/src/migrations/1749100000000-CreateFreightFilesTable.ts b/apps/edr-freight-api/src/migrations/1749100000000-CreateFreightFilesTable.ts deleted file mode 100644 index ebb194833..000000000 --- a/apps/edr-freight-api/src/migrations/1749100000000-CreateFreightFilesTable.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateFreightFilesTable1749100000000 implements MigrationInterface { - name = 'CreateFreightFilesTable1749100000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.files ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - resource_id UUID NOT NULL, - resource VARCHAR(100) NOT NULL, - code VARCHAR(100) NOT NULL, - name VARCHAR(500) NOT NULL, - url TEXT NOT NULL, - size INTEGER NOT NULL, - mime_type VARCHAR(255) NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_freight_files_resource" - ON freight.files (resource_id, resource); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_freight_files_resource_code" - ON freight.files (resource_id, resource, code); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.files CASCADE`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749200000000-BookingFlowRefactor.ts b/apps/edr-freight-api/src/migrations/1749200000000-BookingFlowRefactor.ts deleted file mode 100644 index 162672727..000000000 --- a/apps/edr-freight-api/src/migrations/1749200000000-BookingFlowRefactor.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class BookingFlowRefactor1749200000000 implements MigrationInterface { - name = 'BookingFlowRefactor1749200000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.booking_review_note ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id UUID NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - author_id UUID, - note TEXT NOT NULL, - type VARCHAR(30) NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - deleted_at TIMESTAMPTZ - ); - CREATE INDEX IF NOT EXISTS idx_booking_review_note_booking_id - ON freight.booking_review_note(booking_id); - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS marketing_approved_by_id UUID, - ADD COLUMN IF NOT EXISTS marketing_approved_at TIMESTAMPTZ, - ADD COLUMN IF NOT EXISTS contract_summary TEXT, - ADD COLUMN IF NOT EXISTS locked_at TIMESTAMPTZ; - `); - - await queryRunner.query(` - UPDATE freight.bookings SET status = 'SUBMITTED' - WHERE status IN ('RFQ_SUBMITTED', 'QUOTATION_SENT', 'QUOTATION_APPROVED'); - UPDATE freight.bookings SET status = 'REJECTED' - WHERE status = 'QUOTATION_REJECTED'; - UPDATE freight.bookings SET status = 'CANCELLED' - WHERE status = 'CANCELLED'; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS locked_at, - DROP COLUMN IF EXISTS contract_summary, - DROP COLUMN IF EXISTS marketing_approved_at, - DROP COLUMN IF EXISTS marketing_approved_by_id; - `); - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_review_note;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749200000000-CreateCompaniesModule.ts b/apps/edr-freight-api/src/migrations/1749200000000-CreateCompaniesModule.ts deleted file mode 100644 index c02c9fb5b..000000000 --- a/apps/edr-freight-api/src/migrations/1749200000000-CreateCompaniesModule.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex, TableUnique } from 'typeorm'; - -export class CreateCompaniesModule1749200000000 implements MigrationInterface { - name = 'CreateCompaniesModule1749200000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'companies', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'name', type: 'varchar', length: '200' }, - { name: 'type', type: 'varchar', length: '32' }, - { name: 'status', type: 'varchar', length: '32', default: "'pending'" }, - { name: 'tin', type: 'varchar', length: '10', isUnique: true }, - { name: 'vat_number', type: 'varchar', length: '50', isNullable: true }, - { name: 'business_license', type: 'varchar', length: '100', isNullable: true }, - { name: 'fan_number', type: 'varchar', length: '16', isNullable: true }, - { name: 'country', type: 'varchar', length: '32', default: "'Ethiopia'" }, - { name: 'address', type: 'text', isNullable: true }, - { name: 'phone', type: 'varchar', length: '20', isNullable: true }, - { name: 'email', type: 'varchar', length: '150', isNullable: true }, - { name: 'website', type: 'varchar', length: '200', isNullable: true }, - { name: 'attributes', type: 'jsonb', 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.createTable( - new Table({ - schema: 'freight', - name: 'external_profiles', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'user_id', type: 'uuid' }, - { name: 'company_id', type: 'uuid' }, - { name: 'first_name', type: 'varchar', length: '100' }, - { name: 'last_name', type: 'varchar', length: '100' }, - { name: 'email', type: 'varchar', length: '150', isUnique: true }, - { name: 'phone', type: 'varchar', length: '20', isNullable: true }, - { name: 'national_id', type: 'varchar', length: '50', isNullable: true }, - { name: 'job_title', type: 'varchar', length: '100', isNullable: true }, - { name: 'is_primary_contact', type: 'boolean', default: false }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['company_id'], - referencedTableName: 'companies', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'ff_clients', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'forwarder_company_id', type: 'uuid' }, - { name: 'client_company_id', type: 'uuid' }, - { name: 'relationship_type', type: 'varchar', length: '32', default: "'managed_account'" }, - { name: 'can_book_on_behalf', type: 'boolean', default: true }, - { name: 'can_view_documents', type: 'boolean', default: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['forwarder_company_id'], - referencedTableName: 'companies', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }, - { - columnNames: ['client_company_id'], - referencedTableName: 'companies', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - }, - ], - }), - true, - ); - - await queryRunner.createIndex('freight.companies', new TableIndex({ columnNames: ['tin'] })); - await queryRunner.createIndex('freight.companies', new TableIndex({ columnNames: ['type'] })); - await queryRunner.createIndex('freight.external_profiles', new TableIndex({ columnNames: ['user_id'] })); - await queryRunner.createIndex('freight.external_profiles', new TableIndex({ columnNames: ['company_id'] })); - await queryRunner.createIndex('freight.ff_clients', new TableIndex({ columnNames: ['forwarder_company_id'] })); - await queryRunner.createIndex('freight.ff_clients', new TableIndex({ columnNames: ['client_company_id'] })); - - await queryRunner.createUniqueConstraint('freight.ff_clients', new TableUnique({ - columnNames: ['forwarder_company_id', 'client_company_id'], - })); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.ff_clients'); - await queryRunner.dropTable('freight.external_profiles'); - await queryRunner.dropTable('freight.companies'); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749300000000-AddBookingFreightType.ts b/apps/edr-freight-api/src/migrations/1749300000000-AddBookingFreightType.ts deleted file mode 100644 index 795d93fc3..000000000 --- a/apps/edr-freight-api/src/migrations/1749300000000-AddBookingFreightType.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBookingFreightType1749300000000 implements MigrationInterface { - name = 'AddBookingFreightType1749300000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS freight_type VARCHAR(20); - `); - - await queryRunner.query(` - UPDATE freight.bookings b - SET freight_type = 'CONTAINER' - WHERE EXISTS ( - SELECT 1 FROM freight.booking_container bc WHERE bc.booking_id = b.id - ); - `); - - await queryRunner.query(` - UPDATE freight.bookings b - SET freight_type = 'BULK' - WHERE freight_type IS NULL - AND b.cargo_type_id IS NOT NULL - AND EXISTS ( - SELECT 1 FROM freight.cargo_types ct - WHERE ct.id = b.cargo_type_id AND ct.requires_director_approval = true - ); - `); - - await queryRunner.query(` - UPDATE freight.bookings - SET freight_type = 'CONTAINER' - WHERE freight_type IS NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN cargo_type_id DROP NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN freight_type SET NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD CONSTRAINT chk_bookings_freight_type - CHECK (freight_type IN ('CONTAINER', 'BULK')); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings DROP CONSTRAINT IF EXISTS chk_bookings_freight_type; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings DROP COLUMN IF EXISTS freight_type; - `); - await queryRunner.query(` - UPDATE freight.bookings SET cargo_type_id = ( - SELECT id FROM freight.cargo_types LIMIT 1 - ) WHERE cargo_type_id IS NULL; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN cargo_type_id SET NOT NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749300000000-AddFanNumberToCompanies.ts b/apps/edr-freight-api/src/migrations/1749300000000-AddFanNumberToCompanies.ts deleted file mode 100644 index 4df7ea4ce..000000000 --- a/apps/edr-freight-api/src/migrations/1749300000000-AddFanNumberToCompanies.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddFanNumberToCompanies1749300000000 implements MigrationInterface { - name = 'AddFanNumberToCompanies1749300000000'; - - public async up(queryRunner: QueryRunner): Promise { - // fan_number may already exist when CreateCompaniesModule ran with the full schema - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS fan_number varchar(16) NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS fan_number; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749400000000-AddContractSignatures.ts b/apps/edr-freight-api/src/migrations/1749400000000-AddContractSignatures.ts deleted file mode 100644 index 8126b91ca..000000000 --- a/apps/edr-freight-api/src/migrations/1749400000000-AddContractSignatures.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddContractSignatures1749400000000 implements MigrationInterface { - name = 'AddContractSignatures1749400000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS contract_template_key VARCHAR(80), - ADD COLUMN IF NOT EXISTS contract_generated_at TIMESTAMPTZ, - ADD COLUMN IF NOT EXISTS pricing_breakdown JSONB; - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.booking_contract_signatures ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id UUID NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - signer_role VARCHAR(20) NOT NULL, - signer_user_id UUID, - signer_display_name VARCHAR(200) NOT NULL, - signed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - signature_file_id UUID REFERENCES freight.files(id) ON DELETE SET NULL, - consent_text TEXT, - ip_address VARCHAR(64), - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_booking_contract_signatures_role - UNIQUE (booking_id, signer_role) - ); - CREATE INDEX IF NOT EXISTS idx_booking_contract_signatures_booking_id - ON freight.booking_contract_signatures(booking_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_contract_signatures;`); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS pricing_breakdown, - DROP COLUMN IF EXISTS contract_generated_at, - DROP COLUMN IF EXISTS contract_template_key; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749400000000-AddTrainScheduling.ts b/apps/edr-freight-api/src/migrations/1749400000000-AddTrainScheduling.ts deleted file mode 100644 index 5e61797da..000000000 --- a/apps/edr-freight-api/src/migrations/1749400000000-AddTrainScheduling.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddTrainScheduling1749400000000 implements MigrationInterface { - name = 'AddTrainScheduling1749400000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - code VARCHAR(32) NOT NULL UNIQUE, - name VARCHAR(100) NOT NULL, - capacity_tons NUMERIC(10,3) NOT NULL, - length_meters NUMERIC(10,3) NOT NULL, - max_wagons_per_train INT NULL, - supported_load_types TEXT[] NOT NULL DEFAULT '{}', - 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 - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.locomotives ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - code VARCHAR(32) NOT NULL UNIQUE, - name VARCHAR(100) NULL, - max_pull_weight_tons NUMERIC(10,3) NOT NULL, - status VARCHAR(20) NOT NULL DEFAULT 'AVAILABLE', - available_from TIMESTAMPTZ NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_sets ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - locomotive_id UUID NOT NULL, - total_weight_tons NUMERIC(10,3) NOT NULL, - total_length_meters NUMERIC(10,3) NOT NULL, - wagon_count INT NOT NULL, - status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT fk_train_sets_locomotive FOREIGN KEY (locomotive_id) - REFERENCES freight.locomotives(id) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_set_wagons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_set_id UUID NOT NULL, - wagon_type_id UUID NOT NULL, - sequence_no INT NOT NULL, - capacity_tons NUMERIC(10,3) NOT NULL, - length_meters NUMERIC(10,3) NOT NULL, - assigned_weight_tons NUMERIC(10,3) NOT NULL DEFAULT 0, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT uq_train_set_wagons_sequence UNIQUE (train_set_id, sequence_no), - CONSTRAINT fk_train_set_wagons_train_set FOREIGN KEY (train_set_id) - REFERENCES freight.train_sets(id) ON DELETE CASCADE, - CONSTRAINT fk_train_set_wagons_wagon_type FOREIGN KEY (wagon_type_id) - REFERENCES freight.wagon_types(id) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_schedules ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_set_id UUID NOT NULL UNIQUE, - origin_station_id UUID NOT NULL, - destination_station_id UUID NOT NULL, - scheduled_departure_date TIMESTAMPTZ NOT NULL, - scheduled_arrival_date TIMESTAMPTZ NULL, - status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT fk_train_schedules_train_set FOREIGN KEY (train_set_id) - REFERENCES freight.train_sets(id), - CONSTRAINT fk_train_schedules_origin FOREIGN KEY (origin_station_id) - REFERENCES freight.yards(id), - CONSTRAINT fk_train_schedules_destination FOREIGN KEY (destination_station_id) - REFERENCES freight.yards(id) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_schedule_bookings ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_schedule_id UUID NOT NULL, - booking_id UUID NOT NULL UNIQUE, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT uq_train_schedule_booking UNIQUE (train_schedule_id, booking_id), - CONSTRAINT fk_train_schedule_bookings_schedule FOREIGN KEY (train_schedule_id) - REFERENCES freight.train_schedules(id) ON DELETE CASCADE, - CONSTRAINT fk_train_schedule_bookings_booking FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_booking_allocations ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_set_wagon_id UUID NOT NULL, - booking_id UUID NOT NULL, - allocated_weight_tons NUMERIC(10,3) NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT fk_wagon_booking_allocations_wagon FOREIGN KEY (train_set_wagon_id) - REFERENCES freight.train_set_wagons(id) ON DELETE CASCADE, - CONSTRAINT fk_wagon_booking_allocations_booking FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id) - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_locomotives_status - ON freight.locomotives(status); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_sets_status - ON freight.train_sets(status); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_schedules_departure_status - ON freight.train_schedules(scheduled_departure_date, status); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wagon_booking_allocations_booking - ON freight.wagon_booking_allocations(booking_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_booking_allocations;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_schedule_bookings;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_schedules;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_set_wagons;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_sets;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.locomotives;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_types;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749500000000-AddCompanyIdToBookings.ts b/apps/edr-freight-api/src/migrations/1749500000000-AddCompanyIdToBookings.ts deleted file mode 100644 index 25fbe1806..000000000 --- a/apps/edr-freight-api/src/migrations/1749500000000-AddCompanyIdToBookings.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCompanyIdToBookings1749500000000 implements MigrationInterface { - name = 'AddCompanyIdToBookings1749500000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN customer_id DROP NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS company_id UUID; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_company_id - ON freight.bookings(company_id); - `); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_bookings_company_id' - ) THEN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_company_id" - FOREIGN KEY (company_id) - REFERENCES freight.companies(id); - END IF; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_company_id"; - `); - - await queryRunner.query(` - UPDATE freight.bookings SET customer_id = company_id WHERE customer_id IS NULL AND company_id IS NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN customer_id SET NOT NULL; - `); - await queryRunner.query(` - DROP INDEX IF EXISTS freight.idx_bookings_company_id; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS company_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749600000000-AddBlocksRoleToApprovalStep.ts b/apps/edr-freight-api/src/migrations/1749600000000-AddBlocksRoleToApprovalStep.ts deleted file mode 100644 index a1830c370..000000000 --- a/apps/edr-freight-api/src/migrations/1749600000000-AddBlocksRoleToApprovalStep.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBlocksRoleToApprovalStep1749600000000 implements MigrationInterface { - name = 'AddBlocksRoleToApprovalStep1749600000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_approval_step - ADD COLUMN IF NOT EXISTS blocks_role VARCHAR(30) NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_approval_step - DROP COLUMN IF EXISTS blocks_role; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749700000000-SeedDefaultApprovalRules.ts b/apps/edr-freight-api/src/migrations/1749700000000-SeedDefaultApprovalRules.ts deleted file mode 100644 index f972f50c2..000000000 --- a/apps/edr-freight-api/src/migrations/1749700000000-SeedDefaultApprovalRules.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Seed ITMLS US-06 approval chains if missing (standard + bulk). - */ -export class SeedDefaultApprovalRules1749700000000 implements MigrationInterface { - name = 'SeedDefaultApprovalRules1749700000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - INSERT INTO freight.approval_rules - (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at) - SELECT uuid_generate_v4(), false, 1, 'LINE_STAFF', 'Review & Approve', NULL, now(), now() - WHERE NOT EXISTS ( - SELECT 1 FROM freight.approval_rules - WHERE requires_director_approval = false AND step_order = 1 AND deleted_at IS NULL - ); - - INSERT INTO freight.approval_rules - (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at) - SELECT uuid_generate_v4(), false, 2, 'DIRECTOR', 'Final Signature', 'LINE_STAFF', now(), now() - WHERE NOT EXISTS ( - SELECT 1 FROM freight.approval_rules - WHERE requires_director_approval = false AND step_order = 2 AND deleted_at IS NULL - ); - - INSERT INTO freight.approval_rules - (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at) - SELECT uuid_generate_v4(), true, 1, 'DIRECTOR', 'Review & Approve', 'LINE_STAFF', now(), now() - WHERE NOT EXISTS ( - SELECT 1 FROM freight.approval_rules - WHERE requires_director_approval = true AND step_order = 1 AND deleted_at IS NULL - ); - - INSERT INTO freight.approval_rules - (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at) - SELECT uuid_generate_v4(), true, 2, 'CEO', 'Final Signature', NULL, now(), now() - WHERE NOT EXISTS ( - SELECT 1 FROM freight.approval_rules - WHERE requires_director_approval = true AND step_order = 2 AND deleted_at IS NULL - ); - `); - } - - public async down(_queryRunner: QueryRunner): Promise { - // Keep seeded rules on rollback to avoid breaking in-flight bookings. - } -} diff --git a/apps/edr-freight-api/src/migrations/1749800000000-AddShippingLinesCodeUniqueIndex.ts b/apps/edr-freight-api/src/migrations/1749800000000-AddShippingLinesCodeUniqueIndex.ts deleted file mode 100644 index 374fea724..000000000 --- a/apps/edr-freight-api/src/migrations/1749800000000-AddShippingLinesCodeUniqueIndex.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner, TableIndex } from 'typeorm'; - -/** - * shipping_lines was created without a unique index on code; seeder upserts require it. - */ -export class AddShippingLinesCodeUniqueIndex1749800000000 implements MigrationInterface { - name = 'AddShippingLinesCodeUniqueIndex1749800000000'; - - public async up(queryRunner: QueryRunner): Promise { - const existing = await queryRunner.query( - `SELECT 1 FROM pg_indexes WHERE schemaname = 'freight' AND tablename = 'shipping_lines' AND indexdef ILIKE '%UNIQUE%code%' LIMIT 1`, - ); - if (existing.length === 0) { - await queryRunner.createIndex( - 'freight.shipping_lines', - new TableIndex({ - name: 'UQ_shipping_lines_code', - columnNames: ['code'], - isUnique: true, - }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropIndex('freight.shipping_lines', 'UQ_shipping_lines_code'); - } -} diff --git a/apps/edr-freight-api/src/migrations/1749900000000-CreateFileUploadSettingsTables.ts b/apps/edr-freight-api/src/migrations/1749900000000-CreateFileUploadSettingsTables.ts deleted file mode 100644 index cbbf914d4..000000000 --- a/apps/edr-freight-api/src/migrations/1749900000000-CreateFileUploadSettingsTables.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * file_upload_settings / file_upload_fields entities had no migration; seeder requires both tables. - */ -export class CreateFileUploadSettingsTables1749900000000 implements MigrationInterface { - name = 'CreateFileUploadSettingsTables1749900000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.file_upload_settings ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - code VARCHAR(128) NOT NULL, - label VARCHAR(256) NOT NULL, - description TEXT, - entity VARCHAR(32) NOT NULL DEFAULT 'other', - 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 "UQ_file_upload_settings_code" - ON freight.file_upload_settings (code); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.file_upload_fields ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - setting_id UUID NOT NULL, - file_key VARCHAR(128) NOT NULL, - file_label VARCHAR(256) NOT NULL, - help_text TEXT, - is_required BOOLEAN NOT NULL DEFAULT false, - is_multiple BOOLEAN NOT NULL DEFAULT false, - max_files INTEGER NOT NULL DEFAULT 1, - allowed_extensions TEXT[] NOT NULL DEFAULT '{}'::text[], - max_size_mb INTEGER NOT NULL DEFAULT 10, - display_order INTEGER NOT NULL DEFAULT 0, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT "CHK_file_upload_fields_max_files" CHECK (max_files > 0), - CONSTRAINT "CHK_file_upload_fields_max_size_mb" CHECK (max_size_mb > 0), - CONSTRAINT "FK_file_upload_fields_setting" - FOREIGN KEY (setting_id) - REFERENCES freight.file_upload_settings(id) - ON DELETE CASCADE - ); - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_file_upload_fields_setting_file_key" - ON freight.file_upload_fields (setting_id, file_key); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.file_upload_fields CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.file_upload_settings CASCADE`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000000-AddCompanyContactColumns.ts b/apps/edr-freight-api/src/migrations/1750000000000-AddCompanyContactColumns.ts deleted file mode 100644 index 56d41edf9..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000000-AddCompanyContactColumns.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCompanyContactColumns1750000000000 implements MigrationInterface { - name = 'AddCompanyContactColumns1750000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.companies ADD COLUMN IF NOT EXISTS contact_person_name VARCHAR(100);`); - await queryRunner.query(`ALTER TABLE freight.companies ADD COLUMN IF NOT EXISTS contact_person_phone VARCHAR(20);`); - await queryRunner.query(`ALTER TABLE freight.companies ADD COLUMN IF NOT EXISTS general_manager_name VARCHAR(100);`); - await queryRunner.query(`ALTER TABLE freight.companies ADD COLUMN IF NOT EXISTS general_manager_email VARCHAR(150);`); - await queryRunner.query(`ALTER TABLE freight.companies ADD COLUMN IF NOT EXISTS general_manager_phone VARCHAR(20);`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.companies DROP COLUMN IF EXISTS general_manager_phone;`); - await queryRunner.query(`ALTER TABLE freight.companies DROP COLUMN IF EXISTS general_manager_email;`); - await queryRunner.query(`ALTER TABLE freight.companies DROP COLUMN IF EXISTS general_manager_name;`); - await queryRunner.query(`ALTER TABLE freight.companies DROP COLUMN IF EXISTS contact_person_phone;`); - await queryRunner.query(`ALTER TABLE freight.companies DROP COLUMN IF EXISTS contact_person_name;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000000-AddTrainExtendedColumns.ts b/apps/edr-freight-api/src/migrations/1750000000000-AddTrainExtendedColumns.ts deleted file mode 100644 index b249bd198..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000000-AddTrainExtendedColumns.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Train entity gained extended fields; baseline trains table only had code/capacity/status/notes. - */ -export class AddTrainExtendedColumns1750000000000 implements MigrationInterface { - name = 'AddTrainExtendedColumns1750000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.trains - ADD COLUMN IF NOT EXISTS train_number VARCHAR(20), - ADD COLUMN IF NOT EXISTS train_name VARCHAR(100), - ADD COLUMN IF NOT EXISTS route_id UUID, - ADD COLUMN IF NOT EXISTS origin_station_id UUID, - ADD COLUMN IF NOT EXISTS destination_station_id UUID, - ADD COLUMN IF NOT EXISTS departure_time TIMESTAMPTZ, - ADD COLUMN IF NOT EXISTS arrival_time TIMESTAMPTZ, - ADD COLUMN IF NOT EXISTS locomotive_number VARCHAR(50), - ADD COLUMN IF NOT EXISTS remarks TEXT; - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_trains_train_number" - ON freight.trains (train_number) - WHERE train_number IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_trains_train_number"`); - await queryRunner.query(` - ALTER TABLE freight.trains - DROP COLUMN IF EXISTS remarks, - DROP COLUMN IF EXISTS locomotive_number, - DROP COLUMN IF EXISTS arrival_time, - DROP COLUMN IF EXISTS departure_time, - DROP COLUMN IF EXISTS destination_station_id, - DROP COLUMN IF EXISTS origin_station_id, - DROP COLUMN IF EXISTS route_id, - DROP COLUMN IF EXISTS train_name, - DROP COLUMN IF EXISTS train_number; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000000-CreateFacilitiesTable.ts b/apps/edr-freight-api/src/migrations/1750000000000-CreateFacilitiesTable.ts deleted file mode 100644 index 32e1ff653..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000000-CreateFacilitiesTable.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -export class CreateFacilitiesTable1750000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'facilities', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - generationStrategy: 'uuid', - default: 'gen_random_uuid()', - }, - { - name: 'code', - type: 'varchar', - length: '40', - isUnique: true, - }, - { - name: 'name', - type: 'varchar', - length: '160', - }, - { - name: 'description', - type: 'text', - isNullable: true, - }, - { - name: 'facility_type', - type: 'varchar', - length: '32', - }, - { - name: 'facility_status', - type: 'varchar', - length: '32', - default: "'ACTIVE'", - }, - { - name: 'location_name', - type: 'varchar', - length: '200', - isNullable: true, - }, - { - name: 'country', - type: 'varchar', - length: '100', - isNullable: true, - }, - { - name: 'city', - type: 'varchar', - length: '100', - isNullable: true, - }, - { - name: 'address', - type: 'text', - isNullable: true, - }, - { - name: 'latitude', - type: 'numeric', - precision: 10, - scale: 8, - isNullable: true, - }, - { - name: 'longitude', - type: 'numeric', - precision: 11, - scale: 8, - isNullable: true, - }, - { - name: 'capacity', - type: 'numeric', - precision: 14, - scale: 3, - isNullable: true, - }, - { - name: 'is_active', - type: 'boolean', - default: true, - }, - { - name: 'notes', - type: 'text', - isNullable: true, - }, - { - name: 'created_at', - type: 'timestamp', - default: 'CURRENT_TIMESTAMP', - }, - { - name: 'updated_at', - type: 'timestamp', - default: 'CURRENT_TIMESTAMP', - }, - { - name: 'deleted_at', - type: 'timestamp', - isNullable: true, - }, - ], - }), - ); - - await queryRunner.createIndex( - 'freight.facilities', - new TableIndex({ - name: 'idx_facilities_code', - columnNames: ['code'], - isUnique: true, - }), - ); - - await queryRunner.createIndex( - 'freight.facilities', - new TableIndex({ - name: 'idx_facilities_status', - columnNames: ['facility_status'], - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.facilities'); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000001-AddFacilityIdToWarehouses.ts b/apps/edr-freight-api/src/migrations/1750000000001-AddFacilityIdToWarehouses.ts deleted file mode 100644 index 82f2d92fd..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000001-AddFacilityIdToWarehouses.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn, TableForeignKey } from 'typeorm'; - -export class AddFacilityIdToWarehouses1750000000001 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const table = await queryRunner.getTable('freight.warehouses'); - if (!table) { - // warehouses table doesn't exist yet, skip this migration - return; - } - - const hasColumn = table.columns.some((col) => col.name === 'facility_id'); - if (hasColumn) { - // Column already exists, skip - return; - } - - await queryRunner.addColumn( - 'freight.warehouses', - new TableColumn({ - name: 'facility_id', - type: 'uuid', - isNullable: true, - }), - ); - - await queryRunner.createForeignKey( - 'freight.warehouses', - new TableForeignKey({ - columnNames: ['facility_id'], - referencedColumnNames: ['id'], - referencedTableName: 'facilities', - referencedSchema: 'freight', - onDelete: 'SET NULL', - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const table = await queryRunner.getTable('freight.warehouses'); - if (!table) { - return; - } - const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.includes('facility_id')); - if (foreignKey) { - await queryRunner.dropForeignKey('freight.warehouses', foreignKey); - } - const hasColumn = table.columns.some((col) => col.name === 'facility_id'); - if (hasColumn) { - await queryRunner.dropColumn('freight.warehouses', 'facility_id'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000002-AddProofOfDeliveryToCargoes.ts b/apps/edr-freight-api/src/migrations/1750000000002-AddProofOfDeliveryToCargoes.ts deleted file mode 100644 index 67957f437..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000002-AddProofOfDeliveryToCargoes.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Proof of Delivery (customer pickup) capture on cargoes: - * receiver name, delivered/picked-up timestamp, and delivery remarks. - */ -export class AddProofOfDeliveryToCargoes1750000000002 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const table = await queryRunner.getTable('freight.cargoes'); - if (!table) { - // cargoes table doesn't exist yet, skip this migration - return; - } - - const columnsToAdd = [ - { name: 'receiver_name', type: 'varchar', isNullable: true }, - { name: 'delivered_at', type: 'timestamp', isNullable: true }, - { name: 'delivery_remarks', type: 'text', isNullable: true }, - ]; - - const columnsToCreate = columnsToAdd.filter( - (col) => !table.columns.some((c) => c.name === col.name), - ); - - if (columnsToCreate.length > 0) { - await queryRunner.addColumns( - 'freight.cargoes', - columnsToCreate.map((col) => new TableColumn(col)), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - const table = await queryRunner.getTable('freight.cargoes'); - if (!table) { - return; - } - - const columnNames = ['receiver_name', 'delivered_at', 'delivery_remarks']; - const columnsToRemove = columnNames.filter((name) => - table.columns.some((c) => c.name === name), - ); - - if (columnsToRemove.length > 0) { - await queryRunner.dropColumns('freight.cargoes', columnsToRemove); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1750000000003-AddWarehouseInspection.ts b/apps/edr-freight-api/src/migrations/1750000000003-AddWarehouseInspection.ts deleted file mode 100644 index 88ef8d3a5..000000000 --- a/apps/edr-freight-api/src/migrations/1750000000003-AddWarehouseInspection.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableColumn } from 'typeorm'; - -/** - * Batch 4.5 — warehouse inspection reports + inventory inspection status. - */ -export class AddWarehouseInspection1750000000003 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - // inventory.inspection_status - const inventoryTable = await queryRunner.getTable('freight.warehouse_inventory'); - if (inventoryTable) { - const hasColumn = inventoryTable.columns.some((col) => col.name === 'inspection_status'); - if (!hasColumn) { - await queryRunner.addColumn( - 'freight.warehouse_inventory', - new TableColumn({ name: 'inspection_status', type: 'varchar', length: '20', isNullable: true }), - ); - } - } - - // warehouse_inspection_reports table - const inspectionTable = await queryRunner.getTable('freight.warehouse_inspection_reports'); - if (!inspectionTable) { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'warehouse_inspection_reports', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'inventory_id', type: 'uuid' }, - { name: 'booking_id', type: 'uuid', isNullable: true }, - { name: 'customer_id', type: 'uuid', isNullable: true }, - { name: 'report_type', type: 'varchar', length: '32', default: "'INSPECTION'" }, - { name: 'inspection_status', type: 'varchar', length: '20', default: "'NEEDS_REVIEW'" }, - { name: 'has_damage', type: 'boolean', default: false }, - { name: 'damage_description', type: 'text', isNullable: true }, - { name: 'has_weight_loss', type: 'boolean', default: false }, - { name: 'expected_weight', type: 'numeric', precision: 14, scale: 3, isNullable: true }, - { name: 'actual_weight', type: 'numeric', precision: 14, scale: 3, isNullable: true }, - { name: 'weight_loss', type: 'numeric', precision: 14, scale: 3, isNullable: true }, - { name: 'weight_loss_unit', type: 'varchar', length: '12', isNullable: true }, - { name: 'has_missing_items', type: 'boolean', default: false }, - { name: 'missing_items_description', type: 'text', isNullable: true }, - { name: 'remarks', type: 'text', isNullable: true }, - { name: 'inspected_by_id', type: 'uuid', isNullable: true }, - { name: 'inspected_at', type: 'timestamptz', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - indices: [ - { name: 'idx_wir_inventory', columnNames: ['inventory_id'] }, - { name: 'idx_wir_booking', columnNames: ['booking_id'] }, - { name: 'idx_wir_status', columnNames: ['inspection_status'] }, - ], - }), - true, - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - const inspectionTable = await queryRunner.getTable('freight.warehouse_inspection_reports'); - if (inspectionTable) { - await queryRunner.dropTable('freight.warehouse_inspection_reports', true); - } - - const inventoryTable = await queryRunner.getTable('freight.warehouse_inventory'); - if (inventoryTable) { - const hasColumn = inventoryTable.columns.some((col) => col.name === 'inspection_status'); - if (hasColumn) { - await queryRunner.dropColumn('freight.warehouse_inventory', 'inspection_status'); - } - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1750100000000-AddRoutesAndExtendLocomotives.ts b/apps/edr-freight-api/src/migrations/1750100000000-AddRoutesAndExtendLocomotives.ts deleted file mode 100644 index 421f66ef9..000000000 --- a/apps/edr-freight-api/src/migrations/1750100000000-AddRoutesAndExtendLocomotives.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddRoutesAndExtendLocomotives1750100000000 implements MigrationInterface { - name = 'AddRoutesAndExtendLocomotives1750100000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.locomotives - ADD COLUMN IF NOT EXISTS locomotive_type VARCHAR(20) NOT NULL DEFAULT 'DIESEL', - ADD COLUMN IF NOT EXISTS max_train_length_meters NUMERIC(10,3) NOT NULL DEFAULT 760, - ADD COLUMN IF NOT EXISTS power_kw NUMERIC(10,3) NULL, - ADD COLUMN IF NOT EXISTS traction_force_kn NUMERIC(10,3) NULL, - ADD COLUMN IF NOT EXISTS max_speed_kmh NUMERIC(10,3) NULL; - `); - - await queryRunner.query(` - UPDATE freight.locomotives - SET status = 'OUT_OF_SERVICE' - WHERE status = 'INACTIVE'; - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.routes ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR(120) NOT NULL UNIQUE, - origin_yard_id UUID NOT NULL REFERENCES freight.yards(id), - destination_yard_id UUID NOT NULL REFERENCES freight.yards(id), - 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 - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.route_milestones ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - route_id UUID NOT NULL REFERENCES freight.routes(id) ON DELETE CASCADE, - yard_id UUID NOT NULL REFERENCES freight.yards(id), - sequence_no INT NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT uq_route_milestones_route_sequence UNIQUE (route_id, sequence_no) - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_routes_origin_yard_id - ON freight.routes(origin_yard_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_routes_destination_yard_id - ON freight.routes(destination_yard_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_routes_is_active - ON freight.routes(is_active); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_route_milestones_route_id - ON freight.route_milestones(route_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_route_milestones_yard_id - ON freight.route_milestones(yard_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.route_milestones;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.routes;`); - await queryRunner.query(` - ALTER TABLE freight.locomotives - DROP COLUMN IF EXISTS max_speed_kmh, - DROP COLUMN IF EXISTS traction_force_kn, - DROP COLUMN IF EXISTS power_kw, - DROP COLUMN IF EXISTS max_train_length_meters, - DROP COLUMN IF EXISTS locomotive_type; - `); - await queryRunner.query(` - UPDATE freight.locomotives - SET status = 'INACTIVE' - WHERE status = 'OUT_OF_SERVICE'; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750100000000-CreateFleetCrudTables.ts b/apps/edr-freight-api/src/migrations/1750100000000-CreateFleetCrudTables.ts deleted file mode 100644 index 1763a9db0..000000000 --- a/apps/edr-freight-api/src/migrations/1750100000000-CreateFleetCrudTables.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateFleetCrudTables1750100000000 implements MigrationInterface { - name = 'CreateFleetCrudTables1750100000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE SCHEMA IF NOT EXISTS freight`); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagons ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - wagon_number VARCHAR NOT NULL UNIQUE, - wagon_type_id UUID NOT NULL, - train_id UUID, - sequence_number INT, - tare_weight NUMERIC(10, 2) NOT NULL, - max_payload_weight NUMERIC(10, 2) NOT NULL, - status VARCHAR NOT NULL DEFAULT 'AVAILABLE', - notes TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.containers ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - container_number VARCHAR NOT NULL UNIQUE, - container_type_id UUID NOT NULL, - wagon_id UUID, - position INT, - tare_weight NUMERIC(10, 2) NOT NULL, - max_gross_weight NUMERIC(10, 2) NOT NULL, - seal_number VARCHAR, - status VARCHAR NOT NULL DEFAULT 'AVAILABLE', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.cargoes ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - cargo_reference VARCHAR NOT NULL UNIQUE, - shipment_id UUID NOT NULL, - container_id UUID NOT NULL, - cargo_type_id UUID, - description TEXT, - quantity NUMERIC(12, 3) NOT NULL, - weight NUMERIC(10, 2) NOT NULL, - volume NUMERIC(10, 2), - status VARCHAR NOT NULL DEFAULT 'PENDING', - loaded_at TIMESTAMP, - unloaded_at TIMESTAMP, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_wagons_train_id" ON freight.wagons (train_id)`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_containers_wagon_id" ON freight.containers (wagon_id)`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_cargoes_container_id" ON freight.cargoes (container_id)`); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.wagons - ADD CONSTRAINT "FK_wagons_train_id" - FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.wagons - ADD CONSTRAINT "FK_wagons_wagon_type_id" - FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id); - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.containers - ADD CONSTRAINT "FK_containers_wagon_id" - FOREIGN KEY (wagon_id) REFERENCES freight.wagons(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.containers - ADD CONSTRAINT "FK_containers_container_type_id" - FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id); - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.cargoes - ADD CONSTRAINT "FK_cargoes_container_id" - FOREIGN KEY (container_id) REFERENCES freight.containers(id) ON DELETE RESTRICT; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.cargoes - ADD CONSTRAINT "FK_cargoes_cargo_type_id" - FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id); - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.cargoes CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.containers CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagons CASCADE`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750200000000-AddPhysicalWagonToTrainSetWagons.ts b/apps/edr-freight-api/src/migrations/1750200000000-AddPhysicalWagonToTrainSetWagons.ts deleted file mode 100644 index 9ce1db6c1..000000000 --- a/apps/edr-freight-api/src/migrations/1750200000000-AddPhysicalWagonToTrainSetWagons.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddPhysicalWagonToTrainSetWagons1750200000000 implements MigrationInterface { - name = 'AddPhysicalWagonToTrainSetWagons1750200000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - ADD COLUMN IF NOT EXISTS physical_wagon_id UUID NULL; - `); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM information_schema.table_constraints - WHERE constraint_schema = 'freight' - AND table_name = 'train_set_wagons' - AND constraint_name = 'fk_train_set_wagons_physical_wagon' - ) THEN - ALTER TABLE freight.train_set_wagons - ADD CONSTRAINT fk_train_set_wagons_physical_wagon - FOREIGN KEY (physical_wagon_id) - REFERENCES freight.wagons(id) - ON DELETE SET NULL; - END IF; - END $$; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_set_wagons_physical_wagon - ON freight.train_set_wagons(physical_wagon_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_train_set_wagons_physical_wagon;`); - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - DROP CONSTRAINT IF EXISTS fk_train_set_wagons_physical_wagon; - `); - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - DROP COLUMN IF EXISTS physical_wagon_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts b/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts deleted file mode 100644 index 06dc0b917..000000000 --- a/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class SeedDefaultWagonTypes1750200000000 implements MigrationInterface { - name = 'SeedDefaultWagonTypes1750200000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - INSERT INTO freight.wagon_types ( - code, - name, - capacity_tons, - length_meters, - max_wagons_per_train, - supported_load_types, - is_active - ) - VALUES - ('NW7', 'Double deck sedan wagon', 22, 26.066, NULL, ARRAY['vehicles', 'sedan'], true), - ('NW5', 'Flat wagon (container)', 70, 14.000, 53, ARRAY['container', 'steel', 'machinery'], true), - ('PW2', 'Box wagon', 70, 17.066, 18, ARRAY['general cargo', 'break bulk'], true), - ('GW2', 'Tank wagon', 70, 12.228, 37, ARRAY['liquid', 'fuel'], true), - ('CW4', 'Gondola covered wagon', 70, 13.976, 37, ARRAY['covered bulk cargo'], true), - ('CW3', 'Gondola open wagon', 70, 13.976, NULL, ARRAY['open bulk cargo'], true), - ('KW2', 'Hopper covered wagon', 69, 16.466, NULL, ARRAY['bulk grains'], true), - ('KW3', 'Hopper open wagon', 70, 14.400, NULL, ARRAY['coal', 'bulk cargo'], true), - ('NW6', 'Flat wagon (long cargo)', 70, 18.560, NULL, ARRAY['long cargo'], true), - ('BW1', 'Refrigerated wagon', 38, 21.996, NULL, ARRAY['refrigerated cargo'], true) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - capacity_tons = EXCLUDED.capacity_tons, - length_meters = EXCLUDED.length_meters, - max_wagons_per_train = EXCLUDED.max_wagons_per_train, - supported_load_types = EXCLUDED.supported_load_types, - is_active = true, - deleted_at = NULL, - updated_at = now(); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DELETE FROM freight.wagon_types - WHERE code IN ('NW7', 'NW5', 'PW2', 'GW2', 'CW4', 'CW3', 'KW2', 'KW3', 'NW6', 'BW1'); - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750300000000-AddCurrentLocationToWagons.ts b/apps/edr-freight-api/src/migrations/1750300000000-AddCurrentLocationToWagons.ts deleted file mode 100644 index 454218fd7..000000000 --- a/apps/edr-freight-api/src/migrations/1750300000000-AddCurrentLocationToWagons.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCurrentLocationToWagons1750300000000 implements MigrationInterface { - name = 'AddCurrentLocationToWagons1750300000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS current_location_yard_id UUID NULL; - `); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM information_schema.table_constraints - WHERE constraint_schema = 'freight' - AND table_name = 'wagons' - AND constraint_name = 'FK_wagons_current_location_yard_id' - ) THEN - ALTER TABLE freight.wagons - ADD CONSTRAINT "FK_wagons_current_location_yard_id" - FOREIGN KEY (current_location_yard_id) - REFERENCES freight.yards(id) - ON DELETE SET NULL; - END IF; - END $$; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_wagons_current_location_yard_id" - ON freight.wagons(current_location_yard_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_wagons_current_location_yard_id";`); - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP CONSTRAINT IF EXISTS "FK_wagons_current_location_yard_id"; - `); - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP COLUMN IF EXISTS current_location_yard_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750300000000-AddRouteToTrainSchedules.ts b/apps/edr-freight-api/src/migrations/1750300000000-AddRouteToTrainSchedules.ts deleted file mode 100644 index 027ebfe98..000000000 --- a/apps/edr-freight-api/src/migrations/1750300000000-AddRouteToTrainSchedules.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddRouteToTrainSchedules1750300000000 implements MigrationInterface { - name = 'AddRouteToTrainSchedules1750300000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS route_id UUID NULL; - `); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM pg_constraint - WHERE conname = 'fk_train_schedules_route' - ) THEN - ALTER TABLE freight.train_schedules - ADD CONSTRAINT fk_train_schedules_route - FOREIGN KEY (route_id) REFERENCES freight.routes(id); - END IF; - END $$; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_schedules_route_id - ON freight.train_schedules(route_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_train_schedules_route_id;`); - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP CONSTRAINT IF EXISTS fk_train_schedules_route; - `); - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS route_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750400000000-AddSchedulingAllocationEnhancements.ts b/apps/edr-freight-api/src/migrations/1750400000000-AddSchedulingAllocationEnhancements.ts deleted file mode 100644 index a0ca64303..000000000 --- a/apps/edr-freight-api/src/migrations/1750400000000-AddSchedulingAllocationEnhancements.ts +++ /dev/null @@ -1,321 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSchedulingAllocationEnhancements1750400000000 - implements MigrationInterface -{ - name = 'AddSchedulingAllocationEnhancements1750400000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS wagons_required NUMERIC(6,2) NULL, - ADD COLUMN IF NOT EXISTS scheduling_status VARCHAR(30) NOT NULL DEFAULT 'NOT_SCHEDULED', - ADD COLUMN IF NOT EXISTS hold_started_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS hold_expires_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS scheduled_at TIMESTAMPTZ NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS train_number VARCHAR(20) NULL, - ADD COLUMN IF NOT EXISTS direction VARCHAR(10) NULL, - ADD COLUMN IF NOT EXISTS actual_departure_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS actual_arrival_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS prepared_by_user_id UUID NULL, - ADD COLUMN IF NOT EXISTS checked_by_user_id UUID NULL, - ADD COLUMN IF NOT EXISTS max_wagons INT NOT NULL DEFAULT 53; - `); - - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - ADD COLUMN IF NOT EXISTS physical_wagon_id UUID NULL, - ADD COLUMN IF NOT EXISTS status VARCHAR(20) NOT NULL DEFAULT 'PLANNED'; - `); - - await queryRunner.query(` - ALTER TABLE freight.wagon_booking_allocations - ADD COLUMN IF NOT EXISTS load_type VARCHAR(20) NULL, - ADD COLUMN IF NOT EXISTS status VARCHAR(20) NOT NULL DEFAULT 'PLANNED', - ADD COLUMN IF NOT EXISTS confirmed_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS confirmed_by_user_id UUID NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.wagon_types - ADD COLUMN IF NOT EXISTS equated_length_m NUMERIC(10,3) NULL, - ADD COLUMN IF NOT EXISTS tare_weight_tons NUMERIC(10,3) NULL, - ADD COLUMN IF NOT EXISTS supports_container BOOLEAN NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS max_container_gross_t NUMERIC(10,3) NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS train_set_wagon_id UUID NULL, - ADD COLUMN IF NOT EXISTS current_train_schedule_id UUID NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.containers - ADD COLUMN IF NOT EXISTS booking_id UUID NULL, - ADD COLUMN IF NOT EXISTS wagon_booking_allocation_id UUID NULL, - ADD COLUMN IF NOT EXISTS booking_container_id UUID NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.cargoes - ADD COLUMN IF NOT EXISTS wagon_booking_allocation_id UUID NULL, - ADD COLUMN IF NOT EXISTS booking_id UUID NULL, - ADD COLUMN IF NOT EXISTS load_type VARCHAR(20) NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.cargoes - ALTER COLUMN container_id DROP NOT NULL; - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_allocation_container_items ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - wagon_booking_allocation_id UUID NOT NULL, - booking_container_id UUID NULL, - container_id UUID NULL, - container_number VARCHAR(64) NULL, - container_type_id UUID NOT NULL, - position_on_wagon SMALLINT NULL, - seal_number VARCHAR(64) NULL, - chassis_number VARCHAR(64) NULL, - gross_weight_tons NUMERIC(10,3) NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT fk_waci_allocation FOREIGN KEY (wagon_booking_allocation_id) - REFERENCES freight.wagon_booking_allocations(id) ON DELETE CASCADE, - CONSTRAINT fk_waci_booking_container FOREIGN KEY (booking_container_id) - REFERENCES freight.booking_container(id) ON DELETE SET NULL, - CONSTRAINT fk_waci_container FOREIGN KEY (container_id) - REFERENCES freight.containers(id) ON DELETE SET NULL, - CONSTRAINT fk_waci_container_type FOREIGN KEY (container_type_id) - REFERENCES freight.container_types(id) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_allocation_bulk_loads ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - wagon_booking_allocation_id UUID NOT NULL UNIQUE, - booking_id UUID NOT NULL, - cargo_type_id UUID NULL, - cargo_description TEXT NULL, - pricing_unit VARCHAR(20) NOT NULL DEFAULT 'PER_TON', - quantity NUMERIC(12,3) NOT NULL DEFAULT 0, - weight_tons NUMERIC(10,3) NOT NULL DEFAULT 0, - truck_plate_number VARCHAR(32) NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT fk_wabl_allocation FOREIGN KEY (wagon_booking_allocation_id) - REFERENCES freight.wagon_booking_allocations(id) ON DELETE CASCADE, - CONSTRAINT fk_wabl_booking FOREIGN KEY (booking_id) - REFERENCES freight.bookings(id), - CONSTRAINT fk_wabl_cargo_type FOREIGN KEY (cargo_type_id) - REFERENCES freight.cargo_types(id) ON DELETE SET NULL - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_scheduling_status - ON freight.bookings(scheduling_status); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_schedules_train_number - ON freight.train_schedules(train_number); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_set_wagons_physical_wagon - ON freight.train_set_wagons(physical_wagon_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wagons_train_set_wagon_id - ON freight.wagons(train_set_wagon_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wagons_current_train_schedule_id - ON freight.wagons(current_train_schedule_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_waci_allocation - ON freight.wagon_allocation_container_items(wagon_booking_allocation_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wabl_booking - ON freight.wagon_allocation_bulk_loads(booking_id); - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.train_set_wagons - ADD CONSTRAINT fk_train_set_wagons_physical_wagon - FOREIGN KEY (physical_wagon_id) REFERENCES freight.wagons(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.wagons - ADD CONSTRAINT fk_wagons_train_set_wagon - FOREIGN KEY (train_set_wagon_id) REFERENCES freight.train_set_wagons(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.wagons - ADD CONSTRAINT fk_wagons_current_train_schedule - FOREIGN KEY (current_train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.containers - ADD CONSTRAINT fk_containers_booking - FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.containers - ADD CONSTRAINT fk_containers_wagon_allocation - FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.containers - ADD CONSTRAINT fk_containers_booking_container - FOREIGN KEY (booking_container_id) REFERENCES freight.booking_container(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.cargoes - ADD CONSTRAINT fk_cargoes_wagon_allocation - FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.cargoes - ADD CONSTRAINT fk_cargoes_booking - FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - UPDATE freight.wagon_types SET - equated_length_m = 1.3, - tare_weight_tons = 22.4, - supports_container = true, - max_container_gross_t = 30.48 - WHERE code = 'NW5'; - `); - await queryRunner.query(` - UPDATE freight.wagon_types SET - equated_length_m = 1.6, - tare_weight_tons = 25.2, - supports_container = false - WHERE code = 'PW2'; - `); - await queryRunner.query(` - UPDATE freight.wagon_types SET - equated_length_m = 1.5, - tare_weight_tons = 25.2, - supports_container = false - WHERE code = 'KW2'; - `); - await queryRunner.query(` - UPDATE freight.wagon_types SET - equated_length_m = 1.3, - tare_weight_tons = 23.4, - supports_container = false - WHERE code = 'CW3'; - `); - await queryRunner.query(` - UPDATE freight.wagon_types SET - equated_length_m = 1.3, - tare_weight_tons = 24.8, - supports_container = false - WHERE code = 'CW4'; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_allocation_bulk_loads;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_allocation_container_items;`); - - await queryRunner.query(` - ALTER TABLE freight.cargoes - ALTER COLUMN container_id SET NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS wagons_required, - DROP COLUMN IF EXISTS scheduling_status, - DROP COLUMN IF EXISTS hold_started_at, - DROP COLUMN IF EXISTS hold_expires_at, - DROP COLUMN IF EXISTS scheduled_at; - `); - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS train_number, - DROP COLUMN IF EXISTS direction, - DROP COLUMN IF EXISTS actual_departure_at, - DROP COLUMN IF EXISTS actual_arrival_at, - DROP COLUMN IF EXISTS prepared_by_user_id, - DROP COLUMN IF EXISTS checked_by_user_id, - DROP COLUMN IF EXISTS max_wagons; - `); - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - DROP COLUMN IF EXISTS physical_wagon_id, - DROP COLUMN IF EXISTS status; - `); - await queryRunner.query(` - ALTER TABLE freight.wagon_booking_allocations - DROP COLUMN IF EXISTS load_type, - DROP COLUMN IF EXISTS status, - DROP COLUMN IF EXISTS confirmed_at, - DROP COLUMN IF EXISTS confirmed_by_user_id; - `); - await queryRunner.query(` - ALTER TABLE freight.wagon_types - DROP COLUMN IF EXISTS equated_length_m, - DROP COLUMN IF EXISTS tare_weight_tons, - DROP COLUMN IF EXISTS supports_container, - DROP COLUMN IF EXISTS max_container_gross_t; - `); - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP COLUMN IF EXISTS train_set_wagon_id, - DROP COLUMN IF EXISTS current_train_schedule_id; - `); - await queryRunner.query(` - ALTER TABLE freight.containers - DROP COLUMN IF EXISTS booking_id, - DROP COLUMN IF EXISTS wagon_booking_allocation_id, - DROP COLUMN IF EXISTS booking_container_id; - `); - await queryRunner.query(` - ALTER TABLE freight.cargoes - DROP COLUMN IF EXISTS wagon_booking_allocation_id, - DROP COLUMN IF EXISTS booking_id, - DROP COLUMN IF EXISTS load_type; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750400000000-SeedEdRWagonFleet.ts b/apps/edr-freight-api/src/migrations/1750400000000-SeedEdRWagonFleet.ts deleted file mode 100644 index 0a4e96276..000000000 --- a/apps/edr-freight-api/src/migrations/1750400000000-SeedEdRWagonFleet.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -type FleetRow = { - code: string; - name: string; - count: number; - start: number; - end: number; - capacityTons: number; - tareWeight: number; - lengthMeters: number; - supportedLoadTypes: string[]; -}; - -const FLEET: FleetRow[] = [ - { - code: 'PW2', - name: 'Box wagon', - count: 220, - start: 1, - end: 220, - capacityTons: 70, - tareWeight: 25.2, - lengthMeters: 17.066, - supportedLoadTypes: ['BULK', 'GENERAL_CARGO', 'BAGGED_CARGO', 'BOXED_CARGO'], - }, - { - code: 'CW4', - name: 'Gondola wagon covered', - count: 110, - start: 221, - end: 330, - capacityTons: 70, - tareWeight: 24.8, - lengthMeters: 13.976, - supportedLoadTypes: ['CONTAINER'], - }, - { - code: 'CW3', - name: 'Gondola wagon', - count: 20, - start: 331, - end: 350, - capacityTons: 70, - tareWeight: 23.4, - lengthMeters: 13.976, - supportedLoadTypes: ['BULK', 'COAL', 'ORE'], - }, - { - code: 'KW2', - name: 'Hopper wagon covered', - count: 20, - start: 351, - end: 370, - capacityTons: 69, - tareWeight: 25.2, - lengthMeters: 16.466, - supportedLoadTypes: ['BULK', 'GRAIN'], - }, - { - code: 'KW3', - name: 'Hopper wagon', - count: 20, - start: 371, - end: 390, - capacityTons: 70, - tareWeight: 24, - lengthMeters: 14.4, - supportedLoadTypes: ['BULK', 'COAL'], - }, - { - code: 'NW5', - name: 'Flat wagon container', - count: 550, - start: 391, - end: 940, - capacityTons: 70, - tareWeight: 0, - lengthMeters: 14, - supportedLoadTypes: ['CONTAINER'], - }, -]; - -const wagonNumber = (sequence: number) => `ER${String(sequence).padStart(4, '0')}`; - -export class SeedEdRWagonFleet1750400000000 implements MigrationInterface { - name = 'SeedEdRWagonFleet1750400000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.wagon_types - SET name = 'Flat wagon container', - capacity_tons = 70, - length_meters = 14.000, - supported_load_types = ARRAY['CONTAINER'], - max_wagons_per_train = 53, - is_active = true, - deleted_at = NULL, - updated_at = now() - WHERE code = 'NW5'; - `); - - const [defaultLocation] = await queryRunner.query(` - SELECT id - FROM freight.yards - WHERE code IN ('DJIBOUTI', 'DJIB_PORT', 'NAGAD') - OR lower(label) LIKE '%djibouti%' - ORDER BY - CASE code - WHEN 'DJIBOUTI' THEN 1 - WHEN 'DJIB_PORT' THEN 2 - WHEN 'NAGAD' THEN 3 - ELSE 4 - END, - display_order ASC - LIMIT 1; - `); - const defaultLocationYardId = defaultLocation?.id ?? null; - - for (const row of FLEET) { - await queryRunner.query( - ` - INSERT INTO freight.wagon_types ( - code, - name, - capacity_tons, - length_meters, - max_wagons_per_train, - supported_load_types, - is_active - ) - VALUES ($1, $2, $3, $4, $5, $6::text[], true) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - capacity_tons = EXCLUDED.capacity_tons, - length_meters = EXCLUDED.length_meters, - max_wagons_per_train = EXCLUDED.max_wagons_per_train, - supported_load_types = EXCLUDED.supported_load_types, - is_active = true, - deleted_at = NULL, - updated_at = now(); - `, - [ - row.code, - row.name, - row.capacityTons, - row.lengthMeters, - row.supportedLoadTypes.includes('CONTAINER') ? 53 : 37, - row.supportedLoadTypes, - ], - ); - - const [typeRecord] = await queryRunner.query( - `SELECT id FROM freight.wagon_types WHERE code = $1 LIMIT 1;`, - [row.code], - ); - - if (!typeRecord?.id) { - throw new Error(`wagon_type_seed_failed:${row.code}`); - } - - if (row.end - row.start + 1 !== row.count) { - throw new Error(`wagon_range_mismatch:${row.code}`); - } - - for (let sequence = row.start; sequence <= row.end; sequence += 1) { - await queryRunner.query( - ` - INSERT INTO freight.wagons ( - wagon_number, - wagon_type_id, - tare_weight, - max_payload_weight, - current_location_yard_id, - status, - notes - ) - VALUES ($1, $2, $3, $4, $5, $6, $7) - ON CONFLICT (wagon_number) DO UPDATE SET - wagon_type_id = EXCLUDED.wagon_type_id, - tare_weight = EXCLUDED.tare_weight, - max_payload_weight = EXCLUDED.max_payload_weight, - current_location_yard_id = CASE - WHEN freight.wagons.train_id IS NULL THEN EXCLUDED.current_location_yard_id - ELSE freight.wagons.current_location_yard_id - END, - status = CASE - WHEN freight.wagons.train_id IS NULL THEN EXCLUDED.status - ELSE freight.wagons.status - END, - notes = EXCLUDED.notes, - updated_at = now(); - `, - [ - wagonNumber(sequence), - typeRecord.id, - row.tareWeight, - row.capacityTons, - defaultLocationYardId, - defaultLocationYardId ? 'IMPORT_READY' : 'AVAILABLE', - `Seeded Ethio-Djibouti Railway ${row.code} fleet record.`, - ], - ); - } - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DELETE FROM freight.wagons - WHERE wagon_number BETWEEN 'ER0001' AND 'ER0940'; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750500000000-AddWagonReadiness.ts b/apps/edr-freight-api/src/migrations/1750500000000-AddWagonReadiness.ts deleted file mode 100644 index 17cc23f9a..000000000 --- a/apps/edr-freight-api/src/migrations/1750500000000-AddWagonReadiness.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddWagonReadiness1750500000000 implements MigrationInterface { - name = 'AddWagonReadiness1750500000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS readiness VARCHAR(20) NOT NULL DEFAULT 'IMPORT_READY' - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wagons_readiness - ON freight.wagons (readiness) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_wagons_readiness`); - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP COLUMN IF EXISTS readiness - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750600000000-AddGovernmentBookingFields.ts b/apps/edr-freight-api/src/migrations/1750600000000-AddGovernmentBookingFields.ts deleted file mode 100644 index ce833e4ac..000000000 --- a/apps/edr-freight-api/src/migrations/1750600000000-AddGovernmentBookingFields.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddGovernmentBookingFields1750600000000 implements MigrationInterface { - name = 'AddGovernmentBookingFields1750600000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS is_government BOOLEAN NOT NULL DEFAULT false - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS government_institution VARCHAR(255) NULL - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN company_id DROP NOT NULL - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_is_government - ON freight.bookings (is_government) - WHERE is_government = true AND deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_bookings_is_government`); - await queryRunner.query(` - UPDATE freight.bookings - SET company_id = '00000000-0000-0000-0000-000000000000' - WHERE company_id IS NULL - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - ALTER COLUMN company_id SET NOT NULL - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS government_institution - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS is_government - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750700000000-CreateSchedulingEvents.ts b/apps/edr-freight-api/src/migrations/1750700000000-CreateSchedulingEvents.ts deleted file mode 100644 index 9f92f70b4..000000000 --- a/apps/edr-freight-api/src/migrations/1750700000000-CreateSchedulingEvents.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSchedulingEvents1750700000000 implements MigrationInterface { - name = 'CreateSchedulingEvents1750700000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.scheduling_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_schedule_id UUID NOT NULL, - trigger VARCHAR(40) NOT NULL, - actor_user_id UUID NULL, - reason TEXT NULL, - plan_snapshot JSONB NOT NULL DEFAULT '{}', - displaced_booking_ids JSONB NOT NULL DEFAULT '[]', - 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_scheduling_events_train_schedule_id - ON freight.scheduling_events (train_schedule_id) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_scheduling_events_train_schedule_id`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.scheduling_events`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750800000000-FixContainerWagonsPerUnit.ts b/apps/edr-freight-api/src/migrations/1750800000000-FixContainerWagonsPerUnit.ts deleted file mode 100644 index 1bb1a9518..000000000 --- a/apps/edr-freight-api/src/migrations/1750800000000-FixContainerWagonsPerUnit.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** 20ft = 0.5 wagon slots (2 per wagon); 40ft = 1.0 wagon slot (1 per wagon). */ -export class FixContainerWagonsPerUnit1750800000000 implements MigrationInterface { - name = 'FixContainerWagonsPerUnit1750800000000'; - - public async up(queryRunner: QueryRunner): Promise { - const hasContainerTypes = await queryRunner.hasTable('freight.container_types'); - if (!hasContainerTypes) { - return; - } - - await queryRunner.query(` - UPDATE freight.container_types - SET wagons_per_unit = 0.50 - WHERE size_ft = 20 OR code LIKE '20%'; - `); - await queryRunner.query(` - UPDATE freight.container_types - SET wagons_per_unit = 1.00 - WHERE size_ft = 40 OR code LIKE '40%'; - `); - - const hasBookingContainer = await queryRunner.hasTable('freight.booking_container'); - if (!hasBookingContainer) { - return; - } - - await queryRunner.query(` - UPDATE freight.booking_container bc - SET wagons_required = CEILING(bc.quantity * ct.wagons_per_unit) - FROM freight.container_types ct - WHERE ct.id = bc.container_type_id; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - const hasContainerTypes = await queryRunner.hasTable('freight.container_types'); - if (!hasContainerTypes) { - return; - } - - await queryRunner.query(` - UPDATE freight.container_types SET wagons_per_unit = 1.00; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1750900000000-AddContainerNumberToBookingContainer.ts b/apps/edr-freight-api/src/migrations/1750900000000-AddContainerNumberToBookingContainer.ts deleted file mode 100644 index eb28da8f3..000000000 --- a/apps/edr-freight-api/src/migrations/1750900000000-AddContainerNumberToBookingContainer.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddContainerNumberToBookingContainer1750900000000 implements MigrationInterface { - name = "AddContainerNumberToBookingContainer1750900000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_container - ALTER COLUMN container_type_id DROP NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_container - ADD COLUMN container_number varchar(64); - `); - - await queryRunner.query(` - ALTER TABLE freight.wagon_allocation_container_items - ALTER COLUMN container_type_id DROP NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_allocation_container_items - ALTER COLUMN container_type_id SET NOT NULL; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_container - DROP COLUMN container_number; - `); - - await queryRunner.query(` - ALTER TABLE freight.booking_container - ALTER COLUMN container_type_id SET NOT NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1751000000000-CreateTrainSchedulingGlobalRules.ts b/apps/edr-freight-api/src/migrations/1751000000000-CreateTrainSchedulingGlobalRules.ts deleted file mode 100644 index ac9741c5a..000000000 --- a/apps/edr-freight-api/src/migrations/1751000000000-CreateTrainSchedulingGlobalRules.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreateTrainSchedulingGlobalRules1751000000000 implements MigrationInterface { - name = "CreateTrainSchedulingGlobalRules1751000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE freight.train_scheduling_global_rules ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - max_train_length_meters numeric(10, 2) NOT NULL DEFAULT 760, - max_train_weight_tons numeric(10, 3) NOT NULL DEFAULT 3500, - max_wagons_per_train integer NOT NULL DEFAULT 53, - max_20ft_container_weight_tons numeric(8, 3) NOT NULL DEFAULT 30, - max_20ft_pair_weight_diff_tons numeric(8, 3) NOT NULL DEFAULT 10, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL - ); - `); - - await queryRunner.query(` - INSERT INTO freight.train_scheduling_global_rules ( - max_train_length_meters, - max_train_weight_tons, - max_wagons_per_train, - max_20ft_container_weight_tons, - max_20ft_pair_weight_diff_tons - ) VALUES (760, 3500, 53, 30, 10); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_scheduling_global_rules;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1751000000001-AddDeletedAtToTrainSchedulingGlobalRules.ts b/apps/edr-freight-api/src/migrations/1751000000001-AddDeletedAtToTrainSchedulingGlobalRules.ts deleted file mode 100644 index fd72f6c3b..000000000 --- a/apps/edr-freight-api/src/migrations/1751000000001-AddDeletedAtToTrainSchedulingGlobalRules.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddDeletedAtToTrainSchedulingGlobalRules1751000000001 - implements MigrationInterface -{ - name = "AddDeletedAtToTrainSchedulingGlobalRules1751000000001"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ADD COLUMN IF NOT EXISTS deleted_at timestamptz NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - DROP COLUMN IF EXISTS deleted_at; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1752000000000-CreateCompanyProfiles.ts b/apps/edr-freight-api/src/migrations/1752000000000-CreateCompanyProfiles.ts deleted file mode 100644 index a27cef3ad..000000000 --- a/apps/edr-freight-api/src/migrations/1752000000000-CreateCompanyProfiles.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { - MigrationInterface, - QueryRunner, - Table, - TableIndex, - TableForeignKey, -} from "typeorm"; - -export class CreateCompanyProfiles1752000000000 implements MigrationInterface { - name = "CreateCompanyProfiles1752000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: "freight", - name: "company_profiles", - columns: [ - { - name: "id", - type: "uuid", - isPrimary: true, - generationStrategy: "uuid", - default: "gen_random_uuid()", - }, - { name: "company_id", type: "uuid" }, - { name: "type", type: "varchar", length: "32" }, - { name: "reference", type: "varchar", length: "20", isUnique: true }, - { - name: "status", - type: "varchar", - length: "32", - default: "'active'", - }, - { - name: "business_license", - type: "varchar", - length: "100", - isNullable: true, - }, - { name: "attributes", type: "jsonb", 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.company_profiles", - new TableForeignKey({ - columnNames: ["company_id"], - referencedTableName: "companies", - referencedSchema: "freight", - referencedColumnNames: ["id"], - }), - ); - - await queryRunner.createIndex( - "freight.company_profiles", - new TableIndex({ columnNames: ["company_id"] }), - ); - await queryRunner.createIndex( - "freight.company_profiles", - new TableIndex({ columnNames: ["type"] }), - ); - - await queryRunner.query( - `CREATE SEQUENCE IF NOT EXISTS freight.seq_company_profile_ex START WITH 1`, - ); - await queryRunner.query( - `CREATE SEQUENCE IF NOT EXISTS freight.seq_company_profile_im START WITH 1`, - ); - await queryRunner.query( - `CREATE SEQUENCE IF NOT EXISTS freight.seq_company_profile_ffe START WITH 1`, - ); - await queryRunner.query( - `CREATE SEQUENCE IF NOT EXISTS freight.seq_company_profile_fwj START WITH 1`, - ); - await queryRunner.query( - `CREATE SEQUENCE IF NOT EXISTS freight.seq_company_profile_tr START WITH 1`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable("freight.company_profiles"); - await queryRunner.query( - `DROP SEQUENCE IF EXISTS freight.seq_company_profile_ex`, - ); - await queryRunner.query( - `DROP SEQUENCE IF EXISTS freight.seq_company_profile_im`, - ); - await queryRunner.query( - `DROP SEQUENCE IF EXISTS freight.seq_company_profile_ffe`, - ); - await queryRunner.query( - `DROP SEQUENCE IF EXISTS freight.seq_company_profile_fwj`, - ); - await queryRunner.query( - `DROP SEQUENCE IF EXISTS freight.seq_company_profile_tr`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1752000000001-MoveBusinessLicenseToProfile.ts b/apps/edr-freight-api/src/migrations/1752000000001-MoveBusinessLicenseToProfile.ts deleted file mode 100644 index f15996773..000000000 --- a/apps/edr-freight-api/src/migrations/1752000000001-MoveBusinessLicenseToProfile.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MoveBusinessLicenseToProfile1752000000001 - implements MigrationInterface -{ - name = 'MoveBusinessLicenseToProfile1752000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.company_profiles cp - SET business_license = c.business_license - FROM freight.companies c - WHERE cp.company_id = c.id AND c.business_license IS NOT NULL - `); - - await queryRunner.query( - `ALTER TABLE freight.companies DROP COLUMN IF EXISTS business_license`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.companies ADD COLUMN business_license varchar(100) NULL`, - ); - - await queryRunner.query(` - UPDATE freight.companies c - SET business_license = cp.business_license - FROM ( - SELECT DISTINCT ON (cp2.company_id) - cp2.company_id, cp2.business_license - FROM freight.company_profiles cp2 - WHERE cp2.business_license IS NOT NULL - ORDER BY cp2.company_id, cp2.created_at - ) cp - WHERE cp.company_id = c.id - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1770000000000-CreateVehiclesTable.ts b/apps/edr-freight-api/src/migrations/1770000000000-CreateVehiclesTable.ts deleted file mode 100644 index 2cf09c9f5..000000000 --- a/apps/edr-freight-api/src/migrations/1770000000000-CreateVehiclesTable.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateVehiclesTable1770000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'vehicles' AND table_schema = 'freight') THEN - CREATE TABLE freight.vehicles ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - plate_number VARCHAR NOT NULL UNIQUE, - registration_number VARCHAR NOT NULL UNIQUE, - vehicle_type VARCHAR NOT NULL, - manufacturer VARCHAR NOT NULL, - model VARCHAR NOT NULL, - year INTEGER NOT NULL, - fuel_type VARCHAR NOT NULL, - capacity NUMERIC NOT NULL, - status VARCHAR DEFAULT 'ACTIVE' NOT NULL, - description TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - deleted_at TIMESTAMP NULL - ); - - CREATE INDEX idx_vehicles_plate_number ON freight.vehicles(plate_number); - CREATE INDEX idx_vehicles_registration_number ON freight.vehicles(registration_number); - CREATE INDEX idx_vehicles_status ON freight.vehicles(status); - CREATE INDEX idx_vehicles_vehicle_type ON freight.vehicles(vehicle_type); - CREATE INDEX idx_vehicles_manufacturer ON freight.vehicles(manufacturer); - END IF; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.vehicles CASCADE;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1775000000000-CreateDriversTable.ts b/apps/edr-freight-api/src/migrations/1775000000000-CreateDriversTable.ts deleted file mode 100644 index 8f41587cf..000000000 --- a/apps/edr-freight-api/src/migrations/1775000000000-CreateDriversTable.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateDriversTable1775000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'drivers' AND table_schema = 'freight') THEN - CREATE TABLE freight.drivers ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - license_number VARCHAR NOT NULL UNIQUE, - first_name VARCHAR NOT NULL, - last_name VARCHAR NOT NULL, - email VARCHAR NOT NULL UNIQUE, - phone_number VARCHAR NOT NULL UNIQUE, - date_of_birth DATE NOT NULL, - license_expiry_date DATE NOT NULL, - status VARCHAR DEFAULT 'ACTIVE' NOT NULL, - vehicle_types_authorized VARCHAR[], - address TEXT, - emergency_contact VARCHAR, - notes TEXT, - total_trips INTEGER DEFAULT 0, - rating NUMERIC(3, 2), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - deleted_at TIMESTAMP NULL - ); - - CREATE INDEX idx_drivers_license_number ON freight.drivers(license_number); - CREATE INDEX idx_drivers_email ON freight.drivers(email); - CREATE INDEX idx_drivers_phone_number ON freight.drivers(phone_number); - CREATE INDEX idx_drivers_status ON freight.drivers(status); - END IF; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.drivers CASCADE;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1780639311366-CreatePaymentTable.ts b/apps/edr-freight-api/src/migrations/1780639311366-CreatePaymentTable.ts deleted file mode 100644 index 0382c834b..000000000 --- a/apps/edr-freight-api/src/migrations/1780639311366-CreatePaymentTable.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreatePaymentTable1780639311366 implements MigrationInterface { - name = "CreatePaymentTable1780639311366"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TYPE freight.payments_type_enum AS ENUM ('booking'); - `); - - await queryRunner.query(` - CREATE TYPE freight.payments_method_enum AS ENUM ('telebirr', 'cbe-birr', 'ebirr'); - `); - - await queryRunner.query(` - CREATE TYPE freight.payments_currency_enum AS ENUM ('ETB', 'USD'); - `); - - await queryRunner.query(` - CREATE TYPE freight.payments_status_enum AS ENUM ( - 'action-required', - 'processing', - 'success', - 'failed', - 'canceled', - 'refunded' - ); - `); - - await queryRunner.query(` - CREATE TABLE freight.payments ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - - ref_id varchar(255) NOT NULL, - - type freight.payments_type_enum NOT NULL, - - method freight.payments_method_enum NOT NULL, - - currency freight.payments_currency_enum NOT NULL, - - amount numeric NOT NULL, - - raw_initiation jsonb NOT NULL DEFAULT '{}'::jsonb, - - client_action json, - - merchant_order_id varchar(255) NOT NULL, - - transaction_id varchar(255), - - status freight.payments_status_enum NOT NULL DEFAULT 'action-required', - - paid_at date, - - refunded_at date, - - expires_at date, - - failer_code varchar(30), - - failer_message varchar(255), - - reason varchar(255), - - created_at TIMESTAMP NOT NULL DEFAULT now(), - - CONSTRAINT PK_payments PRIMARY KEY (id), - - CONSTRAINT UQ_payments_merchant_order_id UNIQUE (merchant_order_id), - - CONSTRAINT UQ_payments_transaction_id UNIQUE (transaction_id) - ); -`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP TABLE IF EXISTS freight.payments; - `); - - await queryRunner.query(` - DROP TYPE IF EXISTS freight.payments_status_enum; - `); - - await queryRunner.query(` - DROP TYPE IF EXISTS freight.payments_currency_enum; - `); - - await queryRunner.query(` - DROP TYPE IF EXISTS freight.payments_method_enum; - `); - - await queryRunner.query(` - DROP TYPE IF EXISTS freight.payments_type_enum; - `); - } -} \ No newline at end of file diff --git a/apps/edr-freight-api/src/migrations/1780639978834-AlterClientActionToJsonb.ts b/apps/edr-freight-api/src/migrations/1780639978834-AlterClientActionToJsonb.ts deleted file mode 100644 index 723331ab3..000000000 --- a/apps/edr-freight-api/src/migrations/1780639978834-AlterClientActionToJsonb.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AlterClientActionToJsonb1780639978834 implements MigrationInterface { - name = "AlterClientActionToJsonb1780639978834"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN client_action TYPE jsonb - USING client_action::jsonb; - `); - - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN client_action DROP DEFAULT; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN client_action TYPE json - USING client_action::json; - `); - } - - -} diff --git a/apps/edr-freight-api/src/migrations/1780644945086-UpdatePaymentTimestamp.ts b/apps/edr-freight-api/src/migrations/1780644945086-UpdatePaymentTimestamp.ts deleted file mode 100644 index 6cfc7fc8f..000000000 --- a/apps/edr-freight-api/src/migrations/1780644945086-UpdatePaymentTimestamp.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class UpdatePaymentTimestamp1780644945086 implements MigrationInterface { - name = "UpdatePaymentTimestamp1780644945086"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN refunded_at TYPE timestamp - USING refunded_at::timestamp; - `); - - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN expires_at TYPE timestamp - USING expires_at::timestamp; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN refunded_at TYPE timestamptz - USING refunded_at::timestamptz; - `); - - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN expires_at TYPE timestamptz - USING expires_at::timestamptz; - `); - } -} \ No newline at end of file diff --git a/apps/edr-freight-api/src/migrations/1781000000000-AddLocomotiveReadiness.ts b/apps/edr-freight-api/src/migrations/1781000000000-AddLocomotiveReadiness.ts deleted file mode 100644 index f6d87f41d..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000000-AddLocomotiveReadiness.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddLocomotiveReadiness1781000000000 implements MigrationInterface { - name = 'AddLocomotiveReadiness1781000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.locomotives - ADD COLUMN IF NOT EXISTS readiness VARCHAR(20) NOT NULL DEFAULT 'IMPORT_READY' - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_locomotives_readiness - ON freight.locomotives (readiness) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_locomotives_readiness`); - await queryRunner.query(` - ALTER TABLE freight.locomotives - DROP COLUMN IF EXISTS readiness - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1781000000001-CreateTrainCheckpointEvents.ts b/apps/edr-freight-api/src/migrations/1781000000001-CreateTrainCheckpointEvents.ts deleted file mode 100644 index 7d9ce745a..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000001-CreateTrainCheckpointEvents.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateTrainCheckpointEvents1781000000001 implements MigrationInterface { - name = 'CreateTrainCheckpointEvents1781000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_checkpoint_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - train_schedule_id UUID NOT NULL REFERENCES freight.train_schedules(id) ON DELETE CASCADE, - yard_id UUID NOT NULL, - sequence_no INT NOT NULL, - kind VARCHAR(20) NOT NULL, - occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - note TEXT NULL, - recorded_by_user_id UUID NULL, - 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_train_checkpoint_events_schedule - ON freight.train_checkpoint_events (train_schedule_id, sequence_no) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight.idx_train_checkpoint_events_schedule`, - ); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_checkpoint_events`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1781000000002-AddBatchBookingFields.ts b/apps/edr-freight-api/src/migrations/1781000000002-AddBatchBookingFields.ts deleted file mode 100644 index 0287b55be..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000002-AddBatchBookingFields.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBatchBookingFields1781000000002 implements MigrationInterface { - name = 'AddBatchBookingFields1781000000002'; - - public async up(queryRunner: QueryRunner): Promise { - // Booking → target schedule (pool membership) + 1h pay-window deadline. - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS train_schedule_id UUID NULL, - ADD COLUMN IF NOT EXISTS payment_deadline TIMESTAMPTZ NULL - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_train_schedule_id - ON freight.bookings (train_schedule_id) - WHERE deleted_at IS NULL - `); - - // TrainSchedule → booking-window status (OPEN/FULL/CLOSED). - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS booking_window_status VARCHAR(10) NOT NULL DEFAULT 'OPEN' - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_train_schedules_booking_window_status - ON freight.train_schedules (booking_window_status) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight.idx_train_schedules_booking_window_status`, - ); - await queryRunner.query( - `ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS booking_window_status`, - ); - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_bookings_train_schedule_id`); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS train_schedule_id, - DROP COLUMN IF EXISTS payment_deadline - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1781000000003-AddSelectedForBatchStatus.ts b/apps/edr-freight-api/src/migrations/1781000000003-AddSelectedForBatchStatus.ts deleted file mode 100644 index 1ba9670b2..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000003-AddSelectedForBatchStatus.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSelectedForBatchStatus1781000000003 implements MigrationInterface { - name = 'AddSelectedForBatchStatus1781000000003'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS selected_for_batch_at TIMESTAMPTZ NULL - `); - - await queryRunner.query(` - UPDATE freight.bookings - SET - status = 'SELECTED_FOR_BATCH', - selected_for_batch_at = COALESCE( - payment_deadline - INTERVAL '5 minutes', - updated_at - ) - WHERE status = 'AWAITING_PAYMENT' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.bookings - SET status = 'AWAITING_PAYMENT' - WHERE status = 'SELECTED_FOR_BATCH' - `); - - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS selected_for_batch_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1781000000004-AddDomesticWeightLimitTradeDirection.ts b/apps/edr-freight-api/src/migrations/1781000000004-AddDomesticWeightLimitTradeDirection.ts deleted file mode 100644 index 59b1de22e..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000004-AddDomesticWeightLimitTradeDirection.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Allow DOMESTIC trade direction on weight_limit_rules (domestic corridor bookings). - */ -export class AddDomesticWeightLimitTradeDirection1781000000004 - implements MigrationInterface -{ - name = 'AddDomesticWeightLimitTradeDirection1781000000004'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ BEGIN - ALTER TYPE freight.weight_limit_rules_trade_direction_enum ADD VALUE 'DOMESTIC'; - EXCEPTION - WHEN duplicate_object THEN NULL; - WHEN undefined_object THEN - BEGIN - ALTER TYPE weight_limit_rules_trade_direction_enum ADD VALUE 'DOMESTIC'; - EXCEPTION - WHEN duplicate_object THEN NULL; - END; - END $$; - `); - } - - public async down(_queryRunner: QueryRunner): Promise { - // PostgreSQL does not support removing enum values safely. - } -} diff --git a/apps/edr-freight-api/src/migrations/1781000000005-CreateTrainCompositionRemovalLog.ts b/apps/edr-freight-api/src/migrations/1781000000005-CreateTrainCompositionRemovalLog.ts deleted file mode 100644 index 475a52574..000000000 --- a/apps/edr-freight-api/src/migrations/1781000000005-CreateTrainCompositionRemovalLog.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -export class CreateTrainCompositionRemovalLog1781000000005 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'train_composition_removal_logs', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'uuid_generate_v4()', - }, - { - name: 'schedule_id', - type: 'uuid', - isNullable: false, - }, - { - name: 'booking_id', - type: 'uuid', - isNullable: false, - }, - { - name: 'booking_reference', - type: 'varchar', - length: '64', - isNullable: true, - }, - { - name: 'removed_by_user_id', - type: 'uuid', - isNullable: true, - }, - { - name: 'removed_at', - type: 'timestamptz', - default: 'NOW()', - isNullable: false, - }, - { - name: 'notes', - type: 'text', - isNullable: true, - }, - { - name: 'created_at', - type: 'timestamptz', - default: 'NOW()', - isNullable: false, - }, - { - name: 'updated_at', - type: 'timestamptz', - default: 'NOW()', - isNullable: false, - }, - { - name: 'deleted_at', - type: 'timestamptz', - isNullable: true, - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.train_composition_removal_logs', - new TableIndex({ - columnNames: ['schedule_id'], - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.train_composition_removal_logs', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1782000000000-WagonLocomotiveYardLink.ts b/apps/edr-freight-api/src/migrations/1782000000000-WagonLocomotiveYardLink.ts deleted file mode 100644 index 68100f367..000000000 --- a/apps/edr-freight-api/src/migrations/1782000000000-WagonLocomotiveYardLink.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class WagonLocomotiveYardLink1782000000000 implements MigrationInterface { - name = 'WagonLocomotiveYardLink1782000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS "current_yard_id" UUID NULL; - `); - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_wagon_current_yard' - ) THEN - ALTER TABLE freight.wagons - ADD CONSTRAINT "FK_wagon_current_yard" - FOREIGN KEY ("current_yard_id") REFERENCES freight.yards(id) ON DELETE SET NULL; - END IF; - END $$; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_wagon_current_yard_id" - ON freight.wagons ("current_yard_id"); - `); - - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_wagons_readiness`); - await queryRunner.query(`ALTER TABLE freight.wagons DROP COLUMN IF EXISTS readiness;`); - - await queryRunner.query(` - ALTER TABLE freight.locomotives - ADD COLUMN IF NOT EXISTS "current_yard_id" UUID NULL; - `); - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_locomotive_current_yard' - ) THEN - ALTER TABLE freight.locomotives - ADD CONSTRAINT "FK_locomotive_current_yard" - FOREIGN KEY ("current_yard_id") REFERENCES freight.yards(id) ON DELETE SET NULL; - END IF; - END $$; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_locomotive_current_yard_id" - ON freight.locomotives ("current_yard_id"); - `); - - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_locomotives_readiness`); - await queryRunner.query(`ALTER TABLE freight.locomotives DROP COLUMN IF EXISTS readiness;`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS readiness VARCHAR(20) NOT NULL DEFAULT 'IMPORT_READY'; - `); - await queryRunner.query(` - ALTER TABLE freight.locomotives - ADD COLUMN IF NOT EXISTS readiness VARCHAR(20) NOT NULL DEFAULT 'IMPORT_READY'; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wagons_readiness - ON freight.wagons (readiness) - WHERE deleted_at IS NULL; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_locomotives_readiness - ON freight.locomotives (readiness) - WHERE deleted_at IS NULL; - `); - - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_wagon_current_yard_id"`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_locomotive_current_yard_id"`); - await queryRunner.query(` - ALTER TABLE freight.wagons DROP CONSTRAINT IF EXISTS "FK_wagon_current_yard"; - `); - await queryRunner.query(` - ALTER TABLE freight.locomotives DROP CONSTRAINT IF EXISTS "FK_locomotive_current_yard"; - `); - await queryRunner.query(`ALTER TABLE freight.wagons DROP COLUMN IF EXISTS "current_yard_id";`); - await queryRunner.query(`ALTER TABLE freight.locomotives DROP COLUMN IF EXISTS "current_yard_id";`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1782000000001-AddPaymentWebhookEventAndRefund.ts b/apps/edr-freight-api/src/migrations/1782000000001-AddPaymentWebhookEventAndRefund.ts deleted file mode 100644 index e1cddc05b..000000000 --- a/apps/edr-freight-api/src/migrations/1782000000001-AddPaymentWebhookEventAndRefund.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddPaymentWebhookEventAndRefund1782000000001 implements MigrationInterface { - name = "AddPaymentWebhookEventAndRefund1782000000001"; - - public async up(queryRunner: QueryRunner): Promise { - // Enum for webhook provider — shares the same values as payments_method_enum - // but is a separate type so both tables remain independently evolvable. - await queryRunner.query(` - CREATE TYPE freight.payment_webhook_method_enum AS ENUM ('telebirr', 'cbe-birr', 'ebirr'); - `); - - await queryRunner.query(` - CREATE TABLE freight.payment_webhook_events ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - provider freight.payment_webhook_method_enum NOT NULL, - external_event_id varchar(255) NOT NULL, - merchant_order_id varchar(255), - provider_txn_id varchar(255), - signature_valid boolean NOT NULL, - status varchar(100) NOT NULL, - payload jsonb NOT NULL, - received_at TIMESTAMP NOT NULL DEFAULT now(), - processed_at TIMESTAMP, - processing_error text, - - CONSTRAINT PK_payment_webhook_events PRIMARY KEY (id), - CONSTRAINT UQ_payment_webhook_events_provider_event UNIQUE (provider, external_event_id) - ); - `); - - await queryRunner.query(` - CREATE INDEX IDX_payment_webhook_events_merchant_order_id - ON freight.payment_webhook_events (merchant_order_id); - `); - - await queryRunner.query(` - CREATE TABLE freight.payment_refunds ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - payment_id uuid NOT NULL, - amount_minor int NOT NULL, - reason varchar(255), - provider_refund_id varchar(255), - status varchar(50) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT now(), - - CONSTRAINT PK_payment_refunds PRIMARY KEY (id), - CONSTRAINT FK_payment_refunds_payment - FOREIGN KEY (payment_id) - REFERENCES freight.payments (id) - ON DELETE RESTRICT - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.payment_refunds;`); - await queryRunner.query(`DROP INDEX IF EXISTS freight.IDX_payment_webhook_events_merchant_order_id;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.payment_webhook_events;`); - await queryRunner.query(`DROP TYPE IF EXISTS freight.payment_webhook_method_enum;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1782000000002-ExtendPaymentMethodEnum.ts b/apps/edr-freight-api/src/migrations/1782000000002-ExtendPaymentMethodEnum.ts deleted file mode 100644 index 607926e92..000000000 --- a/apps/edr-freight-api/src/migrations/1782000000002-ExtendPaymentMethodEnum.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class ExtendPaymentMethodEnum1782000000002 implements MigrationInterface { - name = "ExtendPaymentMethodEnum1782000000002"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TYPE freight.payments_method_enum ADD VALUE IF NOT EXISTS 'waafi';`); - await queryRunner.query(`ALTER TYPE freight.payments_method_enum ADD VALUE IF NOT EXISTS 'card';`); - await queryRunner.query(`ALTER TYPE freight.payments_method_enum ADD VALUE IF NOT EXISTS 'dmoney';`); - } - - public async down(_queryRunner: QueryRunner): Promise { - // PostgreSQL does not support removing enum values directly. - // To roll back, recreate the type without the added values and update the column. - } -} diff --git a/apps/edr-freight-api/src/migrations/1783000000000-ReplacePriorityRulesWithPriorityConfigs.ts b/apps/edr-freight-api/src/migrations/1783000000000-ReplacePriorityRulesWithPriorityConfigs.ts deleted file mode 100644 index b8eccbbaf..000000000 --- a/apps/edr-freight-api/src/migrations/1783000000000-ReplacePriorityRulesWithPriorityConfigs.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ReplacePriorityRulesWithPriorityConfigs1783000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE freight.priority_configs ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - type VARCHAR(20) NOT NULL CHECK (type IN ('WAGON', 'CURRENCY')), - label VARCHAR(100) NOT NULL, - currency VARCHAR(5) NULL, - min_wagon_count INT NOT NULL, - max_wagon_count INT NOT NULL, - score_points INT NOT NULL DEFAULT 0, - is_active BOOLEAN NOT NULL DEFAULT false, - display_order INT NOT NULL DEFAULT 1, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT chk_wagon_range CHECK (min_wagon_count <= max_wagon_count), - CONSTRAINT chk_currency_for_type CHECK ( - (type = 'WAGON' AND currency IS NULL) OR - (type = 'CURRENCY' AND currency IS NOT NULL) - ) - ); - `); - - await queryRunner.query(` - CREATE INDEX idx_priority_configs_type_active ON freight.priority_configs (type, is_active); - `); - - await queryRunner.query(` - CREATE INDEX idx_priority_configs_currency_type ON freight.priority_configs (currency, type); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.priority_configs;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1784000000000-CreateSavedSignatures.ts b/apps/edr-freight-api/src/migrations/1784000000000-CreateSavedSignatures.ts deleted file mode 100644 index e0c36f67b..000000000 --- a/apps/edr-freight-api/src/migrations/1784000000000-CreateSavedSignatures.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateSavedSignatures1784000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE freight.saved_signatures ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID NOT NULL, - signer_display_name VARCHAR(200) NOT NULL, - signature_file_id UUID NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL, - CONSTRAINT uq_saved_signatures_user_id UNIQUE (user_id) - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.saved_signatures;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1784000000001-SeedWagonsWithYardAssignment.ts b/apps/edr-freight-api/src/migrations/1784000000001-SeedWagonsWithYardAssignment.ts deleted file mode 100644 index a615fe9a4..000000000 --- a/apps/edr-freight-api/src/migrations/1784000000001-SeedWagonsWithYardAssignment.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Full wagon re-seed — runs in this order: - * - * 1. DELETE all existing wagons (hard delete, not soft). - * 2. UPSERT all 10 standard wagon types so they are guaranteed to exist. - * 3. INSERT 50 wagons per wagon type (500 total), distributed evenly across - * the 5 main operational yards (10 wagons per yard per type): - * - * KALITY — Kality Rail Terminal - * MOJO — Mojo Dry Port - * DIRE_DAWA — Dire Dawa Yard - * DJIB_PORT — Djibouti Port Terminal - * NAGAD — Nagad Terminal, Djibouti - * - * Wagon numbers follow the pattern -NNNN (e.g. NW5-0001 … NW5-0050). - * Yard IDs are fetched live from freight.yards so the migration is safe across - * all environments regardless of UUID values. - */ -export class SeedWagonsWithYardAssignment1784000000001 - implements MigrationInterface -{ - name = 'SeedWagonsWithYardAssignment1784000000001'; - - public async up(queryRunner: QueryRunner): Promise { - // ── STEP 1: Remove all wagons ────────────────────────────────────────── - await queryRunner.query(`DELETE FROM freight.wagons;`); - - // ── STEP 2: Ensure all 10 wagon types exist ──────────────────────────── - await queryRunner.query(` - INSERT INTO freight.wagon_types ( - code, - name, - capacity_tons, - length_meters, - max_wagons_per_train, - supported_load_types, - is_active, - tare_weight_tons - ) - VALUES - ('NW7', 'Double deck sedan wagon', 22, 26.066, NULL, ARRAY['vehicles', 'sedan'], true, 18.0), - ('NW5', 'Flat wagon (container)', 70, 14.000, 53, ARRAY['container', 'steel', 'machinery'], true, 22.0), - ('PW2', 'Box wagon', 70, 17.066, 18, ARRAY['general cargo', 'break bulk'], true, 20.0), - ('GW2', 'Tank wagon', 70, 12.228, 37, ARRAY['liquid', 'fuel'], true, 25.0), - ('CW4', 'Gondola covered wagon', 70, 13.976, 37, ARRAY['covered bulk cargo'], true, 22.0), - ('CW3', 'Gondola open wagon', 70, 13.976, NULL, ARRAY['open bulk cargo'], true, 20.0), - ('KW2', 'Hopper covered wagon', 69, 16.466, NULL, ARRAY['bulk grains'], true, 22.0), - ('KW3', 'Hopper open wagon', 70, 14.400, NULL, ARRAY['coal', 'bulk cargo'], true, 20.0), - ('NW6', 'Flat wagon (long cargo)', 70, 18.560, NULL, ARRAY['long cargo'], true, 22.0), - ('BW1', 'Refrigerated wagon', 38, 21.996, NULL, ARRAY['refrigerated cargo'], true, 24.0) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - capacity_tons = EXCLUDED.capacity_tons, - length_meters = EXCLUDED.length_meters, - max_wagons_per_train = EXCLUDED.max_wagons_per_train, - supported_load_types = EXCLUDED.supported_load_types, - is_active = true, - tare_weight_tons = EXCLUDED.tare_weight_tons, - deleted_at = NULL, - updated_at = now(); - `); - - // ── STEP 3: Seed 50 wagons per type across 5 yards ──────────────────── - await queryRunner.query(` - DO $$ - DECLARE - wt RECORD; - yard_kality UUID; - yard_mojo UUID; - yard_dire_dawa UUID; - yard_djib_port UUID; - yard_nagad UUID; - yards UUID[]; - i INT; - yard_id UUID; - wagon_num TEXT; - v_tare NUMERIC; - v_payload NUMERIC; - BEGIN - -- Fetch yard IDs by code (safe across envs — UUIDs differ per DB) - SELECT id INTO yard_kality FROM freight.yards WHERE code = 'KALITY' LIMIT 1; - SELECT id INTO yard_mojo FROM freight.yards WHERE code = 'MOJO' LIMIT 1; - SELECT id INTO yard_dire_dawa FROM freight.yards WHERE code = 'DIRE_DAWA' LIMIT 1; - SELECT id INTO yard_djib_port FROM freight.yards WHERE code = 'DJIB_PORT' LIMIT 1; - SELECT id INTO yard_nagad FROM freight.yards WHERE code = 'NAGAD' LIMIT 1; - - IF yard_kality IS NULL OR yard_mojo IS NULL OR yard_dire_dawa IS NULL - OR yard_djib_port IS NULL OR yard_nagad IS NULL - THEN - RAISE EXCEPTION 'One or more operational yards not found. Run the yards seed first.'; - END IF; - - yards := ARRAY[ - yard_kality, - yard_mojo, - yard_dire_dawa, - yard_djib_port, - yard_nagad - ]; - - FOR wt IN - SELECT id, code, capacity_tons, tare_weight_tons - FROM freight.wagon_types - WHERE is_active = true - ORDER BY code - LOOP - v_tare := COALESCE(wt.tare_weight_tons, 20.0); - v_payload := COALESCE(wt.capacity_tons, 60.0); - - FOR i IN 1 .. 50 LOOP - wagon_num := wt.code || '-' || LPAD(i::TEXT, 4, '0'); - yard_id := yards[ ((i - 1) % 5) + 1 ]; -- round-robin: 1→K, 2→M, 3→D, 4→J, 5→N, 6→K … - - INSERT INTO freight.wagons ( - id, - wagon_number, - wagon_type_id, - tare_weight, - max_payload_weight, - status, - current_yard_id, - train_id, - sequence_number, - notes, - train_set_wagon_id, - current_train_schedule_id, - created_at, - updated_at - ) - VALUES ( - uuid_generate_v4(), - wagon_num, - wt.id, - v_tare, - v_payload, - 'Available', - yard_id, - NULL, NULL, NULL, NULL, NULL, - now(), now() - ) - ON CONFLICT (wagon_number) DO NOTHING; - END LOOP; - - RAISE NOTICE 'Seeded 50 wagons for type %.', wt.code; - END LOOP; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Remove all seeded wagons (full wipe — mirrors what up() did) - await queryRunner.query(`DELETE FROM freight.wagons;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1784100000000-AddBookingRouteDayIndex.ts b/apps/edr-freight-api/src/migrations/1784100000000-AddBookingRouteDayIndex.ts deleted file mode 100644 index 544600bef..000000000 --- a/apps/edr-freight-api/src/migrations/1784100000000-AddBookingRouteDayIndex.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Day-level booking pool: customers select a DAY (route + day), not a specific - * train. The batch engine's pool query filters bookings on - * (origin_yard_id, destination_yard_id, scheduled_date, status); this partial - * index backs that scan. - */ -export class AddBookingRouteDayIndex1784100000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_route_day - ON freight.bookings (origin_yard_id, destination_yard_id, scheduled_date, status) - WHERE deleted_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_bookings_route_day;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1790000000000-CreateWarehouseModule.ts b/apps/edr-freight-api/src/migrations/1790000000000-CreateWarehouseModule.ts deleted file mode 100644 index 0f9021ff2..000000000 --- a/apps/edr-freight-api/src/migrations/1790000000000-CreateWarehouseModule.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateWarehouseModule1790000000000 implements MigrationInterface { - name = 'CreateWarehouseModule1790000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouses ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR(160) NOT NULL, - code VARCHAR(40) NOT NULL UNIQUE, - type VARCHAR(32) NOT NULL, - station_id UUID NULL, - location_name VARCHAR(200) NULL, - capacity_weight NUMERIC(14,3) NULL, - capacity_containers INT NULL, - current_weight NUMERIC(14,3) NOT NULL DEFAULT 0, - current_containers INT NOT NULL DEFAULT 0, - status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', - 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 - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_yards ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - warehouse_id UUID NOT NULL REFERENCES freight.warehouses(id) ON DELETE CASCADE, - name VARCHAR(160) NOT NULL, - code VARCHAR(40) NOT NULL, - type VARCHAR(32) NOT NULL, - capacity_weight NUMERIC(14,3) NULL, - capacity_containers INT NULL, - current_weight NUMERIC(14,3) NOT NULL DEFAULT 0, - current_containers INT NOT NULL DEFAULT 0, - status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', - 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, - CONSTRAINT uq_warehouse_yards_code UNIQUE (warehouse_id, code) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_zones ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - yard_id UUID NOT NULL REFERENCES freight.warehouse_yards(id) ON DELETE CASCADE, - name VARCHAR(160) NOT NULL, - code VARCHAR(40) NOT NULL, - type VARCHAR(32) NOT NULL, - capacity_weight NUMERIC(14,3) NULL, - capacity_containers INT NULL, - current_weight NUMERIC(14,3) NOT NULL DEFAULT 0, - current_containers INT NOT NULL DEFAULT 0, - status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', - 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, - CONSTRAINT uq_warehouse_zones_code UNIQUE (yard_id, code) - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_inventory ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - warehouse_id UUID NOT NULL REFERENCES freight.warehouses(id), - yard_id UUID NOT NULL REFERENCES freight.warehouse_yards(id), - zone_id UUID NOT NULL REFERENCES freight.warehouse_zones(id), - booking_id UUID NOT NULL, - cargo_id UUID NULL, - container_id UUID NULL, - goods_id UUID NULL, - quantity NUMERIC(12,3) NOT NULL DEFAULT 0, - weight NUMERIC(14,3) NOT NULL DEFAULT 0, - volume NUMERIC(12,3) NULL, - status VARCHAR(32) NOT NULL DEFAULT 'ARRIVED_AT_WAREHOUSE', - inspection_status VARCHAR(20) NULL, - arrived_at TIMESTAMPTZ NULL, - inspected_at TIMESTAMPTZ NULL, - ready_for_loading_at TIMESTAMPTZ NULL, - notes TEXT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ NULL - ); - `); - - const indexes: Array<[string, string, string]> = [ - ['idx_warehouses_type', 'warehouses', 'type'], - ['idx_warehouses_status', 'warehouses', 'status'], - ['idx_warehouses_station_id', 'warehouses', 'station_id'], - ['idx_warehouse_yards_warehouse_id', 'warehouse_yards', 'warehouse_id'], - ['idx_warehouse_yards_type', 'warehouse_yards', 'type'], - ['idx_warehouse_yards_status', 'warehouse_yards', 'status'], - ['idx_warehouse_zones_yard_id', 'warehouse_zones', 'yard_id'], - ['idx_warehouse_zones_type', 'warehouse_zones', 'type'], - ['idx_warehouse_zones_status', 'warehouse_zones', 'status'], - ['idx_warehouse_inventory_warehouse_id', 'warehouse_inventory', 'warehouse_id'], - ['idx_warehouse_inventory_yard_id', 'warehouse_inventory', 'yard_id'], - ['idx_warehouse_inventory_zone_id', 'warehouse_inventory', 'zone_id'], - ['idx_warehouse_inventory_booking_id', 'warehouse_inventory', 'booking_id'], - ['idx_warehouse_inventory_cargo_id', 'warehouse_inventory', 'cargo_id'], - ['idx_warehouse_inventory_container_id', 'warehouse_inventory', 'container_id'], - ['idx_warehouse_inventory_goods_id', 'warehouse_inventory', 'goods_id'], - ['idx_warehouse_inventory_status', 'warehouse_inventory', 'status'], - ]; - - for (const [indexName, table, column] of indexes) { - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS ${indexName} ON freight.${table}(${column});`, - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_inventory;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_zones;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_yards;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouses;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1790000000001-WarehouseBatch2.ts b/apps/edr-freight-api/src/migrations/1790000000001-WarehouseBatch2.ts deleted file mode 100644 index a1431d7bd..000000000 --- a/apps/edr-freight-api/src/migrations/1790000000001-WarehouseBatch2.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class WarehouseBatch21790000000001 implements MigrationInterface { - name = 'WarehouseBatch21790000000001'; - - public async up(queryRunner: QueryRunner): Promise { - // ── Capacity columns (weight + volume) on warehouse / yard / zone ────── - for (const table of ['warehouses', 'warehouse_yards', 'warehouse_zones']) { - await queryRunner.query(` - ALTER TABLE freight.${table} - ADD COLUMN IF NOT EXISTS max_weight NUMERIC(14,3) NULL, - ADD COLUMN IF NOT EXISTS max_volume NUMERIC(14,3) NULL, - ADD COLUMN IF NOT EXISTS current_volume NUMERIC(14,3) NOT NULL DEFAULT 0; - `); - // Backfill max_weight from the Batch 1 capacity_weight column. - await queryRunner.query(` - UPDATE freight.${table} SET max_weight = capacity_weight WHERE max_weight IS NULL; - `); - } - - // ── Inventory lifecycle: migrate Batch 1 statuses to Batch 2 set ─────── - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - ALTER COLUMN status SET DEFAULT 'RECEIVED'; - `); - await queryRunner.query(` - UPDATE freight.warehouse_inventory SET status = 'RECEIVED' WHERE status = 'ARRIVED_AT_WAREHOUSE'; - `); - await queryRunner.query(` - UPDATE freight.warehouse_inventory SET status = 'STORED' WHERE status = 'UNDER_INSPECTION'; - `); - - // ── New lifecycle timestamps ────────────────────────────────────────── - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - ADD COLUMN IF NOT EXISTS stored_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS reserved_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS loaded_at TIMESTAMPTZ NULL, - ADD COLUMN IF NOT EXISTS dispatched_at TIMESTAMPTZ NULL; - `); - - // booking_id becomes nullable (inventory can exist before booking linkage). - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory ALTER COLUMN booking_id DROP NOT NULL; - `); - - // ── Movement history ────────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_inventory_movement ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - inventory_id UUID NOT NULL REFERENCES freight.warehouse_inventory(id) ON DELETE CASCADE, - from_warehouse_id UUID NOT NULL, - from_yard_id UUID NOT NULL, - from_zone_id UUID NOT NULL, - to_warehouse_id UUID NOT NULL, - to_yard_id UUID NOT NULL, - to_zone_id UUID NOT NULL, - remarks TEXT NULL, - moved_by VARCHAR(120) NULL, - moved_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_warehouse_inventory_movement_inventory_id - ON freight.warehouse_inventory_movement(inventory_id); - `); - - // ── Activity log ────────────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_activity_log ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - inventory_id UUID NULL, - warehouse_id UUID NULL, - activity_type VARCHAR(40) NOT NULL, - description TEXT NULL, - performed_by VARCHAR(120) NULL, - 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_warehouse_activity_log_inventory_id - ON freight.warehouse_activity_log(inventory_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_activity_log_warehouse_id - ON freight.warehouse_activity_log(warehouse_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_activity_log_activity_type - ON freight.warehouse_activity_log(activity_type); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_activity_log;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_inventory_movement;`); - - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - DROP COLUMN IF EXISTS stored_at, - DROP COLUMN IF EXISTS reserved_at, - DROP COLUMN IF EXISTS loaded_at, - DROP COLUMN IF EXISTS dispatched_at; - `); - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory ALTER COLUMN status SET DEFAULT 'RECEIVED'; - `); - - for (const table of ['warehouses', 'warehouse_yards', 'warehouse_zones']) { - await queryRunner.query(` - ALTER TABLE freight.${table} - DROP COLUMN IF EXISTS max_weight, - DROP COLUMN IF EXISTS max_volume, - DROP COLUMN IF EXISTS current_volume; - `); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1790000000002-WarehouseBatch3.ts b/apps/edr-freight-api/src/migrations/1790000000002-WarehouseBatch3.ts deleted file mode 100644 index 4dcc9329c..000000000 --- a/apps/edr-freight-api/src/migrations/1790000000002-WarehouseBatch3.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Batch 3 — Warehouse → Loading → Train Departure visibility. - * Adds the warehouse_loadings record (inventory ↔ wagon). Does NOT touch any - * scheduling / wagon tables — the warehouse only reads from those. - */ -export class WarehouseBatch31790000000002 implements MigrationInterface { - name = 'WarehouseBatch31790000000002'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_loadings ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - warehouse_inventory_id UUID NOT NULL REFERENCES freight.warehouse_inventory(id) ON DELETE CASCADE, - booking_id UUID NULL, - wagon_id UUID NOT NULL, - loaded_at TIMESTAMPTZ NOT NULL DEFAULT now(), - loaded_by VARCHAR(120) NULL, - loaded_weight NUMERIC(14,3) NULL, - notes TEXT NULL, - 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_warehouse_loadings_inventory_id - ON freight.warehouse_loadings(warehouse_inventory_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_loadings_booking_id - ON freight.warehouse_loadings(booking_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_loadings_wagon_id - ON freight.warehouse_loadings(wagon_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_loadings;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000000-AddActiveModeAndOnboardingToExternalProfiles.ts b/apps/edr-freight-api/src/migrations/1791000000000-AddActiveModeAndOnboardingToExternalProfiles.ts deleted file mode 100644 index 8484ca0f9..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000000-AddActiveModeAndOnboardingToExternalProfiles.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddActiveModeAndOnboardingToExternalProfiles1791000000000 - implements MigrationInterface -{ - name = 'AddActiveModeAndOnboardingToExternalProfiles1791000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.external_profiles - ADD COLUMN IF NOT EXISTS active_profile_type varchar(32); - `); - - await queryRunner.query(` - ALTER TABLE freight.external_profiles - ADD COLUMN IF NOT EXISTS onboarding_step varchar(40); - `); - - await queryRunner.query(` - ALTER TABLE freight.external_profiles - ADD COLUMN IF NOT EXISTS onboarding_completed boolean NOT NULL DEFAULT false; - `); - - // Existing users already use the portal — never re-gate them behind the - // new onboarding wizard. - await queryRunner.query(` - UPDATE freight.external_profiles - SET onboarding_completed = true - WHERE onboarding_completed = false; - `); - - // Backfill the active mode for existing users from their company's - // operational profiles. Prefer importer, then exporter, then whichever - // single profile the company has (forwarder/dj/transporter). - await queryRunner.query(` - UPDATE freight.external_profiles ep - SET active_profile_type = cp.type - FROM ( - SELECT DISTINCT ON (company_id) company_id, type - FROM freight.company_profiles - ORDER BY company_id, - CASE type - WHEN 'importer' THEN 0 - WHEN 'exporter' THEN 1 - ELSE 2 - END - ) cp - WHERE ep.company_id = cp.company_id - AND ep.active_profile_type IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.external_profiles - DROP COLUMN IF EXISTS onboarding_completed; - `); - await queryRunner.query(` - ALTER TABLE freight.external_profiles - DROP COLUMN IF EXISTS onboarding_step; - `); - await queryRunner.query(` - ALTER TABLE freight.external_profiles - DROP COLUMN IF EXISTS active_profile_type; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000000-AddWarehouseAllocationAndFeeRules.ts b/apps/edr-freight-api/src/migrations/1791000000000-AddWarehouseAllocationAndFeeRules.ts deleted file mode 100644 index 1cad0fe66..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000000-AddWarehouseAllocationAndFeeRules.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableColumn } from 'typeorm'; - -/** - * Batch 5 — warehouse allocation rules, storage/demurrage fee rules, - * and demurrage lifecycle timestamps on inventory. Idempotent. - */ -export class AddWarehouseAllocationAndFeeRules1791000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'warehouse_allocation_rules', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'name', type: 'varchar', length: '160' }, - { name: 'priority', type: 'int', default: 100 }, - { name: 'freight_type', type: 'varchar', length: '16', isNullable: true }, - { name: 'trade_direction', type: 'varchar', length: '16', isNullable: true }, - { name: 'cargo_type_code', type: 'varchar', length: '50', isNullable: true }, - { name: 'container_status', type: 'varchar', length: '24', isNullable: true }, - { name: 'requires_inspection', type: 'boolean', isNullable: true }, - { name: 'target_facility_code', type: 'varchar', length: '40', isNullable: true }, - { name: 'target_yard_code', type: 'varchar', length: '40' }, - { name: 'target_warehouse_code', type: 'varchar', length: '40', isNullable: true }, - { name: 'target_zone_code', type: 'varchar', length: '40', isNullable: true }, - { name: 'storage_type', type: 'varchar', length: '80', isNullable: true }, - { name: 'is_active', type: 'boolean', default: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - indices: [ - { name: 'idx_war_priority', columnNames: ['priority'] }, - { name: 'idx_war_active', columnNames: ['is_active'] }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'warehouse_fee_rules', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'name', type: 'varchar', length: '160' }, - { name: 'rule_type', type: 'varchar', length: '20' }, - { name: 'priority', type: 'int', default: 100 }, - { name: 'freight_type', type: 'varchar', length: '16', isNullable: true }, - { name: 'trade_direction', type: 'varchar', length: '16', isNullable: true }, - { name: 'cargo_type_code', type: 'varchar', length: '50', isNullable: true }, - { name: 'container_type', type: 'varchar', length: '40', isNullable: true }, - { name: 'facility_id', type: 'uuid', isNullable: true }, - { name: 'warehouse_id', type: 'uuid', isNullable: true }, - { name: 'yard_id', type: 'uuid', isNullable: true }, - { name: 'zone_id', type: 'uuid', isNullable: true }, - { name: 'free_days', type: 'int', default: 0 }, - { name: 'rate_per_day', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'tiers', type: 'jsonb', default: "'[]'" }, - { name: 'currency', type: 'varchar', length: '8', default: "'USD'" }, - { name: 'is_active', type: 'boolean', default: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - indices: [ - { name: 'idx_wfr_type', columnNames: ['rule_type'] }, - { name: 'idx_wfr_active', columnNames: ['is_active'] }, - ], - }), - true, - ); - - const inventoryTable = await queryRunner.getTable('freight.warehouse_inventory'); - if (inventoryTable) { - const columnsToAdd = [ - { name: 'inspection_started_at', type: 'timestamptz', isNullable: true }, - { name: 'inspection_completed_at', type: 'timestamptz', isNullable: true }, - { name: 'ready_for_pickup_at', type: 'timestamptz', isNullable: true }, - { name: 'release_date', type: 'timestamptz', isNullable: true }, - { name: 'gate_cleared_at', type: 'timestamptz', isNullable: true }, - ]; - - const columnsToCreate = columnsToAdd.filter( - (col) => !inventoryTable.columns.some((c) => c.name === col.name), - ); - - if (columnsToCreate.length > 0) { - await queryRunner.addColumns( - 'freight.warehouse_inventory', - columnsToCreate.map((col) => new TableColumn(col)), - ); - } - } - } - - public async down(queryRunner: QueryRunner): Promise { - const inventoryTable = await queryRunner.getTable('freight.warehouse_inventory'); - if (inventoryTable) { - const columnNames = [ - 'inspection_started_at', - 'inspection_completed_at', - 'ready_for_pickup_at', - 'release_date', - 'gate_cleared_at', - ]; - const columnsToRemove = columnNames.filter((name) => - inventoryTable.columns.some((c) => c.name === name), - ); - - if (columnsToRemove.length > 0) { - await queryRunner.dropColumns('freight.warehouse_inventory', columnsToRemove); - } - } - - const feeRulesTable = await queryRunner.getTable('freight.warehouse_fee_rules'); - if (feeRulesTable) { - await queryRunner.dropTable('freight.warehouse_fee_rules', true); - } - - const allocationRulesTable = await queryRunner.getTable('freight.warehouse_allocation_rules'); - if (allocationRulesTable) { - await queryRunner.dropTable('freight.warehouse_allocation_rules', true); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000001-AddCompanyProfileIdToBookings.ts b/apps/edr-freight-api/src/migrations/1791000000001-AddCompanyProfileIdToBookings.ts deleted file mode 100644 index 0ca1a0d28..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000001-AddCompanyProfileIdToBookings.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCompanyProfileIdToBookings1791000000001 - implements MigrationInterface -{ - name = 'AddCompanyProfileIdToBookings1791000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS company_profile_id UUID; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_bookings_company_profile_id - ON freight.bookings(company_profile_id); - `); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_bookings_company_profile_id' - ) THEN - ALTER TABLE freight.bookings - ADD CONSTRAINT "FK_bookings_company_profile_id" - FOREIGN KEY (company_profile_id) - REFERENCES freight.company_profiles(id); - END IF; - END $$; - `); - - // Backfill by natural mapping: IMPORT → importer profile, EXPORT → exporter - // profile, for each booking's own company. - await queryRunner.query(` - UPDATE freight.bookings b - SET company_profile_id = cp.id - FROM freight.company_profiles cp - WHERE cp.company_id = b.company_id - AND b.company_profile_id IS NULL - AND ( - (b.trade_direction = 'IMPORT' AND cp.type = 'importer') OR - (b.trade_direction = 'EXPORT' AND cp.type = 'exporter') - ); - `); - - // Forwarder / single-profile companies: one profile per company, so the - // mapping is unambiguous regardless of trade direction. - await queryRunner.query(` - UPDATE freight.bookings b - SET company_profile_id = cp.id - FROM freight.company_profiles cp - JOIN freight.companies c ON c.id = cp.company_id - WHERE cp.company_id = b.company_id - AND c.type <> 'customer' - AND b.company_profile_id IS NULL; - `); - - // Remaining customer-owned rows (e.g. DOMESTIC, or a direction with no - // matching profile): attribute to the company's importer profile, else its - // exporter profile, so nothing disappears from the customer's list. - await queryRunner.query(` - UPDATE freight.bookings b - SET company_profile_id = cp.id - FROM ( - SELECT DISTINCT ON (company_id) company_id, id - FROM freight.company_profiles - ORDER BY company_id, - CASE type - WHEN 'importer' THEN 0 - WHEN 'exporter' THEN 1 - ELSE 2 - END - ) cp - WHERE cp.company_id = b.company_id - AND b.company_id IS NOT NULL - AND b.company_profile_id IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP CONSTRAINT IF EXISTS "FK_bookings_company_profile_id"; - `); - await queryRunner.query(` - DROP INDEX IF EXISTS freight.idx_bookings_company_profile_id; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS company_profile_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000001-AddWarehouseFeeInvoices.ts b/apps/edr-freight-api/src/migrations/1791000000001-AddWarehouseFeeInvoices.ts deleted file mode 100644 index 662a35739..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000001-AddWarehouseFeeInvoices.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { MigrationInterface, QueryRunner, Table } from 'typeorm'; - -/** Batch 6 — warehouse fee invoices + invoice items. Idempotent (createTable ifNotExists). */ -export class AddWarehouseFeeInvoices1791000000001 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'warehouse_fee_invoices', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'invoice_number', type: 'varchar', length: '40', isUnique: true }, - { name: 'booking_id', type: 'uuid', isNullable: true }, - { name: 'customer_id', type: 'uuid', isNullable: true }, - { name: 'inventory_id', type: 'uuid' }, - { name: 'facility_id', type: 'uuid', isNullable: true }, - { name: 'warehouse_id', type: 'uuid', isNullable: true }, - { name: 'yard_id', type: 'uuid', isNullable: true }, - { name: 'zone_id', type: 'uuid', isNullable: true }, - { name: 'invoice_type', type: 'varchar', length: '32', default: "'MIXED_WAREHOUSE_FEES'" }, - { name: 'status', type: 'varchar', length: '20', default: "'DRAFT'" }, - { name: 'subtotal_amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'tax_amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'total_amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'paid_amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'balance_amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'currency', type: 'varchar', length: '8', default: "'USD'" }, - { name: 'period_start', type: 'timestamptz', isNullable: true }, - { name: 'period_end', type: 'timestamptz', isNullable: true }, - { name: 'issued_at', type: 'timestamptz', isNullable: true }, - { name: 'due_date', type: 'timestamptz', isNullable: true }, - { name: 'paid_at', type: 'timestamptz', isNullable: true }, - { name: 'cancelled_at', type: 'timestamptz', isNullable: true }, - { name: 'payments', type: 'jsonb', default: "'[]'" }, - { name: 'notes', type: 'text', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - indices: [ - { name: 'idx_wfi_booking', columnNames: ['booking_id'] }, - { name: 'idx_wfi_inventory', columnNames: ['inventory_id'] }, - { name: 'idx_wfi_status', columnNames: ['status'] }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'warehouse_fee_invoice_items', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'invoice_id', type: 'uuid' }, - { name: 'fee_rule_id', type: 'uuid', isNullable: true }, - { name: 'fee_type', type: 'varchar', length: '32' }, - { name: 'description', type: 'varchar', length: '255' }, - { name: 'quantity', type: 'numeric', precision: 12, scale: 2, default: 1 }, - { name: 'unit_rate', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'amount', type: 'numeric', precision: 14, scale: 2, default: 0 }, - { name: 'currency', type: 'varchar', length: '8', default: "'USD'" }, - { name: 'chargeable_days', type: 'int', isNullable: true }, - { name: 'free_days', type: 'int', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['invoice_id'], - referencedSchema: 'freight', - referencedTableName: 'warehouse_fee_invoices', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - indices: [{ name: 'idx_wfii_invoice', columnNames: ['invoice_id'] }], - }), - true, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.warehouse_fee_invoice_items', true); - await queryRunner.dropTable('freight.warehouse_fee_invoices', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000002-AddImportPickupDeliveryColumns.ts b/apps/edr-freight-api/src/migrations/1791000000002-AddImportPickupDeliveryColumns.ts deleted file mode 100644 index 3e272c859..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000002-AddImportPickupDeliveryColumns.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Import pickup branch on warehouse_inventory: - * - release_order_reference: DO / release order number sent to the customer - * - delivered_at: when the goods were handed over (proof of delivery) - * - * Idempotent: the shared dev DB may already carry some of these columns - * (added by another checkout), so only add what is missing. - */ -export class AddImportPickupDeliveryColumns1791000000002 implements MigrationInterface { - private readonly table = 'freight.warehouse_inventory'; - - public async up(queryRunner: QueryRunner): Promise { - if (!(await queryRunner.hasColumn(this.table, 'release_order_reference'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ name: 'release_order_reference', type: 'varchar', length: '100', isNullable: true }), - ); - } - if (!(await queryRunner.hasColumn(this.table, 'delivered_at'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ name: 'delivered_at', type: 'timestamptz', isNullable: true }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - if (await queryRunner.hasColumn(this.table, 'release_order_reference')) { - await queryRunner.dropColumn(this.table, 'release_order_reference'); - } - if (await queryRunner.hasColumn(this.table, 'delivered_at')) { - await queryRunner.dropColumn(this.table, 'delivered_at'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000002-AddNationalityToCompanies.ts b/apps/edr-freight-api/src/migrations/1791000000002-AddNationalityToCompanies.ts deleted file mode 100644 index 1a05a9e45..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000002-AddNationalityToCompanies.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddNationalityToCompanies1791000000002 - implements MigrationInterface -{ - name = "AddNationalityToCompanies1791000000002"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS nationality varchar(32); - `); - - // Existing companies default to Ethiopian (country defaults to Ethiopia). - await queryRunner.query(` - UPDATE freight.companies - SET nationality = 'ethiopian' - WHERE nationality IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS nationality; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000003-AddBusinessLicenseFilesToCompanyProfiles.ts b/apps/edr-freight-api/src/migrations/1791000000003-AddBusinessLicenseFilesToCompanyProfiles.ts deleted file mode 100644 index d1e0412f0..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000003-AddBusinessLicenseFilesToCompanyProfiles.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddBusinessLicenseFilesToCompanyProfiles1791000000003 - implements MigrationInterface -{ - name = "AddBusinessLicenseFilesToCompanyProfiles1791000000003"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.company_profiles - ADD COLUMN IF NOT EXISTS business_license_files jsonb; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.company_profiles - DROP COLUMN IF EXISTS business_license_files; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000003-AddETradeFieldsToCompanies.ts b/apps/edr-freight-api/src/migrations/1791000000003-AddETradeFieldsToCompanies.ts deleted file mode 100644 index 07f0d2555..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000003-AddETradeFieldsToCompanies.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddETradeFieldsToCompanies1791000000003 - implements MigrationInterface -{ - name = "AddETradeFieldsToCompanies1791000000003"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS licence_number varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS status_description text; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS date_registered varchar(50); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS renewed_from varchar(50); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS renewal_date varchar(50); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS renewed_to varchar(50); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS region varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS zone varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS woreda varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS kebele varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS house_no varchar(100); - `); - await queryRunner.query(` - ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS etrade_phone varchar(20); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS licence_number; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS status_description; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS date_registered; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS renewed_from; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS renewal_date; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS renewed_to; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS region; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS zone; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS woreda; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS kebele; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS house_no; - `); - await queryRunner.query(` - ALTER TABLE freight.companies - DROP COLUMN IF EXISTS etrade_phone; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000003-AddInventoryUnloadedAt.ts b/apps/edr-freight-api/src/migrations/1791000000003-AddInventoryUnloadedAt.ts deleted file mode 100644 index 6009d9ea4..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000003-AddInventoryUnloadedAt.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Batch 8 — train-arrival unload landing state on warehouse_inventory: - * - unloaded_at: when the goods were unloaded off the arrived train (before storage/inspection) - * - * The `status` column is a free varchar, so the new 'UNLOADED' value needs no schema change. - * Idempotent: the shared dev DB may already carry this column (added by another checkout). - */ -export class AddInventoryUnloadedAt1791000000003 implements MigrationInterface { - private readonly table = 'freight.warehouse_inventory'; - - public async up(queryRunner: QueryRunner): Promise { - if (!(await queryRunner.hasColumn(this.table, 'unloaded_at'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ name: 'unloaded_at', type: 'timestamptz', isNullable: true }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - if (await queryRunner.hasColumn(this.table, 'unloaded_at')) { - await queryRunner.dropColumn(this.table, 'unloaded_at'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000004-AddFacilityIdToWarehousesFix.ts b/apps/edr-freight-api/src/migrations/1791000000004-AddFacilityIdToWarehousesFix.ts deleted file mode 100644 index df239a375..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000004-AddFacilityIdToWarehousesFix.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn, TableForeignKey } from 'typeorm'; - -/** - * Fix: migration 1750000000001 (AddFacilityIdToWarehouses) silently skipped because - * the freight.warehouses table didn't exist yet at that timestamp. The column was - * never added. Add it now with idempotent guards. - */ -export class AddFacilityIdToWarehousesFix1791000000004 implements MigrationInterface { - private readonly table = 'freight.warehouses'; - - public async up(queryRunner: QueryRunner): Promise { - if (!(await queryRunner.hasColumn(this.table, 'facility_id'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ - name: 'facility_id', - type: 'uuid', - isNullable: true, - }), - ); - } - - const table = await queryRunner.getTable(this.table); - const hasFk = table?.foreignKeys.some((fk) => fk.columnNames.includes('facility_id')); - if (!hasFk) { - await queryRunner.createForeignKey( - this.table, - new TableForeignKey({ - columnNames: ['facility_id'], - referencedColumnNames: ['id'], - referencedTableName: 'facilities', - referencedSchema: 'freight', - onDelete: 'SET NULL', - }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - const table = await queryRunner.getTable(this.table); - if (!table) return; - - const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.includes('facility_id')); - if (foreignKey) { - await queryRunner.dropForeignKey(this.table, foreignKey); - } - - if (await queryRunner.hasColumn(this.table, 'facility_id')) { - await queryRunner.dropColumn(this.table, 'facility_id'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1791000000005-AddWarehouseInventoryInspectionStatusFix.ts b/apps/edr-freight-api/src/migrations/1791000000005-AddWarehouseInventoryInspectionStatusFix.ts deleted file mode 100644 index 4a59e33b1..000000000 --- a/apps/edr-freight-api/src/migrations/1791000000005-AddWarehouseInventoryInspectionStatusFix.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Fix for fresh deployments: AddWarehouseInspection1750000000003 runs before - * the warehouse_inventory table exists, so it cannot add inspection_status. - */ -export class AddWarehouseInventoryInspectionStatusFix1791000000005 implements MigrationInterface { - private readonly table = 'freight.warehouse_inventory'; - - public async up(queryRunner: QueryRunner): Promise { - if ((await queryRunner.hasTable(this.table)) && !(await queryRunner.hasColumn(this.table, 'inspection_status'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ name: 'inspection_status', type: 'varchar', length: '20', isNullable: true }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - if ((await queryRunner.hasTable(this.table)) && (await queryRunner.hasColumn(this.table, 'inspection_status'))) { - await queryRunner.dropColumn(this.table, 'inspection_status'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1791999999999-CreateDropdownSettings.ts b/apps/edr-freight-api/src/migrations/1791999999999-CreateDropdownSettings.ts deleted file mode 100644 index d86efa239..000000000 --- a/apps/edr-freight-api/src/migrations/1791999999999-CreateDropdownSettings.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Creates the generic dropdown settings tables (freight.dropdown_settings + - * freight.dropdown_options) backing the DropdownSetting / DropdownOption - * entities. These tables previously only existed via `synchronize` on some - * databases; this migration makes them part of the migration history so the - * SeedGeneralContractPeriod migration (which inserts into them) can run on a - * fresh database. Idempotent so it is safe on DBs where the tables already exist. - */ -export class CreateDropdownSettings1791999999999 - implements MigrationInterface -{ - name = 'CreateDropdownSettings1791999999999'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS "freight"."dropdown_settings" ( - "id" uuid NOT NULL DEFAULT gen_random_uuid(), - "code" varchar(128) NOT NULL, - "label" varchar(256) NOT NULL, - "description" text, - "multiple" boolean NOT NULL DEFAULT false, - "meta" jsonb, - "created_at" timestamptz NOT NULL DEFAULT now(), - "updated_at" timestamptz NOT NULL DEFAULT now(), - "deleted_at" timestamptz, - CONSTRAINT "PK_dropdown_settings" PRIMARY KEY ("id") - ); - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_dropdown_settings_code" - ON "freight"."dropdown_settings" ("code"); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS "freight"."dropdown_options" ( - "id" uuid NOT NULL DEFAULT gen_random_uuid(), - "setting_id" uuid NOT NULL, - "value" varchar(256) NOT NULL, - "label" varchar(256) NOT NULL, - "note" text, - "is_disabled" boolean NOT NULL DEFAULT false, - "display_order" integer NOT NULL DEFAULT 0, - "meta" jsonb, - "created_at" timestamptz NOT NULL DEFAULT now(), - "updated_at" timestamptz NOT NULL DEFAULT now(), - "deleted_at" timestamptz, - CONSTRAINT "PK_dropdown_options" PRIMARY KEY ("id"), - CONSTRAINT "FK_dropdown_options_setting" FOREIGN KEY ("setting_id") - REFERENCES "freight"."dropdown_settings" ("id") ON DELETE CASCADE - ); - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_dropdown_options_setting_value" - ON "freight"."dropdown_options" ("setting_id", "value"); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP TABLE IF EXISTS "freight"."dropdown_options";`, - ); - await queryRunner.query( - `DROP TABLE IF EXISTS "freight"."dropdown_settings";`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1792000000000-AddUnitOfMeasureToCargoTypes.ts b/apps/edr-freight-api/src/migrations/1792000000000-AddUnitOfMeasureToCargoTypes.ts deleted file mode 100644 index 6ec9d60cd..000000000 --- a/apps/edr-freight-api/src/migrations/1792000000000-AddUnitOfMeasureToCargoTypes.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddUnitOfMeasureToCargoTypes1792000000000 - implements MigrationInterface -{ - name = 'AddUnitOfMeasureToCargoTypes1792000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.cargo_types ADD COLUMN IF NOT EXISTS unit_of_measure VARCHAR(16);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.cargo_types DROP COLUMN IF EXISTS unit_of_measure;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1792000000001-AddBookingTypeAndContractFields.ts b/apps/edr-freight-api/src/migrations/1792000000001-AddBookingTypeAndContractFields.ts deleted file mode 100644 index c55186a38..000000000 --- a/apps/edr-freight-api/src/migrations/1792000000001-AddBookingTypeAndContractFields.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddBookingTypeAndContractFields1792000000001 - implements MigrationInterface -{ - name = 'AddBookingTypeAndContractFields1792000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS booking_type VARCHAR(20) NOT NULL DEFAULT 'ONE_TIME';`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ;`, - ); - // General contracts have no shipment date at creation — relax the NOT NULL. - await queryRunner.query( - `ALTER TABLE freight.bookings ALTER COLUMN scheduled_date DROP NOT NULL;`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_bookings_booking_type ON freight.bookings (booking_type);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight.idx_bookings_booking_type;`, - ); - // Reinstate NOT NULL only if no null rows exist (general contracts would block it). - await queryRunner.query( - `ALTER TABLE freight.bookings ALTER COLUMN scheduled_date SET NOT NULL;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS expires_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS booking_type;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1792000000002-CreateBookingOrders.ts b/apps/edr-freight-api/src/migrations/1792000000002-CreateBookingOrders.ts deleted file mode 100644 index ceb98b5d1..000000000 --- a/apps/edr-freight-api/src/migrations/1792000000002-CreateBookingOrders.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -export class CreateBookingOrders1792000000002 implements MigrationInterface { - name = 'CreateBookingOrders1792000000002'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'booking_orders', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'reference', type: 'varchar', length: '64', isUnique: true }, - { name: 'contract_booking_id', type: 'uuid' }, - { name: 'booking_id', type: 'uuid', isNullable: true }, - { name: 'company_id', type: 'uuid', isNullable: true }, - { name: 'scheduled_date', type: 'timestamptz' }, - { name: 'status', type: 'varchar', length: '40', default: "'PAID'" }, - { name: 'scheduling_status', type: 'varchar', length: '30', default: "'NOT_SCHEDULED'" }, - { name: 'train_schedule_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.createIndex( - 'freight.booking_orders', - new TableIndex({ name: 'idx_booking_orders_contract', columnNames: ['contract_booking_id'] }), - ); - await queryRunner.createIndex( - 'freight.booking_orders', - new TableIndex({ name: 'idx_booking_orders_company', columnNames: ['company_id'] }), - ); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'booking_order_lines', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'order_id', type: 'uuid' }, - { name: 'container_type_id', type: 'uuid', isNullable: true }, - { name: 'quantity', type: 'numeric', precision: 12, scale: 3 }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['order_id'], - referencedSchema: 'freight', - referencedTableName: 'booking_orders', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.booking_order_lines', - new TableIndex({ name: 'idx_booking_order_lines_order', columnNames: ['order_id'] }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.booking_order_lines', true); - await queryRunner.dropTable('freight.booking_orders', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1792000000003-SeedGeneralContractPeriod.ts b/apps/edr-freight-api/src/migrations/1792000000003-SeedGeneralContractPeriod.ts deleted file mode 100644 index e6c0708d4..000000000 --- a/apps/edr-freight-api/src/migrations/1792000000003-SeedGeneralContractPeriod.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Seeds the global "general contract period" setting (months). Stored as a - * dropdown_settings row with a single option whose `value` holds the month count - * so backoffice can manage it through the existing settings UI later. - */ -export class SeedGeneralContractPeriod1792000000003 - implements MigrationInterface -{ - name = 'SeedGeneralContractPeriod1792000000003'; - private readonly code = 'general_contract_period'; - - public async up(queryRunner: QueryRunner): Promise { - const existing = await queryRunner.query( - `SELECT id FROM freight.dropdown_settings WHERE code = $1 LIMIT 1;`, - [this.code], - ); - if (existing.length > 0) return; - - const inserted = await queryRunner.query( - `INSERT INTO freight.dropdown_settings (code, label, description, multiple) - VALUES ($1, $2, $3, false) - RETURNING id;`, - [ - this.code, - 'General Contract Period (months)', - 'How many months a general contract stays open for ordering after activation.', - ], - ); - const settingId = inserted[0].id; - - await queryRunner.query( - `INSERT INTO freight.dropdown_options (setting_id, value, label, display_order) - VALUES ($1, $2, $3, 0);`, - [settingId, '3', '3 months'], - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM freight.dropdown_settings WHERE code = $1;`, - [this.code], - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1792000000004-SeedContractValidityPeriods.ts b/apps/edr-freight-api/src/migrations/1792000000004-SeedContractValidityPeriods.ts deleted file mode 100644 index e635d19c1..000000000 --- a/apps/edr-freight-api/src/migrations/1792000000004-SeedContractValidityPeriods.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Seeds the admin-configurable "contract validity periods" setting (days). Stored - * as a dropdown_settings row whose options each hold a day count in `value`, so - * backoffice manages them through the existing Dropdown Settings UI and the - * contract staff-accept dialog only offers the configured durations. - */ -export class SeedContractValidityPeriods1792000000004 - implements MigrationInterface -{ - name = 'SeedContractValidityPeriods1792000000004'; - private readonly code = 'contract_validity_periods'; - private readonly options: Array<{ value: string; label: string }> = [ - { value: '180', label: '6 months' }, - { value: '365', label: '1 year' }, - { value: '730', label: '2 years' }, - ]; - - public async up(queryRunner: QueryRunner): Promise { - const existing = await queryRunner.query( - `SELECT id FROM freight.dropdown_settings WHERE code = $1 LIMIT 1;`, - [this.code], - ); - if (existing.length > 0) return; - - const inserted = await queryRunner.query( - `INSERT INTO freight.dropdown_settings (code, label, description, multiple) - VALUES ($1, $2, $3, false) - RETURNING id;`, - [ - this.code, - 'Contract Validity Periods (days)', - 'Validity durations (in days) a staff can choose when accepting a submitted contract.', - ], - ); - const settingId = inserted[0].id; - - for (let i = 0; i < this.options.length; i++) { - const opt = this.options[i]; - await queryRunner.query( - `INSERT INTO freight.dropdown_options (setting_id, value, label, display_order) - VALUES ($1, $2, $3, $4);`, - [settingId, opt.value, opt.label, i], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM freight.dropdown_settings WHERE code = $1;`, - [this.code], - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1800000000001-AddVehicleDriverAssignment.ts b/apps/edr-freight-api/src/migrations/1800000000001-AddVehicleDriverAssignment.ts deleted file mode 100644 index 7a45a881b..000000000 --- a/apps/edr-freight-api/src/migrations/1800000000001-AddVehicleDriverAssignment.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Add driver assignment fields to vehicles table - */ -export class AddVehicleDriverAssignment1800000000001 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const vehiclesTable = await queryRunner.getTable('freight.vehicles'); - if (vehiclesTable) { - const hasAssignedDriverId = vehiclesTable.columns.some((col) => col.name === 'assigned_driver_id'); - if (!hasAssignedDriverId) { - await queryRunner.addColumn( - 'freight.vehicles', - new TableColumn({ - name: 'assigned_driver_id', - type: 'uuid', - isNullable: true, - }), - ); - } - - const hasAssignedDriverName = vehiclesTable.columns.some((col) => col.name === 'assigned_driver_name'); - if (!hasAssignedDriverName) { - await queryRunner.addColumn( - 'freight.vehicles', - new TableColumn({ - name: 'assigned_driver_name', - type: 'varchar', - isNullable: true, - }), - ); - } - } - } - - public async down(queryRunner: QueryRunner): Promise { - const vehiclesTable = await queryRunner.getTable('freight.vehicles'); - if (vehiclesTable) { - const hasAssignedDriverId = vehiclesTable.columns.some((col) => col.name === 'assigned_driver_id'); - if (hasAssignedDriverId) { - await queryRunner.dropColumn('freight.vehicles', 'assigned_driver_id'); - } - - const hasAssignedDriverName = vehiclesTable.columns.some((col) => col.name === 'assigned_driver_name'); - if (hasAssignedDriverName) { - await queryRunner.dropColumn('freight.vehicles', 'assigned_driver_name'); - } - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000000-CreateFirstMile.ts b/apps/edr-freight-api/src/migrations/1810000000000-CreateFirstMile.ts deleted file mode 100644 index 10c4f3a44..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000000-CreateFirstMile.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; - -/** - * Create the freight.first_mile table — one row per booking's first-mile - * (door → terminal) leg, with payment split and an optional assigned vehicle. - */ -export class CreateFirstMile1810000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.first_mile'); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: 'freight.first_mile', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'gen_random_uuid()', - }, - { name: 'booking_id', type: 'uuid', isNullable: false }, - { - name: 'status', - type: 'varchar', - length: '30', - default: `'PAYMENT_PENDING'`, - isNullable: false, - }, - { - name: 'advanced_payment', - type: 'numeric', - precision: 14, - scale: 2, - default: 0, - isNullable: false, - }, - { - name: 'remaining_payment', - type: 'numeric', - precision: 14, - scale: 2, - default: 0, - isNullable: false, - }, - { - name: 'estimated_km', - type: 'numeric', - precision: 10, - scale: 2, - isNullable: true, - }, - { - name: 'exact_km', - type: 'numeric', - precision: 10, - scale: 2, - isNullable: true, - }, - { name: 'vehicle_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.first_mile', - new TableForeignKey({ - columnNames: ['booking_id'], - referencedTableName: 'freight.bookings', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - - await queryRunner.createForeignKey( - 'freight.first_mile', - new TableForeignKey({ - columnNames: ['vehicle_id'], - referencedTableName: 'freight.vehicles', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - - await queryRunner.query( - `CREATE INDEX "IDX_first_mile_booking_id" ON "freight"."first_mile" ("booking_id")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_first_mile_status" ON "freight"."first_mile" ("status")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_first_mile_vehicle_id" ON "freight"."first_mile" ("vehicle_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.first_mile'); - if (exists) { - await queryRunner.dropTable('freight.first_mile'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000001-CreateLastMile.ts b/apps/edr-freight-api/src/migrations/1810000000001-CreateLastMile.ts deleted file mode 100644 index 3c0ee8dfc..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000001-CreateLastMile.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; - -/** - * Create the freight.last_mile table — one row per booking's last-mile - * (terminal → door) leg, with payment split and an optional assigned vehicle. - */ -export class CreateLastMile1810000000001 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.last_mile'); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: 'freight.last_mile', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'gen_random_uuid()', - }, - { name: 'booking_id', type: 'uuid', isNullable: false }, - { - name: 'status', - type: 'varchar', - length: '30', - default: `'PAYMENT_PENDING'`, - isNullable: false, - }, - { - name: 'advanced_payment', - type: 'numeric', - precision: 14, - scale: 2, - default: 0, - isNullable: false, - }, - { - name: 'remaining_payment', - type: 'numeric', - precision: 14, - scale: 2, - default: 0, - isNullable: false, - }, - { - name: 'estimated_km', - type: 'numeric', - precision: 10, - scale: 2, - isNullable: true, - }, - { - name: 'exact_km', - type: 'numeric', - precision: 10, - scale: 2, - isNullable: true, - }, - { name: 'vehicle_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', - new TableForeignKey({ - columnNames: ['booking_id'], - referencedTableName: 'freight.bookings', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - - await queryRunner.createForeignKey( - 'freight.last_mile', - new TableForeignKey({ - columnNames: ['vehicle_id'], - referencedTableName: 'freight.vehicles', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - - await queryRunner.query( - `CREATE INDEX "IDX_last_mile_booking_id" ON "freight"."last_mile" ("booking_id")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_last_mile_status" ON "freight"."last_mile" ("status")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_last_mile_vehicle_id" ON "freight"."last_mile" ("vehicle_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.last_mile'); - if (exists) { - await queryRunner.dropTable('freight.last_mile'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts b/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts deleted file mode 100644 index a2a1aae17..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -export class AddVehicleCodeAndPlates1810000000002 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const hasCode = await queryRunner.hasColumn('freight.vehicles', 'code'); - if (!hasCode) { - await queryRunner.addColumn( - 'freight.vehicles', - new TableColumn({ name: 'code', type: 'varchar', isNullable: true }), - ); - } - - const hasPower = await queryRunner.hasColumn('freight.vehicles', 'power_plate_no'); - if (!hasPower) { - await queryRunner.addColumn( - 'freight.vehicles', - new TableColumn({ name: 'power_plate_no', type: 'varchar', isNullable: true }), - ); - } - - const hasTrailer = await queryRunner.hasColumn('freight.vehicles', 'trailer_plate_no'); - if (!hasTrailer) { - await queryRunner.addColumn( - 'freight.vehicles', - new TableColumn({ name: 'trailer_plate_no', type: 'varchar', isNullable: true }), - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumn('freight.vehicles', 'trailer_plate_no'); - await queryRunner.dropColumn('freight.vehicles', 'power_plate_no'); - await queryRunner.dropColumn('freight.vehicles', 'code'); - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000002-CreateLastMileContainerAllocations.ts b/apps/edr-freight-api/src/migrations/1810000000002-CreateLastMileContainerAllocations.ts deleted file mode 100644 index b2026b753..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000002-CreateLastMileContainerAllocations.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; - -/** - * Create the freight.last_mile_container_allocations table — container allocation - * records linking last-mile deliveries with containers and vehicles. - */ -export class CreateLastMileContainerAllocations1810000000002 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.last_mile_container_allocations'); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: 'freight.last_mile_container_allocations', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'gen_random_uuid()', - }, - { name: 'last_mile_id', type: 'uuid', isNullable: false }, - { name: 'container_id', type: 'uuid', isNullable: false }, - { name: 'vehicle_id', type: 'uuid', isNullable: true }, - { - name: 'container_type', - type: 'text', - isNullable: false, - }, - { - name: 'quantity', - type: 'integer', - default: 1, - isNullable: false, - }, - { 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_container_allocations', - new TableForeignKey({ - columnNames: ['last_mile_id'], - referencedTableName: 'freight.last_mile', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - - await queryRunner.createForeignKey( - 'freight.last_mile_container_allocations', - new TableForeignKey({ - columnNames: ['vehicle_id'], - referencedTableName: 'freight.vehicles', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - - await queryRunner.query( - `CREATE INDEX "IDX_last_mile_container_allocations_last_mile_id" ON "freight"."last_mile_container_allocations" ("last_mile_id")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_last_mile_container_allocations_vehicle_id" ON "freight"."last_mile_container_allocations" ("vehicle_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.last_mile_container_allocations'); - if (exists) { - await queryRunner.dropTable('freight.last_mile_container_allocations'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000002-MakeCompanyProfileReferenceNullable.ts b/apps/edr-freight-api/src/migrations/1810000000002-MakeCompanyProfileReferenceNullable.ts deleted file mode 100644 index bc1765cfe..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000002-MakeCompanyProfileReferenceNullable.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Company-profile references are now minted only when a profile is approved - * (status → Active); pending profiles carry NULL. Drop the NOT NULL constraint - * on freight.company_profiles.reference. The existing unique index is kept — - * Postgres treats NULLs as distinct, so multiple pending (NULL) profiles don't - * collide. - */ -export class MakeCompanyProfileReferenceNullable1810000000002 - implements MigrationInterface -{ - name = "MakeCompanyProfileReferenceNullable1810000000002"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" DROP NOT NULL`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - // Reinstating NOT NULL requires every row to have a reference; any pending - // (NULL) profiles get a placeholder so the constraint can be re-applied. - await queryRunner.query( - `UPDATE "freight"."company_profiles" SET "reference" = 'PENDING-' || left(replace("id"::text, '-', ''), 12) WHERE "reference" IS NULL`, - ); - await queryRunner.query( - `ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" SET NOT NULL`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000003-CreateOtpVerifications.ts b/apps/edr-freight-api/src/migrations/1810000000003-CreateOtpVerifications.ts deleted file mode 100644 index ec0610f52..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000003-CreateOtpVerifications.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner, Table } from "typeorm"; - -/** - * Create the public.otp_verifications table backing the OTP module - * (OtpVerification entity). One row per phone, holding the latest server-issued - * code and whether that phone has been verified. - */ -export class CreateOtpVerifications1810000000003 - implements MigrationInterface -{ - name = "CreateOtpVerifications1810000000003"; - - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable("otp_verifications"); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: "otp_verifications", - columns: [ - { - name: "id", - type: "uuid", - isPrimary: true, - default: "gen_random_uuid()", - }, - { name: "phone", type: "varchar", isUnique: true }, - { name: "otp", type: "varchar" }, - { name: "verified", type: "boolean", default: false }, - { name: "created_at", type: "timestamptz", default: "now()" }, - { name: "updated_at", type: "timestamptz", default: "now()" }, - { name: "deleted_at", type: "timestamptz", isNullable: true }, - ], - }), - true, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable("otp_verifications", true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1810000000004-AddPostPaymentCompletedColumn.ts b/apps/edr-freight-api/src/migrations/1810000000004-AddPostPaymentCompletedColumn.ts deleted file mode 100644 index aeedae2b1..000000000 --- a/apps/edr-freight-api/src/migrations/1810000000004-AddPostPaymentCompletedColumn.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -export class AddPostPaymentCompletedColumn1810000000004 implements MigrationInterface { - name = 'AddPostPaymentCompletedColumn1810000000004'; - - public async up(queryRunner: QueryRunner): Promise { - const firstMileTable = await queryRunner.hasTable('freight.first_mile_deliveries'); - if (firstMileTable) { - const hasColumn = await queryRunner.hasColumn('freight.first_mile_deliveries', 'is_post_payment_completed'); - if (!hasColumn) { - await queryRunner.addColumn( - 'freight.first_mile_deliveries', - new TableColumn({ - name: 'is_post_payment_completed', - type: 'boolean', - default: false, - isNullable: false, - }) - ); - } - } - - const lastMileTable = await queryRunner.hasTable('freight.last_mile_deliveries'); - if (lastMileTable) { - const hasColumn = await queryRunner.hasColumn('freight.last_mile_deliveries', 'is_post_payment_completed'); - if (!hasColumn) { - await queryRunner.addColumn( - 'freight.last_mile_deliveries', - new TableColumn({ - name: 'is_post_payment_completed', - type: 'boolean', - default: false, - isNullable: false, - }) - ); - } - } - } - - public async down(queryRunner: QueryRunner): Promise { - const lastMileTable = await queryRunner.hasTable('freight.last_mile_deliveries'); - if (lastMileTable) { - await queryRunner.dropColumn('freight.last_mile_deliveries', 'is_post_payment_completed'); - } - - const firstMileTable = await queryRunner.hasTable('freight.first_mile_deliveries'); - if (firstMileTable) { - await queryRunner.dropColumn('freight.first_mile_deliveries', 'is_post_payment_completed'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000000-DropAllowConsolidation.ts b/apps/edr-freight-api/src/migrations/1820000000000-DropAllowConsolidation.ts deleted file mode 100644 index dd232b28a..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000000-DropAllowConsolidation.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Consolidation is now system-managed: the backend consolidates partial-wagon - * container bookings automatically, derived from the container quantities. The - * `allow_consolidation` opt-in flag is therefore redundant and is dropped. - * `consolidation_partner_id` (the actual pairing link) is unaffected. - */ -export class DropAllowConsolidation1820000000000 implements MigrationInterface { - name = 'DropAllowConsolidation1820000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS allow_consolidation;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS allow_consolidation BOOLEAN NOT NULL DEFAULT false;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000001-CreateContractRouteLines.ts b/apps/edr-freight-api/src/migrations/1820000000001-CreateContractRouteLines.ts deleted file mode 100644 index 23eda1730..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000001-CreateContractRouteLines.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Multi-route general contracts: a contract may reserve quantity across several - * routes. Each (contract, route, container type) is a row here; drawdown orders - * reference the route line they drew from via booking_orders.route_line_id. - */ -export class CreateContractRouteLines1820000000001 - implements MigrationInterface -{ - name = 'CreateContractRouteLines1820000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'contract_route_lines', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'contract_booking_id', type: 'uuid' }, - { name: 'origin_yard_id', type: 'uuid' }, - { name: 'destination_yard_id', type: 'uuid' }, - { name: 'container_type_id', type: 'uuid', isNullable: true }, - { name: 'quantity', type: 'numeric', precision: 12, scale: 3 }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['contract_booking_id'], - referencedSchema: 'freight', - referencedTableName: 'bookings', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.contract_route_lines', - new TableIndex({ - name: 'idx_contract_route_lines_contract', - columnNames: ['contract_booking_id'], - }), - ); - - await queryRunner.query( - `ALTER TABLE freight.booking_orders ADD COLUMN IF NOT EXISTS route_line_id uuid;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_orders DROP COLUMN IF EXISTS route_line_id;`, - ); - await queryRunner.dropTable('freight.contract_route_lines', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000002-CreateBookingDocumentReview.ts b/apps/edr-freight-api/src/migrations/1820000000002-CreateBookingDocumentReview.ts deleted file mode 100644 index 0237648f7..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000002-CreateBookingDocumentReview.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Per-document GL review for the post-counter-sign clearance gate. One row per - * required clearance document; GL marks each APPROVED or QUERIED before the - * booking can proceed to operations. - */ -export class CreateBookingDocumentReview1820000000002 - implements MigrationInterface -{ - name = 'CreateBookingDocumentReview1820000000002'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'booking_document_review', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'setting_code', type: 'varchar', length: '128' }, - { name: 'file_key', type: 'varchar', length: '128' }, - { name: 'file_record_id', type: 'uuid', isNullable: true }, - { name: 'status', type: 'varchar', length: '20', default: "'PENDING'" }, - { name: 'note', type: 'text', isNullable: true }, - { name: 'reviewed_by_staff_id', type: 'uuid', isNullable: true }, - { name: 'reviewed_at', type: 'timestamptz', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['booking_id'], - referencedSchema: 'freight', - referencedTableName: 'bookings', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.booking_document_review', - new TableIndex({ name: 'idx_booking_document_review_booking', columnNames: ['booking_id'] }), - ); - await queryRunner.createIndex( - 'freight.booking_document_review', - new TableIndex({ name: 'idx_booking_document_review_status', columnNames: ['status'] }), - ); - await queryRunner.createIndex( - 'freight.booking_document_review', - new TableIndex({ - name: 'uq_booking_document_review_doc', - columnNames: ['booking_id', 'setting_code', 'file_key'], - isUnique: true, - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.booking_document_review', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000003-AddPriceAdjustment.ts b/apps/edr-freight-api/src/migrations/1820000000003-AddPriceAdjustment.ts deleted file mode 100644 index 7ad97e7bf..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000003-AddPriceAdjustment.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Staff price adjustment: an optional override of a booking's computed total, - * with who/when/why. When set, the customer sees the adjusted total + a badge. - */ -export class AddPriceAdjustment1820000000003 implements MigrationInterface { - name = 'AddPriceAdjustment1820000000003'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS adjusted_total_amount numeric(14,2);`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS adjusted_by_staff_id uuid;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS adjusted_at timestamptz;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS adjustment_reason text;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS adjustment_reason;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS adjusted_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS adjusted_by_staff_id;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS adjusted_total_amount;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000004-FoldSurchargeTypesIntoRates.ts b/apps/edr-freight-api/src/migrations/1820000000004-FoldSurchargeTypesIntoRates.ts deleted file mode 100644 index d4eadf34e..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000004-FoldSurchargeTypesIntoRates.ts +++ /dev/null @@ -1,187 +0,0 @@ -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 { - // ── 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 { - // 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; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000005-AddContractValidityWindow.ts b/apps/edr-freight-api/src/migrations/1820000000005-AddContractValidityWindow.ts deleted file mode 100644 index 56d923ff7..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000005-AddContractValidityWindow.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Contract validity window. When the backoffice accepts a price-confirmed - * booking, staff define how many days the contract stays valid. The window runs - * from the accept moment (valid_from) through valid_from + N days (valid_until). - * Outside that window the contract is considered expired. - */ -export class AddContractValidityWindow1820000000005 - implements MigrationInterface -{ - name = 'AddContractValidityWindow1820000000005'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_validity_days integer;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_valid_from timestamptz;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_valid_until timestamptz;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_valid_until;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_valid_from;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_validity_days;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000006-AddCustomsAgentAndMileCoordinates.ts b/apps/edr-freight-api/src/migrations/1820000000006-AddCustomsAgentAndMileCoordinates.ts deleted file mode 100644 index 11d1b617a..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000006-AddCustomsAgentAndMileCoordinates.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Booking now captures: - * - customs clearing as an explicit flag + the customs clearing agent name - * (shown when the service includes customs), and - * - first/last-mile pickup & delivery coordinates (lat/lng) alongside the - * existing address text, so the map picker can store and restore the pin. - * - * Shipping line is no longer collected from the booking form; the column stays - * for historical data and the (now dormant) shipping-line pricing trigger. - */ -export class AddCustomsAgentAndMileCoordinates1820000000006 - implements MigrationInterface -{ - name = 'AddCustomsAgentAndMileCoordinates1820000000006'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS first_mile_pickup_lat numeric(10,7) NULL, - ADD COLUMN IF NOT EXISTS first_mile_pickup_lng numeric(10,7) NULL, - ADD COLUMN IF NOT EXISTS last_mile_delivery_lat numeric(10,7) NULL, - ADD COLUMN IF NOT EXISTS last_mile_delivery_lng numeric(10,7) NULL, - ADD COLUMN IF NOT EXISTS customs_clearing_enabled boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS customs_clearing_agent varchar(200) NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS customs_clearing_agent, - DROP COLUMN IF EXISTS customs_clearing_enabled, - DROP COLUMN IF EXISTS last_mile_delivery_lng, - DROP COLUMN IF EXISTS last_mile_delivery_lat, - DROP COLUMN IF EXISTS first_mile_pickup_lng, - DROP COLUMN IF EXISTS first_mile_pickup_lat; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000010-AddGeneralContractOrderFields.ts b/apps/edr-freight-api/src/migrations/1820000000010-AddGeneralContractOrderFields.ts deleted file mode 100644 index a23c152b5..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000010-AddGeneralContractOrderFields.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * General-contract drawdown order fields: - * - booking_order_lines.hazardous_quantity / reefer_quantity — per-order counts - * the customer enters when toggling hazardous/reefer; drive the surcharge - * rates on the spawned child booking. - * - bookings.is_reefer — booking-level refrigerated flag so REEFER_SURCHARGE - * applies to a contract order even when the container type is not a reefer. - * - contract_route_lines.km — road distance configured with the route; road - * orders bill KM × the PER_KM rate. - * - * NOTE: the shared dev DB has no applied migration history, so these columns - * are also hand-applied there. ADD COLUMN IF NOT EXISTS keeps that idempotent. - */ -export class AddGeneralContractOrderFields1820000000010 - implements MigrationInterface -{ - name = 'AddGeneralContractOrderFields1820000000010'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_order_lines ADD COLUMN IF NOT EXISTS hazardous_quantity numeric(12,3) NOT NULL DEFAULT 0;`, - ); - await queryRunner.query( - `ALTER TABLE freight.booking_order_lines ADD COLUMN IF NOT EXISTS reefer_quantity numeric(12,3) NOT NULL DEFAULT 0;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS is_reefer boolean NOT NULL DEFAULT false;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_route_lines ADD COLUMN IF NOT EXISTS km numeric(10,2);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_route_lines DROP COLUMN IF EXISTS km;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS is_reefer;`, - ); - await queryRunner.query( - `ALTER TABLE freight.booking_order_lines DROP COLUMN IF EXISTS reefer_quantity;`, - ); - await queryRunner.query( - `ALTER TABLE freight.booking_order_lines DROP COLUMN IF EXISTS hazardous_quantity;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000011-AddTrainSetLocomotives.ts b/apps/edr-freight-api/src/migrations/1820000000011-AddTrainSetLocomotives.ts deleted file mode 100644 index b014e71a2..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000011-AddTrainSetLocomotives.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Multi-locomotive train sets: a train set is now pulled by 2+ locomotives. - * - * Adds the `freight.train_set_locomotives` link table (train set ⇄ locomotive, - * with an order index) and backfills one row per existing train set from its - * current `locomotive_id`, so existing read paths keep resolving locomotives. - * The `train_sets.locomotive_id` column is retained as the "primary" locomotive. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. IF NOT EXISTS keeps that idempotent. - */ -export class AddTrainSetLocomotives1820000000011 implements MigrationInterface { - name = 'AddTrainSetLocomotives1820000000011'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_set_locomotives ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - train_set_id uuid NOT NULL, - locomotive_id uuid NOT NULL, - sequence_no int NOT NULL DEFAULT 0, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT "PK_train_set_locomotives" PRIMARY KEY (id), - CONSTRAINT "FK_train_set_locomotives_train_set" FOREIGN KEY (train_set_id) - REFERENCES freight.train_sets (id) ON DELETE CASCADE, - CONSTRAINT "FK_train_set_locomotives_locomotive" FOREIGN KEY (locomotive_id) - REFERENCES freight.locomotives (id) - ); - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_train_set_locomotives_set_loco" - ON freight.train_set_locomotives (train_set_id, locomotive_id); - `); - - // Backfill: one link row per existing train set, from its current primary loco. - await queryRunner.query(` - INSERT INTO freight.train_set_locomotives (train_set_id, locomotive_id, sequence_no) - SELECT ts.id, ts.locomotive_id, 0 - FROM freight.train_sets ts - WHERE ts.locomotive_id IS NOT NULL - AND NOT EXISTS ( - SELECT 1 FROM freight.train_set_locomotives tsl - WHERE tsl.train_set_id = ts.id AND tsl.locomotive_id = ts.locomotive_id - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."UQ_train_set_locomotives_set_loco";`, - ); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_set_locomotives;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts b/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts deleted file mode 100644 index 757c20720..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Contact email/phone for an external profile is sourced from IAM (the user's - * identity) and from the company record, so the duplicated `email`/`phone` - * columns on external_profiles are redundant and are dropped. Dropping `email` - * also removes its UNIQUE constraint. - */ -export class DropEmailPhoneFromExternalProfiles1820000000011 - implements MigrationInterface -{ - name = 'DropEmailPhoneFromExternalProfiles1820000000011'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS email;`, - ); - await queryRunner.query( - `ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS phone;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - // Re-added as nullable (the original email was UNIQUE NOT NULL) since the - // dropped values cannot be recovered to satisfy those constraints. - await queryRunner.query( - `ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS email varchar(150);`, - ); - await queryRunner.query( - `ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS phone varchar(20);`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1820000000012-AddEstimatedShipmentDate.ts b/apps/edr-freight-api/src/migrations/1820000000012-AddEstimatedShipmentDate.ts deleted file mode 100644 index 6b77f53a3..000000000 --- a/apps/edr-freight-api/src/migrations/1820000000012-AddEstimatedShipmentDate.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * The booking wizard now captures a NON-BINDING estimated shipment date instead - * of the binding scheduledDate. The binding scheduledDate (validated against - * open train departures) is set later, at the operation-request step. - */ -export class AddEstimatedShipmentDate1820000000012 - implements MigrationInterface -{ - name = 'AddEstimatedShipmentDate1820000000012'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS estimated_shipment_date timestamptz NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS estimated_shipment_date; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000000-CreateInterchangeDocuments.ts b/apps/edr-freight-api/src/migrations/1821000000000-CreateInterchangeDocuments.ts deleted file mode 100644 index 386eabd4e..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000000-CreateInterchangeDocuments.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { MigrationInterface, QueryRunner, Table } from 'typeorm'; - -export class CreateInterchangeDocuments1821000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'interchange_documents', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'document_no', type: 'varchar', length: '40', isUnique: true }, - { name: 'direction', type: 'varchar', length: '10' }, - { name: 'schedule_id', type: 'uuid', isNullable: true }, - { name: 'train_no', type: 'varchar', length: '40', isNullable: true }, - { name: 'route_id', type: 'uuid', isNullable: true }, - { name: 'origin_facility_id', type: 'uuid', isNullable: true }, - { name: 'destination_facility_id', type: 'uuid', isNullable: true }, - { name: 'handover_location', type: 'varchar', length: '255' }, - { name: 'handover_from', type: 'varchar', length: '255' }, - { name: 'handover_to', type: 'varchar', length: '255' }, - { name: 'operator_name', type: 'varchar', length: '255', isNullable: true }, - { name: 'port_operator_name', type: 'varchar', length: '255', isNullable: true }, - { name: 'shipping_line_name', type: 'varchar', length: '255', isNullable: true }, - { name: 'customs_reference', type: 'varchar', length: '120', isNullable: true }, - { name: 'manifest_reference', type: 'varchar', length: '120', isNullable: true }, - { name: 'status', type: 'varchar', length: '20', default: "'DRAFT'" }, - { name: 'generated_at', type: 'timestamptz', isNullable: true }, - { name: 'acknowledged_at', type: 'timestamptz', isNullable: true }, - { name: 'generated_by', type: 'varchar', length: '120', isNullable: true }, - { name: 'acknowledged_by', type: 'varchar', length: '120', isNullable: true }, - { name: 'remarks', type: 'text', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - indices: [ - { name: 'idx_interchange_documents_direction', columnNames: ['direction'] }, - { name: 'idx_interchange_documents_status', columnNames: ['status'] }, - { name: 'idx_interchange_documents_schedule', columnNames: ['schedule_id'] }, - ], - }), - true, - ); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'interchange_document_items', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, default: 'uuid_generate_v4()' }, - { name: 'interchange_document_id', type: 'uuid' }, - { name: 'booking_id', type: 'uuid', isNullable: true }, - { name: 'booking_reference', type: 'varchar', length: '64', isNullable: true }, - { name: 'item_type', type: 'varchar', length: '20' }, - { name: 'booking_container_id', type: 'uuid', isNullable: true }, - { name: 'booking_cargo_id', type: 'uuid', isNullable: true }, - { name: 'container_number', type: 'varchar', length: '64', isNullable: true }, - { name: 'seal_number', type: 'varchar', length: '100', isNullable: true }, - { name: 'cargo_id', type: 'uuid', isNullable: true }, - { name: 'cargo_type', type: 'varchar', length: '255', isNullable: true }, - { name: 'cargo_description', type: 'text', isNullable: true }, - { name: 'weight', type: 'numeric', precision: 14, scale: 3, isNullable: true }, - { name: 'quantity', type: 'numeric', precision: 12, scale: 3, isNullable: true }, - { name: 'package_count', type: 'int', isNullable: true }, - { name: 'wagon_number', type: 'varchar', length: '80', isNullable: true }, - { name: 'condition_status', type: 'varchar', length: '20', default: "'GOOD'" }, - { name: 'damage_description', type: 'text', isNullable: true }, - { name: 'remarks', type: 'text', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['interchange_document_id'], - referencedSchema: 'freight', - referencedTableName: 'interchange_documents', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - { - columnNames: ['booking_id'], - referencedSchema: 'freight', - referencedTableName: 'bookings', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }, - ], - indices: [ - { name: 'idx_interchange_items_document', columnNames: ['interchange_document_id'] }, - { name: 'idx_interchange_items_booking', columnNames: ['booking_id'] }, - ], - }), - true, - ); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_interchange_active_schedule_direction - ON freight.interchange_documents(schedule_id, direction) - WHERE schedule_id IS NOT NULL AND status <> 'CANCELLED' AND deleted_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX IF EXISTS freight.uq_interchange_active_schedule_direction;'); - await queryRunner.dropTable('freight.interchange_document_items', true); - await queryRunner.dropTable('freight.interchange_documents', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000001-EnsureWarehouseInventoryInspectionStatus.ts b/apps/edr-freight-api/src/migrations/1821000000001-EnsureWarehouseInventoryInspectionStatus.ts deleted file mode 100644 index 523772b39..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000001-EnsureWarehouseInventoryInspectionStatus.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Catch-up for environments where AddWarehouseInspection ran before the - * warehouse module table existed. Production needs this column for unload and - * inspection flows because the WarehouseInventory entity maps inspectionStatus. - */ -export class EnsureWarehouseInventoryInspectionStatus1821000000001 implements MigrationInterface { - private readonly table = 'freight.warehouse_inventory'; - - public async up(queryRunner: QueryRunner): Promise { - if (!(await queryRunner.hasColumn(this.table, 'inspection_status'))) { - await queryRunner.addColumn( - this.table, - new TableColumn({ - name: 'inspection_status', - type: 'varchar', - length: '20', - isNullable: true, - }), - ); - } - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_inventory_inspection_status - ON freight.warehouse_inventory(inspection_status) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS freight.idx_warehouse_inventory_inspection_status - `); - - if (await queryRunner.hasColumn(this.table, 'inspection_status')) { - await queryRunner.dropColumn(this.table, 'inspection_status'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000002-AddDistanceColumnsToVehicles.ts b/apps/edr-freight-api/src/migrations/1821000000002-AddDistanceColumnsToVehicles.ts deleted file mode 100644 index 98fa8b228..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000002-AddDistanceColumnsToVehicles.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddDistanceColumnsToVehicles1821000000002 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS estimated_distance_km NUMERIC, - ADD COLUMN IF NOT EXISTS actual_distance_km NUMERIC; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS estimated_distance_km, - DROP COLUMN IF EXISTS actual_distance_km; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000002-CreateInvoices.ts b/apps/edr-freight-api/src/migrations/1821000000002-CreateInvoices.ts deleted file mode 100644 index 4c2fb5d95..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000002-CreateInvoices.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Freight billing — `invoices` + `invoice_lines` tables. - * - * Matches: - * - billing/entities/invoice.entity.ts - * - billing/entities/invoice-line.entity.ts - * - * The status enum mirrors `Freight.InvoiceStatus` and uses TypeORM's default - * enum-type name (`
__enum`) so the entity's `type: "enum"` - * column resolves to it without an explicit `enumName`. - */ -export class CreateInvoices1821000000002 implements MigrationInterface { - name = "CreateInvoices1821000000002"; - - public async up(queryRunner: QueryRunner): Promise { - const typeExists = await queryRunner.query( - `SELECT 1 FROM pg_type WHERE typname = 'invoices_status_enum' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'freight');`, - ); - - if (!typeExists.length) { - await queryRunner.query(` - CREATE TYPE freight.invoices_status_enum AS ENUM ( - 'DRAFT', - 'PENDING', - 'PAID', - 'OVERDUE', - 'CANCELLED', - 'REFUNDED' - ); - `); - } - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.invoices ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - invoice_number varchar(64) NOT NULL, - company_id uuid NOT NULL, - company_profile_id uuid NOT NULL, - total_amount numeric(14, 2) NOT NULL, - currency varchar(8) NOT NULL DEFAULT 'ETB', - status freight.invoices_status_enum NOT NULL DEFAULT 'DRAFT', - source varchar(255) NOT NULL, - source_id varchar(255) NOT NULL, - type varchar(255) NOT NULL, - issued_at timestamptz, - payment_id uuid, - due_at timestamptz NOT NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT pk_invoices PRIMARY KEY (id), - CONSTRAINT uq_invoices_invoice_number UNIQUE (invoice_number), - CONSTRAINT fk_invoices_company FOREIGN KEY (company_id) - REFERENCES freight.companies (id) ON DELETE RESTRICT, - CONSTRAINT fk_invoices_company_profile FOREIGN KEY (company_profile_id) - REFERENCES freight.company_profiles (id) ON DELETE RESTRICT, - CONSTRAINT fk_invoices_payment FOREIGN KEY (payment_id) - REFERENCES freight.payments (id) ON DELETE SET NULL - ); - `); - - await queryRunner.query( - ` - ALTER TABLE freight.invoices - ADD COLUMN IF NOT EXISTS id uuid DEFAULT uuid_generate_v4(), - ADD COLUMN IF NOT EXISTS invoice_number varchar(64), - ADD COLUMN IF NOT EXISTS company_id uuid, - ADD COLUMN IF NOT EXISTS company_profile_id uuid, - ADD COLUMN IF NOT EXISTS total_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS currency varchar(8) NOT NULL DEFAULT 'ETB', - ADD COLUMN IF NOT EXISTS status freight.invoices_status_enum NOT NULL DEFAULT 'DRAFT', - ADD COLUMN IF NOT EXISTS source varchar(255), - ADD COLUMN IF NOT EXISTS source_id varchar(255), - ADD COLUMN IF NOT EXISTS type varchar(255), - ADD COLUMN IF NOT EXISTS issued_at timestamptz, - ADD COLUMN IF NOT EXISTS payment_id uuid, - ADD COLUMN IF NOT EXISTS due_at timestamptz, - ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now(), - ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now(), - ADD COLUMN IF NOT EXISTS deleted_at timestamptz; - `, - ); - await queryRunner.query(` - UPDATE freight.invoices - SET due_at = COALESCE(due_at, issued_at, created_at, now()) - WHERE due_at IS NULL; - `); - await queryRunner.query(`ALTER TABLE freight.invoices ALTER COLUMN due_at SET NOT NULL;`); - - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE contype = 'p' - AND conrelid = 'freight.invoices'::regclass - ) THEN - ALTER TABLE freight.invoices ADD CONSTRAINT pk_invoices PRIMARY KEY (id); - END IF; - - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE conname = 'uq_invoices_invoice_number' - AND conrelid = 'freight.invoices'::regclass - ) THEN - ALTER TABLE freight.invoices ADD CONSTRAINT uq_invoices_invoice_number UNIQUE (invoice_number); - END IF; - - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE conname = 'fk_invoices_company' - AND conrelid = 'freight.invoices'::regclass - ) THEN - ALTER TABLE freight.invoices ADD CONSTRAINT fk_invoices_company - FOREIGN KEY (company_id) REFERENCES freight.companies (id) ON DELETE RESTRICT; - END IF; - - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE conname = 'fk_invoices_company_profile' - AND conrelid = 'freight.invoices'::regclass - ) THEN - ALTER TABLE freight.invoices ADD CONSTRAINT fk_invoices_company_profile - FOREIGN KEY (company_profile_id) REFERENCES freight.company_profiles (id) ON DELETE RESTRICT; - END IF; - - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE conname = 'fk_invoices_payment' - AND conrelid = 'freight.invoices'::regclass - ) THEN - ALTER TABLE freight.invoices ADD CONSTRAINT fk_invoices_payment - FOREIGN KEY (payment_id) REFERENCES freight.payments (id) ON DELETE SET NULL; - END IF; - END $$; - `); - - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_invoices_company ON freight.invoices (company_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_invoices_company_profile ON freight.invoices (company_profile_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_invoices_source ON freight.invoices (source, source_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_invoices_status ON freight.invoices (status);`, - ); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.invoice_lines ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - invoice_id uuid NOT NULL, - charge_type varchar NOT NULL, - description varchar(255), - quantity numeric(12, 2) NOT NULL DEFAULT 1, - unit_rate numeric(14, 2) NOT NULL DEFAULT 0, - amount numeric(14, 2) NOT NULL, - currency varchar(8) NOT NULL DEFAULT 'ETB', - metadata jsonb, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT pk_invoice_lines PRIMARY KEY (id), - CONSTRAINT fk_invoice_lines_invoice FOREIGN KEY (invoice_id) - REFERENCES freight.invoices (id) ON DELETE CASCADE - ); - `); - - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_invoice_lines_invoice ON freight.invoice_lines (invoice_id);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.invoice_lines;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.invoices;`); - await queryRunner.query( - `DROP TYPE IF EXISTS freight.invoices_status_enum;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000003-AddCompanyKindAndGovBookingLinks.ts b/apps/edr-freight-api/src/migrations/1821000000003-AddCompanyKindAndGovBookingLinks.ts deleted file mode 100644 index 95ea3db1b..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000003-AddCompanyKindAndGovBookingLinks.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Government bookings now bill to a real seeded government company + an explicit - * importer/exporter profile, instead of carrying a null company + free-text - * institution. This migration: - * - * 1. Adds `companies.kind` (commercial | government). - * 2. Seeds the Ethiopian government entities + their importer/exporter - * profiles (mirrors src/seed/data/gov-companies.data.ts — keep in sync). - * 3. Backfills every booking with a NULL company_id / company_profile_id so - * the NOT NULL constraints below can be applied: - * - NULL company_id → the default government company. - * - NULL company_profile_id → the company's profile matching the booking - * trade direction; else any profile of the company; else the default - * government importer profile. - * 4. Enforces NOT NULL on bookings.company_id and bookings.company_profile_id. - */ -export class AddCompanyKindAndGovBookingLinks1821000000003 - implements MigrationInterface -{ - name = "AddCompanyKindAndGovBookingLinks1821000000003"; - - // Mirrors src/seed/data/gov-companies.data.ts - private readonly govCompanies = [ - { id: "0a1b0001-0000-4000-8000-000000000001", name: "Federal Government of Ethiopia", tin: "0000000001", email: "procurement@gov.et", phone: "+251111000001", im: "0b1c0001-0000-4000-8000-000000000001", ex: "0b1c0001-0000-4000-8000-000000000002", imRef: "IM-90001", exRef: "EX-90001" }, - { id: "0a1b0002-0000-4000-8000-000000000002", name: "Ministry of National Defense", tin: "0000000002", email: "logistics@mod.gov.et", phone: "+251111000002", im: "0b1c0002-0000-4000-8000-000000000001", ex: "0b1c0002-0000-4000-8000-000000000002", imRef: "IM-90002", exRef: "EX-90002" }, - { id: "0a1b0003-0000-4000-8000-000000000003", name: "Ethiopian Roads Administration", tin: "0000000003", email: "supply@era.gov.et", phone: "+251111000003", im: "0b1c0003-0000-4000-8000-000000000001", ex: "0b1c0003-0000-4000-8000-000000000002", imRef: "IM-90003", exRef: "EX-90003" }, - { id: "0a1b0004-0000-4000-8000-000000000004", name: "Ministry of Agriculture", tin: "0000000004", email: "imports@moa.gov.et", phone: "+251111000004", im: "0b1c0004-0000-4000-8000-000000000001", ex: "0b1c0004-0000-4000-8000-000000000002", imRef: "IM-90004", exRef: "EX-90004" }, - { id: "0a1b0005-0000-4000-8000-000000000005", name: "Ministry of Trade and Regional Integration", tin: "0000000005", email: "trade@motri.gov.et", phone: "+251111000005", im: "0b1c0005-0000-4000-8000-000000000001", ex: "0b1c0005-0000-4000-8000-000000000002", imRef: "IM-90005", exRef: "EX-90005" }, - { id: "0a1b0006-0000-4000-8000-000000000006", name: "Ethiopian Disaster Risk Management Commission", tin: "0000000006", email: "relief@edrmc.gov.et", phone: "+251111000006", im: "0b1c0006-0000-4000-8000-000000000001", ex: "0b1c0006-0000-4000-8000-000000000002", imRef: "IM-90006", exRef: "EX-90006" }, - ]; - - private get defaultCompanyId(): string { - return this.govCompanies[0].id; - } - private get defaultImporterProfileId(): string { - return this.govCompanies[0].im; - } - - public async up(queryRunner: QueryRunner): Promise { - // 1. kind column - await queryRunner.query( - `ALTER TABLE "freight"."companies" ADD COLUMN IF NOT EXISTS "kind" varchar(20) NOT NULL DEFAULT 'commercial'`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_companies_kind" ON "freight"."companies" ("kind")`, - ); - - // 2. seed government companies + importer/exporter profiles (idempotent) - for (const g of this.govCompanies) { - await queryRunner.query( - `INSERT INTO "freight"."companies" ("id", "name", "type", "kind", "status", "tin", "country", "email", "phone") - VALUES ($1, $2, 'customer', 'government', 'active', $3, 'Ethiopia', $4, $5) - ON CONFLICT ("id") DO NOTHING`, - [g.id, g.name, g.tin, g.email, g.phone], - ); - await queryRunner.query( - `INSERT INTO "freight"."company_profiles" ("id", "company_id", "type", "reference", "status") - VALUES ($1, $2, 'importer', $3, 'active'), ($4, $2, 'exporter', $5, 'active') - ON CONFLICT ("id") DO NOTHING`, - [g.im, g.id, g.imRef, g.ex, g.exRef], - ); - } - - // 3a. backfill NULL company_id → default government company - await queryRunner.query( - `UPDATE "freight"."bookings" SET "company_id" = $1 WHERE "company_id" IS NULL`, - [this.defaultCompanyId], - ); - - // 3b. backfill NULL company_profile_id → profile matching trade direction - await queryRunner.query( - `UPDATE "freight"."bookings" b - SET "company_profile_id" = cp."id" - FROM "freight"."company_profiles" cp - WHERE b."company_profile_id" IS NULL - AND cp."company_id" = b."company_id" - AND cp."deleted_at" IS NULL - AND cp."type" = CASE b."trade_direction" - WHEN 'IMPORT' THEN 'importer' - WHEN 'EXPORT' THEN 'exporter' - ELSE NULL END`, - ); - - // 3c. fallback → any profile of the booking's company - await queryRunner.query( - `UPDATE "freight"."bookings" b - SET "company_profile_id" = ( - SELECT cp."id" FROM "freight"."company_profiles" cp - WHERE cp."company_id" = b."company_id" AND cp."deleted_at" IS NULL - ORDER BY cp."created_at" ASC LIMIT 1) - WHERE b."company_profile_id" IS NULL - AND EXISTS ( - SELECT 1 FROM "freight"."company_profiles" cp - WHERE cp."company_id" = b."company_id" AND cp."deleted_at" IS NULL)`, - ); - - // 3d. final fallback → default government importer profile - await queryRunner.query( - `UPDATE "freight"."bookings" SET "company_profile_id" = $1 WHERE "company_profile_id" IS NULL`, - [this.defaultImporterProfileId], - ); - - // 4. enforce NOT NULL - await queryRunner.query( - `ALTER TABLE "freight"."bookings" ALTER COLUMN "company_id" SET NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "freight"."bookings" ALTER COLUMN "company_profile_id" SET NOT NULL`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."bookings" ALTER COLUMN "company_profile_id" DROP NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "freight"."bookings" ALTER COLUMN "company_id" DROP NOT NULL`, - ); - await queryRunner.query( - `DROP INDEX IF EXISTS "freight"."IDX_companies_kind"`, - ); - await queryRunner.query( - `ALTER TABLE "freight"."companies" DROP COLUMN IF EXISTS "kind"`, - ); - // Seeded government rows are intentionally left in place. - } -} diff --git a/apps/edr-freight-api/src/migrations/1821000000004-MakePaymentsTypeGeneric.ts b/apps/edr-freight-api/src/migrations/1821000000004-MakePaymentsTypeGeneric.ts deleted file mode 100644 index 9f0e8e7bd..000000000 --- a/apps/edr-freight-api/src/migrations/1821000000004-MakePaymentsTypeGeneric.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Make the payment projection source-agnostic so any domain (not just bookings) - * can own a payment intent. - * - * - `payments.type` enum `('booking')` → `varchar(50)`. It now stores the - * invoice SOURCE (e.g. 'booking', 'demurrage'), supplied by the caller, so a - * new domain no longer needs an enum migration to write its intents. - * - adds `payments.reference_type varchar(40)` — the gateway reference type - * (`PaymentReferenceType`) the intent was opened with, so the reconcile/poll - * path can query the provider without hardcoding it. - * - * Matches payment/entities/payment.entity.ts. - */ -export class MakePaymentsTypeGeneric1821000000004 implements MigrationInterface { - name = "MakePaymentsTypeGeneric1821000000004"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.payments ALTER COLUMN type TYPE varchar(50) USING type::text;`, - ); - await queryRunner.query(`DROP TYPE IF EXISTS freight.payments_type_enum;`); - - await queryRunner.query( - `ALTER TABLE freight.payments ADD COLUMN reference_type varchar(40);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.payments DROP COLUMN IF EXISTS reference_type;`, - ); - - // Restore the single-value enum. Any non-'booking' rows would block the cast; - // collapse them first so the down migration is safe. - await queryRunner.query( - `UPDATE freight.payments SET type = 'booking' WHERE type <> 'booking';`, - ); - await queryRunner.query( - `CREATE TYPE freight.payments_type_enum AS ENUM ('booking');`, - ); - await queryRunner.query( - `ALTER TABLE freight.payments ALTER COLUMN type TYPE freight.payments_type_enum USING type::freight.payments_type_enum;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1822000000000-CreateContracts.ts b/apps/edr-freight-api/src/migrations/1822000000000-CreateContracts.ts deleted file mode 100644 index 7995e5023..000000000 --- a/apps/edr-freight-api/src/migrations/1822000000000-CreateContracts.ts +++ /dev/null @@ -1,357 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Contract–Booking separation (additive phase). Introduces a first-class - * `freight.contracts` aggregate that owns the legal/commercial agreement (scope - * + unit rates, no quantities) and spawns shipment `bookings` via `contract_id`. - * - * Purely additive: no legacy columns are dropped here. The data backfill and - * legacy-column removal happen in a later cutover migration. - * - * See docs/new-doc.md §5. - */ -export class CreateContracts1822000000000 implements MigrationInterface { - name = 'CreateContracts1822000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // ── contracts ─────────────────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contracts ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - reference VARCHAR(64) NOT NULL UNIQUE, - - company_id UUID, - company_profile_id UUID, - is_government BOOLEAN NOT NULL DEFAULT FALSE, - government_institution VARCHAR(255), - - contract_kind VARCHAR(20) NOT NULL, - renewal_of_id UUID REFERENCES freight.contracts(id), - trade_direction VARCHAR(10) NOT NULL, - freight_type VARCHAR(20) NOT NULL, - - service_type_id UUID NOT NULL, - payment_currency VARCHAR(5) NOT NULL, - customs_clearing_enabled BOOLEAN NOT NULL DEFAULT FALSE, - customs_clearing_agent VARCHAR(200), - equipment_return VARCHAR(20), - - first_mile_pickup_address TEXT, - first_mile_pickup_lat NUMERIC(10,7), - first_mile_pickup_lng NUMERIC(10,7), - last_mile_delivery_address TEXT, - last_mile_delivery_lat NUMERIC(10,7), - last_mile_delivery_lng NUMERIC(10,7), - - is_hazardous BOOLEAN NOT NULL DEFAULT FALSE, - is_reefer BOOLEAN NOT NULL DEFAULT FALSE, - - estimated_shipment_date TIMESTAMPTZ, - contract_validity_days INT, - contract_valid_from TIMESTAMPTZ, - contract_valid_until TIMESTAMPTZ, - expires_at TIMESTAMPTZ, - - status VARCHAR(40) NOT NULL DEFAULT 'DRAFT', - clearance_status VARCHAR(40) NOT NULL DEFAULT 'NOT_APPLICABLE', - clearance_cycle_number INT NOT NULL DEFAULT 0, - - pricing_breakdown JSONB, - pricing_display_mode VARCHAR(20) DEFAULT 'UNIT_RATES', - - contract_type VARCHAR(20), - contract_template_key VARCHAR(128), - contract_generated_at TIMESTAMPTZ, - contract_summary TEXT, - version_number INT NOT NULL DEFAULT 1, - financial_terms JSONB, - - approved_by_staff_id UUID, - approved_by_staff_at TIMESTAMPTZ, - signed_by_director_id UUID, - signed_by_director_at TIMESTAMPTZ, - signed_by_ceo_id UUID, - signed_by_ceo_at TIMESTAMPTZ, - customer_signed_at TIMESTAMPTZ, - fully_executed_at TIMESTAMPTZ, - locked_at TIMESTAMPTZ, - - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contracts_company ON freight.contracts(company_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contracts_status ON freight.contracts(status);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contracts_kind ON freight.contracts(contract_kind);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contracts_valid_until ON freight.contracts(contract_valid_until);`); - - // ── contract_routes ────────────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_routes ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - origin_yard_id UUID NOT NULL, - destination_yard_id UUID NOT NULL, - km NUMERIC(10,2), - sort_order SMALLINT NOT NULL DEFAULT 0, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_contract_route UNIQUE (contract_id, origin_yard_id, destination_yard_id) - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_routes_contract ON freight.contract_routes(contract_id);`); - - // ── contract_cargo_scope ───────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_cargo_scope ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - container_size VARCHAR(10), - cargo_type_id UUID, - cargo_free_text VARCHAR(200), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_contract_container_size UNIQUE NULLS NOT DISTINCT (contract_id, container_size) - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_cargo_scope_contract ON freight.contract_cargo_scope(contract_id);`); - - // ── contract_signatures ────────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_signatures ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - role VARCHAR(20) NOT NULL, - signer_display_name VARCHAR(255) NOT NULL, - signature_file_id UUID, - consent_text TEXT, - signed_at TIMESTAMPTZ NOT NULL DEFAULT now(), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_signatures_contract ON freight.contract_signatures(contract_id);`); - - // ── contract_approval_steps ────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_approval_steps ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - step_order SMALLINT NOT NULL DEFAULT 0, - required_role VARCHAR(40) NOT NULL, - blocks_role VARCHAR(40), - status VARCHAR(20) NOT NULL DEFAULT 'PENDING', - acted_by_staff_id UUID, - acted_at TIMESTAMPTZ, - note TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_approval_steps_contract ON freight.contract_approval_steps(contract_id);`); - - // ── contract_rate_snapshots ────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_rate_snapshots ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - rate_id UUID, - rate_code VARCHAR(64) NOT NULL, - description VARCHAR(255), - unit_price NUMERIC(14,2) NOT NULL, - unit_of_measure VARCHAR(32) NOT NULL, - currency VARCHAR(5) NOT NULL, - container_size VARCHAR(10), - is_surcharge BOOLEAN DEFAULT FALSE, - conditional_on VARCHAR(32), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_rate_snapshots_contract ON freight.contract_rate_snapshots(contract_id);`); - - // ── contract_review_notes ──────────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_review_notes ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - note_type VARCHAR(40) NOT NULL, - body TEXT NOT NULL, - author_role VARCHAR(20), - author_user_id UUID, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_review_notes_contract ON freight.contract_review_notes(contract_id);`); - - // ── contract_clearance_cycles ──────────────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_clearance_cycles ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - cycle_number INT NOT NULL, - status VARCHAR(40) NOT NULL DEFAULT 'AWAITING_DOCUMENTS', - booking_id UUID, - started_at TIMESTAMPTZ NOT NULL DEFAULT now(), - clearance_ready_at TIMESTAMPTZ, - completed_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_contract_clearance_cycle UNIQUE (contract_id, cycle_number) - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_clearance_cycles_contract ON freight.contract_clearance_cycles(contract_id);`); - - // ── contract_document_review (pre-booking clearance, Path B) ───────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_document_review ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - contract_id UUID NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - clearance_cycle_id UUID REFERENCES freight.contract_clearance_cycles(id), - setting_code VARCHAR(128) NOT NULL, - file_key VARCHAR(128) NOT NULL, - file_record_id UUID, - status VARCHAR(20) NOT NULL DEFAULT 'PENDING', - note TEXT, - uploaded_by_role VARCHAR(20) NOT NULL DEFAULT 'CUSTOMER', - reviewed_by_staff_id UUID, - reviewed_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_contract_document_review_doc - UNIQUE NULLS NOT DISTINCT (contract_id, clearance_cycle_id, setting_code, file_key) - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_doc_review_contract ON freight.contract_document_review(contract_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_contract_doc_review_status ON freight.contract_document_review(status);`); - - // ── clearance_milestones (GL tracking) ─────────────────────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.clearance_milestones ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id UUID REFERENCES freight.bookings(id) ON DELETE CASCADE, - contract_id UUID REFERENCES freight.contracts(id) ON DELETE CASCADE, - clearance_cycle_id UUID REFERENCES freight.contract_clearance_cycles(id), - milestone_code VARCHAR(64) NOT NULL, - milestone_label VARCHAR(255) NOT NULL, - status VARCHAR(20) NOT NULL DEFAULT 'PENDING', - owner_region VARCHAR(5), - triggered_by_doc BOOLEAN DEFAULT FALSE, - triggered_at TIMESTAMPTZ, - triggered_by_user_id UUID, - note TEXT, - sort_order SMALLINT NOT NULL DEFAULT 0, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_clearance_milestones_booking ON freight.clearance_milestones(booking_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_clearance_milestones_contract ON freight.clearance_milestones(contract_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_clearance_milestones_region ON freight.clearance_milestones(owner_region, status);`); - // booking-scoped and contract-cycle-scoped uniqueness for milestone codes - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_clearance_milestone_booking - ON freight.clearance_milestones(booking_id, milestone_code) WHERE booking_id IS NOT NULL; - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_clearance_milestone_cycle - ON freight.clearance_milestones(clearance_cycle_id, milestone_code) WHERE clearance_cycle_id IS NOT NULL; - `); - - // ── booking_container_units (per-unit container detail) ────────────────── - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.booking_container_units ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - booking_container_id UUID NOT NULL REFERENCES freight.booking_container(id) ON DELETE CASCADE, - container_number VARCHAR(64) NOT NULL, - seal_number VARCHAR(64), - vgm_tons NUMERIC(10,3) NOT NULL, - is_hazardous BOOLEAN DEFAULT FALSE, - is_reefer BOOLEAN DEFAULT FALSE, - sort_order SMALLINT NOT NULL DEFAULT 0, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_booking_container_unit_number UNIQUE (booking_container_id, container_number) - ); - `); - - // ── ALTER bookings ─────────────────────────────────────────────────────── - await queryRunner.query(`ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_id UUID REFERENCES freight.contracts(id);`); - await queryRunner.query(`ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_route_id UUID REFERENCES freight.contract_routes(id);`); - await queryRunner.query(`ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS created_by_role VARCHAR(20) DEFAULT 'CUSTOMER';`); - await queryRunner.query(`ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS created_by_user_id UUID;`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_bookings_contract ON freight.bookings(contract_id);`); - // One active booking per ONE_TIME contract. Postgres forbids a subquery in an - // index predicate, so we denormalize the contract kind onto the booking and - // predicate on that. The column is stamped at booking creation from the - // contract; the app layer (ContractBookingService) is the primary guard and - // this index is the backstop. - await queryRunner.query(`ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS contract_kind VARCHAR(20);`); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_one_active_booking_per_one_time_contract - ON freight.bookings (contract_id) - WHERE status NOT IN ('EXPIRED', 'CANCELLED', 'COMPLETED', 'REJECTED') - AND contract_id IS NOT NULL - AND contract_kind = 'ONE_TIME'; - `); - - // ── ALTER booking_container ────────────────────────────────────────────── - await queryRunner.query(`ALTER TABLE freight.booking_container ADD COLUMN IF NOT EXISTS container_size VARCHAR(10);`); - await queryRunner.query(`ALTER TABLE freight.booking_container ADD COLUMN IF NOT EXISTS hazardous_quantity SMALLINT DEFAULT 0;`); - await queryRunner.query(`ALTER TABLE freight.booking_container ADD COLUMN IF NOT EXISTS reefer_quantity SMALLINT DEFAULT 0;`); - - // ── ALTER booking_document_review (denormalized contract link) ─────────── - await queryRunner.query(`ALTER TABLE freight.booking_document_review ADD COLUMN IF NOT EXISTS contract_id UUID REFERENCES freight.contracts(id);`); - - // ── Extend file_upload_fields with phased GL metadata ──────────────────── - await queryRunner.query(`ALTER TABLE freight.file_upload_fields ADD COLUMN IF NOT EXISTS phase VARCHAR(40);`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields ADD COLUMN IF NOT EXISTS owner_region VARCHAR(5);`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields ADD COLUMN IF NOT EXISTS trade_direction VARCHAR(10);`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields ADD COLUMN IF NOT EXISTS triggers_milestone_code VARCHAR(64);`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.file_upload_fields DROP COLUMN IF EXISTS triggers_milestone_code;`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields DROP COLUMN IF EXISTS trade_direction;`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields DROP COLUMN IF EXISTS owner_region;`); - await queryRunner.query(`ALTER TABLE freight.file_upload_fields DROP COLUMN IF EXISTS phase;`); - - await queryRunner.query(`ALTER TABLE freight.booking_document_review DROP COLUMN IF EXISTS contract_id;`); - - await queryRunner.query(`ALTER TABLE freight.booking_container DROP COLUMN IF EXISTS reefer_quantity;`); - await queryRunner.query(`ALTER TABLE freight.booking_container DROP COLUMN IF EXISTS hazardous_quantity;`); - await queryRunner.query(`ALTER TABLE freight.booking_container DROP COLUMN IF EXISTS container_size;`); - - await queryRunner.query(`DROP INDEX IF EXISTS freight.uq_one_active_booking_per_one_time_contract;`); - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_bookings_contract;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_kind;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS created_by_user_id;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS created_by_role;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_route_id;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS contract_id;`); - - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_container_units;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.clearance_milestones;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_document_review;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_clearance_cycles;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_review_notes;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_rate_snapshots;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_approval_steps;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_signatures;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_cargo_scope;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_routes;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contracts;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1822000000000-CreateImportDjiboutiOperations.ts b/apps/edr-freight-api/src/migrations/1822000000000-CreateImportDjiboutiOperations.ts deleted file mode 100644 index 981918f25..000000000 --- a/apps/edr-freight-api/src/migrations/1822000000000-CreateImportDjiboutiOperations.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey, TableIndex } from 'typeorm'; - -export class CreateImportDjiboutiOperations1822000000000 implements MigrationInterface { - name = 'CreateImportDjiboutiOperations1822000000000'; - - async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'import_djibouti_operations', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'train_schedule_id', type: 'uuid', isUnique: true }, - { name: 'documents', type: 'jsonb', default: "'{}'::jsonb" }, - { name: 'gatepass_granted_at', type: 'timestamptz', isNullable: true }, - { name: 'ready_for_loading_at', type: 'timestamptz', isNullable: true }, - { name: 'loaded_on_train_at', type: 'timestamptz', isNullable: true }, - { name: 'departed_from_djibouti_at', type: 'timestamptz', isNullable: true }, - { name: 'load_list_generated_at', type: 'timestamptz', isNullable: true }, - { name: 'performed_by', type: 'varchar', length: '120', isNullable: true }, - { name: 'notes', type: 'text', 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.createIndex( - 'freight.import_djibouti_operations', - new TableIndex({ - name: 'idx_import_djibouti_operations_schedule', - columnNames: ['train_schedule_id'], - }), - ); - - await queryRunner.createForeignKey( - 'freight.import_djibouti_operations', - new TableForeignKey({ - columnNames: ['train_schedule_id'], - referencedTableName: 'train_schedules', - referencedSchema: 'freight', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - } - - async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.import_djibouti_operations', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1823000000000-BackfillContractsFromBookings.ts b/apps/edr-freight-api/src/migrations/1823000000000-BackfillContractsFromBookings.ts deleted file mode 100644 index 552e4affd..000000000 --- a/apps/edr-freight-api/src/migrations/1823000000000-BackfillContractsFromBookings.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Data backfill for the contract–booking separation (docs/new-doc.md §17). - * - * For every legacy `booking_type = 'GENERAL_CONTRACT'` booking we synthesise a - * `freight.contracts` row from its contract-phase columns, copy its routes - * (contract_route_lines → contract_routes, dropping quantity), and point the - * contract + every child shipment booking (linked via booking_orders) at it. - * - * Per §19 item 1, historical ONE_TIME bookings that went through the full - * contract flow get a contract parent inserted and `contract_id` set on the same - * booking row (no row split). - * - * Idempotent: skips bookings that already have `contract_id` set, and matches a - * synthesised contract by a deterministic `CTR-` reference. - */ -export class BackfillContractsFromBookings1823000000000 - implements MigrationInterface -{ - name = 'BackfillContractsFromBookings1823000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // 1. One contract per GENERAL_CONTRACT booking, carrying the contract-phase - // columns. Reference is derived from the source booking id so re-runs are - // idempotent (ON CONFLICT DO NOTHING on the unique reference). - await queryRunner.query(` - INSERT INTO freight.contracts ( - reference, company_id, company_profile_id, is_government, government_institution, - contract_kind, trade_direction, freight_type, service_type_id, payment_currency, - customs_clearing_enabled, customs_clearing_agent, equipment_return, - first_mile_pickup_address, first_mile_pickup_lat, first_mile_pickup_lng, - last_mile_delivery_address, last_mile_delivery_lat, last_mile_delivery_lng, - is_hazardous, is_reefer, estimated_shipment_date, - contract_validity_days, contract_valid_from, contract_valid_until, expires_at, - status, clearance_status, clearance_cycle_number, - pricing_breakdown, contract_type, contract_template_key, contract_generated_at, - contract_summary, version_number, - approved_by_staff_id, approved_by_staff_at, - signed_by_director_id, signed_by_director_at, - signed_by_ceo_id, signed_by_ceo_at, customer_signed_at, fully_executed_at, - created_at, updated_at - ) - SELECT - 'CTR-' || b.id::text, b.company_id, b.company_profile_id, b.is_government, b.government_institution, - 'GENERAL', b.trade_direction, b.freight_type, b.service_type_id, b.payment_currency, - b.customs_clearing_enabled, b.customs_clearing_agent, b.equipment_return, - b.first_mile_pickup_address, b.first_mile_pickup_lat, b.first_mile_pickup_lng, - b.last_mile_delivery_address, b.last_mile_delivery_lat, b.last_mile_delivery_lng, - b.is_hazardous, b.is_reefer, b.estimated_shipment_date, - b.contract_validity_days, b.contract_valid_from, b.contract_valid_until, b.expires_at, - CASE - WHEN b.status IN ('CONTRACT_ACTIVE') THEN 'CONTRACT_ACTIVE' - WHEN b.status IN ('CONTRACT_CLOSED') THEN 'CONTRACT_CLOSED' - WHEN b.status IN ('EXPIRED') THEN 'EXPIRED' - WHEN b.status IN ('CANCELLED') THEN 'CANCELLED' - WHEN b.status IN ('REJECTED') THEN 'REJECTED' - ELSE 'CONTRACT_ACTIVE' - END, - CASE WHEN b.customs_clearing_enabled THEN 'NOT_APPLICABLE' ELSE 'NOT_APPLICABLE' END, - 0, - b.pricing_breakdown, - b.contract_type, b.contract_template_key, b.contract_generated_at, - b.contract_summary, COALESCE(b.version_number, 1), - b.approved_by_staff_id, b.approved_by_staff_at, - b.signed_by_director_id, b.signed_by_director_at, - b.signed_by_ceo_id, b.signed_by_ceo_at, b.customer_signed_at, b.fully_executed_at, - b.created_at, b.updated_at - FROM freight.bookings b - WHERE b.booking_type = 'GENERAL_CONTRACT' - ON CONFLICT (reference) DO NOTHING; - `); - - // 2. Copy each general contract's route lines into contract_routes (no qty). - await queryRunner.query(` - INSERT INTO freight.contract_routes (contract_id, origin_yard_id, destination_yard_id, km, sort_order, created_at, updated_at) - SELECT c.id, crl.origin_yard_id, crl.destination_yard_id, crl.km, 0, now(), now() - FROM freight.contract_route_lines crl - JOIN freight.contracts c ON c.reference = 'CTR-' || crl.contract_booking_id::text - ON CONFLICT (contract_id, origin_yard_id, destination_yard_id) DO NOTHING; - `); - - // 3. Point the general-contract booking itself at its new contract, and stamp - // the denormalized contract_kind for the active-booking index. - await queryRunner.query(` - UPDATE freight.bookings b - SET contract_id = c.id, contract_kind = 'GENERAL', created_by_role = 'CUSTOMER' - FROM freight.contracts c - WHERE c.reference = 'CTR-' || b.id::text - AND b.booking_type = 'GENERAL_CONTRACT' - AND b.contract_id IS NULL; - `); - - // 4. Point each child shipment booking (spawned via booking_orders) at the - // same contract as its parent general contract. - await queryRunner.query(` - UPDATE freight.bookings child - SET contract_id = c.id, contract_kind = 'GENERAL', created_by_role = 'CUSTOMER' - FROM freight.booking_orders bo - JOIN freight.contracts c ON c.reference = 'CTR-' || bo.contract_booking_id::text - WHERE child.id = bo.booking_id - AND child.contract_id IS NULL; - `); - - // 5. Historical ONE_TIME bookings that completed the contract flow: synthesise - // a contract parent and point the same booking row at it (no row split). - await queryRunner.query(` - INSERT INTO freight.contracts ( - reference, company_id, company_profile_id, is_government, government_institution, - contract_kind, trade_direction, freight_type, service_type_id, payment_currency, - customs_clearing_enabled, customs_clearing_agent, equipment_return, - first_mile_pickup_address, first_mile_pickup_lat, first_mile_pickup_lng, - last_mile_delivery_address, last_mile_delivery_lat, last_mile_delivery_lng, - is_hazardous, is_reefer, estimated_shipment_date, - contract_validity_days, contract_valid_from, contract_valid_until, - status, clearance_status, clearance_cycle_number, - pricing_breakdown, contract_type, contract_template_key, contract_generated_at, - contract_summary, version_number, - approved_by_staff_id, approved_by_staff_at, - signed_by_director_id, signed_by_director_at, - signed_by_ceo_id, signed_by_ceo_at, customer_signed_at, fully_executed_at, - created_at, updated_at - ) - SELECT - 'CTR-' || b.id::text, b.company_id, b.company_profile_id, b.is_government, b.government_institution, - 'ONE_TIME', b.trade_direction, b.freight_type, b.service_type_id, b.payment_currency, - b.customs_clearing_enabled, b.customs_clearing_agent, b.equipment_return, - b.first_mile_pickup_address, b.first_mile_pickup_lat, b.first_mile_pickup_lng, - b.last_mile_delivery_address, b.last_mile_delivery_lat, b.last_mile_delivery_lng, - b.is_hazardous, b.is_reefer, b.estimated_shipment_date, - b.contract_validity_days, b.contract_valid_from, b.contract_valid_until, - 'FULLY_EXECUTED', 'NOT_APPLICABLE', 0, - b.pricing_breakdown, b.contract_type, b.contract_template_key, b.contract_generated_at, - b.contract_summary, COALESCE(b.version_number, 1), - b.approved_by_staff_id, b.approved_by_staff_at, - b.signed_by_director_id, b.signed_by_director_at, - b.signed_by_ceo_id, b.signed_by_ceo_at, b.customer_signed_at, b.fully_executed_at, - b.created_at, b.updated_at - FROM freight.bookings b - WHERE COALESCE(b.booking_type, 'ONE_TIME') = 'ONE_TIME' - AND b.contract_id IS NULL - AND b.contract_generated_at IS NOT NULL - ON CONFLICT (reference) DO NOTHING; - `); - - await queryRunner.query(` - UPDATE freight.bookings b - SET contract_id = c.id, contract_kind = 'ONE_TIME', created_by_role = 'CUSTOMER' - FROM freight.contracts c - WHERE c.reference = 'CTR-' || b.id::text - AND COALESCE(b.booking_type, 'ONE_TIME') = 'ONE_TIME' - AND b.contract_id IS NULL; - `); - - // 6. Build a single route per ONE_TIME contract from the booking's own - // origin/destination (general contracts already got their routes in step 2). - await queryRunner.query(` - INSERT INTO freight.contract_routes (contract_id, origin_yard_id, destination_yard_id, sort_order, created_at, updated_at) - SELECT c.id, b.origin_yard_id, b.destination_yard_id, 0, now(), now() - FROM freight.bookings b - JOIN freight.contracts c ON c.id = b.contract_id AND c.contract_kind = 'ONE_TIME' - WHERE b.origin_yard_id IS NOT NULL AND b.destination_yard_id IS NOT NULL - ON CONFLICT (contract_id, origin_yard_id, destination_yard_id) DO NOTHING; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Unlink bookings and drop the synthesised contracts (and their cascaded routes). - await queryRunner.query(` - UPDATE freight.bookings SET contract_id = NULL, contract_route_id = NULL - WHERE contract_id IN (SELECT id FROM freight.contracts WHERE reference LIKE 'CTR-%'); - `); - await queryRunner.query(`DELETE FROM freight.contracts WHERE reference LIKE 'CTR-%';`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1823000000000-CreateImportOperationsTables.ts b/apps/edr-freight-api/src/migrations/1823000000000-CreateImportOperationsTables.ts deleted file mode 100644 index 1a198e983..000000000 --- a/apps/edr-freight-api/src/migrations/1823000000000-CreateImportOperationsTables.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -export class CreateImportOperationsTables1823000000000 implements MigrationInterface { - name = 'CreateImportOperationsTables1823000000000'; - - async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'djibouti_import_incidents', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid' }, - { name: 'container_number', type: 'varchar', length: '80', isNullable: true }, - { name: 'cargo_id', type: 'uuid', isNullable: true }, - { name: 'facility', type: 'varchar', length: '120', isNullable: true }, - { name: 'station', type: 'varchar', length: '120', isNullable: true }, - { name: 'incident_type', type: 'varchar', length: '40' }, - { name: 'description', type: 'text' }, - { name: 'photos', type: 'jsonb', default: "'[]'::jsonb" }, - { name: 'reported_by', type: 'varchar', length: '120', isNullable: true }, - { name: 'reported_at', type: 'timestamptz' }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - }), - true, - ); - await queryRunner.createIndex('freight.djibouti_import_incidents', new TableIndex({ name: 'idx_djibouti_incidents_booking', columnNames: ['booking_id'] })); - await queryRunner.createIndex('freight.djibouti_import_incidents', new TableIndex({ name: 'idx_djibouti_incidents_container', columnNames: ['container_number'] })); - await queryRunner.createIndex('freight.djibouti_import_incidents', new TableIndex({ name: 'idx_djibouti_incidents_type', columnNames: ['incident_type'] })); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'import_customs_finalizations', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'booking_id', type: 'uuid', isUnique: true }, - { name: 'documents', type: 'jsonb', default: "'{}'::jsonb" }, - { name: 'declaration_serial_number', type: 'varchar', length: '120', isNullable: true }, - { name: 'duties_taxes_notified_at', type: 'timestamptz', isNullable: true }, - { name: 'duties_taxes_paid_at', type: 'timestamptz', isNullable: true }, - { name: 'customs_risk', type: 'varchar', length: '12', isNullable: true }, - { name: 'import_release_permitted_at', type: 'timestamptz', isNullable: true }, - { name: 'completed_at', type: 'timestamptz', isNullable: true }, - { name: 'performed_by', type: 'varchar', length: '120', isNullable: true }, - { name: 'notes', type: 'text', 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.createIndex('freight.import_customs_finalizations', new TableIndex({ name: 'idx_import_customs_booking', columnNames: ['booking_id'] })); - await queryRunner.createIndex('freight.import_customs_finalizations', new TableIndex({ name: 'idx_import_customs_risk', columnNames: ['customs_risk'] })); - - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'empty_container_returns', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' }, - { name: 'container_number', type: 'varchar', length: '80' }, - { name: 'booking_id', type: 'uuid', isNullable: true }, - { name: 'customer_id', type: 'uuid', isNullable: true }, - { name: 'return_date', type: 'timestamptz' }, - { name: 'facility', type: 'varchar', length: '120', isNullable: true }, - { name: 'yard', type: 'varchar', length: '120', isNullable: true }, - { name: 'zone', type: 'varchar', length: '120', isNullable: true }, - { name: 'condition', type: 'text', isNullable: true }, - { name: 'handover_note', type: 'text', isNullable: true }, - { name: 'status', type: 'varchar', length: '40', default: "'RETURNED'" }, - { name: 'wagon_allocation_reference', type: 'varchar', length: '120', isNullable: true }, - { name: 'performed_by', type: 'varchar', length: '120', 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.createIndex('freight.empty_container_returns', new TableIndex({ name: 'idx_empty_returns_container', columnNames: ['container_number'] })); - await queryRunner.createIndex('freight.empty_container_returns', new TableIndex({ name: 'idx_empty_returns_booking', columnNames: ['booking_id'] })); - await queryRunner.createIndex('freight.empty_container_returns', new TableIndex({ name: 'idx_empty_returns_status', columnNames: ['status'] })); - } - - async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.empty_container_returns', true); - await queryRunner.dropTable('freight.import_customs_finalizations', true); - await queryRunner.dropTable('freight.djibouti_import_incidents', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1824000000000-DropLegacyContractTables.ts b/apps/edr-freight-api/src/migrations/1824000000000-DropLegacyContractTables.ts deleted file mode 100644 index 06bcff14a..000000000 --- a/apps/edr-freight-api/src/migrations/1824000000000-DropLegacyContractTables.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Cutover cleanup (docs/new-doc.md §17 Phase 4). Runs AFTER the backfill - * (1823…) so every legacy general contract + drawdown already lives in the - * `contracts` aggregate. - * - * Drops the now-unused booking-as-contract artifacts: - * - `bookings.booking_type` (every booking is a real shipment now) - * - `bookings.previous_contract_id` (renewal lives on `contracts.renewal_of_id`) - * - the `booking_orders` / `booking_order_lines` drawdown ledger - * - `contract_route_lines` (superseded by `contract_routes`) - * - * The shipment/payment/scheduling/allocation columns on `bookings` are kept — - * the operational pipeline is unchanged. - */ -export class DropLegacyContractTables1824000000000 implements MigrationInterface { - name = 'DropLegacyContractTables1824000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // booking_order_lines references booking_orders → drop child first. - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_order_lines CASCADE;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_orders CASCADE;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_route_lines CASCADE;`); - - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS booking_type;`); - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS previous_contract_id;`); - } - - public async down(queryRunner: QueryRunner): Promise { - // Re-add the dropped columns (data is not restored — this is a one-way cutover). - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS booking_type VARCHAR(20) DEFAULT 'ONE_TIME';`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS previous_contract_id UUID;`, - ); - // The legacy ledger/route tables are intentionally NOT recreated here; restore - // from a backup if a rollback past the cutover is ever required. - } -} diff --git a/apps/edr-freight-api/src/migrations/1825000000000-AddGlOperations.ts b/apps/edr-freight-api/src/migrations/1825000000000-AddGlOperations.ts deleted file mode 100644 index cf0cc51f4..000000000 --- a/apps/edr-freight-api/src/migrations/1825000000000-AddGlOperations.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Global Logistics Phase-2 operational features (docs/new-doc.md §11–§13, gap - * matrix #14/#16/#17/#18): - * - `clearance_milestones.metadata` — structured payload for RISK_ASSIGNED - * (risk level) and DUTY_TAXES_ADVISED (amount, currency, declaration serial) - * - `bookings.gl_station_yard_id` / `gl_assigned_staff_id` / `gl_assigned_at` - * — station routing + staff binding (GL US-02) - * - `freight.clearance_incidents` — cargo exception/damage reports with photos - * (GL Import US-07) - */ -export class AddGlOperations1825000000000 implements MigrationInterface { - name = 'AddGlOperations1825000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.clearance_milestones ADD COLUMN IF NOT EXISTS metadata JSONB;`, - ); - - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS gl_station_yard_id UUID;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS gl_assigned_staff_id UUID;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS gl_assigned_at TIMESTAMPTZ;`, - ); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.clearance_incidents ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id UUID NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - incident_type VARCHAR(32) NOT NULL, - description TEXT NOT NULL, - photo_file_ids JSONB NOT NULL DEFAULT '[]', - reported_by_user_id UUID, - reported_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - deleted_at TIMESTAMPTZ - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_clearance_incidents_booking ON freight.clearance_incidents(booking_id);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.clearance_incidents CASCADE;`); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS gl_assigned_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS gl_assigned_staff_id;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS gl_station_yard_id;`, - ); - await queryRunner.query( - `ALTER TABLE freight.clearance_milestones DROP COLUMN IF EXISTS metadata;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1825000000000-CreateBookingContainerAllocations.ts b/apps/edr-freight-api/src/migrations/1825000000000-CreateBookingContainerAllocations.ts deleted file mode 100644 index 70b0832f5..000000000 --- a/apps/edr-freight-api/src/migrations/1825000000000-CreateBookingContainerAllocations.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; - -/** - * Create the freight.booking_container_allocations table — container-to-vehicle - * allocation mapping for flexible routing of containers across available vehicles. - */ -export class CreateBookingContainerAllocations1825000000000 implements MigrationInterface { - name = 'CreateBookingContainerAllocations1825000000000'; - - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.booking_container_allocations'); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: 'freight.booking_container_allocations', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'gen_random_uuid()', - }, - { name: 'booking_id', type: 'uuid', isNullable: false }, - { name: 'container_id', type: 'uuid', isNullable: false }, - { name: 'vehicle_id', type: 'uuid', isNullable: true }, - { - name: 'container_type', - type: 'text', - isNullable: false, - }, - { - name: 'quantity', - type: 'integer', - default: 1, - isNullable: false, - }, - { 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.booking_container_allocations', - new TableForeignKey({ - columnNames: ['booking_id'], - referencedTableName: 'freight.bookings', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - - await queryRunner.createForeignKey( - 'freight.booking_container_allocations', - new TableForeignKey({ - columnNames: ['vehicle_id'], - referencedTableName: 'freight.vehicles', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - - await queryRunner.query( - `CREATE INDEX "IDX_booking_container_allocations_booking_id" ON "freight"."booking_container_allocations" ("booking_id")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_booking_container_allocations_vehicle_id" ON "freight"."booking_container_allocations" ("vehicle_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.booking_container_allocations'); - if (exists) { - await queryRunner.dropTable('freight.booking_container_allocations'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1826000000000-AddCargoScopeQuantityCap.ts b/apps/edr-freight-api/src/migrations/1826000000000-AddCargoScopeQuantityCap.ts deleted file mode 100644 index 97428c11b..000000000 --- a/apps/edr-freight-api/src/migrations/1826000000000-AddCargoScopeQuantityCap.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * GENERAL contracts can be booked repeatedly until a total cargo quantity cap is - * reached (e.g. 100 containers across many shipments). `quantity_cap` on each - * cargo-scope line holds that ceiling (containers per size, or tons/items for - * bulk). NULL = uncapped; always NULL for ONE_TIME (single booking). - */ -export class AddCargoScopeQuantityCap1826000000000 implements MigrationInterface { - name = 'AddCargoScopeQuantityCap1826000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_cargo_scope ADD COLUMN IF NOT EXISTS quantity_cap NUMERIC(12,2);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_cargo_scope DROP COLUMN IF EXISTS quantity_cap;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1827000000000-CreateBookingRequests.ts b/apps/edr-freight-api/src/migrations/1827000000000-CreateBookingRequests.ts deleted file mode 100644 index e88824e28..000000000 --- a/apps/edr-freight-api/src/migrations/1827000000000-CreateBookingRequests.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Customer shipment requests for GENERAL customs (Path B) contracts. The customer - * submits date + quantities; Global Logistics reviews, then creates the booking - * on their behalf and per-booking clearance begins. Additive — no change to - * existing tables; ONE_TIME contracts are unaffected. - */ -export class CreateBookingRequests1827000000000 implements MigrationInterface { - name = 'CreateBookingRequests1827000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'booking_requests', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'reference', type: 'varchar', length: '40', default: "''" }, - { name: 'contract_id', type: 'uuid' }, - { name: 'requested_by_user_id', type: 'uuid', isNullable: true }, - { name: 'contract_route_id', type: 'uuid', isNullable: true }, - { name: 'scheduled_date', type: 'timestamptz', isNullable: true }, - { name: 'status', type: 'varchar', length: '16', default: "'PENDING'" }, - { name: 'requested_lines', type: 'jsonb', default: "'{}'::jsonb" }, - { name: 'notes', type: 'text', isNullable: true }, - { name: 'created_booking_id', type: 'uuid', isNullable: true }, - { name: 'reviewed_by_staff_id', type: 'uuid', isNullable: true }, - { name: 'reviewed_at', type: 'timestamptz', isNullable: true }, - { name: 'review_note', type: 'text', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['contract_id'], - referencedSchema: 'freight', - referencedTableName: 'contracts', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - { - columnNames: ['created_booking_id'], - referencedSchema: 'freight', - referencedTableName: 'bookings', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.booking_requests', - new TableIndex({ name: 'idx_booking_requests_contract', columnNames: ['contract_id'] }), - ); - await queryRunner.createIndex( - 'freight.booking_requests', - new TableIndex({ name: 'idx_booking_requests_status', columnNames: ['status'] }), - ); - await queryRunner.createIndex( - 'freight.booking_requests', - new TableIndex({ - name: 'idx_booking_requests_contract_status', - columnNames: ['contract_id', 'status'], - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.booking_requests', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/1828000000000-AddBulkHazmatReeferQuantity.ts b/apps/edr-freight-api/src/migrations/1828000000000-AddBulkHazmatReeferQuantity.ts deleted file mode 100644 index cc9437eaf..000000000 --- a/apps/edr-freight-api/src/migrations/1828000000000-AddBulkHazmatReeferQuantity.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Bulk / break-bulk freight can now declare HOW MUCH of the cargo is hazardous - * or refrigerated, in the cargo's own unit of measure (tons for PER_TON, item - * count for PER_ITEM). These two columns hold that amount on the booking; they - * stay 0 for container freight (which tracks it per line on booking_container) - * and for bulk cargo with no hazardous/reefer portion. The existing - * is_hazardous / is_reefer booleans remain the surcharge trigger. - */ -export class AddBulkHazmatReeferQuantity1828000000000 implements MigrationInterface { - name = 'AddBulkHazmatReeferQuantity1828000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS bulk_hazardous_quantity NUMERIC(12,3) NOT NULL DEFAULT 0;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS bulk_reefer_quantity NUMERIC(12,3) NOT NULL DEFAULT 0;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS bulk_reefer_quantity;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS bulk_hazardous_quantity;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1828000000000-AddGrnNumberToWarehouseInventory.ts b/apps/edr-freight-api/src/migrations/1828000000000-AddGrnNumberToWarehouseInventory.ts deleted file mode 100644 index c57a43aaa..000000000 --- a/apps/edr-freight-api/src/migrations/1828000000000-AddGrnNumberToWarehouseInventory.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddGrnNumberToWarehouseInventory1828000000000 implements MigrationInterface { - name = 'AddGrnNumberToWarehouseInventory1828000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - ADD COLUMN IF NOT EXISTS grn_number VARCHAR(100) NULL - `); - - await queryRunner.query(` - UPDATE freight.warehouse_inventory - SET grn_number = substring(notes FROM 'GRN Number: ([^\\n\\r]+)') - WHERE grn_number IS NULL - AND notes IS NOT NULL - AND notes ~ 'GRN Number: ' - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_inventory_grn_number - ON freight.warehouse_inventory(grn_number) - WHERE grn_number IS NOT NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_warehouse_inventory_grn_number`); - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - DROP COLUMN IF EXISTS grn_number - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1828000000000-ExtendInvoicesForPartialPayment.ts b/apps/edr-freight-api/src/migrations/1828000000000-ExtendInvoicesForPartialPayment.ts deleted file mode 100644 index 55239c13f..000000000 --- a/apps/edr-freight-api/src/migrations/1828000000000-ExtendInvoicesForPartialPayment.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Extend `freight.invoices` into the billing record of record for every source - * (booking, demurrage, warehouse fees, …) so warehouse fee invoices can be - * centralized onto it instead of the parallel `warehouse_fee_invoices` table. - * - * Adds money tracking that supports partial payment (`subtotal/tax/paid/balance`), - * a `paid_at` stamp, a `payments` jsonb ledger, and the `ISSUED` / `PARTIALLY_PAID` - * statuses the warehouse flow uses. - * - * Matches billing/entities/invoice.entity.ts. All columns are additive with - * defaults, so existing booking/demurrage rows are unaffected. - */ -export class ExtendInvoicesForPartialPayment1828000000000 - implements MigrationInterface -{ - name = "ExtendInvoicesForPartialPayment1828000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // New statuses. ADD VALUE is non-transactional-value-safe on PG 12+ as long - // as the value is not referenced in the same transaction (it is not here). - await queryRunner.query( - `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'ISSUED' BEFORE 'PENDING';`, - ); - await queryRunner.query( - `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'PARTIALLY_PAID' BEFORE 'PAID';`, - ); - - await queryRunner.query(` - ALTER TABLE freight.invoices - ADD COLUMN IF NOT EXISTS subtotal_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS tax_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS paid_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS balance_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS paid_at timestamptz, - ADD COLUMN IF NOT EXISTS payments jsonb NOT NULL DEFAULT '[]'; - `); - - // Backfill existing rows: subtotal mirrors the total (no tax was modeled), - // the outstanding balance is the full total for unpaid invoices. - await queryRunner.query(` - UPDATE freight.invoices - SET subtotal_amount = total_amount, - balance_amount = total_amount; - `); - - // Already-settled invoices: fully paid, zero balance, stamped from updated_at. - await queryRunner.query(` - UPDATE freight.invoices - SET paid_amount = total_amount, - balance_amount = 0, - paid_at = updated_at - WHERE status = 'PAID'; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.invoices - DROP COLUMN IF EXISTS payments, - DROP COLUMN IF EXISTS paid_at, - DROP COLUMN IF EXISTS balance_amount, - DROP COLUMN IF EXISTS paid_amount, - DROP COLUMN IF EXISTS tax_amount, - DROP COLUMN IF EXISTS subtotal_amount; - `); - // Postgres cannot drop individual enum values; ISSUED / PARTIALLY_PAID are - // left on freight.invoices_status_enum (harmless, unused after down). - } -} diff --git a/apps/edr-freight-api/src/migrations/1829000000000-CentralizeWarehouseInvoices.ts b/apps/edr-freight-api/src/migrations/1829000000000-CentralizeWarehouseInvoices.ts deleted file mode 100644 index 75082c5c4..000000000 --- a/apps/edr-freight-api/src/migrations/1829000000000-CentralizeWarehouseInvoices.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Fold warehouse fee invoices into the central billing system. - * - * Warehouse fee invoices are no longer a standalone aggregate: each becomes a - * global `freight.invoices` row (`source = 'warehouse'`, `source_id = - * inventory_id`) with its items as `freight.invoice_lines`. The warehouse - * service is now a thin layer over `BillingService`. This migration backfills the - * existing rows (preserving ids, numbers, status, amounts and payment history), - * then drops the two legacy tables. - * - * Rows that cannot be billed centrally — no company to bill (`company_id` / - * `company_profile_id` underivable from the customer or the booking) — are not - * migrated; they could never have been charged through the gateway and are - * dropped with the table. - */ -export class CentralizeWarehouseInvoices1829000000000 implements MigrationInterface { - name = 'CentralizeWarehouseInvoices1829000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ - BEGIN - IF EXISTS ( - SELECT 1 - FROM information_schema.columns - WHERE table_schema = 'freight' - AND table_name = 'invoices' - AND column_name = 'booking_id' - ) THEN - ALTER TABLE freight.invoices ALTER COLUMN booking_id DROP NOT NULL; - END IF; - - IF EXISTS ( - SELECT 1 - FROM information_schema.columns - WHERE table_schema = 'freight' - AND table_name = 'invoices' - AND column_name = 'amount' - ) THEN - ALTER TABLE freight.invoices ALTER COLUMN amount DROP NOT NULL; - END IF; - END $$; - `); - - // 1. Invoice headers. Keep the same id so items still link, and so any - // external reference to the invoice id stays valid. - await queryRunner.query(` - INSERT INTO freight.invoices ( - id, invoice_number, company_id, company_profile_id, - subtotal_amount, tax_amount, total_amount, paid_amount, balance_amount, - currency, status, source, source_id, type, - issued_at, paid_at, payments, payment_id, due_at, - created_at, updated_at, deleted_at - ) - SELECT - fee.id, - fee.invoice_number, - COALESCE(fee.customer_id, b.company_id), - COALESCE( - b.company_profile_id, - (SELECT cp.id - FROM freight.company_profiles cp - WHERE cp.company_id = COALESCE(fee.customer_id, b.company_id) - AND cp.deleted_at IS NULL - ORDER BY cp.created_at ASC - LIMIT 1) - ), - fee.subtotal_amount, fee.tax_amount, fee.total_amount, fee.paid_amount, fee.balance_amount, - fee.currency, - fee.status::freight.invoices_status_enum, - 'warehouse', - fee.inventory_id, - fee.invoice_type, - fee.issued_at, - fee.paid_at, - COALESCE(fee.payments, '[]'::jsonb), - NULL, - COALESCE(fee.due_date, fee.issued_at, fee.created_at), - fee.created_at, fee.updated_at, fee.deleted_at - FROM freight.warehouse_fee_invoices fee - LEFT JOIN freight.bookings b ON b.id = fee.booking_id - WHERE COALESCE(fee.customer_id, b.company_id) IS NOT NULL - AND COALESCE( - b.company_profile_id, - (SELECT cp.id - FROM freight.company_profiles cp - WHERE cp.company_id = COALESCE(fee.customer_id, b.company_id) - AND cp.deleted_at IS NULL - ORDER BY cp.created_at ASC - LIMIT 1) - ) IS NOT NULL - ON CONFLICT (id) DO NOTHING; - `); - - // 2. Invoice lines — only for items whose parent invoice migrated. Warehouse - // fee fields (fee_rule_id / chargeable_days / free_days) move into the - // line's jsonb metadata. - await queryRunner.query(` - INSERT INTO freight.invoice_lines ( - id, invoice_id, charge_type, description, quantity, unit_rate, amount, - currency, metadata, created_at, updated_at, deleted_at - ) - SELECT - item.id, - item.invoice_id, - item.fee_type, - item.description, - item.quantity, - item.unit_rate, - item.amount, - item.currency, - jsonb_build_object( - 'feeRuleId', item.fee_rule_id, - 'chargeableDays', item.chargeable_days, - 'freeDays', item.free_days - ), - item.created_at, item.updated_at, item.deleted_at - FROM freight.warehouse_fee_invoice_items item - JOIN freight.invoices i ON i.id = item.invoice_id AND i.source = 'warehouse' - ON CONFLICT (id) DO NOTHING; - `); - - // 3. Drop the legacy tables (items first — FK to invoices). - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_fee_invoice_items;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_fee_invoices;`); - } - - public async down(queryRunner: QueryRunner): Promise { - // Recreate the legacy tables … - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_fee_invoices ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - invoice_number varchar(40) NOT NULL, - booking_id uuid, - customer_id uuid, - inventory_id uuid NOT NULL, - facility_id uuid, - warehouse_id uuid, - yard_id uuid, - zone_id uuid, - invoice_type varchar(32) NOT NULL DEFAULT 'MIXED_WAREHOUSE_FEES', - status varchar(20) NOT NULL DEFAULT 'DRAFT', - subtotal_amount numeric(14,2) NOT NULL DEFAULT 0, - tax_amount numeric(14,2) NOT NULL DEFAULT 0, - total_amount numeric(14,2) NOT NULL DEFAULT 0, - paid_amount numeric(14,2) NOT NULL DEFAULT 0, - balance_amount numeric(14,2) NOT NULL DEFAULT 0, - currency varchar(8) NOT NULL DEFAULT 'USD', - period_start timestamptz, - period_end timestamptz, - issued_at timestamptz, - due_date timestamptz, - paid_at timestamptz, - cancelled_at timestamptz, - payments jsonb NOT NULL DEFAULT '[]', - notes text, - CONSTRAINT "PK_warehouse_fee_invoices" PRIMARY KEY (id), - CONSTRAINT "UQ_warehouse_fee_invoices_invoice_number" UNIQUE (invoice_number) - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_warehouse_fee_invoices_booking_id" ON freight.warehouse_fee_invoices (booking_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_warehouse_fee_invoices_inventory_id" ON freight.warehouse_fee_invoices (inventory_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_warehouse_fee_invoices_status" ON freight.warehouse_fee_invoices (status);`, - ); - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_fee_invoice_items ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - invoice_id uuid NOT NULL, - fee_rule_id uuid, - fee_type varchar(32) NOT NULL, - description varchar(255) NOT NULL, - quantity numeric(12,2) NOT NULL DEFAULT 1, - unit_rate numeric(14,2) NOT NULL DEFAULT 0, - amount numeric(14,2) NOT NULL DEFAULT 0, - currency varchar(8) NOT NULL DEFAULT 'USD', - chargeable_days int, - free_days int, - CONSTRAINT "PK_warehouse_fee_invoice_items" PRIMARY KEY (id), - CONSTRAINT "FK_warehouse_fee_invoice_items_invoice" - FOREIGN KEY (invoice_id) REFERENCES freight.warehouse_fee_invoices (id) ON DELETE CASCADE - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_warehouse_fee_invoice_items_invoice_id" ON freight.warehouse_fee_invoice_items (invoice_id);`, - ); - - // … then copy the warehouse-source invoices back, deriving the typed FKs and - // period from the linked inventory item. - await queryRunner.query(` - INSERT INTO freight.warehouse_fee_invoices ( - id, created_at, updated_at, deleted_at, invoice_number, - booking_id, customer_id, inventory_id, facility_id, warehouse_id, yard_id, zone_id, - invoice_type, status, subtotal_amount, tax_amount, total_amount, paid_amount, balance_amount, - currency, period_start, period_end, issued_at, due_date, paid_at, cancelled_at, payments, notes - ) - SELECT - i.id, i.created_at, i.updated_at, i.deleted_at, i.invoice_number, - inv.booking_id, i.company_id, i.source_id, w.facility_id, inv.warehouse_id, inv.yard_id, inv.zone_id, - i.type, i.status::text, i.subtotal_amount, i.tax_amount, i.total_amount, i.paid_amount, i.balance_amount, - i.currency, inv.arrived_at, i.issued_at, i.issued_at, i.due_at, i.paid_at, - CASE WHEN i.status::text = 'CANCELLED' THEN i.updated_at ELSE NULL END, - i.payments, NULL - FROM freight.invoices i - LEFT JOIN freight.warehouse_inventory inv ON inv.id = i.source_id - LEFT JOIN freight.warehouses w ON w.id = inv.warehouse_id - WHERE i.source = 'warehouse' - ON CONFLICT (id) DO NOTHING; - `); - await queryRunner.query(` - INSERT INTO freight.warehouse_fee_invoice_items ( - id, created_at, updated_at, deleted_at, invoice_id, fee_rule_id, fee_type, - description, quantity, unit_rate, amount, currency, chargeable_days, free_days - ) - SELECT - l.id, l.created_at, l.updated_at, l.deleted_at, l.invoice_id, - NULLIF(l.metadata->>'feeRuleId', '')::uuid, - l.charge_type, - COALESCE(l.description, ''), - l.quantity, l.unit_rate, l.amount, l.currency, - NULLIF(l.metadata->>'chargeableDays', '')::int, - NULLIF(l.metadata->>'freeDays', '')::int - FROM freight.invoice_lines l - JOIN freight.invoices i ON i.id = l.invoice_id AND i.source = 'warehouse' - ON CONFLICT (id) DO NOTHING; - `); - - // Remove the migrated rows from the central tables. - await queryRunner.query(` - DELETE FROM freight.invoice_lines - WHERE invoice_id IN (SELECT id FROM freight.invoices WHERE source = 'warehouse'); - `); - await queryRunner.query(`DELETE FROM freight.invoices WHERE source = 'warehouse';`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1829000000000-PhasedClearanceCycleMeta.ts b/apps/edr-freight-api/src/migrations/1829000000000-PhasedClearanceCycleMeta.ts deleted file mode 100644 index 75288e94c..000000000 --- a/apps/edr-freight-api/src/migrations/1829000000000-PhasedClearanceCycleMeta.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class PhasedClearanceCycleMeta1829000000000 implements MigrationInterface { - name = 'PhasedClearanceCycleMeta1829000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS duty_required BOOLEAN;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS vessel_departure_date DATE;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS ro_amendment_requested_at TIMESTAMPTZ;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS ro_hold_reason TEXT;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS current_phase VARCHAR(40);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS duty_required;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS vessel_departure_date;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS ro_amendment_requested_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS ro_hold_reason;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS current_phase;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1829000000001-SeedRoVesselMinDays.ts b/apps/edr-freight-api/src/migrations/1829000000001-SeedRoVesselMinDays.ts deleted file mode 100644 index 7165ea7a8..000000000 --- a/apps/edr-freight-api/src/migrations/1829000000001-SeedRoVesselMinDays.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** Admin-configurable minimum days between today and export RO vessel departure. */ -export class SeedRoVesselMinDays1829000000001 implements MigrationInterface { - name = 'SeedRoVesselMinDays1829000000001'; - private readonly code = 'ro_vessel_min_days'; - private readonly options: Array<{ value: string; label: string }> = [ - { value: '2', label: '2 days' }, - { value: '3', label: '3 days' }, - ]; - - public async up(queryRunner: QueryRunner): Promise { - const existing = await queryRunner.query( - `SELECT id FROM freight.dropdown_settings WHERE code = $1 LIMIT 1;`, - [this.code], - ); - if (existing.length > 0) return; - - const inserted = await queryRunner.query( - `INSERT INTO freight.dropdown_settings (code, label, description, multiple) - VALUES ($1, $2, $3, false) - RETURNING id;`, - [ - this.code, - 'RO vessel minimum lead time (days)', - 'Minimum days between today and the vessel departure date on an export Release Order.', - ], - ); - const settingId = inserted[0].id; - - for (let i = 0; i < this.options.length; i++) { - const opt = this.options[i]; - await queryRunner.query( - `INSERT INTO freight.dropdown_options (setting_id, value, label, display_order) - VALUES ($1, $2, $3, $4);`, - [settingId, opt.value, opt.label, i], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM freight.dropdown_settings WHERE code = $1;`, [ - this.code, - ]); - } -} diff --git a/apps/edr-freight-api/src/migrations/1829000000002-BookingClearanceMeta.ts b/apps/edr-freight-api/src/migrations/1829000000002-BookingClearanceMeta.ts deleted file mode 100644 index c108b7baa..000000000 --- a/apps/edr-freight-api/src/migrations/1829000000002-BookingClearanceMeta.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class BookingClearanceMeta1829000000002 implements MigrationInterface { - name = 'BookingClearanceMeta1829000000002'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS clearance_current_phase VARCHAR(40);`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS duty_required BOOLEAN;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS vessel_departure_date DATE;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS ro_amendment_requested_at TIMESTAMPTZ;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS ro_hold_reason TEXT;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS clearance_current_phase;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS duty_required;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS vessel_departure_date;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS ro_amendment_requested_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS ro_hold_reason;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts b/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts deleted file mode 100644 index e4b353b94..000000000 --- a/apps/edr-freight-api/src/migrations/1830000000000-AddExpiredInvoiceStatus.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add the `EXPIRED` invoice status. An invoice expires when its source's pay - * window closes before settlement (e.g. a booking whose `paymentDeadline` - * lapses) — driven event-style from the domain via `BillingService.expirePayable`, - * which emits `${source}.invoice.expired`. Terminal and not settle-able (kept out - * of `OPEN_STATUSES`), so it is distinct from `CANCELLED` (manual void) and - * `OVERDUE` (still payable). - * - * Matches Freight.InvoiceStatus in packages/types. ADD VALUE only — additive and - * not referenced in this same transaction, so it is PG 12+ safe. - */ -export class AddExpiredInvoiceStatus1830000000000 implements MigrationInterface { - name = "AddExpiredInvoiceStatus1830000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'EXPIRED' AFTER 'REFUNDED';`, - ); - } - - public async down(): Promise { - // Postgres cannot drop individual enum values; EXPIRED is left on - // freight.invoices_status_enum (harmless, unused after down). - } -} diff --git a/apps/edr-freight-api/src/migrations/1830000000000-CreateFirstMileContainerAllocations.ts b/apps/edr-freight-api/src/migrations/1830000000000-CreateFirstMileContainerAllocations.ts deleted file mode 100644 index b91e88633..000000000 --- a/apps/edr-freight-api/src/migrations/1830000000000-CreateFirstMileContainerAllocations.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; - -/** - * Create freight.first_mile_container_allocations table — tracks - * container allocations per first-mile shipment with optional vehicle assignment. - */ -export class CreateFirstMileContainerAllocations1830000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.first_mile_container_allocations'); - if (exists) return; - - await queryRunner.createTable( - new Table({ - name: 'freight.first_mile_container_allocations', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - default: 'gen_random_uuid()', - }, - { name: 'first_mile_id', type: 'uuid', isNullable: false }, - { name: 'container_id', type: 'uuid', isNullable: false }, - { name: 'vehicle_id', type: 'uuid', isNullable: true }, - { name: 'container_type', type: 'text', isNullable: false }, - { - name: 'quantity', - type: 'int', - default: 1, - isNullable: false, - }, - { 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.first_mile_container_allocations', - new TableForeignKey({ - columnNames: ['first_mile_id'], - referencedTableName: 'freight.first_mile', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }), - ); - - await queryRunner.createForeignKey( - 'freight.first_mile_container_allocations', - new TableForeignKey({ - columnNames: ['vehicle_id'], - referencedTableName: 'freight.vehicles', - referencedColumnNames: ['id'], - onDelete: 'SET NULL', - }), - ); - - await queryRunner.query( - `CREATE INDEX "IDX_first_mile_container_allocations_first_mile_id" ON "freight"."first_mile_container_allocations" ("first_mile_id")`, - ); - await queryRunner.query( - `CREATE INDEX "IDX_first_mile_container_allocations_vehicle_id" ON "freight"."first_mile_container_allocations" ("vehicle_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable('freight.first_mile_container_allocations'); - if (exists) { - await queryRunner.dropTable('freight.first_mile_container_allocations'); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/1830000000000-DropCargoTypeShowFreeTextBox.ts b/apps/edr-freight-api/src/migrations/1830000000000-DropCargoTypeShowFreeTextBox.ts deleted file mode 100644 index 5bdfe1f30..000000000 --- a/apps/edr-freight-api/src/migrations/1830000000000-DropCargoTypeShowFreeTextBox.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class DropCargoTypeShowFreeTextBox1830000000000 implements MigrationInterface { - name = 'DropCargoTypeShowFreeTextBox1830000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.cargo_types - DROP COLUMN IF EXISTS show_free_text_box - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.cargo_types - ADD COLUMN IF NOT EXISTS show_free_text_box boolean NOT NULL DEFAULT false - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1830000000001-RouteStatusAndSegmentKm.ts b/apps/edr-freight-api/src/migrations/1830000000001-RouteStatusAndSegmentKm.ts deleted file mode 100644 index 701b52c18..000000000 --- a/apps/edr-freight-api/src/migrations/1830000000001-RouteStatusAndSegmentKm.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RouteStatusAndSegmentKm1830000000001 implements MigrationInterface { - name = 'RouteStatusAndSegmentKm1830000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.routes - ADD COLUMN IF NOT EXISTS status varchar(32) NOT NULL DEFAULT 'AVAILABLE' - `); - - await queryRunner.query(` - UPDATE freight.routes - SET status = CASE WHEN is_active = true THEN 'AVAILABLE' ELSE 'STOP_WORKING' END - `); - - await queryRunner.query(` - DROP INDEX IF EXISTS freight."IDX_routes_name" - `); - await queryRunner.query(` - ALTER TABLE freight.routes DROP COLUMN IF EXISTS name - `); - await queryRunner.query(` - ALTER TABLE freight.routes DROP COLUMN IF EXISTS is_active - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_routes_status" ON freight.routes (status) - `); - - await queryRunner.query(` - ALTER TABLE freight.route_milestones - ADD COLUMN IF NOT EXISTS distance_km numeric(10,2) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.route_milestones DROP COLUMN IF EXISTS distance_km - `); - - await queryRunner.query(` - ALTER TABLE freight.routes - ADD COLUMN IF NOT EXISTS name varchar(120) - `); - await queryRunner.query(` - UPDATE freight.routes SET name = id::text WHERE name IS NULL - `); - await queryRunner.query(` - ALTER TABLE freight.routes ALTER COLUMN name SET NOT NULL - `); - - await queryRunner.query(` - ALTER TABLE freight.routes - ADD COLUMN IF NOT EXISTS is_active boolean NOT NULL DEFAULT true - `); - await queryRunner.query(` - UPDATE freight.routes - SET is_active = CASE WHEN status = 'AVAILABLE' THEN true ELSE false END - `); - - await queryRunner.query(` - ALTER TABLE freight.routes DROP COLUMN IF EXISTS status - `); - await queryRunner.query(` - DROP INDEX IF EXISTS freight."IDX_routes_status" - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "IDX_routes_name" ON freight.routes (name) - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1830000000002-PreClearanceFinalizedAt.ts b/apps/edr-freight-api/src/migrations/1830000000002-PreClearanceFinalizedAt.ts deleted file mode 100644 index df57cd828..000000000 --- a/apps/edr-freight-api/src/migrations/1830000000002-PreClearanceFinalizedAt.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class PreClearanceFinalizedAt1830000000002 implements MigrationInterface { - name = 'PreClearanceFinalizedAt1830000000002'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles ADD COLUMN IF NOT EXISTS pre_clearance_finalized_at TIMESTAMPTZ;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS pre_clearance_finalized_at TIMESTAMPTZ;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_clearance_cycles DROP COLUMN IF EXISTS pre_clearance_finalized_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS pre_clearance_finalized_at;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1831000000000-AddWarehouseFeeRuleTiers.ts b/apps/edr-freight-api/src/migrations/1831000000000-AddWarehouseFeeRuleTiers.ts deleted file mode 100644 index c6da11cc8..000000000 --- a/apps/edr-freight-api/src/migrations/1831000000000-AddWarehouseFeeRuleTiers.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddWarehouseFeeRuleTiers1831000000000 implements MigrationInterface { - name = 'AddWarehouseFeeRuleTiers1831000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_fee_rules - ADD COLUMN IF NOT EXISTS tiers jsonb NOT NULL DEFAULT '[]'; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_fee_rules - DROP COLUMN IF EXISTS tiers; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1832000000000-AddCustomerTruckAssignmentToBookings.ts b/apps/edr-freight-api/src/migrations/1832000000000-AddCustomerTruckAssignmentToBookings.ts deleted file mode 100644 index c137ca264..000000000 --- a/apps/edr-freight-api/src/migrations/1832000000000-AddCustomerTruckAssignmentToBookings.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddCustomerTruckAssignmentToBookings1832000000000 implements MigrationInterface { - name = 'AddCustomerTruckAssignmentToBookings1832000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS customer_truck_plate_number varchar(32), - ADD COLUMN IF NOT EXISTS customer_truck_driver_name varchar(120), - ADD COLUMN IF NOT EXISTS customer_truck_type varchar(60), - ADD COLUMN IF NOT EXISTS customer_truck_container_number varchar(16), - ADD COLUMN IF NOT EXISTS customer_truck_assigned_at timestamptz, - ADD COLUMN IF NOT EXISTS customer_truck_arrived_at timestamptz - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS customer_truck_arrived_at, - DROP COLUMN IF EXISTS customer_truck_assigned_at, - DROP COLUMN IF EXISTS customer_truck_container_number, - DROP COLUMN IF EXISTS customer_truck_type, - DROP COLUMN IF EXISTS customer_truck_driver_name, - DROP COLUMN IF EXISTS customer_truck_plate_number - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1840000000000-CreateFuelTables.ts b/apps/edr-freight-api/src/migrations/1840000000000-CreateFuelTables.ts deleted file mode 100644 index a74a58f8e..000000000 --- a/apps/edr-freight-api/src/migrations/1840000000000-CreateFuelTables.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreateFuelTables1840000000000 implements MigrationInterface { - name = "CreateFuelTables1840000000000"; - - public async up(queryRunner: QueryRunner): Promise { - const fuelPurchasesExists = await queryRunner.query( - `SELECT 1 FROM information_schema.tables WHERE table_schema = 'freight' AND table_name = 'fuel_purchases';`, - ); - - if (!fuelPurchasesExists.length) { - await queryRunner.query(` - CREATE TABLE freight.fuel_purchases ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - purchase_date timestamptz NOT NULL, - liters numeric(10, 2) NOT NULL, - cost_per_liter numeric(10, 2) NOT NULL, - total_cost numeric(14, 2) NOT NULL, - fuel_station varchar(255) NULL, - payment_method varchar(50) DEFAULT 'CASH', - odometer_reading numeric(10, 2) NULL, - driver_id uuid NULL, - receipt_number varchar(255) NULL, - notes text NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL, - CONSTRAINT pk_fuel_purchases PRIMARY KEY (id), - CONSTRAINT fk_fuel_purchases_vehicle FOREIGN KEY (vehicle_id) - REFERENCES freight.vehicles (id) ON DELETE CASCADE - ); - `); - - await queryRunner.query( - `CREATE INDEX idx_fuel_purchases_vehicle ON freight.fuel_purchases (vehicle_id);`, - ); - await queryRunner.query( - `CREATE INDEX idx_fuel_purchases_date ON freight.fuel_purchases (purchase_date);`, - ); - } - - const fuelConsumptionExists = await queryRunner.query( - `SELECT 1 FROM information_schema.tables WHERE table_schema = 'freight' AND table_name = 'fuel_consumption';`, - ); - - if (!fuelConsumptionExists.length) { - await queryRunner.query(` - CREATE TABLE freight.fuel_consumption ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - month date NOT NULL, - total_liters numeric(10, 2) NOT NULL, - total_cost numeric(14, 2) NOT NULL, - total_distance_km numeric(10, 2) NOT NULL, - fuel_efficiency_km_per_l numeric(10, 2) NULL, - number_of_purchases integer DEFAULT 0, - average_cost_per_liter numeric(10, 2) NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL, - CONSTRAINT pk_fuel_consumption PRIMARY KEY (id), - CONSTRAINT fk_fuel_consumption_vehicle FOREIGN KEY (vehicle_id) - REFERENCES freight.vehicles (id) ON DELETE CASCADE, - CONSTRAINT uq_fuel_consumption_vehicle_month UNIQUE (vehicle_id, month) - ); - `); - - await queryRunner.query( - `CREATE INDEX idx_fuel_consumption_vehicle_month ON freight.fuel_consumption (vehicle_id, month);`, - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.fuel_consumption;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.fuel_purchases;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1850000000000-CreateMaintenanceTables.ts b/apps/edr-freight-api/src/migrations/1850000000000-CreateMaintenanceTables.ts deleted file mode 100644 index 26d4afe21..000000000 --- a/apps/edr-freight-api/src/migrations/1850000000000-CreateMaintenanceTables.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CreateMaintenanceTables1850000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - // Create maintenance_schedules table - const scheduleTableExists = await queryRunner.query(` - SELECT EXISTS( - SELECT 1 FROM information_schema.tables - WHERE table_schema = 'freight' AND table_name = 'maintenance_schedules' - ) - `); - - if (!scheduleTableExists[0].exists) { - await queryRunner.query(` - CREATE TABLE "freight"."maintenance_schedules" ( - "id" uuid NOT NULL DEFAULT gen_random_uuid(), - "vehicle_id" uuid NOT NULL, - "maintenance_type" varchar NOT NULL, - "description" varchar NOT NULL, - "scheduled_date" timestamptz NOT NULL, - "completed_date" timestamptz, - "estimated_cost" numeric(14,2), - "actual_cost" numeric(14,2), - "status" varchar NOT NULL DEFAULT 'SCHEDULED', - "odometer_reading" numeric, - "service_provider" varchar, - "notes" text, - "next_due_km" numeric, - "next_due_date" timestamptz, - "created_at" timestamptz NOT NULL DEFAULT now(), - "updated_at" timestamptz NOT NULL DEFAULT now(), - "deleted_at" timestamptz, - PRIMARY KEY ("id") - ) - `); - - await queryRunner.query( - `CREATE INDEX "idx_maintenance_schedules_vehicle_date" ON "freight"."maintenance_schedules" ("vehicle_id", "scheduled_date")` - ); - } - - // Create maintenance_costs table - const costsTableExists = await queryRunner.query(` - SELECT EXISTS( - SELECT 1 FROM information_schema.tables - WHERE table_schema = 'freight' AND table_name = 'maintenance_costs' - ) - `); - - if (!costsTableExists[0].exists) { - await queryRunner.query(` - CREATE TABLE "freight"."maintenance_costs" ( - "id" uuid NOT NULL DEFAULT gen_random_uuid(), - "vehicle_id" uuid NOT NULL, - "maintenance_schedule_id" uuid, - "incurred_date" timestamptz NOT NULL, - "cost_amount" numeric(14,2) NOT NULL, - "cost_type" varchar NOT NULL, - "description" varchar NOT NULL, - "service_provider" varchar, - "invoice_number" varchar, - "notes" text, - "created_at" timestamptz NOT NULL DEFAULT now(), - "updated_at" timestamptz NOT NULL DEFAULT now(), - "deleted_at" timestamptz, - PRIMARY KEY ("id"), - CONSTRAINT "fk_maintenance_schedule" FOREIGN KEY ("maintenance_schedule_id") - REFERENCES "freight"."maintenance_schedules" ("id") ON DELETE SET NULL - ) - `); - - await queryRunner.query( - `CREATE INDEX "idx_maintenance_costs_vehicle_date" ON "freight"."maintenance_costs" ("vehicle_id", "incurred_date")` - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS "freight"."maintenance_costs"`); - await queryRunner.query(`DROP TABLE IF EXISTS "freight"."maintenance_schedules"`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1860000000000-AddPaidToFirstAndLastMile.ts b/apps/edr-freight-api/src/migrations/1860000000000-AddPaidToFirstAndLastMile.ts deleted file mode 100644 index 261e16099..000000000 --- a/apps/edr-freight-api/src/migrations/1860000000000-AddPaidToFirstAndLastMile.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add paid column to first_mile and last_mile tables to track invoice payment status. - */ -export class AddPaidToFirstAndLastMile1860000000000 - implements MigrationInterface -{ - name = "AddPaidToFirstAndLastMile1860000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.first_mile - ADD COLUMN IF NOT EXISTS paid boolean NOT NULL DEFAULT false; - `); - - await queryRunner.query(` - ALTER TABLE freight.last_mile - ADD COLUMN IF NOT EXISTS paid boolean NOT NULL DEFAULT false; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.first_mile - DROP COLUMN IF EXISTS paid; - `); - - await queryRunner.query(` - ALTER TABLE freight.last_mile - DROP COLUMN IF EXISTS paid; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1861000000000-AddBookingWindowGlobalRules.ts b/apps/edr-freight-api/src/migrations/1861000000000-AddBookingWindowGlobalRules.ts deleted file mode 100644 index a98fcd80d..000000000 --- a/apps/edr-freight-api/src/migrations/1861000000000-AddBookingWindowGlobalRules.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddBookingWindowGlobalRules1861000000000 implements MigrationInterface { - name = "AddBookingWindowGlobalRules1861000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ADD COLUMN import_window_lead_days integer NOT NULL DEFAULT 3, - ADD COLUMN export_booking_lead_hours integer NOT NULL DEFAULT 24, - ADD COLUMN window_open_hour integer NOT NULL DEFAULT 8, - ADD COLUMN window_duration_hours numeric(4, 2) NOT NULL DEFAULT 3, - ADD COLUMN doc_review_minutes integer NOT NULL DEFAULT 30, - ADD COLUMN payment_window_minutes integer NOT NULL DEFAULT 60, - ADD COLUMN reopen_delay_minutes integer NOT NULL DEFAULT 90; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - DROP COLUMN IF EXISTS import_window_lead_days, - DROP COLUMN IF EXISTS export_booking_lead_hours, - DROP COLUMN IF EXISTS window_open_hour, - DROP COLUMN IF EXISTS window_duration_hours, - DROP COLUMN IF EXISTS doc_review_minutes, - DROP COLUMN IF EXISTS payment_window_minutes, - DROP COLUMN IF EXISTS reopen_delay_minutes; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1861000000001-ReleaseStuckAssignedLocomotives.ts b/apps/edr-freight-api/src/migrations/1861000000001-ReleaseStuckAssignedLocomotives.ts deleted file mode 100644 index 0d5155391..000000000 --- a/apps/edr-freight-api/src/migrations/1861000000001-ReleaseStuckAssignedLocomotives.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * arriveSchedule used to release only the primary locomotive of a train set, leaving - * secondary locomotives ASSIGNED forever. Locomotives are now only ASSIGNED while out - * on a dispatched train — release every ASSIGNED locomotive that is not attached to a - * currently-DISPATCHED schedule. - */ -export class ReleaseStuckAssignedLocomotives1861000000001 implements MigrationInterface { - name = "ReleaseStuckAssignedLocomotives1861000000001"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.locomotives l - SET status = 'AVAILABLE' - WHERE l.status = 'ASSIGNED' - AND NOT EXISTS ( - SELECT 1 - FROM freight.train_schedules ts - JOIN freight.train_sets tset ON tset.id = ts.train_set_id - JOIN ( - SELECT tsl.train_set_id, tsl.locomotive_id - FROM freight.train_set_locomotives tsl - WHERE tsl.deleted_at IS NULL - UNION - SELECT t.id AS train_set_id, t.locomotive_id - FROM freight.train_sets t - WHERE t.locomotive_id IS NOT NULL - ) loco ON loco.train_set_id = tset.id - WHERE ts.status = 'DISPATCHED' - AND ts.deleted_at IS NULL - AND loco.locomotive_id = l.id - ); - `); - } - - public async down(): Promise { - // Data fix — not reversible. - } -} diff --git a/apps/edr-freight-api/src/migrations/1862000000000-AddScheduleWindowPhases.ts b/apps/edr-freight-api/src/migrations/1862000000000-AddScheduleWindowPhases.ts deleted file mode 100644 index cae33a534..000000000 --- a/apps/edr-freight-api/src/migrations/1862000000000-AddScheduleWindowPhases.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddScheduleWindowPhases1862000000000 implements MigrationInterface { - name = "AddScheduleWindowPhases1862000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN window_phase varchar(20) NULL, - ADD COLUMN window_opens_at timestamptz NULL, - ADD COLUMN window_closes_at timestamptz NULL, - ADD COLUMN doc_review_ends_at timestamptz NULL, - ADD COLUMN doc_review_completed_at timestamptz NULL, - ADD COLUMN payment_phase_ends_at timestamptz NULL, - ADD COLUMN booking_cycle_no integer NOT NULL DEFAULT 0; - `); - await queryRunner.query(` - CREATE INDEX idx_train_schedules_window_phase - ON freight.train_schedules (window_phase) - WHERE window_phase IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_train_schedules_window_phase;`); - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS window_phase, - DROP COLUMN IF EXISTS window_opens_at, - DROP COLUMN IF EXISTS window_closes_at, - DROP COLUMN IF EXISTS doc_review_ends_at, - DROP COLUMN IF EXISTS doc_review_completed_at, - DROP COLUMN IF EXISTS payment_phase_ends_at, - DROP COLUMN IF EXISTS booking_cycle_no; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1863000000000-CreateBookingBatchOffers.ts b/apps/edr-freight-api/src/migrations/1863000000000-CreateBookingBatchOffers.ts deleted file mode 100644 index 779807a57..000000000 --- a/apps/edr-freight-api/src/migrations/1863000000000-CreateBookingBatchOffers.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class CreateBookingBatchOffers1863000000000 implements MigrationInterface { - name = "CreateBookingBatchOffers1863000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE freight.booking_batch_offers ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id uuid NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - train_schedule_id uuid NOT NULL REFERENCES freight.train_schedules(id) ON DELETE CASCADE, - offered_wagons integer NOT NULL, - total_wagons integer NOT NULL, - offered_lines jsonb NULL, - offered_weight_tons numeric(12, 3) NOT NULL, - offered_amount numeric(14, 2) NOT NULL, - offered_pricing_breakdown jsonb NULL, - invoice_id uuid NULL, - payment_deadline timestamptz NOT NULL, - status varchar(10) NOT NULL DEFAULT 'OFFERED', - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL - ); - `); - await queryRunner.query( - `CREATE INDEX idx_booking_batch_offers_booking ON freight.booking_batch_offers (booking_id);`, - ); - await queryRunner.query( - `CREATE INDEX idx_booking_batch_offers_schedule ON freight.booking_batch_offers (train_schedule_id);`, - ); - await queryRunner.query( - `CREATE INDEX idx_booking_batch_offers_status ON freight.booking_batch_offers (status);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_batch_offers;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1870000000000-AddLocationToVehicles.ts b/apps/edr-freight-api/src/migrations/1870000000000-AddLocationToVehicles.ts deleted file mode 100644 index 3434631a2..000000000 --- a/apps/edr-freight-api/src/migrations/1870000000000-AddLocationToVehicles.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add location_id column to vehicles table to track vehicle base location. - */ -export class AddLocationToVehicles1870000000000 implements MigrationInterface { - name = "AddLocationToVehicles1870000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS location_id uuid; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS location_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1870000000000-RepairSynchronizeDrift.ts b/apps/edr-freight-api/src/migrations/1870000000000-RepairSynchronizeDrift.ts deleted file mode 100644 index 32f1e6f0c..000000000 --- a/apps/edr-freight-api/src/migrations/1870000000000-RepairSynchronizeDrift.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Repairs schema drift on databases that were originally built by TypeORM - * `synchronize` (at an older entity snapshot) and never had their migration - * history recorded. Such databases have `freight.migrations` empty while most - * of the schema already exists, so a from-scratch migration run aborts on the - * first non-idempotent statement and never reaches the columns/tables added - * after synchronize was last used. - * - * The deployment procedure for those databases is: - * 1. Baseline every pre-existing migration into `freight.migrations`. - * 2. Run migrations — this file is the only pending one and back-fills the - * objects the drift scan found missing. - * - * Every statement is idempotent (IF NOT EXISTS / guarded CREATE TYPE), so it is - * also safe on a clean database where the earlier migrations already created - * these objects — it simply no-ops. - */ -export class RepairSynchronizeDrift1870000000000 - implements MigrationInterface -{ - name = 'RepairSynchronizeDrift1870000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // --- enum types (derived from entities that never had a source migration) --- - await queryRunner.query(`DO $$ BEGIN - CREATE TYPE freight.consignments_cargo_type_enum AS ENUM ( - 'CONTAINER', 'BULK_LIQUID', 'BULK_DRY', 'GENERAL', 'REFRIGERATED', 'HAZARDOUS' - ); - EXCEPTION WHEN duplicate_object THEN null; END $$;`); - await queryRunner.query(`DO $$ BEGIN - CREATE TYPE freight.consignments_status_enum AS ENUM ( - 'PENDING', 'LOADED', 'IN_TRANSIT', 'AT_DESTINATION', 'DELIVERED', 'RETURNED' - ); - EXCEPTION WHEN duplicate_object THEN null; END $$;`); - await queryRunner.query(`DO $$ BEGIN - CREATE TYPE freight.tracking_events_status_enum AS ENUM ( - 'PENDING', 'LOADED', 'IN_TRANSIT', 'AT_DESTINATION', 'DELIVERED', 'RETURNED' - ); - EXCEPTION WHEN duplicate_object THEN null; END $$;`); - - // --- missing tables --- - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.consignments ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - booking_id uuid NOT NULL, - tracking_number varchar(64) NOT NULL, - cargo_type freight.consignments_cargo_type_enum NOT NULL, - weight_kg numeric(12, 2) NOT NULL, - status freight.consignments_status_enum NOT NULL DEFAULT 'PENDING', - origin_station varchar(128) NOT NULL, - destination_station varchar(128) NOT NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT pk_consignments PRIMARY KEY (id), - CONSTRAINT uq_consignments_tracking_number UNIQUE (tracking_number) - );`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.tracking_events ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - consignment_id uuid NOT NULL, - location varchar(256) NOT NULL, - status freight.tracking_events_status_enum NOT NULL, - occurred_at timestamptz NOT NULL, - description text, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT pk_tracking_events PRIMARY KEY (id) - );`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.fuel_purchases ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - purchase_date timestamptz NOT NULL, - liters numeric(10, 2) NOT NULL, - cost_per_liter numeric(10, 2) NOT NULL, - total_cost numeric(14, 2) NOT NULL, - fuel_station varchar(255) NULL, - payment_method varchar(50) DEFAULT 'CASH', - odometer_reading numeric(10, 2) NULL, - driver_id uuid NULL, - receipt_number varchar(255) NULL, - notes text NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL, - CONSTRAINT pk_fuel_purchases PRIMARY KEY (id), - CONSTRAINT fk_fuel_purchases_vehicle FOREIGN KEY (vehicle_id) - REFERENCES freight.vehicles (id) ON DELETE CASCADE - );`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_fuel_purchases_vehicle ON freight.fuel_purchases (vehicle_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_fuel_purchases_date ON freight.fuel_purchases (purchase_date);`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.fuel_consumption ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - month date NOT NULL, - total_liters numeric(10, 2) NOT NULL, - total_cost numeric(14, 2) NOT NULL, - total_distance_km numeric(10, 2) NOT NULL, - fuel_efficiency_km_per_l numeric(10, 2) NULL, - number_of_purchases integer DEFAULT 0, - average_cost_per_liter numeric(10, 2) NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL, - CONSTRAINT pk_fuel_consumption PRIMARY KEY (id), - CONSTRAINT fk_fuel_consumption_vehicle FOREIGN KEY (vehicle_id) - REFERENCES freight.vehicles (id) ON DELETE CASCADE, - CONSTRAINT uq_fuel_consumption_vehicle_month UNIQUE (vehicle_id, month) - );`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_fuel_consumption_vehicle_month ON freight.fuel_consumption (vehicle_id, month);`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.maintenance_schedules ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - maintenance_type varchar NOT NULL, - description varchar NOT NULL, - scheduled_date timestamptz NOT NULL, - completed_date timestamptz, - estimated_cost numeric(14,2), - actual_cost numeric(14,2), - status varchar NOT NULL DEFAULT 'SCHEDULED', - odometer_reading numeric, - service_provider varchar, - notes text, - next_due_km numeric, - next_due_date timestamptz, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - PRIMARY KEY (id) - );`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_maintenance_schedules_vehicle_date ON freight.maintenance_schedules (vehicle_id, scheduled_date);`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.maintenance_costs ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL, - maintenance_schedule_id uuid, - incurred_date timestamptz NOT NULL, - cost_amount numeric(14,2) NOT NULL, - cost_type varchar NOT NULL, - description varchar NOT NULL, - service_provider varchar, - invoice_number varchar, - notes text, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - PRIMARY KEY (id), - CONSTRAINT fk_maintenance_schedule FOREIGN KEY (maintenance_schedule_id) - REFERENCES freight.maintenance_schedules (id) ON DELETE SET NULL - );`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_maintenance_costs_vehicle_date ON freight.maintenance_costs (vehicle_id, incurred_date);`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.otp_verifications ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - phone varchar NOT NULL, - otp varchar NOT NULL, - verified boolean NOT NULL DEFAULT false, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT pk_otp_verifications PRIMARY KEY (id), - CONSTRAINT uq_otp_verifications_phone UNIQUE (phone) - );`); - - await queryRunner.query(`CREATE TABLE IF NOT EXISTS freight.booking_batch_offers ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id uuid NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - train_schedule_id uuid NOT NULL REFERENCES freight.train_schedules(id) ON DELETE CASCADE, - offered_wagons integer NOT NULL, - total_wagons integer NOT NULL, - offered_lines jsonb NULL, - offered_weight_tons numeric(12, 3) NOT NULL, - offered_amount numeric(14, 2) NOT NULL, - offered_pricing_breakdown jsonb NULL, - invoice_id uuid NULL, - payment_deadline timestamptz NOT NULL, - status varchar(10) NOT NULL DEFAULT 'OFFERED', - 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_booking_batch_offers_booking ON freight.booking_batch_offers (booking_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_booking_batch_offers_schedule ON freight.booking_batch_offers (train_schedule_id);`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_booking_batch_offers_status ON freight.booking_batch_offers (status);`); - - // --- missing columns on existing tables --- - await queryRunner.query(`ALTER TABLE freight.invoices - ADD COLUMN IF NOT EXISTS subtotal_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS tax_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS paid_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS balance_amount numeric(14, 2) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS paid_at timestamptz;`); - - await queryRunner.query(`ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS booking_type varchar(20) NOT NULL DEFAULT 'ONE_TIME', - ADD COLUMN IF NOT EXISTS customer_truck_plate_number varchar(32), - ADD COLUMN IF NOT EXISTS customer_truck_driver_name varchar(120), - ADD COLUMN IF NOT EXISTS customer_truck_type varchar(60), - ADD COLUMN IF NOT EXISTS customer_truck_container_number varchar(16), - ADD COLUMN IF NOT EXISTS customer_truck_assigned_at timestamptz, - ADD COLUMN IF NOT EXISTS customer_truck_arrived_at timestamptz, - ADD COLUMN IF NOT EXISTS bulk_hazardous_quantity numeric(12,3) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS bulk_reefer_quantity numeric(12,3) NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS clearance_current_phase varchar(40), - ADD COLUMN IF NOT EXISTS duty_required boolean, - ADD COLUMN IF NOT EXISTS vessel_departure_date date, - ADD COLUMN IF NOT EXISTS ro_amendment_requested_at timestamptz, - ADD COLUMN IF NOT EXISTS ro_hold_reason text, - ADD COLUMN IF NOT EXISTS pre_clearance_finalized_at timestamptz;`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_bookings_booking_type ON freight.bookings (booking_type);`); - - await queryRunner.query(`ALTER TABLE freight.cargoes - ADD COLUMN IF NOT EXISTS receiver_name varchar, - ADD COLUMN IF NOT EXISTS delivered_at timestamp, - ADD COLUMN IF NOT EXISTS delivery_remarks text;`); - - await queryRunner.query(`ALTER TABLE freight.contract_clearance_cycles - ADD COLUMN IF NOT EXISTS duty_required boolean, - ADD COLUMN IF NOT EXISTS vessel_departure_date date, - ADD COLUMN IF NOT EXISTS ro_amendment_requested_at timestamptz, - ADD COLUMN IF NOT EXISTS ro_hold_reason text, - ADD COLUMN IF NOT EXISTS current_phase varchar(40), - ADD COLUMN IF NOT EXISTS pre_clearance_finalized_at timestamptz;`); - - await queryRunner.query(`ALTER TABLE freight.first_mile - ADD COLUMN IF NOT EXISTS paid boolean NOT NULL DEFAULT false;`); - await queryRunner.query(`ALTER TABLE freight.last_mile - ADD COLUMN IF NOT EXISTS paid boolean NOT NULL DEFAULT false;`); - - await queryRunner.query(`ALTER TABLE freight.route_milestones - ADD COLUMN IF NOT EXISTS distance_km numeric(10,2);`); - - await queryRunner.query(`ALTER TABLE freight.routes - ADD COLUMN IF NOT EXISTS status varchar(32) NOT NULL DEFAULT 'AVAILABLE';`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_routes_status" ON freight.routes (status);`); - - await queryRunner.query(`ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS window_phase varchar(20) NULL, - ADD COLUMN IF NOT EXISTS window_opens_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS window_closes_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS doc_review_ends_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS doc_review_completed_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS payment_phase_ends_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS booking_cycle_no integer NOT NULL DEFAULT 0;`); - await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_train_schedules_window_phase - ON freight.train_schedules (window_phase) WHERE window_phase IS NOT NULL;`); - - await queryRunner.query(`ALTER TABLE freight.train_scheduling_global_rules - ADD COLUMN IF NOT EXISTS import_window_lead_days integer NOT NULL DEFAULT 3, - ADD COLUMN IF NOT EXISTS export_booking_lead_hours integer NOT NULL DEFAULT 24, - ADD COLUMN IF NOT EXISTS window_open_hour integer NOT NULL DEFAULT 8, - ADD COLUMN IF NOT EXISTS window_duration_hours numeric(4, 2) NOT NULL DEFAULT 3, - ADD COLUMN IF NOT EXISTS doc_review_minutes integer NOT NULL DEFAULT 30, - ADD COLUMN IF NOT EXISTS payment_window_minutes integer NOT NULL DEFAULT 60, - ADD COLUMN IF NOT EXISTS reopen_delay_minutes integer NOT NULL DEFAULT 90;`); - } - - public async down(): Promise { - // No-op: this migration only repairs drift by additively creating objects - // that other migrations own. Rolling it back would drop objects those - // migrations legitimately created. Revert individual feature migrations - // instead if needed. - } -} diff --git a/apps/edr-freight-api/src/migrations/1880000000000-AddVehicleStatuses.ts b/apps/edr-freight-api/src/migrations/1880000000000-AddVehicleStatuses.ts deleted file mode 100644 index 484a2686b..000000000 --- a/apps/edr-freight-api/src/migrations/1880000000000-AddVehicleStatuses.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add FREE and BUSY statuses to vehicle status enum. - */ -export class AddVehicleStatuses1880000000000 implements MigrationInterface { - name = "AddVehicleStatuses1880000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // Create enum type if it doesn't exist - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'vehicles_status_enum' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'freight')) THEN - CREATE TYPE freight.vehicles_status_enum AS ENUM ('ACTIVE', 'FREE', 'BUSY', 'MAINTENANCE', 'RETIRED', 'OUT_OF_SERVICE'); - ELSE - -- Add values if enum already exists but doesn't have them - ALTER TYPE freight.vehicles_status_enum ADD VALUE IF NOT EXISTS 'FREE' BEFORE 'MAINTENANCE'; - ALTER TYPE freight.vehicles_status_enum ADD VALUE IF NOT EXISTS 'BUSY' AFTER 'FREE'; - END IF; - END $$; - `); - } - - public async down(_queryRunner: QueryRunner): Promise { - // Note: Postgres cannot drop individual enum values, so the down migration is a no-op - // The enum values FREE and BUSY will remain but will be unused after downgrade - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000000-SeparateVehicleAvailability.ts b/apps/edr-freight-api/src/migrations/1890000000000-SeparateVehicleAvailability.ts deleted file mode 100644 index c0015c3c6..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000000-SeparateVehicleAvailability.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Split the mixed vehicle status into two fields: - * - status: operational state (ACTIVE, MAINTENANCE, RETIRED, OUT_OF_SERVICE) - * - availability: assignment state (FREE, BUSY) - * - * Existing FREE/BUSY statuses are moved to availability and the status is - * normalized back to ACTIVE. - */ -export class SeparateVehicleAvailability1890000000000 implements MigrationInterface { - name = "SeparateVehicleAvailability1890000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS availability varchar DEFAULT 'FREE' - `); - await queryRunner.query(` - UPDATE freight.vehicles SET availability = 'BUSY' WHERE status = 'BUSY' - `); - await queryRunner.query(` - UPDATE freight.vehicles SET availability = 'FREE' WHERE availability IS NULL - `); - await queryRunner.query(` - UPDATE freight.vehicles SET status = 'ACTIVE' WHERE status IN ('FREE', 'BUSY') - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Fold availability back into status before dropping the column - await queryRunner.query(` - UPDATE freight.vehicles SET status = availability - WHERE status = 'ACTIVE' AND availability IN ('FREE', 'BUSY') - `); - await queryRunner.query(` - ALTER TABLE freight.vehicles DROP COLUMN IF EXISTS availability - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000001-AddVehicleCodeAndPlates.ts b/apps/edr-freight-api/src/migrations/1890000000001-AddVehicleCodeAndPlates.ts deleted file mode 100644 index 6f9faa1f8..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000001-AddVehicleCodeAndPlates.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add code, power_plate_no and trailer_plate_no columns to vehicles. - * These fields existed in the DTO and UI form but had no entity columns, - * so submitted values were silently dropped. - */ -export class AddVehicleCodeAndPlates1890000000001 implements MigrationInterface { - name = "AddVehicleCodeAndPlates1890000000001"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS code varchar, - ADD COLUMN IF NOT EXISTS power_plate_no varchar, - ADD COLUMN IF NOT EXISTS trailer_plate_no varchar - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS code, - DROP COLUMN IF EXISTS power_plate_no, - DROP COLUMN IF EXISTS trailer_plate_no - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000002-AddFaydaVerificationSessions.ts b/apps/edr-freight-api/src/migrations/1890000000002-AddFaydaVerificationSessions.ts deleted file mode 100644 index 10b358eea..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000002-AddFaydaVerificationSessions.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Session store for the VeriFayda 2.0 OIDC verification flow (ported from - * passenger-api). One row per started verification; `state` is the - * single-use CSRF token linking the eSignet redirect back to the session. - */ -export class AddFaydaVerificationSessions1890000000002 implements MigrationInterface { - name = "AddFaydaVerificationSessions1890000000002"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.fayda_verification_sessions ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - state varchar NOT NULL UNIQUE, - code_verifier varchar NOT NULL, - purpose varchar NOT NULL DEFAULT 'VERIFY', - platform varchar NOT NULL DEFAULT 'WEB', - save_to_account boolean NOT NULL DEFAULT false, - status varchar NOT NULL DEFAULT 'PENDING', - error_code varchar, - error_description text, - iam_user_id uuid, - expires_at timestamptz NOT NULL, - completed_at timestamptz, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FAYDA_SESSIONS_EXPIRES_AT" - ON freight.fayda_verification_sessions (expires_at) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FAYDA_SESSIONS_IAM_USER_ID" - ON freight.fayda_verification_sessions (iam_user_id) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.fayda_verification_sessions`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000003-AddDriverFaydaVerification.ts b/apps/edr-freight-api/src/migrations/1890000000003-AddDriverFaydaVerification.ts deleted file mode 100644 index ba8003143..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000003-AddDriverFaydaVerification.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Track Fayda identity verification on drivers: whether the driver's - * identity was verified through VeriFayda and the OIDC subject it was - * verified against. - */ -export class AddDriverFaydaVerification1890000000003 implements MigrationInterface { - name = "AddDriverFaydaVerification1890000000003"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.drivers - ADD COLUMN IF NOT EXISTS fayda_verified boolean DEFAULT false, - ADD COLUMN IF NOT EXISTS fayda_sub varchar - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.drivers - DROP COLUMN IF EXISTS fayda_verified, - DROP COLUMN IF EXISTS fayda_sub - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000004-AddLastMileVehicleAssignments.ts b/apps/edr-freight-api/src/migrations/1890000000004-AddLastMileVehicleAssignments.ts deleted file mode 100644 index 7c1413617..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000004-AddLastMileVehicleAssignments.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Allow more than one vehicle per last-mile delivery. Junction table joins - * last_mile ⇄ vehicles; existing single vehicle_id values are backfilled as - * the first assignment so nothing is lost. - */ -export class AddLastMileVehicleAssignments1890000000004 implements MigrationInterface { - name = "AddLastMileVehicleAssignments1890000000004"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.last_mile_vehicle_assignments ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - last_mile_id uuid NOT NULL REFERENCES freight.last_mile(id) ON DELETE CASCADE, - vehicle_id uuid NOT NULL REFERENCES freight.vehicles(id), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT "UQ_LAST_MILE_VEHICLE" UNIQUE (last_mile_id, vehicle_id) - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_LM_VEHICLE_ASSIGNMENTS_VEHICLE" - ON freight.last_mile_vehicle_assignments (vehicle_id) - `); - // Backfill: existing single-vehicle assignments become the first row - await queryRunner.query(` - INSERT INTO freight.last_mile_vehicle_assignments (last_mile_id, vehicle_id) - SELECT id, vehicle_id FROM freight.last_mile - WHERE vehicle_id IS NOT NULL AND deleted_at IS NULL - ON CONFLICT (last_mile_id, vehicle_id) DO NOTHING - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.last_mile_vehicle_assignments`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000005-AddDriverGender.ts b/apps/edr-freight-api/src/migrations/1890000000005-AddDriverGender.ts deleted file mode 100644 index 2ec26e034..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000005-AddDriverGender.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Store the driver's gender. Prefilled from the Fayda VERIFY response - * (Male/Female) but editable; nullable so existing rows and manual, - * non-Fayda driver records stay valid. - */ -export class AddDriverGender1890000000005 implements MigrationInterface { - name = "AddDriverGender1890000000005"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.drivers - ADD COLUMN IF NOT EXISTS gender varchar - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.drivers - DROP COLUMN IF EXISTS gender - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000006-AddDriverFaydaSubUnique.ts b/apps/edr-freight-api/src/migrations/1890000000006-AddDriverFaydaSubUnique.ts deleted file mode 100644 index 04c9a7000..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000006-AddDriverFaydaSubUnique.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Enforce one driver record per verified Fayda identity. A unique index on - * fayda_sub blocks a second driver from being created against the same Fayda - * OIDC subject; NULLs stay distinct so legacy/unverified rows are unaffected. - */ -export class AddDriverFaydaSubUnique1890000000006 implements MigrationInterface { - name = "AddDriverFaydaSubUnique1890000000006"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_FAYDA_SUB" - ON freight.drivers (fayda_sub) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS freight."UQ_DRIVERS_FAYDA_SUB" - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000007-DriverUniquePartialSoftDelete.ts b/apps/edr-freight-api/src/migrations/1890000000007-DriverUniquePartialSoftDelete.ts deleted file mode 100644 index 77d0a3043..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000007-DriverUniquePartialSoftDelete.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Make driver uniqueness soft-delete aware. The original table used plain - * column UNIQUE constraints (drivers_email_key, etc.) which count soft-deleted - * rows, so deleting a driver then re-adding the same email/phone/license/Fayda - * identity failed at the DB with a raw 500 — even though the service's own - * (deleted_at-excluding) duplicate check saw nothing. Replace them with partial - * unique indexes scoped to live rows (deleted_at IS NULL) so uniqueness matches - * what the service enforces and freed values become reusable after deletion. - */ -export class DriverUniquePartialSoftDelete1890000000007 implements MigrationInterface { - name = "DriverUniquePartialSoftDelete1890000000007"; - - public async up(queryRunner: QueryRunner): Promise { - // Drop the full-table unique constraints from CreateDriversTable... - await queryRunner.query(` - ALTER TABLE freight.drivers - DROP CONSTRAINT IF EXISTS drivers_email_key, - DROP CONSTRAINT IF EXISTS drivers_phone_number_key, - DROP CONSTRAINT IF EXISTS drivers_license_number_key - `); - // ...and the plain fayda_sub unique index from 1890000000006. - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_DRIVERS_FAYDA_SUB"`); - - // Re-add each as a partial unique index scoped to non-deleted rows. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_EMAIL_ACTIVE" - ON freight.drivers (email) WHERE deleted_at IS NULL - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_PHONE_ACTIVE" - ON freight.drivers (phone_number) WHERE deleted_at IS NULL - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_LICENSE_ACTIVE" - ON freight.drivers (license_number) WHERE deleted_at IS NULL - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_FAYDA_SUB_ACTIVE" - ON freight.drivers (fayda_sub) WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_DRIVERS_EMAIL_ACTIVE"`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_DRIVERS_PHONE_ACTIVE"`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_DRIVERS_LICENSE_ACTIVE"`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_DRIVERS_FAYDA_SUB_ACTIVE"`); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_DRIVERS_FAYDA_SUB" - ON freight.drivers (fayda_sub) - `); - await queryRunner.query(` - ALTER TABLE freight.drivers - ADD CONSTRAINT drivers_email_key UNIQUE (email), - ADD CONSTRAINT drivers_phone_number_key UNIQUE (phone_number), - ADD CONSTRAINT drivers_license_number_key UNIQUE (license_number) - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000008-AddFleetEvents.ts b/apps/edr-freight-api/src/migrations/1890000000008-AddFleetEvents.ts deleted file mode 100644 index 8fbb688d3..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000008-AddFleetEvents.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Append-only audit log for fleet activity (driver↔vehicle assignments, vehicle - * status/availability transitions, first/last-mile vehicle assignments + mile - * status changes). Queried by vehicle_id or driver_id to build a per-record - * timeline. Populated going forward — existing records have no back-history. - */ -export class AddFleetEvents1890000000008 implements MigrationInterface { - name = "AddFleetEvents1890000000008"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.fleet_events ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - event_type varchar NOT NULL, - vehicle_id uuid, - driver_id uuid, - first_mile_id uuid, - last_mile_id uuid, - from_value varchar, - to_value varchar, - label varchar, - metadata jsonb, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FLEET_EVENTS_VEHICLE" - ON freight.fleet_events (vehicle_id, created_at) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FLEET_EVENTS_DRIVER" - ON freight.fleet_events (driver_id, created_at) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.fleet_events`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000009-AddLastMileAssignmentContainerNumber.ts b/apps/edr-freight-api/src/migrations/1890000000009-AddLastMileAssignmentContainerNumber.ts deleted file mode 100644 index d8bc1c5c0..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000009-AddLastMileAssignmentContainerNumber.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Container number carried by each vehicle on a last-mile delivery. Auto-filled - * from the booking's container number when present, else entered by the operator - * at assignment time. - */ -export class AddLastMileAssignmentContainerNumber1890000000009 - implements MigrationInterface -{ - name = "AddLastMileAssignmentContainerNumber1890000000009"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - ADD COLUMN IF NOT EXISTS container_number varchar - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - DROP COLUMN IF EXISTS container_number - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1890000000010-AddLastMileAssignmentDistance.ts b/apps/edr-freight-api/src/migrations/1890000000010-AddLastMileAssignmentDistance.ts deleted file mode 100644 index fc2d30552..000000000 --- a/apps/edr-freight-api/src/migrations/1890000000010-AddLastMileAssignmentDistance.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Per-vehicle actual distance on a last-mile delivery. A booking served by - * several trucks records each truck's km; the record's total (last_mile.exact_km) - * is their sum and drives the invoice. - */ -export class AddLastMileAssignmentDistance1890000000010 - implements MigrationInterface -{ - name = "AddLastMileAssignmentDistance1890000000010"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - ADD COLUMN IF NOT EXISTS distance_km numeric(10,2) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - DROP COLUMN IF EXISTS distance_km - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1900000000000-AddEmailToOtpVerifications.ts b/apps/edr-freight-api/src/migrations/1900000000000-AddEmailToOtpVerifications.ts deleted file mode 100644 index 55a6568c3..000000000 --- a/apps/edr-freight-api/src/migrations/1900000000000-AddEmailToOtpVerifications.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Support email as a second OTP channel alongside phone (e.g. signup lets the - * user choose which one to verify). `phone` becomes nullable since an - * email-channel row has none, and `email` is added as a nullable unique column - * mirroring `phone`'s shape. - */ -export class AddEmailToOtpVerifications1900000000000 - implements MigrationInterface -{ - name = "AddEmailToOtpVerifications1900000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // The table lives in the `freight` schema (the OtpVerification entity pins - // schema: "freight"). An earlier version of this migration targeted - // `public.otp_verifications`, which does not exist there — leaving the real - // freight table without an `email` column and OTP send failing with - // `column OtpVerification.email does not exist`. Target `freight` explicitly. - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - ALTER COLUMN phone DROP NOT NULL - `); - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - ADD COLUMN IF NOT EXISTS email varchar UNIQUE - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - DROP COLUMN IF EXISTS email - `); - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - ALTER COLUMN phone SET NOT NULL - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1900000000000-AddLoadingStatusToTrainScheduleBookings.ts b/apps/edr-freight-api/src/migrations/1900000000000-AddLoadingStatusToTrainScheduleBookings.ts deleted file mode 100644 index 6c7235e3b..000000000 --- a/apps/edr-freight-api/src/migrations/1900000000000-AddLoadingStatusToTrainScheduleBookings.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Track per-booking loading confirmation (LOADED/UNLOADED) on train_schedule_bookings. - * Tracking only — does not gate dispatch. - */ -export class AddLoadingStatusToTrainScheduleBookings1900000000000 - implements MigrationInterface -{ - name = "AddLoadingStatusToTrainScheduleBookings1900000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedule_bookings - ADD COLUMN IF NOT EXISTS loading_status varchar(20) NOT NULL DEFAULT 'UNLOADED' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedule_bookings - DROP COLUMN IF EXISTS loading_status - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1900000000000-SimplifyRatesAndWeightLimitRules.ts b/apps/edr-freight-api/src/migrations/1900000000000-SimplifyRatesAndWeightLimitRules.ts deleted file mode 100644 index 7a661bc7c..000000000 --- a/apps/edr-freight-api/src/migrations/1900000000000-SimplifyRatesAndWeightLimitRules.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Simplify the rate + weight-limit configuration model: - * - * 1. Drop the effective_from / effective_to validity window from both - * `rates` and `weight_limit_rules`. Rates are now activated purely by - * the approval workflow (status = LIVE) and weight limits are always - * active for their container + direction. No time-travel scheduling. - * - * 2. Enforce "one rate per pattern" with partial unique indexes so the same - * configuration (e.g. FIRST_MILE for a given container type) cannot be - * duplicated. NULL scope columns are COALESCE-normalised because Postgres - * treats NULLs as distinct in a plain unique index. - * - * This migration is destructive on the date columns — existing effective_* - * values are dropped. - */ -export class SimplifyRatesAndWeightLimitRules1900000000000 implements MigrationInterface { - name = 'SimplifyRatesAndWeightLimitRules1900000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // ── 1. De-duplicate existing data so the unique indexes can be created ── - // Keep the most recently-created row per pattern, soft-delete the rest. - await queryRunner.query(` - WITH ranked AS ( - SELECT id, - row_number() OVER ( - PARTITION BY rate_type, - COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(trade_direction, ''), - rate_unit - ORDER BY created_at DESC, id DESC - ) AS rn - FROM freight.rates - WHERE deleted_at IS NULL AND status <> 'SUPERSEDED' - ) - UPDATE freight.rates r - SET deleted_at = now() - FROM ranked - WHERE r.id = ranked.id AND ranked.rn > 1; - `); - - await queryRunner.query(` - WITH ranked AS ( - SELECT id, - row_number() OVER ( - PARTITION BY container_type_id, trade_direction - ORDER BY created_at DESC, id DESC - ) AS rn - FROM freight.weight_limit_rules - WHERE deleted_at IS NULL - ) - UPDATE freight.weight_limit_rules w - SET deleted_at = now() - FROM ranked - WHERE w.id = ranked.id AND ranked.rn > 1; - `); - - // ── 2. Drop the effective-date indexes + columns ─────────────────────── - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_rates_effective_from";`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_weight_limit_rules_effective_from";`); - // Indexes created by TypeORM's @Index carry generated hashed names — drop - // any index that references the effective_from column defensively. - await queryRunner.query(` - DO $$ - DECLARE idx record; - BEGIN - FOR idx IN - SELECT indexname FROM pg_indexes - WHERE schemaname = 'freight' - AND tablename IN ('rates', 'weight_limit_rules') - AND indexdef ILIKE '%effective_from%' - LOOP - EXECUTE format('DROP INDEX IF EXISTS freight.%I', idx.indexname); - END LOOP; - END $$; - `); - - await queryRunner.query(`ALTER TABLE freight.rates DROP COLUMN IF EXISTS effective_from;`); - await queryRunner.query(`ALTER TABLE freight.rates DROP COLUMN IF EXISTS effective_to;`); - await queryRunner.query(`ALTER TABLE freight.weight_limit_rules DROP COLUMN IF EXISTS effective_from;`); - await queryRunner.query(`ALTER TABLE freight.weight_limit_rules DROP COLUMN IF EXISTS effective_to;`); - - // ── 3. One-rate-per-pattern partial unique indexes ───────────────────── - // The unit is part of the identity so a surcharge can legitimately carry two - // rows that bill different ways (e.g. reefer PER_CONTAINER + reefer PER_TON), - // while still blocking a true duplicate (same rateType + scope + unit). - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_rates_pattern" - ON freight.rates ( - rate_type, - COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(trade_direction, ''), - rate_unit - ) - WHERE deleted_at IS NULL AND status <> 'SUPERSEDED'; - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_weight_limit_rules_pattern" - ON freight.weight_limit_rules (container_type_id, trade_direction) - WHERE deleted_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_rates_pattern";`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_weight_limit_rules_pattern";`); - - await queryRunner.query(`ALTER TABLE freight.rates ADD COLUMN IF NOT EXISTS effective_from date;`); - await queryRunner.query(`UPDATE freight.rates SET effective_from = COALESCE(effective_from, created_at::date);`); - await queryRunner.query(`ALTER TABLE freight.rates ALTER COLUMN effective_from SET NOT NULL;`); - await queryRunner.query(`ALTER TABLE freight.rates ADD COLUMN IF NOT EXISTS effective_to date;`); - - await queryRunner.query(`ALTER TABLE freight.weight_limit_rules ADD COLUMN IF NOT EXISTS effective_from date;`); - await queryRunner.query(`ALTER TABLE freight.weight_limit_rules ADD COLUMN IF NOT EXISTS effective_to date;`); - - await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_rates_effective_from" ON freight.rates (effective_from);`); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_weight_limit_rules_effective_from" ON freight.weight_limit_rules (effective_from);`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/1910000000000-WidenWindowDurationHoursPrecision.ts b/apps/edr-freight-api/src/migrations/1910000000000-WidenWindowDurationHoursPrecision.ts deleted file mode 100644 index 194c0d056..000000000 --- a/apps/edr-freight-api/src/migrations/1910000000000-WidenWindowDurationHoursPrecision.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Widen train_scheduling_global_rules.window_duration_hours from numeric(4,2) - * to numeric(6,4). The UI now lets staff enter the booking-window duration in - * minutes / hours / days and converts to the column's native hours unit; a - * 4-minute window is 0.0667h, which numeric(4,2) rounds to 0.07 (≈3.96 min). - * Four decimals store sub-minute durations exactly (0.0667h → 4.00 min). - */ -export class WidenWindowDurationHoursPrecision1910000000000 - implements MigrationInterface -{ - name = "WidenWindowDurationHoursPrecision1910000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ALTER COLUMN window_duration_hours TYPE numeric(6, 4); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ALTER COLUMN window_duration_hours TYPE numeric(4, 2); - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1920000000000-AddScheduleWindowRuleSnapshot.ts b/apps/edr-freight-api/src/migrations/1920000000000-AddScheduleWindowRuleSnapshot.ts deleted file mode 100644 index d48e127c3..000000000 --- a/apps/edr-freight-api/src/migrations/1920000000000-AddScheduleWindowRuleSnapshot.ts +++ /dev/null @@ -1,58 +0,0 @@ -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; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1930000000000-AddMaxCapacityToWeightLimitRules.ts b/apps/edr-freight-api/src/migrations/1930000000000-AddMaxCapacityToWeightLimitRules.ts deleted file mode 100644 index b1218a9b3..000000000 --- a/apps/edr-freight-api/src/migrations/1930000000000-AddMaxCapacityToWeightLimitRules.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add a hard per-unit weight ceiling to weight limit rules. - * - * maxVgmTons stays the soft "overweight" threshold (surcharge + warning); - * max_capacity_tons is the absolute ceiling above which a booking cannot be - * created at all. Null means no ceiling (existing behavior). - */ -export class AddMaxCapacityToWeightLimitRules1930000000000 - implements MigrationInterface -{ - name = "AddMaxCapacityToWeightLimitRules1930000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.weight_limit_rules - ADD COLUMN IF NOT EXISTS max_capacity_tons numeric(8, 3); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.weight_limit_rules - DROP COLUMN IF EXISTS max_capacity_tons; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1940000000000-AddFirstMileVehicleAssignments.ts b/apps/edr-freight-api/src/migrations/1940000000000-AddFirstMileVehicleAssignments.ts deleted file mode 100644 index 42f2c4eba..000000000 --- a/apps/edr-freight-api/src/migrations/1940000000000-AddFirstMileVehicleAssignments.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Allow more than one vehicle per first-mile pickup. Junction table joins - * first_mile ⇄ vehicles, with each truck's container number + actual distance; - * existing single vehicle_id values are backfilled as the first assignment so - * nothing is lost. Mirrors the last-mile vehicle-assignment schema. - */ -export class AddFirstMileVehicleAssignments1940000000000 implements MigrationInterface { - name = "AddFirstMileVehicleAssignments1940000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.first_mile_vehicle_assignments ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - first_mile_id uuid NOT NULL REFERENCES freight.first_mile(id) ON DELETE CASCADE, - vehicle_id uuid NOT NULL REFERENCES freight.vehicles(id), - container_number varchar, - distance_km numeric(10,2), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT "UQ_FIRST_MILE_VEHICLE" UNIQUE (first_mile_id, vehicle_id) - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FM_VEHICLE_ASSIGNMENTS_VEHICLE" - ON freight.first_mile_vehicle_assignments (vehicle_id) - `); - // Backfill: existing single-vehicle assignments become the first row - await queryRunner.query(` - INSERT INTO freight.first_mile_vehicle_assignments (first_mile_id, vehicle_id) - SELECT id, vehicle_id FROM freight.first_mile - WHERE vehicle_id IS NOT NULL AND deleted_at IS NULL - ON CONFLICT (first_mile_id, vehicle_id) DO NOTHING - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.first_mile_vehicle_assignments`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1940000000000-AddWagonTypeFkToCargoAndContainerTypes.ts b/apps/edr-freight-api/src/migrations/1940000000000-AddWagonTypeFkToCargoAndContainerTypes.ts deleted file mode 100644 index c7ab60577..000000000 --- a/apps/edr-freight-api/src/migrations/1940000000000-AddWagonTypeFkToCargoAndContainerTypes.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Replace load-type string matching with a real wagon-type foreign key. - * - * Before this migration, train scheduling picked a wagon type by matching - * strings — a hardcoded cargo-code → wagon-code map for bulk (COFFEE→KW2, …) - * and a fixed NW5 default for every container. This adds `wagon_type_id` FKs on - * `cargo_types` and `container_types` so scheduling resolves the wagon type - * through the relation instead. - * - * The columns are NULLABLE: cargo grouping rows and container/legacy cargo that - * never ship in bulk have no wagon type, and forcing one onto them is - * meaningless. Scheduling enforces the requirement at run time (it throws when a - * scheduled bulk cargo type or a container type in the batch has no wagon type). - * - * Backfill reproduces the old hardcoded resolution one final time so existing - * bulk cargo + container rows are not left unset. After this, the runtime map is - * removed — the FK is the single source of truth. - */ -export class AddWagonTypeFkToCargoAndContainerTypes1940000000000 - implements MigrationInterface -{ - name = "AddWagonTypeFkToCargoAndContainerTypes1940000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // ── Columns + FKs ──────────────────────────────────────────────────────── - await queryRunner.query(` - ALTER TABLE freight.cargo_types - ADD COLUMN IF NOT EXISTS wagon_type_id uuid; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - ADD COLUMN IF NOT EXISTS wagon_type_id uuid; - `); - - await queryRunner.query(` - ALTER TABLE freight.cargo_types - ADD CONSTRAINT fk_cargo_types_wagon_type - FOREIGN KEY (wagon_type_id) - REFERENCES freight.wagon_types(id) - ON DELETE RESTRICT; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - ADD CONSTRAINT fk_container_types_wagon_type - FOREIGN KEY (wagon_type_id) - REFERENCES freight.wagon_types(id) - ON DELETE RESTRICT; - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_cargo_types_wagon_type_id - ON freight.cargo_types (wagon_type_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_container_types_wagon_type_id - ON freight.container_types (wagon_type_id); - `); - - // ── Backfill: old cargo-code → wagon-code map (one last time) ───────────── - // COFFEE/GRAIN/WHEAT/SORGHUM/CORN → KW2, FERTILIZER/SUGAR → PW2, - // COAL → KW3, STEEL/ORE → CW3. Unmapped bulk cargo → CW3 (old default). - const cargoCodeToWagon: Record = { - COFFEE: "KW2", - GRAIN: "KW2", - WHEAT: "KW2", - SORGHUM: "KW2", - CORN: "KW2", - FERTILIZER: "PW2", - SUGAR: "PW2", - COAL: "KW3", - STEEL: "CW3", - ORE: "CW3", - }; - - for (const [cargoCode, wagonCode] of Object.entries(cargoCodeToWagon)) { - await queryRunner.query( - ` - UPDATE freight.cargo_types ct - SET wagon_type_id = wt.id - FROM freight.wagon_types wt - WHERE wt.code = $1 - AND UPPER(TRIM(ct.code)) = $2 - AND ct.wagon_type_id IS NULL; - `, - [wagonCode, cargoCode], - ); - } - - // Remaining bulk cargo (PER_TON) without a mapped code → default bulk wagon CW3. - await queryRunner.query(` - UPDATE freight.cargo_types ct - SET wagon_type_id = wt.id - FROM freight.wagon_types wt - WHERE wt.code = 'CW3' - AND ct.wagon_type_id IS NULL - AND ct.unit_of_measure = 'PER_TON'; - `); - - // All container types → the old container default wagon NW5. - await queryRunner.query(` - UPDATE freight.container_types ct - SET wagon_type_id = wt.id - FROM freight.wagon_types wt - WHERE wt.code = 'NW5' - AND ct.wagon_type_id IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS freight.idx_container_types_wagon_type_id; - `); - await queryRunner.query(` - DROP INDEX IF EXISTS freight.idx_cargo_types_wagon_type_id; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types - DROP CONSTRAINT IF EXISTS fk_container_types_wagon_type; - `); - await queryRunner.query(` - ALTER TABLE freight.cargo_types - DROP CONSTRAINT IF EXISTS fk_cargo_types_wagon_type; - `); - await queryRunner.query(` - ALTER TABLE freight.container_types DROP COLUMN IF EXISTS wagon_type_id; - `); - await queryRunner.query(` - ALTER TABLE freight.cargo_types DROP COLUMN IF EXISTS wagon_type_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1950000000000-AddCustomerTruckAssignments.ts b/apps/edr-freight-api/src/migrations/1950000000000-AddCustomerTruckAssignments.ts deleted file mode 100644 index 7c95199b1..000000000 --- a/apps/edr-freight-api/src/migrations/1950000000000-AddCustomerTruckAssignments.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Multi-truck customer (self-haul) assignment. Replaces the single - * booking.customer_truck_* fields with a per-booking list of trucks, each - * carrying 1–2 containers and tracking its own arrival. The legacy - * booking.customer_truck_* columns are kept as a synced booking-level flag - * (any truck assigned / all trucks arrived) so the warehouse exit-gate and - * delivery-approval logic keep working. - */ -export class AddCustomerTruckAssignments1950000000000 implements MigrationInterface { - name = 'AddCustomerTruckAssignments1950000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.customer_truck_assignments ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id uuid NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - plate_number varchar(32) NOT NULL, - driver_name varchar(120) NOT NULL, - truck_type varchar(60) NOT NULL, - assigned_at timestamptz NOT NULL DEFAULT now(), - arrived_at timestamptz, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_customer_truck_assignments_booking" ON freight.customer_truck_assignments (booking_id);`, - ); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.customer_truck_containers ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - assignment_id uuid NOT NULL REFERENCES freight.customer_truck_assignments(id) ON DELETE CASCADE, - booking_id uuid NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - container_number varchar(64) NOT NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_customer_truck_containers_assignment" ON freight.customer_truck_containers (assignment_id);`, - ); - // One container number can be loaded onto exactly one truck per booking. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_customer_truck_containers_booking_number" - ON freight.customer_truck_containers (booking_id, container_number) - WHERE deleted_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.customer_truck_containers;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.customer_truck_assignments;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1950000000000-AddVehicleCompliance.ts b/apps/edr-freight-api/src/migrations/1950000000000-AddVehicleCompliance.ts deleted file mode 100644 index f83f0a236..000000000 --- a/apps/edr-freight-api/src/migrations/1950000000000-AddVehicleCompliance.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Vehicle Compliance & Expiry Alerts. - * - Adds expiry-tracking columns to freight.vehicles. - * - Creates freight.compliance_records for per-document compliance tracking. - */ -export class AddVehicleCompliance1950000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - // Vehicle expiry / compliance columns. - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS vin VARCHAR, - ADD COLUMN IF NOT EXISTS ownership VARCHAR, - ADD COLUMN IF NOT EXISTS insurance_expiry DATE, - ADD COLUMN IF NOT EXISTS registration_expiry DATE, - ADD COLUMN IF NOT EXISTS next_inspection_date DATE; - `); - - // Compliance records table. - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.compliance_records ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - vehicle_id UUID NOT NULL REFERENCES freight.vehicles(id), - type VARCHAR NOT NULL, - document_number VARCHAR, - issued_date DATE, - expiry_date DATE NOT NULL, - status VARCHAR NOT NULL DEFAULT 'VALID', - notes TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_compliance_records_vehicle_id ON freight.compliance_records(vehicle_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_compliance_records_expiry_date ON freight.compliance_records(expiry_date);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_compliance_records_type ON freight.compliance_records(type);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.compliance_records CASCADE;`); - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS vin, - DROP COLUMN IF EXISTS ownership, - DROP COLUMN IF EXISTS insurance_expiry, - DROP COLUMN IF EXISTS registration_expiry, - DROP COLUMN IF EXISTS next_inspection_date; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1950000000000-AddWindowCloseHour.ts b/apps/edr-freight-api/src/migrations/1950000000000-AddWindowCloseHour.ts deleted file mode 100644 index 6ff9bdc12..000000000 --- a/apps/edr-freight-api/src/migrations/1950000000000-AddWindowCloseHour.ts +++ /dev/null @@ -1,52 +0,0 @@ -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; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1950000000000-CreateNotifications.ts b/apps/edr-freight-api/src/migrations/1950000000000-CreateNotifications.ts deleted file mode 100644 index c5c608a95..000000000 --- a/apps/edr-freight-api/src/migrations/1950000000000-CreateNotifications.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * In-app notification inbox. One row per recipient per logical notification; - * producers fan out by inserting many rows. Indexed for the two hot queries: - * unread-count (recipient + is_read) and the newest-first list (recipient + - * created_at). Enum-like columns are stored as varchar to avoid PG enum churn. - */ -export class CreateNotifications1950000000000 implements MigrationInterface { - name = "CreateNotifications1950000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.notifications ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - recipient_user_id uuid NOT NULL, - audience varchar(20) NOT NULL, - type varchar(48) NOT NULL DEFAULT 'GENERIC', - title varchar(200) NOT NULL, - body text NOT NULL, - link varchar, - data jsonb, - priority varchar(12) NOT NULL DEFAULT 'NORMAL', - is_read boolean NOT NULL DEFAULT false, - read_at timestamptz, - channels_sent jsonb, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_NOTIFICATIONS_RECIPIENT_UNREAD" - ON freight.notifications (recipient_user_id, is_read) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_NOTIFICATIONS_RECIPIENT_CREATED" - ON freight.notifications (recipient_user_id, created_at) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_NOTIFICATIONS_RECIPIENT_CREATED"`, - ); - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_NOTIFICATIONS_RECIPIENT_UNREAD"`, - ); - await queryRunner.query(`DROP TABLE IF EXISTS freight.notifications`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1960000000000-AddContainerReceiptToBookingContainerUnits.ts b/apps/edr-freight-api/src/migrations/1960000000000-AddContainerReceiptToBookingContainerUnits.ts deleted file mode 100644 index 59a0441c5..000000000 --- a/apps/edr-freight-api/src/migrations/1960000000000-AddContainerReceiptToBookingContainerUnits.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-container receive tracking. A booking's containers arrive individually - * (on separate self-haul trucks), so each container unit tracks whether it has - * been received into the port and, once staff confirm it, the GRN it belongs to. - * A single GRN covers the containers received together — so if the whole booking - * arrives at once, all its units share one GRN (per-booking GRN). - */ -export class AddContainerReceiptToBookingContainerUnits1960000000000 - implements MigrationInterface -{ - name = 'AddContainerReceiptToBookingContainerUnits1960000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_container_units - ADD COLUMN IF NOT EXISTS received_to_port boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS received_at timestamptz, - ADD COLUMN IF NOT EXISTS grn_number varchar(100) - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_booking_container_units_grn" ON freight.booking_container_units (grn_number);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_booking_container_units_grn";`); - await queryRunner.query(` - ALTER TABLE freight.booking_container_units - DROP COLUMN IF EXISTS received_to_port, - DROP COLUMN IF EXISTS received_at, - DROP COLUMN IF EXISTS grn_number - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1960000000000-AddIncidents.ts b/apps/edr-freight-api/src/migrations/1960000000000-AddIncidents.ts deleted file mode 100644 index dbb2994c3..000000000 --- a/apps/edr-freight-api/src/migrations/1960000000000-AddIncidents.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Accident & Incident register for the fleet. Tracks accidents, breakdowns, - * traffic violations, thefts and other incidents against a vehicle, driver - * and/or booking, with severity, damage estimate, insurance claim tracking and - * a lifecycle status. Queried by driver_id for per-driver incident history. - */ -export class AddIncidents1960000000000 implements MigrationInterface { - name = 'AddIncidents1960000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.incidents ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - vehicle_id uuid, - driver_id uuid, - booking_id uuid, - type varchar NOT NULL, - severity varchar NOT NULL, - occurred_at timestamptz NOT NULL, - location varchar, - description text NOT NULL, - damage_estimate numeric(14,2), - status varchar NOT NULL DEFAULT 'REPORTED', - insurance_claim_number varchar, - reported_by varchar - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_INCIDENTS_DRIVER" - ON freight.incidents (driver_id, occurred_at) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_INCIDENTS_VEHICLE" - ON freight.incidents (vehicle_id, occurred_at) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.incidents`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1970000000000-AddCustomerTruckDeparture.ts b/apps/edr-freight-api/src/migrations/1970000000000-AddCustomerTruckDeparture.ts deleted file mode 100644 index e36420751..000000000 --- a/apps/edr-freight-api/src/migrations/1970000000000-AddCustomerTruckDeparture.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Import self-haul trucks are weighed on leaving. The customer does not - * pre-specify what an import truck takes — staff register the containers loaded - * and the weighed gross when the truck departs. These columns capture that. - */ -export class AddCustomerTruckDeparture1970000000000 implements MigrationInterface { - name = 'AddCustomerTruckDeparture1970000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.customer_truck_assignments - ADD COLUMN IF NOT EXISTS gross_weight_kg numeric(14, 2), - ADD COLUMN IF NOT EXISTS departed_at timestamptz - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.customer_truck_assignments - DROP COLUMN IF EXISTS gross_weight_kg, - DROP COLUMN IF EXISTS departed_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1970000000000-AddMaintenanceDepth.ts b/apps/edr-freight-api/src/migrations/1970000000000-AddMaintenanceDepth.ts deleted file mode 100644 index 87b52ceff..000000000 --- a/apps/edr-freight-api/src/migrations/1970000000000-AddMaintenanceDepth.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddMaintenanceDepth1970000000000 implements MigrationInterface { - name = 'AddMaintenanceDepth1970000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE SCHEMA IF NOT EXISTS freight`); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.work_orders ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - vehicle_id UUID NOT NULL, - title VARCHAR NOT NULL, - description TEXT, - status VARCHAR NOT NULL DEFAULT 'OPEN', - priority VARCHAR NOT NULL DEFAULT 'MEDIUM', - assigned_to VARCHAR, - opened_at TIMESTAMPTZ NOT NULL DEFAULT now(), - closed_at TIMESTAMPTZ, - labor_cost NUMERIC(14, 2), - parts_cost NUMERIC(14, 2), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.parts ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR NOT NULL, - sku VARCHAR, - category VARCHAR, - quantity_in_stock INT NOT NULL DEFAULT 0, - reorder_level INT NOT NULL DEFAULT 0, - unit_cost NUMERIC(14, 2), - location VARCHAR, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warranties ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - vehicle_id UUID NOT NULL, - component VARCHAR NOT NULL, - provider VARCHAR, - start_date DATE, - expiry_date DATE NOT NULL, - coverage_notes TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ - ); - `); - - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_work_orders_vehicle_id_status" ON freight.work_orders (vehicle_id, status)`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_parts_category" ON freight.parts (category)`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_warranties_vehicle_id_expiry_date" ON freight.warranties (vehicle_id, expiry_date)`, - ); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.work_orders - ADD CONSTRAINT "FK_work_orders_vehicle_id" - FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - - await queryRunner.query(` - DO $$ BEGIN - ALTER TABLE freight.warranties - ADD CONSTRAINT "FK_warranties_vehicle_id" - FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; - EXCEPTION WHEN duplicate_object THEN NULL; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.warranties CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.parts CASCADE`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.work_orders CASCADE`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1980000000000-AddBookingHandovers.ts b/apps/edr-freight-api/src/migrations/1980000000000-AddBookingHandovers.ts deleted file mode 100644 index a47ff6297..000000000 --- a/apps/edr-freight-api/src/migrations/1980000000000-AddBookingHandovers.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Structured import handover records. Replaces the ad-hoc handover notes so a - * booking can carry one handover (single truck) or several (one per truck when - * multiple trucks are used). Timing differs by mile type: - * - SELF_HAUL: generated on first truck arrival, signed before the truck leaves. - * - EDR_LAST_MILE: generated at delivery (after exit); signed on delivery. - */ -export class AddBookingHandovers1980000000000 implements MigrationInterface { - name = 'AddBookingHandovers1980000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.booking_handovers ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - booking_id uuid NOT NULL REFERENCES freight.bookings(id) ON DELETE CASCADE, - truck_assignment_id uuid REFERENCES freight.customer_truck_assignments(id) ON DELETE SET NULL, - truck_plate varchar(32), - mile_type varchar(20) NOT NULL, - reference varchar(100) NOT NULL, - generated_at timestamptz NOT NULL DEFAULT now(), - signed_at timestamptz, - signed_by_user_id uuid, - delivered_at timestamptz, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_booking_handovers_booking" ON freight.booking_handovers (booking_id);`, - ); - // At most one live handover per (booking, customer truck). EDR trucks (which - // aren't customer_truck_assignments) and per-booking handovers are de-duped - // in the service, since a NULL truck_assignment_id can't be uniquely indexed. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_booking_handovers_booking_truck" - ON freight.booking_handovers (booking_id, truck_assignment_id) - WHERE deleted_at IS NULL AND truck_assignment_id IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.booking_handovers;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1980000000000-AddProcurement.ts b/apps/edr-freight-api/src/migrations/1980000000000-AddProcurement.ts deleted file mode 100644 index 6d4304aaf..000000000 --- a/apps/edr-freight-api/src/migrations/1980000000000-AddProcurement.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddProcurement1980000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.vendors ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - name varchar NOT NULL, - type varchar, - contact_person varchar, - phone varchar, - email varchar, - address varchar, - is_active boolean NOT NULL DEFAULT true - ); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.asset_acquisitions ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - vehicle_id uuid, - vendor_id uuid, - acquisition_type varchar NOT NULL, - acquisition_date date NOT NULL, - cost numeric(14,2), - useful_life_months integer, - salvage_value numeric(14,2), - lease_start date, - lease_end date, - monthly_payment numeric(14,2), - status varchar NOT NULL DEFAULT 'ACTIVE', - notes text - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_asset_acquisitions_vehicle_date - ON freight.asset_acquisitions(vehicle_id, acquisition_date); - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.asset_disposals ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - vehicle_id uuid NOT NULL, - disposal_date date NOT NULL, - method varchar NOT NULL, - sale_price numeric(14,2), - buyer varchar, - notes text - ); - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_asset_disposals_vehicle_date - ON freight.asset_disposals(vehicle_id, disposal_date); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.asset_disposals CASCADE;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.asset_acquisitions CASCADE;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.vendors CASCADE;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1980000000000-YardCountryEnumAndRouteDirection.ts b/apps/edr-freight-api/src/migrations/1980000000000-YardCountryEnumAndRouteDirection.ts deleted file mode 100644 index 3274b4d1c..000000000 --- a/apps/edr-freight-api/src/migrations/1980000000000-YardCountryEnumAndRouteDirection.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Yard country becomes a two-value enum (Ethiopia | Djibouti) and every route - * freezes its trade direction from the yard countries: - * Ethiopia → Djibouti = EXPORT, Djibouti → Ethiopia = IMPORT, - * same country = DOMESTIC (shown as "Intercity"; disabled for scheduling - * and contracts for now). - * - * Existing yard rows are normalized case-insensitively; anything mentioning - * Djibouti maps there, everything else maps to Ethiopia (the line only serves - * these two countries). A CHECK constraint keeps future writes honest. - */ -export class YardCountryEnumAndRouteDirection1980000000000 implements MigrationInterface { - name = 'YardCountryEnumAndRouteDirection1980000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.yards - SET country = CASE - WHEN lower(trim(country)) LIKE '%djib%' THEN 'Djibouti' - ELSE 'Ethiopia' - END - `); - await queryRunner.query(` - ALTER TABLE freight.yards - DROP CONSTRAINT IF EXISTS chk_yards_country, - ADD CONSTRAINT chk_yards_country CHECK (country IN ('Ethiopia', 'Djibouti')) - `); - - await queryRunner.query(` - ALTER TABLE freight.routes - ADD COLUMN IF NOT EXISTS direction varchar(10) - `); - await queryRunner.query(` - UPDATE freight.routes r - SET direction = CASE - WHEN o.country = 'Djibouti' AND d.country = 'Ethiopia' THEN 'IMPORT' - WHEN o.country = 'Ethiopia' AND d.country = 'Djibouti' THEN 'EXPORT' - ELSE 'DOMESTIC' - END - FROM freight.yards o, freight.yards d - WHERE o.id = r.origin_yard_id - AND d.id = r.destination_yard_id - `); - // Orphan origin/destination (deleted yard) — no way to classify; park as - // DOMESTIC, which is blocked everywhere, so nothing can schedule on it. - await queryRunner.query(` - UPDATE freight.routes SET direction = 'DOMESTIC' WHERE direction IS NULL - `); - await queryRunner.query(` - ALTER TABLE freight.routes - ALTER COLUMN direction SET NOT NULL, - DROP CONSTRAINT IF EXISTS chk_routes_direction, - ADD CONSTRAINT chk_routes_direction CHECK (direction IN ('IMPORT', 'EXPORT', 'DOMESTIC')) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.routes - DROP CONSTRAINT IF EXISTS chk_routes_direction, - DROP COLUMN IF EXISTS direction - `); - await queryRunner.query(` - ALTER TABLE freight.yards DROP CONSTRAINT IF EXISTS chk_yards_country - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1990000000000-AddDoubleHandlingBasisAndMachinery.ts b/apps/edr-freight-api/src/migrations/1990000000000-AddDoubleHandlingBasisAndMachinery.ts deleted file mode 100644 index be4ed060a..000000000 --- a/apps/edr-freight-api/src/migrations/1990000000000-AddDoubleHandlingBasisAndMachinery.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Double-handling fee support. warehouse_fee_rules.basis: how a - * DOUBLE_HANDLING_FEE rule is charged — PER_CONTAINER | PER_TON | PER_ITEM - * (null for the day-based fee types). The PER_TON / PER_ITEM quantity comes from - * the booking's cargo total (cargo_total_weight_vgm, expressed in the cargo's - * unit of measure), so no new booking column is needed. - */ -export class AddDoubleHandlingBasisAndMachinery1990000000000 implements MigrationInterface { - name = 'AddDoubleHandlingBasisAndMachinery1990000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.warehouse_fee_rules ADD COLUMN IF NOT EXISTS basis varchar(20)`, - ); - // machinery_units is not used (PER_ITEM reads cargo_total_weight_vgm); drop it - // if a prior version of this migration added it. - await queryRunner.query(`ALTER TABLE freight.bookings DROP COLUMN IF EXISTS machinery_units`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.warehouse_fee_rules DROP COLUMN IF EXISTS basis`); - } -} diff --git a/apps/edr-freight-api/src/migrations/1990000000000-AddVehiclePricePerKm.ts b/apps/edr-freight-api/src/migrations/1990000000000-AddVehiclePricePerKm.ts deleted file mode 100644 index 7767cd796..000000000 --- a/apps/edr-freight-api/src/migrations/1990000000000-AddVehiclePricePerKm.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Per-km haulage rate on a vehicle (mainly trucks) plus the currency it's - * quoted in (ETB | USD, default ETB). - */ -export class AddVehiclePricePerKm1990000000000 implements MigrationInterface { - name = "AddVehiclePricePerKm1990000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS price_per_km numeric(14,2), - ADD COLUMN IF NOT EXISTS currency varchar(8) NOT NULL DEFAULT 'ETB' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS price_per_km, - DROP COLUMN IF EXISTS currency - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/1990000000000-SegmentCorridorBookings.ts b/apps/edr-freight-api/src/migrations/1990000000000-SegmentCorridorBookings.ts deleted file mode 100644 index ca88ef7cd..000000000 --- a/apps/edr-freight-api/src/migrations/1990000000000-SegmentCorridorBookings.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Segment corridor bookings: a booking may ride only part of a train's route - * (its own origin→destination leg), so dispatch/arrival become per-booking - * facts and wagon capacity is consumed per leg instead of per whole route. - * - * - bookings.loaded_at / arrived_at (+ by-user): operator-confirmed load at - * the booking's origin yard and unload at its destination yard. Clearance - * gates read arrived_at, not the train's actual_arrival_at. - * - train_set_wagons.board_yard_id / alight_yard_id: the leg a consist slot - * occupies; NULL/NULL = whole route (legacy). Non-overlapping legs coexist - * without consuming each other's capacity. - * - wagon_movements: auditable ledger of every physical wagon relocation - * (loaded leg / empty reposition / manual correction) with the acting user. - */ -export class SegmentCorridorBookings1990000000000 implements MigrationInterface { - name = 'SegmentCorridorBookings1990000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS loaded_at timestamptz, - ADD COLUMN IF NOT EXISTS loaded_by_user_id uuid, - ADD COLUMN IF NOT EXISTS arrived_at timestamptz, - ADD COLUMN IF NOT EXISTS arrived_by_user_id uuid; - `); - - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - ADD COLUMN IF NOT EXISTS board_yard_id uuid REFERENCES freight.yards(id) ON DELETE SET NULL, - ADD COLUMN IF NOT EXISTS alight_yard_id uuid REFERENCES freight.yards(id) ON DELETE SET NULL; - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_movements ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - wagon_id uuid NOT NULL REFERENCES freight.wagons(id) ON DELETE CASCADE, - from_yard_id uuid REFERENCES freight.yards(id), - to_yard_id uuid NOT NULL REFERENCES freight.yards(id), - train_schedule_id uuid REFERENCES freight.train_schedules(id) ON DELETE SET NULL, - booking_id uuid REFERENCES freight.bookings(id) ON DELETE SET NULL, - kind varchar(30) NOT NULL, - moved_by_user_id uuid, - occurred_at timestamptz NOT NULL DEFAULT now(), - note text, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ); - `); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_wagon_movements_wagon_occurred" ON freight.wagon_movements (wagon_id, occurred_at);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_wagon_movements_schedule" ON freight.wagon_movements (train_schedule_id);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_movements;`); - await queryRunner.query(` - ALTER TABLE freight.train_set_wagons - DROP COLUMN IF EXISTS board_yard_id, - DROP COLUMN IF EXISTS alight_yard_id; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS loaded_at, - DROP COLUMN IF EXISTS loaded_by_user_id, - DROP COLUMN IF EXISTS arrived_at, - DROP COLUMN IF EXISTS arrived_by_user_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2000000000000-AddCustomsPriorityConfig.ts b/apps/edr-freight-api/src/migrations/2000000000000-AddCustomsPriorityConfig.ts deleted file mode 100644 index c7009c303..000000000 --- a/apps/edr-freight-api/src/migrations/2000000000000-AddCustomsPriorityConfig.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Moves service-level priority off the service_types table and onto the - * admin-managed priority_configs table as a new CUSTOMS rule type. - * - * - Drops service_types.priority_bonus_points (replaced by CUSTOMS configs). - * - Widens priority_configs.type CHECK to allow 'CUSTOMS' (currency must be - * null, same as WAGON). - * - Seeds the two customs wagon-count tiers: 1–10 → 7 pts, 11–53 → 15 pts. - * CUSTOMS rules apply only when the booking's service type includesCustoms. - */ -export class AddCustomsPriorityConfig2000000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.service_types DROP COLUMN IF EXISTS priority_bonus_points; - `); - - await queryRunner.query(` - ALTER TABLE freight.priority_configs - DROP CONSTRAINT IF EXISTS priority_configs_type_check; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_configs - ADD CONSTRAINT priority_configs_type_check - CHECK (type IN ('WAGON', 'CURRENCY', 'CUSTOMS')); - `); - - await queryRunner.query(` - ALTER TABLE freight.priority_configs - DROP CONSTRAINT IF EXISTS chk_currency_for_type; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_configs - ADD CONSTRAINT chk_currency_for_type CHECK ( - (type = 'WAGON' AND currency IS NULL) OR - (type = 'CURRENCY' AND currency IS NOT NULL) OR - (type = 'CUSTOMS' AND currency IS NULL) - ); - `); - - await queryRunner.query(` - INSERT INTO freight.priority_configs - (type, label, currency, min_wagon_count, max_wagon_count, score_points, is_active, display_order) - VALUES - ('CUSTOMS', 'With customs 1–10 wagons', NULL, 1, 10, 7, true, 1), - ('CUSTOMS', 'With customs 11–53 wagons', NULL, 11, 53, 15, true, 2); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DELETE FROM freight.priority_configs WHERE type = 'CUSTOMS'; - `); - - await queryRunner.query(` - ALTER TABLE freight.priority_configs - DROP CONSTRAINT IF EXISTS chk_currency_for_type; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_configs - ADD CONSTRAINT chk_currency_for_type CHECK ( - (type = 'WAGON' AND currency IS NULL) OR - (type = 'CURRENCY' AND currency IS NOT NULL) - ); - `); - - await queryRunner.query(` - ALTER TABLE freight.priority_configs - DROP CONSTRAINT IF EXISTS priority_configs_type_check; - `); - await queryRunner.query(` - ALTER TABLE freight.priority_configs - ADD CONSTRAINT priority_configs_type_check - CHECK (type IN ('WAGON', 'CURRENCY')); - `); - - await queryRunner.query(` - ALTER TABLE freight.service_types - ADD COLUMN IF NOT EXISTS priority_bonus_points INT NOT NULL DEFAULT 0; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2000000000000-AddGpsTracking.ts b/apps/edr-freight-api/src/migrations/2000000000000-AddGpsTracking.ts deleted file mode 100644 index 3d440c678..000000000 --- a/apps/edr-freight-api/src/migrations/2000000000000-AddGpsTracking.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * GPS tracking: physical trackers (gps_devices, one denormalized latest fix per - * device for the live map) + append-only fix history (gps_positions). - */ -export class AddGpsTracking2000000000000 implements MigrationInterface { - name = "AddGpsTracking2000000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.gps_devices ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - imei varchar(20) NOT NULL UNIQUE, - name varchar, - vehicle_id uuid REFERENCES freight.vehicles(id), - status varchar(16) NOT NULL DEFAULT 'REGISTERED', - last_seen_at timestamptz, - last_lat numeric(10,6), - last_lng numeric(10,6), - last_speed numeric(6,2), - last_course int, - last_fix_at timestamptz, - voltage_level int, - gsm_level int, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_DEVICES_VEHICLE" - ON freight.gps_devices (vehicle_id) - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.gps_positions ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - device_id uuid NOT NULL, - imei varchar(20) NOT NULL, - vehicle_id uuid, - lat numeric(10,6) NOT NULL, - lng numeric(10,6) NOT NULL, - speed numeric(6,2) NOT NULL DEFAULT 0, - course int NOT NULL DEFAULT 0, - satellites int NOT NULL DEFAULT 0, - positioned boolean NOT NULL DEFAULT false, - gps_time timestamptz NOT NULL, - alarm int NOT NULL DEFAULT 0, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_POSITIONS_DEVICE_TIME" - ON freight.gps_positions (device_id, gps_time) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_POSITIONS_VEHICLE_TIME" - ON freight.gps_positions (vehicle_id, gps_time) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.gps_positions`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.gps_devices`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2000000000000-AddTruckDetentionTiming.ts b/apps/edr-freight-api/src/migrations/2000000000000-AddTruckDetentionTiming.ts deleted file mode 100644 index ce7bfd326..000000000 --- a/apps/edr-freight-api/src/migrations/2000000000000-AddTruckDetentionTiming.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Truck detention support. - * - last_mile.arrived_at / delivered_at: the detention window for an EDR - * last-mile vehicle. The clock runs from arrival at destination; the customer - * has a grace period (default 3h) to clear/return, after which detention - * accrues per truck per day until delivered_at (or now, if still out). - * - warehouse_fee_rules.free_hours: configurable grace window (hours) for a - * TRUCK_DETENTION_FEE rule; null/0 falls back to the 3-hour default. - */ -export class AddTruckDetentionTiming2000000000000 implements MigrationInterface { - name = 'AddTruckDetentionTiming2000000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.last_mile ADD COLUMN IF NOT EXISTS arrived_at timestamptz`, - ); - await queryRunner.query( - `ALTER TABLE freight.last_mile ADD COLUMN IF NOT EXISTS delivered_at timestamptz`, - ); - await queryRunner.query( - `ALTER TABLE freight.warehouse_fee_rules ADD COLUMN IF NOT EXISTS free_hours int`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.warehouse_fee_rules DROP COLUMN IF EXISTS free_hours`); - await queryRunner.query(`ALTER TABLE freight.last_mile DROP COLUMN IF EXISTS delivered_at`); - await queryRunner.query(`ALTER TABLE freight.last_mile DROP COLUMN IF EXISTS arrived_at`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2000000000000-CreateCompanyChangeRequest.ts b/apps/edr-freight-api/src/migrations/2000000000000-CreateCompanyChangeRequest.ts deleted file mode 100644 index 9d8d2b5c9..000000000 --- a/apps/edr-freight-api/src/migrations/2000000000000-CreateCompanyChangeRequest.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Staging table for customer profile edits that require backoffice review. An - * already-approved company's settings edits are snapshotted here (Pending) - * instead of being written to the live `companies` row; a reviewer approves - * (snapshot applied) or rejects with a note (customer amends & resubmits). - */ -export class CreateCompanyChangeRequest2000000000000 - implements MigrationInterface -{ - name = 'CreateCompanyChangeRequest2000000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'company_change_request', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'company_id', type: 'uuid' }, - { name: 'snapshot', type: 'jsonb' }, - { name: 'documents', type: 'jsonb', isNullable: true }, - { name: 'status', type: 'varchar', length: '20', default: "'pending'" }, - { name: 'note', type: 'text', isNullable: true }, - { name: 'submitted_by', type: 'uuid', isNullable: true }, - { name: 'submitted_at', type: 'timestamptz', isNullable: true }, - { name: 'reviewed_by', type: 'uuid', isNullable: true }, - { name: 'reviewed_at', type: 'timestamptz', isNullable: true }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['company_id'], - referencedSchema: 'freight', - referencedTableName: 'companies', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.company_change_request', - new TableIndex({ name: 'idx_company_change_request_company', columnNames: ['company_id'] }), - ); - await queryRunner.createIndex( - 'freight.company_change_request', - new TableIndex({ name: 'idx_company_change_request_status', columnNames: ['status'] }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.company_change_request', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/2000000000001-AddCompanyProfileReview.ts b/apps/edr-freight-api/src/migrations/2000000000001-AddCompanyProfileReview.ts deleted file mode 100644 index 2c2fdf3e1..000000000 --- a/apps/edr-freight-api/src/migrations/2000000000001-AddCompanyProfileReview.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; - -/** - * Adds reviewer note/id/timestamp to company_profiles so a rejected operational - * role (new ProfileStatus 'rejected') can carry the reason back to the customer, - * who can then amend and reapply. - */ -export class AddCompanyProfileReview2000000000001 - implements MigrationInterface -{ - name = 'AddCompanyProfileReview2000000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.addColumns('freight.company_profiles', [ - new TableColumn({ name: 'review_note', type: 'text', isNullable: true }), - new TableColumn({ name: 'reviewed_by', type: 'uuid', isNullable: true }), - new TableColumn({ name: 'reviewed_at', type: 'timestamptz', isNullable: true }), - ]); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumns('freight.company_profiles', [ - 'review_note', - 'reviewed_by', - 'reviewed_at', - ]); - } -} diff --git a/apps/edr-freight-api/src/migrations/2010000000000-AddConsolidationResumeStatus.ts b/apps/edr-freight-api/src/migrations/2010000000000-AddConsolidationResumeStatus.ts deleted file mode 100644 index cb6f7dc91..000000000 --- a/apps/edr-freight-api/src/migrations/2010000000000-AddConsolidationResumeStatus.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds bookings.consolidation_resume_status: the status a booking parked in - * PENDING_CONSOLIDATION returns to once it pairs with a wagon partner. - * - * Direct customer bookings leave it NULL (they resume to SUBMITTED, unchanged). - * Contract-drawdown bookings (GL shipments) set it to the status - * createUnderContract would otherwise have used (OPERATION_REQUEST_PENDING or - * AWAITING_DOCUMENTS), so pairing resumes them into the contract-booking flow - * instead of wrongly moving them to SUBMITTED. - */ -export class AddConsolidationResumeStatus2010000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS consolidation_resume_status VARCHAR(40); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS consolidation_resume_status; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2010000000000-AddFeeRuleVehicleType.ts b/apps/edr-freight-api/src/migrations/2010000000000-AddFeeRuleVehicleType.ts deleted file mode 100644 index a71f3cb5b..000000000 --- a/apps/edr-freight-api/src/migrations/2010000000000-AddFeeRuleVehicleType.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Truck-detention rules can be scoped by vehicle type (TRUCK / VAN / TRAILER / - * TANKER / FLATBED / …), so different truck types carry different detention - * rates. Null = applies to any truck type. - */ -export class AddFeeRuleVehicleType2010000000000 implements MigrationInterface { - name = 'AddFeeRuleVehicleType2010000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.warehouse_fee_rules ADD COLUMN IF NOT EXISTS vehicle_type varchar(20)`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE freight.warehouse_fee_rules DROP COLUMN IF EXISTS vehicle_type`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2020000000000-RepairOtpEmailSchema.ts b/apps/edr-freight-api/src/migrations/2020000000000-RepairOtpEmailSchema.ts deleted file mode 100644 index e11923a4d..000000000 --- a/apps/edr-freight-api/src/migrations/2020000000000-RepairOtpEmailSchema.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Repair: AddEmailToOtpVerifications1900000000000 originally altered - * `public.otp_verifications`, but the OtpVerification entity pins - * schema: "freight". On any DB where that migration already ran (and is recorded - * as executed, so it won't run again), the real `freight.otp_verifications` table - * never got the `email` column and `phone` was never made nullable — so OTP send - * dies with `column OtpVerification.email does not exist`. - * - * This migration re-applies the change against the correct schema. Idempotent - * (IF NOT EXISTS / no-op DROP NOT NULL), and guarded so it's a no-op when the - * freight table is absent. - */ -export class RepairOtpEmailSchema2020000000000 implements MigrationInterface { - name = "RepairOtpEmailSchema2020000000000"; - - public async up(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable("freight.otp_verifications"); - if (!exists) return; - - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - ALTER COLUMN phone DROP NOT NULL - `); - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - ADD COLUMN IF NOT EXISTS email varchar UNIQUE - `); - } - - public async down(queryRunner: QueryRunner): Promise { - const exists = await queryRunner.hasTable("freight.otp_verifications"); - if (!exists) return; - - await queryRunner.query(` - ALTER TABLE freight.otp_verifications - DROP COLUMN IF EXISTS email - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts b/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts deleted file mode 100644 index 333a0f541..000000000 --- a/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Weights are tonnes everywhere. Warehouse / yard / zone capacity was stored in - * kg (e.g. 25000, 5000, 2500) — convert existing rows to tonnes (÷1000). Cargo - * weight (warehouse_inventory.weight ← cargo_total_weight_vgm) is already tonnes - * and is NOT touched; truck gross weight has no data yet. Runs exactly once - * (tracked by TypeORM) — re-running would divide again. - */ -export class WarehouseCapacityKgToTons2020000000000 implements MigrationInterface { - name = 'WarehouseCapacityKgToTons2020000000000'; - - private readonly tables = ['warehouses', 'warehouse_yards', 'warehouse_zones']; - private readonly columns = ['capacity_weight', 'current_weight', 'max_weight']; - - public async up(queryRunner: QueryRunner): Promise { - for (const table of this.tables) { - for (const column of this.columns) { - await queryRunner.query( - `UPDATE freight.${table} SET ${column} = ${column} / 1000.0 WHERE ${column} IS NOT NULL`, - ); - } - } - } - - public async down(queryRunner: QueryRunner): Promise { - for (const table of this.tables) { - for (const column of this.columns) { - await queryRunner.query( - `UPDATE freight.${table} SET ${column} = ${column} * 1000.0 WHERE ${column} IS NOT NULL`, - ); - } - } - } -} diff --git a/apps/edr-freight-api/src/migrations/2030000000000-AddTrainScheduleReference.ts b/apps/edr-freight-api/src/migrations/2030000000000-AddTrainScheduleReference.ts deleted file mode 100644 index a05465c53..000000000 --- a/apps/edr-freight-api/src/migrations/2030000000000-AddTrainScheduleReference.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds train_schedules.reference: a human-facing unique schedule number - * S-YYYY-NNNNN (per-year sequence, like bookings' BK-YYYY-NNNNNN). - * - * - Adds the nullable column. - * - Backfills existing rows: within each created-at year, numbers rows by - * created_at ascending (oldest → S--00001). Deterministic order. - * - Adds a partial unique index (NULLs allowed so a future insert can stage - * the row before the app stamps its reference). - */ -export class AddTrainScheduleReference2030000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS reference VARCHAR(20); - `); - - // Backfill per-year, ordered by created_at (oldest = 00001). Uses the row's - // own created-at year as the reference year so historical rows keep a - // sensible number. - await queryRunner.query(` - WITH numbered AS ( - SELECT - id, - EXTRACT(YEAR FROM created_at)::int AS yr, - ROW_NUMBER() OVER ( - PARTITION BY EXTRACT(YEAR FROM created_at) - ORDER BY created_at ASC, id ASC - ) AS seq - FROM freight.train_schedules - WHERE reference IS NULL - ) - UPDATE freight.train_schedules ts - SET reference = 'S-' || numbered.yr || '-' || LPAD(numbered.seq::text, 5, '0') - FROM numbered - WHERE ts.id = numbered.id; - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS ux_train_schedules_reference - ON freight.train_schedules (reference) - WHERE reference IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS freight.ux_train_schedules_reference; - `); - await queryRunner.query(` - ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS reference; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2040000000000-AddLocomotiveOverageTolerance.ts b/apps/edr-freight-api/src/migrations/2040000000000-AddLocomotiveOverageTolerance.ts deleted file mode 100644 index 4bda8dde1..000000000 --- a/apps/edr-freight-api/src/migrations/2040000000000-AddLocomotiveOverageTolerance.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds locomotives.overage_tolerance_tons / overage_tolerance_meters: an - * optional per-locomotive deviation allowance above max_pull_weight_tons / - * max_train_length_meters. Nullable, defaults to no tolerance so existing - * strict-cap behavior is unchanged until staff sets a value. - */ -export class AddLocomotiveOverageTolerance2040000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.locomotives - ADD COLUMN IF NOT EXISTS overage_tolerance_tons NUMERIC(10, 3), - ADD COLUMN IF NOT EXISTS overage_tolerance_meters NUMERIC(10, 3); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.locomotives - DROP COLUMN IF EXISTS overage_tolerance_tons, - DROP COLUMN IF EXISTS overage_tolerance_meters; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2040000000000-MigrateLicenseFilesToFileRecords.ts b/apps/edr-freight-api/src/migrations/2040000000000-MigrateLicenseFilesToFileRecords.ts deleted file mode 100644 index d3720de33..000000000 --- a/apps/edr-freight-api/src/migrations/2040000000000-MigrateLicenseFilesToFileRecords.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Business-license files used to live inline as a jsonb array on - * `company_profiles.business_license_files`. They now belong to the FileRecord - * model (`freight.files`, resource `company_profiles`, code `business_license`) - * so they get stable ids and stream through `GET /api/files/:id` — the same - * proxy path regular documents use — instead of broken direct-MinIO URLs. - * - * This copies each existing inline entry into `freight.files` by reference - * (keeping the stored object URL — no bytes are re-uploaded). The original jsonb - * column is left intact for rollback safety. - */ -export class MigrateLicenseFilesToFileRecords2040000000000 - implements MigrationInterface -{ - name = "MigrateLicenseFilesToFileRecords2040000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - INSERT INTO freight.files - (id, resource_id, resource, code, name, url, size, mime_type, created_at, updated_at) - SELECT - gen_random_uuid(), - cp.id, - 'company_profiles', - 'business_license', - COALESCE(elem->>'name', 'license'), - elem->>'url', - COALESCE(NULLIF(elem->>'size', '')::int, 0), - COALESCE(NULLIF(elem->>'mimeType', ''), 'application/octet-stream'), - now(), - now() - FROM freight.company_profiles cp - CROSS JOIN LATERAL jsonb_array_elements(cp.business_license_files) AS elem - WHERE cp.business_license_files IS NOT NULL - AND jsonb_typeof(cp.business_license_files) = 'array' - AND elem->>'url' IS NOT NULL - AND NOT EXISTS ( - SELECT 1 FROM freight.files f - WHERE f.resource_id = cp.id - AND f.resource = 'company_profiles' - AND f.code = 'business_license' - AND f.url = elem->>'url' - AND f.deleted_at IS NULL - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Reverse the model migration by dropping the license FileRecords. The - // original jsonb column was never cleared, so the data still exists there. - await queryRunner.query(` - DELETE FROM freight.files - WHERE resource = 'company_profiles' - AND code = 'business_license'; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2050000000000-AddCustomerTruckContainerLoadedAt.ts b/apps/edr-freight-api/src/migrations/2050000000000-AddCustomerTruckContainerLoadedAt.ts deleted file mode 100644 index 332df2423..000000000 --- a/apps/edr-freight-api/src/migrations/2050000000000-AddCustomerTruckContainerLoadedAt.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds customer_truck_containers.loaded_at so an assignment (customer planning - * which containers ride which truck) is distinct from the container actually - * being loaded. Stage LOADED now requires loaded_at; customer assignment alone - * keeps the container at its prior stage (RECEIVED/GRN) with its planned truck - * shown. Backfills containers on already-departed trucks (they left loaded). - */ -export class AddCustomerTruckContainerLoadedAt2050000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.customer_truck_containers - ADD COLUMN IF NOT EXISTS loaded_at TIMESTAMPTZ; - `); - - await queryRunner.query(` - UPDATE freight.customer_truck_containers ctc - SET loaded_at = a.departed_at - FROM freight.customer_truck_assignments a - WHERE a.id = ctc.assignment_id - AND a.departed_at IS NOT NULL - AND ctc.deleted_at IS NULL - AND ctc.loaded_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.customer_truck_containers DROP COLUMN IF EXISTS loaded_at; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2050000000000-DropWagonTypeMaxWagonsPerTrain.ts b/apps/edr-freight-api/src/migrations/2050000000000-DropWagonTypeMaxWagonsPerTrain.ts deleted file mode 100644 index 927504ee6..000000000 --- a/apps/edr-freight-api/src/migrations/2050000000000-DropWagonTypeMaxWagonsPerTrain.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Drops wagon_types.max_wagons_per_train. Train wagon-count caps are already - * derived from locomotive + wagon length/weight (train-capacity.util.ts) and - * the global train_scheduling_global_rules row — this per-wagon-type override - * was unused by that derivation and only added a confusing "Max / train" - * field to the wagon type form. - */ -export class DropWagonTypeMaxWagonsPerTrain2050000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_types - DROP COLUMN IF EXISTS max_wagons_per_train; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_types - ADD COLUMN IF NOT EXISTS max_wagons_per_train INT; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2060000000000-CreateYardDistances.ts b/apps/edr-freight-api/src/migrations/2060000000000-CreateYardDistances.ts deleted file mode 100644 index 42352237d..000000000 --- a/apps/edr-freight-api/src/migrations/2060000000000-CreateYardDistances.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Configured rail distance between two yards (Configuration → Yard Distances). - * Route creation resolves each segment's km from here (symmetric lookup: - * one A↔B row serves both directions) instead of accepting free-text km, - * and snapshots the value onto route_milestones.distance_km. - * - * Uniqueness is a partial index (deleted_at IS NULL) so a soft-deleted pair - * can be re-created. - */ -export class CreateYardDistances2060000000000 implements MigrationInterface { - name = 'CreateYardDistances2060000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.yard_distances ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - from_yard_id uuid NOT NULL REFERENCES freight.yards(id), - to_yard_id uuid NOT NULL REFERENCES freight.yards(id), - distance_km numeric(10,2) NOT NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_yard_distances_from_yard - ON freight.yard_distances (from_yard_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_yard_distances_to_yard - ON freight.yard_distances (to_yard_id); - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_yard_distances_pair - ON freight.yard_distances (from_yard_id, to_yard_id) - WHERE deleted_at IS NULL; - `); - // Backfill from segments already stored on existing routes so editing them - // does not immediately fail the "pair not configured" check. One row per - // unordered pair; where routes disagree the longest segment wins. - await queryRunner.query(` - INSERT INTO freight.yard_distances (from_yard_id, to_yard_id, distance_km) - SELECT DISTINCT ON (LEAST(prev_yard_id, yard_id), GREATEST(prev_yard_id, yard_id)) - prev_yard_id, yard_id, distance_km - FROM ( - SELECT - yard_id, - distance_km, - LAG(yard_id) OVER (PARTITION BY route_id ORDER BY sequence_no) AS prev_yard_id - FROM freight.route_milestones - WHERE deleted_at IS NULL - ) segments - WHERE prev_yard_id IS NOT NULL - AND distance_km IS NOT NULL - AND distance_km > 0 - ORDER BY LEAST(prev_yard_id, yard_id), GREATEST(prev_yard_id, yard_id), distance_km DESC - ON CONFLICT DO NOTHING; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.yard_distances;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2060000000000-SeedRailWagonTypes.ts b/apps/edr-freight-api/src/migrations/2060000000000-SeedRailWagonTypes.ts deleted file mode 100644 index ed9e8fae2..000000000 --- a/apps/edr-freight-api/src/migrations/2060000000000-SeedRailWagonTypes.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Upserts the 10 real EDR wagon types (code, name, capacity, length, tare - * weight) by code. Overwrites any existing row with the same code so - * previously-seeded demo values (e.g. NW5/PW2/CW3 from demo-bookings.seeder) - * are replaced with the real spec. - */ -export class SeedRailWagonTypes2060000000000 implements MigrationInterface { - private readonly wagonTypes = [ - { code: 'NW7', name: 'Double deck sedan wagon', capacityTons: 22, lengthMeters: 26.066, tareWeightTons: 37.1 }, - { code: 'NW5', name: 'Flat wagon', capacityTons: 70, lengthMeters: 13.966, tareWeightTons: 22.4 }, - { code: 'PW2', name: 'Box wagon', capacityTons: 70, lengthMeters: 17.066, tareWeightTons: 25.2 }, - { code: 'GW2', name: 'Tank wagon', capacityTons: 70, lengthMeters: 12.228, tareWeightTons: 23 }, - { code: 'CW4', name: 'Gondola covered wagon', capacityTons: 70, lengthMeters: 13.976, tareWeightTons: 24.8 }, - { code: 'CW3', name: 'Gondola open wagon', capacityTons: 70, lengthMeters: 13.976, tareWeightTons: 23.4 }, - { code: 'KW2', name: 'Hopper covered wagon', capacityTons: 69, lengthMeters: 16.466, tareWeightTons: 25.2 }, - { code: 'KW3', name: 'Hopper wagon open', capacityTons: 70, lengthMeters: 14.4, tareWeightTons: 24 }, - { code: 'NW6', name: 'Flat wagon (long)', capacityTons: 70, lengthMeters: 18.56, tareWeightTons: 25.3 }, - { code: 'BW1', name: 'Refrigerated wagon', capacityTons: 38, lengthMeters: 21.996, tareWeightTons: 32.1 }, - ]; - - public async up(queryRunner: QueryRunner): Promise { - for (const wt of this.wagonTypes) { - await queryRunner.query( - ` - INSERT INTO freight.wagon_types (code, name, capacity_tons, length_meters, tare_weight_tons, is_active) - VALUES ($1, $2, $3, $4, $5, true) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - capacity_tons = EXCLUDED.capacity_tons, - length_meters = EXCLUDED.length_meters, - tare_weight_tons = EXCLUDED.tare_weight_tons; - `, - [wt.code, wt.name, wt.capacityTons, wt.lengthMeters, wt.tareWeightTons], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM freight.wagon_types WHERE code = ANY($1);`, - [this.wagonTypes.map((wt) => wt.code)], - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2070000000000-MakeWagonTypeTareWeightRequired.ts b/apps/edr-freight-api/src/migrations/2070000000000-MakeWagonTypeTareWeightRequired.ts deleted file mode 100644 index ff85f3f24..000000000 --- a/apps/edr-freight-api/src/migrations/2070000000000-MakeWagonTypeTareWeightRequired.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Tare weight becomes mandatory on a wagon type. - * - * The locomotive's pull limit is a GROSS limit — it drags the wagon as well as - * the cargo — so capacity math cannot run without a tare. A NULL tare silently - * read as zero and let trains overbook by the tare fraction (~27% on a PW2 - * consist), so the column is now NOT NULL. - * - * Any row still missing a tare predates 2060000000000-SeedRailWagonTypes (which - * upserts the ten real EDR types). Backfill those by code first, and give any - * remaining custom/demo type the NW5 flat-wagon tare rather than fail the - * migration — a wrong-but-plausible tare is recoverable in the admin UI; a - * blocked deploy is not. - */ -export class MakeWagonTypeTareWeightRequired2070000000000 implements MigrationInterface { - private readonly tareByCode: Array<[string, number]> = [ - ['NW7', 37.1], - ['NW5', 22.4], - ['PW2', 25.2], - ['GW2', 23], - ['CW4', 24.8], - ['CW3', 23.4], - ['KW2', 25.2], - ['KW3', 24], - ['NW6', 25.3], - ['BW1', 32.1], - ]; - - /** NW5 flat wagon — the commonest type in the fleet (550 of 1100). */ - private readonly fallbackTareTons = 22.4; - - public async up(queryRunner: QueryRunner): Promise { - for (const [code, tareWeightTons] of this.tareByCode) { - await queryRunner.query( - `UPDATE freight.wagon_types - SET tare_weight_tons = $2 - WHERE code = $1 AND tare_weight_tons IS NULL;`, - [code, tareWeightTons], - ); - } - - await queryRunner.query( - `UPDATE freight.wagon_types - SET tare_weight_tons = $1 - WHERE tare_weight_tons IS NULL;`, - [this.fallbackTareTons], - ); - - await queryRunner.query( - `ALTER TABLE freight.wagon_types - ALTER COLUMN tare_weight_tons SET NOT NULL;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.wagon_types - ALTER COLUMN tare_weight_tons DROP NOT NULL;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2080000000000-DropWagonSpecColumns.ts b/apps/edr-freight-api/src/migrations/2080000000000-DropWagonSpecColumns.ts deleted file mode 100644 index 0fe3569f4..000000000 --- a/apps/edr-freight-api/src/migrations/2080000000000-DropWagonSpecColumns.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Wagon spec belongs to the wagon TYPE, not to each physical wagon. - * - * `wagons.tare_weight` and `wagons.max_payload_weight` duplicated - * `wagon_types.tare_weight_tons` / `wagon_types.capacity_tons` on all 1100 rows, - * with nothing keeping them in step. They had drifted completely: every wagon - * disagreed with its type's tare (seeded ~20T against a real 22.4T NW5), and a - * third disagreed on payload (NW5 wagons claiming 22T–70T against a flat 70T). - * None of those numbers came from the railway. - * - * Nothing reads them for capacity — that math resolves tare and capacity through - * `wagon_type_id` — so dropping them removes a source of fiction rather than a - * source of truth. `wagon_type_id` is NOT NULL with no orphans, so the type is - * always reachable. - * - * A wagon re-tared after repair would need a nullable override column on - * `wagons` falling back to the type; deliberately not added, since no such - * per-wagon value exists today. - */ -export class DropWagonSpecColumns2080000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP COLUMN IF EXISTS tare_weight, - DROP COLUMN IF EXISTS max_payload_weight; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Re-add nullable, backfill from the owning type, then restore NOT NULL. - // The pre-drop values were drifted seed data and are not recoverable — the - // type's spec is what they should always have held. - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS tare_weight NUMERIC(10, 2), - ADD COLUMN IF NOT EXISTS max_payload_weight NUMERIC(10, 2); - `); - await queryRunner.query(` - UPDATE freight.wagons w - SET tare_weight = t.tare_weight_tons, - max_payload_weight = t.capacity_tons - FROM freight.wagon_types t - WHERE t.id = w.wagon_type_id; - `); - await queryRunner.query(` - ALTER TABLE freight.wagons - ALTER COLUMN tare_weight SET NOT NULL, - ALTER COLUMN max_payload_weight SET NOT NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2090000000000-CreateContractTemplates.ts b/apps/edr-freight-api/src/migrations/2090000000000-CreateContractTemplates.ts deleted file mode 100644 index a553319cc..000000000 --- a/apps/edr-freight-api/src/migrations/2090000000000-CreateContractTemplates.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -import { CONTRACT_TEMPLATE_DEFAULTS } from '../seed/data/contract-template-defaults'; - -/** - * Creates freight.contract_templates — the six editable contract document - * templates (direction × freight type) whose dynamic articles drive the - * generated contract PDF — and seeds them from the EDR reference contract - * documents. Seeding is idempotent (ON CONFLICT (code) DO NOTHING) so admin - * edits are never overwritten by redeploys. - */ -export class CreateContractTemplates2090000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_templates ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - code VARCHAR(40) NOT NULL, - name VARCHAR(200) NOT NULL, - description TEXT, - document_title VARCHAR(300) NOT NULL, - whereas_clauses JSONB NOT NULL DEFAULT '[]', - articles JSONB NOT NULL DEFAULT '[]', - is_active BOOLEAN NOT NULL DEFAULT TRUE, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), - deleted_at TIMESTAMPTZ, - CONSTRAINT uq_contract_templates_code UNIQUE (code) - ); - `); - - for (const seed of CONTRACT_TEMPLATE_DEFAULTS) { - const articles = seed.articles.map((article, index) => ({ - ...article, - order: index + 1, - })); - await queryRunner.query( - ` - INSERT INTO freight.contract_templates - (code, name, description, document_title, whereas_clauses, articles) - VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb) - ON CONFLICT (code) DO NOTHING; - `, - [ - seed.code, - seed.name, - seed.description, - seed.documentTitle, - JSON.stringify(seed.whereasClauses), - JSON.stringify(articles), - ], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.contract_templates;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2090000000000-RepairGrnNumberColumn.ts b/apps/edr-freight-api/src/migrations/2090000000000-RepairGrnNumberColumn.ts deleted file mode 100644 index aa2f998a2..000000000 --- a/apps/edr-freight-api/src/migrations/2090000000000-RepairGrnNumberColumn.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Repairs `freight.warehouse_inventory.grn_number`. - * - * AddGrnNumberToWarehouseInventory1828000000000 is recorded in `migrations` but - * the column is absent on at least one environment - it was added, then dropped - * out-of-band (a stray `synchronize: true`, same class of damage that - * RepairSynchronizeDrift1870000000000 already had to undo). Because TypeORM has - * the original recorded, it will never re-run it. - * - * Without the column, everything that reads or writes a GRN fails with - * `column ... grn_number does not exist`: - * - bulkReceive() -> INSERT names grn_number (receive to warehouse) - * - importQueueByStatuses() -> Unloaded + Dispatch queues - * - exportInventoryByStatus() -> Received / Ready-To-Load / Loaded tabs - * - grnDocument() -> GRN PDF - * - * Idempotent: a no-op on environments where the column survived. - */ -export class RepairGrnNumberColumn2090000000000 implements MigrationInterface { - name = 'RepairGrnNumberColumn2090000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_inventory - ADD COLUMN IF NOT EXISTS grn_number VARCHAR(100) NULL - `); - - // Recover the GRN for rows received before the column existed: it was also - // written into the receive note as "GRN Number: ". - await queryRunner.query(` - UPDATE freight.warehouse_inventory - SET grn_number = substring(notes FROM 'GRN Number: ([^\\n\\r]+)') - WHERE grn_number IS NULL - AND notes IS NOT NULL - AND notes ~ 'GRN Number: ' - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_inventory_grn_number - ON freight.warehouse_inventory(grn_number) - WHERE grn_number IS NOT NULL - `); - } - - /** - * Deliberately a no-op. Dropping the column is what broke these environments - * in the first place, and the original 1828 migration already owns its own - * down(). Reverting this repair must not re-introduce the outage. - */ - public async down(): Promise { - // intentionally empty - } -} diff --git a/apps/edr-freight-api/src/migrations/2100000000000-CompanyProfileDefaultPending.ts b/apps/edr-freight-api/src/migrations/2100000000000-CompanyProfileDefaultPending.ts deleted file mode 100644 index aafa9715f..000000000 --- a/apps/edr-freight-api/src/migrations/2100000000000-CompanyProfileDefaultPending.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * `company_profiles.status` defaulted to 'active', so any insert that omitted - * the column produced an operational role that was approved without ever being - * reviewed. Every live write path already passes 'pending' explicitly; this - * closes the hole at the schema level. - * - * Deliberately no data backfill. A role approved through setCompanyProfileStatus - * always stamps `reviewed_at`, so `status = 'active' AND reviewed_at IS NULL` - * flags a role that skipped review — but it also matches rows approved before - * `reviewed_at` existed (migration 2000000000001). Auditing that set is a - * judgement call about real customers, not something to automate here. - */ -export class CompanyProfileDefaultPending2100000000000 - implements MigrationInterface -{ - name = 'CompanyProfileDefaultPending2100000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."company_profiles" ALTER COLUMN "status" SET DEFAULT 'pending'`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."company_profiles" ALTER COLUMN "status" SET DEFAULT 'active'`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2100000000000-WarehouseLoadingTrainAssociation.ts b/apps/edr-freight-api/src/migrations/2100000000000-WarehouseLoadingTrainAssociation.ts deleted file mode 100644 index 26afdf82a..000000000 --- a/apps/edr-freight-api/src/migrations/2100000000000-WarehouseLoadingTrainAssociation.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Auto-load onto a selected train: a warehouse_loadings row now records WHICH - * train the item was loaded onto (train_schedule_id), and wagon_id becomes - * nullable because a schedule-level load may not resolve to a single wagon. - */ -export class WarehouseLoadingTrainAssociation2100000000000 implements MigrationInterface { - name = 'WarehouseLoadingTrainAssociation2100000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_loadings - ADD COLUMN IF NOT EXISTS train_schedule_id UUID NULL - `); - await queryRunner.query(` - ALTER TABLE freight.warehouse_loadings - ALTER COLUMN wagon_id DROP NOT NULL - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_warehouse_loadings_train_schedule - ON freight.warehouse_loadings(train_schedule_id) - WHERE train_schedule_id IS NOT NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_warehouse_loadings_train_schedule`); - await queryRunner.query(` - ALTER TABLE freight.warehouse_loadings DROP COLUMN IF EXISTS train_schedule_id - `); - // wagon_id stays nullable on revert: restoring NOT NULL would fail on rows - // recorded without a wagon and re-introduce the outage this fixes. - } -} diff --git a/apps/edr-freight-api/src/migrations/2110000000000-AddBookingIsSplit.ts b/apps/edr-freight-api/src/migrations/2110000000000-AddBookingIsSplit.ts deleted file mode 100644 index 8e5ded189..000000000 --- a/apps/edr-freight-api/src/migrations/2110000000000-AddBookingIsSplit.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Partial-batch splits no longer promote a ONE_TIME contract to GENERAL. - * Instead the reduced booking is flagged is_split, and the booking gate lets - * the customer book exactly the remainder under the still-ONE_TIME contract. - */ -export class AddBookingIsSplit2110000000000 implements MigrationInterface { - name = 'AddBookingIsSplit2110000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS is_split BOOLEAN NOT NULL DEFAULT FALSE - `); - // Quantities the booking carried before the split — the remainder ledger - // for ONE_TIME contracts, which have no quantity cap to derive it from. - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS pre_split_quantities JSONB NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings DROP COLUMN IF EXISTS pre_split_quantities - `); - await queryRunner.query(` - ALTER TABLE freight.bookings DROP COLUMN IF EXISTS is_split - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2110000000000-RepairVehicleAvailabilityColumn.ts b/apps/edr-freight-api/src/migrations/2110000000000-RepairVehicleAvailabilityColumn.ts deleted file mode 100644 index c68a6c720..000000000 --- a/apps/edr-freight-api/src/migrations/2110000000000-RepairVehicleAvailabilityColumn.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Repair migration. `SeparateVehicleAvailability1890000000000` is recorded in - * public.migrations but the `availability` column is absent on some databases - * (recorded-but-not-applied drift). Because the original is already recorded, - * TypeORM will not re-run it, so `vehiclesService.findAll` (a query builder that - * selects every entity column) 500s with `column "availability" does not exist`. - * - * This re-adds the column idempotently and backfills. Safe to run everywhere: - * `IF NOT EXISTS` makes it a no-op where the column already exists. - */ -export class RepairVehicleAvailabilityColumn2110000000000 - implements MigrationInterface -{ - name = "RepairVehicleAvailabilityColumn2110000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS availability varchar DEFAULT 'FREE' - `); - await queryRunner.query(` - UPDATE freight.vehicles SET availability = 'FREE' WHERE availability IS NULL - `); - } - - public async down(): Promise { - // No-op: dropping a column other code now depends on would reintroduce the - // drift. The original SeparateVehicleAvailability migration owns the column. - } -} diff --git a/apps/edr-freight-api/src/migrations/2120000000000-AddLastMileProofOfDelivery.ts b/apps/edr-freight-api/src/migrations/2120000000000-AddLastMileProofOfDelivery.ts deleted file mode 100644 index ed5054e87..000000000 --- a/apps/edr-freight-api/src/migrations/2120000000000-AddLastMileProofOfDelivery.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Proof of delivery for EDR last-mile: recipient name, a captured signature - * (stored as a file), delivery photos (file ids), notes, and the capture time. - * Recorded when the driver completes the delivery. - */ -export class AddLastMileProofOfDelivery2120000000000 - implements MigrationInterface -{ - name = "AddLastMileProofOfDelivery2120000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile - ADD COLUMN IF NOT EXISTS pod_recipient_name varchar(160), - ADD COLUMN IF NOT EXISTS pod_signature_file_id uuid, - ADD COLUMN IF NOT EXISTS pod_photo_file_ids text[] NOT NULL DEFAULT '{}', - ADD COLUMN IF NOT EXISTS pod_notes text, - ADD COLUMN IF NOT EXISTS pod_captured_at timestamptz - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile - DROP COLUMN IF EXISTS pod_recipient_name, - DROP COLUMN IF EXISTS pod_signature_file_id, - DROP COLUMN IF EXISTS pod_photo_file_ids, - DROP COLUMN IF EXISTS pod_notes, - DROP COLUMN IF EXISTS pod_captured_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2120000000000-AddScheduleWagonAllocationSnapshot.ts b/apps/edr-freight-api/src/migrations/2120000000000-AddScheduleWagonAllocationSnapshot.ts deleted file mode 100644 index 651c4ba13..000000000 --- a/apps/edr-freight-api/src/migrations/2120000000000-AddScheduleWagonAllocationSnapshot.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add a frozen wagon-allocation snapshot to each train schedule. - * - * Once a schedule leaves the editable DRAFT/SCHEDULED phase (dispatch / arrive / - * cancel), the same physical wagons get released and re-pinned onto later trains. - * The live wagon↔slot joins then no longer describe THIS train's plan, so an - * admin viewing a past schedule saw a mangled or "unavailable" allocation. - * - * This jsonb column stores a one-shot frozen copy of the wagon plan (per-slot - * physical wagon + booking allocations) captured at the transition. Non-editable - * schedules render from the snapshot; DRAFT/SCHEDULED still read live. NULL on - * legacy rows and while editable — the read path falls back to the live joins. - */ -export class AddScheduleWagonAllocationSnapshot2120000000000 - implements MigrationInterface -{ - name = "AddScheduleWagonAllocationSnapshot2120000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS wagon_allocation_snapshot jsonb; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS wagon_allocation_snapshot; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2130000000000-AddHandoverSignerName.ts b/apps/edr-freight-api/src/migrations/2130000000000-AddHandoverSignerName.ts deleted file mode 100644 index 4e4c5f5fc..000000000 --- a/apps/edr-freight-api/src/migrations/2130000000000-AddHandoverSignerName.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * The person who signs off a handover must record their full name (a signature - * is optional, especially for self-haul). Stored per handover record. - */ -export class AddHandoverSignerName2130000000000 implements MigrationInterface { - name = "AddHandoverSignerName2130000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_handovers - ADD COLUMN IF NOT EXISTS signer_name varchar(160) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_handovers - DROP COLUMN IF EXISTS signer_name - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2140000000000-CreateAccrualAcks.ts b/apps/edr-freight-api/src/migrations/2140000000000-CreateAccrualAcks.ts deleted file mode 100644 index 5e13a6e3d..000000000 --- a/apps/edr-freight-api/src/migrations/2140000000000-CreateAccrualAcks.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Accrual alert acknowledgements: ops can mark an in-warehouse item's fee - * accrual as reviewed (optionally snoozed until a date) so it stops nudging and - * drops down the accrual dashboard. One row per inventory item. - */ -export class CreateAccrualAcks2140000000000 implements MigrationInterface { - name = "CreateAccrualAcks2140000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_accrual_acks ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - inventory_id uuid NOT NULL UNIQUE, - acknowledged_by uuid, - acknowledged_at timestamptz NOT NULL DEFAULT now(), - snooze_until timestamptz, - note text, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now() - ) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.warehouse_accrual_acks`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2150000000000-TrainBuilder.ts b/apps/edr-freight-api/src/migrations/2150000000000-TrainBuilder.ts deleted file mode 100644 index 24fa50feb..000000000 --- a/apps/edr-freight-api/src/migrations/2150000000000-TrainBuilder.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Train Builder: a `Train` becomes a first-class buildable consist — a coded - * train (e.g. 81001) assembled in one yard from 2+ locomotives and ordered - * wagons, then reused by scheduling ("schedule the train" instead of picking - * locomotives per departure). - * - * - `freight.train_locomotives` — link table train ⇄ locomotive with an order - * index (mirrors `train_set_locomotives`). - * - `trains.current_yard_id` — yard the train sits in; wagons/locomotives may - * only be attached from this yard. - * - `train_sets.train_id` — which built train an operational set was formed - * from, so schedules can surface the train code and the lifecycle can sync - * the train's status/yard on dispatch/arrival/cancel. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. IF NOT EXISTS keeps that idempotent. - */ -export class TrainBuilder2150000000000 implements MigrationInterface { - name = 'TrainBuilder2150000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.train_locomotives ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - train_id uuid NOT NULL, - locomotive_id uuid NOT NULL, - sequence_no int NOT NULL DEFAULT 0, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT "PK_train_locomotives" PRIMARY KEY (id), - CONSTRAINT "FK_train_locomotives_train" FOREIGN KEY (train_id) - REFERENCES freight.trains (id) ON DELETE CASCADE, - CONSTRAINT "FK_train_locomotives_locomotive" FOREIGN KEY (locomotive_id) - REFERENCES freight.locomotives (id) - ); - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_train_locomotives_train_loco" - ON freight.train_locomotives (train_id, locomotive_id); - `); - - await queryRunner.query(` - ALTER TABLE freight.trains - ADD COLUMN IF NOT EXISTS current_yard_id uuid; - `); - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_trains_current_yard' - ) THEN - ALTER TABLE freight.trains - ADD CONSTRAINT "FK_trains_current_yard" FOREIGN KEY (current_yard_id) - REFERENCES freight.yards (id) ON DELETE SET NULL; - END IF; - END $$; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_trains_current_yard_id" - ON freight.trains (current_yard_id); - `); - - await queryRunner.query(` - ALTER TABLE freight.train_sets - ADD COLUMN IF NOT EXISTS train_id uuid; - `); - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FK_train_sets_train' - ) THEN - ALTER TABLE freight.train_sets - ADD CONSTRAINT "FK_train_sets_train" FOREIGN KEY (train_id) - REFERENCES freight.trains (id) ON DELETE SET NULL; - END IF; - END $$; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_train_sets_train_id" - ON freight.train_sets (train_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_train_sets_train_id";`); - await queryRunner.query(` - ALTER TABLE freight.train_sets - DROP CONSTRAINT IF EXISTS "FK_train_sets_train", - DROP COLUMN IF EXISTS train_id; - `); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_trains_current_yard_id";`); - await queryRunner.query(` - ALTER TABLE freight.trains - DROP CONSTRAINT IF EXISTS "FK_trains_current_yard", - DROP COLUMN IF EXISTS current_yard_id; - `); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_train_locomotives_train_loco";`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.train_locomotives;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2160000000000-MultiWagonTypePerCargoAndContainer.ts b/apps/edr-freight-api/src/migrations/2160000000000-MultiWagonTypePerCargoAndContainer.ts deleted file mode 100644 index 0fc391904..000000000 --- a/apps/edr-freight-api/src/migrations/2160000000000-MultiWagonTypePerCargoAndContainer.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * A container type / cargo type can now be carried by SEVERAL wagon types - * (e.g. a 20ft container rides NX70 or NW5). Replaces the single - * `wagon_type_id` FK on both tables with proper link tables; train scheduling - * resolves the wagon type from the list, picking whichever type the schedule's - * built train (or the yard) actually has. - * - * Backfills one link row from each existing `wagon_type_id`, then drops the - * old column — the single-FK field is removed from the API and UI entirely. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. IF NOT EXISTS keeps that idempotent. - */ -export class MultiWagonTypePerCargoAndContainer2160000000000 implements MigrationInterface { - name = 'MultiWagonTypePerCargoAndContainer2160000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.container_type_wagon_types ( - container_type_id uuid NOT NULL, - wagon_type_id uuid NOT NULL, - CONSTRAINT "PK_container_type_wagon_types" PRIMARY KEY (container_type_id, wagon_type_id), - CONSTRAINT "FK_ctwt_container_type" FOREIGN KEY (container_type_id) - REFERENCES freight.container_types (id) ON DELETE CASCADE, - CONSTRAINT "FK_ctwt_wagon_type" FOREIGN KEY (wagon_type_id) - REFERENCES freight.wagon_types (id) ON DELETE RESTRICT - ); - `); - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.cargo_type_wagon_types ( - cargo_type_id uuid NOT NULL, - wagon_type_id uuid NOT NULL, - CONSTRAINT "PK_cargo_type_wagon_types" PRIMARY KEY (cargo_type_id, wagon_type_id), - CONSTRAINT "FK_cgwt_cargo_type" FOREIGN KEY (cargo_type_id) - REFERENCES freight.cargo_types (id) ON DELETE CASCADE, - CONSTRAINT "FK_cgwt_wagon_type" FOREIGN KEY (wagon_type_id) - REFERENCES freight.wagon_types (id) ON DELETE RESTRICT - ); - `); - - // Backfill from the old single FK (column may already be gone on re-run). - await queryRunner.query(` - DO $$ - BEGIN - IF EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_schema = 'freight' AND table_name = 'container_types' - AND column_name = 'wagon_type_id' - ) THEN - INSERT INTO freight.container_type_wagon_types (container_type_id, wagon_type_id) - SELECT ct.id, ct.wagon_type_id - FROM freight.container_types ct - WHERE ct.wagon_type_id IS NOT NULL - ON CONFLICT DO NOTHING; - END IF; - END $$; - `); - await queryRunner.query(` - DO $$ - BEGIN - IF EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_schema = 'freight' AND table_name = 'cargo_types' - AND column_name = 'wagon_type_id' - ) THEN - INSERT INTO freight.cargo_type_wagon_types (cargo_type_id, wagon_type_id) - SELECT cg.id, cg.wagon_type_id - FROM freight.cargo_types cg - WHERE cg.wagon_type_id IS NOT NULL - ON CONFLICT DO NOTHING; - END IF; - END $$; - `); - - // Old single-FK column is fully retired (API + UI now use the lists). - await queryRunner.query(` - ALTER TABLE freight.container_types DROP COLUMN IF EXISTS wagon_type_id; - `); - await queryRunner.query(` - ALTER TABLE freight.cargo_types DROP COLUMN IF EXISTS wagon_type_id; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.container_types ADD COLUMN IF NOT EXISTS wagon_type_id uuid - REFERENCES freight.wagon_types (id) ON DELETE RESTRICT; - `); - await queryRunner.query(` - ALTER TABLE freight.cargo_types ADD COLUMN IF NOT EXISTS wagon_type_id uuid - REFERENCES freight.wagon_types (id) ON DELETE RESTRICT; - `); - // Restore the first linked wagon type per row, then drop the link tables. - await queryRunner.query(` - UPDATE freight.container_types ct - SET wagon_type_id = link.wagon_type_id - FROM ( - SELECT DISTINCT ON (container_type_id) container_type_id, wagon_type_id - FROM freight.container_type_wagon_types - ORDER BY container_type_id, wagon_type_id - ) link - WHERE link.container_type_id = ct.id; - `); - await queryRunner.query(` - UPDATE freight.cargo_types cg - SET wagon_type_id = link.wagon_type_id - FROM ( - SELECT DISTINCT ON (cargo_type_id) cargo_type_id, wagon_type_id - FROM freight.cargo_type_wagon_types - ORDER BY cargo_type_id, wagon_type_id - ) link - WHERE link.cargo_type_id = cg.id; - `); - await queryRunner.query(`DROP TABLE IF EXISTS freight.container_type_wagon_types;`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.cargo_type_wagon_types;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2170000000000-CreateWagonTransferRequests.ts b/apps/edr-freight-api/src/migrations/2170000000000-CreateWagonTransferRequests.ts deleted file mode 100644 index 2b73eaa0c..000000000 --- a/apps/edr-freight-api/src/migrations/2170000000000-CreateWagonTransferRequests.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Two-person wagon-transfer request queue. A requester records a count-only - * request (N wagons of a type, from yard → to yard); OCC staff later pick the - * physical wagons and execute the move. Replaces the single-step instant - * bulk-transfer as the customer-facing yard-to-yard relocation path. - */ -export class CreateWagonTransferRequests2170000000000 - implements MigrationInterface -{ - name = 'CreateWagonTransferRequests2170000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.wagon_transfer_requests ( - id uuid NOT NULL DEFAULT gen_random_uuid(), - from_yard_id uuid NOT NULL, - to_yard_id uuid NOT NULL, - wagon_type_id uuid NOT NULL, - quantity integer NOT NULL, - status varchar(20) NOT NULL DEFAULT 'PENDING', - requested_by_user_id uuid NULL, - fulfilled_by_user_id uuid NULL, - fulfilled_at timestamptz NULL, - note text NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz NULL, - CONSTRAINT pk_wagon_transfer_requests PRIMARY KEY (id), - CONSTRAINT fk_wtr_from_yard FOREIGN KEY (from_yard_id) REFERENCES freight.yards (id), - CONSTRAINT fk_wtr_to_yard FOREIGN KEY (to_yard_id) REFERENCES freight.yards (id), - CONSTRAINT fk_wtr_wagon_type FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types (id), - CONSTRAINT chk_wtr_quantity CHECK (quantity > 0) - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wtr_status_from_yard - ON freight.wagon_transfer_requests (status, from_yard_id) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight.idx_wtr_status_from_yard`, - ); - await queryRunner.query( - `DROP TABLE IF EXISTS freight.wagon_transfer_requests`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2170000000000-ScheduleWagonAdjustmentLogs.ts b/apps/edr-freight-api/src/migrations/2170000000000-ScheduleWagonAdjustmentLogs.ts deleted file mode 100644 index 7fecfccbb..000000000 --- a/apps/edr-freight-api/src/migrations/2170000000000-ScheduleWagonAdjustmentLogs.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Consist adjustments from a schedule: staff can trim free wagons off a built - * train when their tare pushes gross weight over the locomotives' pull limit - * (incl. overage tolerance), or couple extra yard wagons on while weight and - * length headroom remain. Each add/remove is logged here so the schedule keeps - * an auditable history; the built train itself is updated in place. - * - * Plain columns (no FKs) so the history survives wagon/train deletion. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. IF NOT EXISTS keeps that idempotent. - */ -export class ScheduleWagonAdjustmentLogs2170000000000 implements MigrationInterface { - name = 'ScheduleWagonAdjustmentLogs2170000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.schedule_wagon_adjustment_logs ( - id uuid NOT NULL DEFAULT uuid_generate_v4(), - train_schedule_id uuid NOT NULL, - train_id uuid NOT NULL, - action varchar(10) NOT NULL, - wagon_id uuid NOT NULL, - wagon_number varchar(50) NOT NULL, - adjusted_by_user_id uuid, - occurred_at timestamptz NOT NULL DEFAULT now(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - CONSTRAINT "PK_schedule_wagon_adjustment_logs" PRIMARY KEY (id) - ); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_swal_train_schedule_id" - ON freight.schedule_wagon_adjustment_logs (train_schedule_id); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_swal_train_id" - ON freight.schedule_wagon_adjustment_logs (train_id); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_swal_train_id";`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_swal_train_schedule_id";`); - await queryRunner.query(`DROP TABLE IF EXISTS freight.schedule_wagon_adjustment_logs;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2180000000000-LinkWagonMovementToTransferRequest.ts b/apps/edr-freight-api/src/migrations/2180000000000-LinkWagonMovementToTransferRequest.ts deleted file mode 100644 index 3f10fa874..000000000 --- a/apps/edr-freight-api/src/migrations/2180000000000-LinkWagonMovementToTransferRequest.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Link each physical wagon move back to the transfer request that drove it, so - * the history can show "Request S→K, 3× NX70 → wagons W101, W102, W103". - * Nullable — legacy moves and non-request manual corrections carry no request. - * Also indexes `moved_by_user_id` for the per-user history queries. - */ -export class LinkWagonMovementToTransferRequest2180000000000 - implements MigrationInterface -{ - name = 'LinkWagonMovementToTransferRequest2180000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_movements - ADD COLUMN IF NOT EXISTS transfer_request_id uuid NULL - `); - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'fk_wm_transfer_request' - ) THEN - ALTER TABLE freight.wagon_movements - ADD CONSTRAINT fk_wm_transfer_request - FOREIGN KEY (transfer_request_id) - REFERENCES freight.wagon_transfer_requests (id) ON DELETE SET NULL; - END IF; - END $$; - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wm_transfer_request - ON freight.wagon_movements (transfer_request_id) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_wm_moved_by - ON freight.wagon_movements (moved_by_user_id) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_wm_moved_by`); - await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_wm_transfer_request`); - await queryRunner.query(` - ALTER TABLE freight.wagon_movements - DROP CONSTRAINT IF EXISTS fk_wm_transfer_request - `); - await queryRunner.query(` - ALTER TABLE freight.wagon_movements - DROP COLUMN IF EXISTS transfer_request_id - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2190000000000-DropReopenDelayMinutes.ts b/apps/edr-freight-api/src/migrations/2190000000000-DropReopenDelayMinutes.ts deleted file mode 100644 index 5a667e2e4..000000000 --- a/apps/edr-freight-api/src/migrations/2190000000000-DropReopenDelayMinutes.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Drop the unused reopen-delay knob from the global rules. - * - * The window engine never honoured `reopen_delay_minutes`: a not-yet-full train - * reopens as soon as its payment phase settles, so the real gap between a cycle - * closing and reopening is doc review + payment — nothing else. The per-schedule - * `rule_reopen_delay_minutes` snapshot stays: it freezes that derived gap at - * creation so the batch board keeps projecting the cycles the customer was shown. - */ -export class DropReopenDelayMinutes2190000000000 implements MigrationInterface { - name = "DropReopenDelayMinutes2190000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - DROP COLUMN IF EXISTS reopen_delay_minutes; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ADD COLUMN IF NOT EXISTS reopen_delay_minutes integer NOT NULL DEFAULT 90; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2200000000000-TrainNumberPair.ts b/apps/edr-freight-api/src/migrations/2200000000000-TrainNumberPair.ts deleted file mode 100644 index 65a3d3cda..000000000 --- a/apps/edr-freight-api/src/migrations/2200000000000-TrainNumberPair.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Every built train owns a fixed pair of run numbers, typed at build time: - * an EXPORT number (odd, e.g. 8001) and an IMPORT number (even, e.g. 8002). - * Scheduling copies the route-direction-matched number onto the schedule at - * creation; legacy trains with a null pair keep dispatch-time pool assignment. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. IF NOT EXISTS keeps that idempotent. - */ -export class TrainNumberPair2200000000000 implements MigrationInterface { - name = 'TrainNumberPair2200000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.trains - ADD COLUMN IF NOT EXISTS import_train_number varchar(20), - ADD COLUMN IF NOT EXISTS export_train_number varchar(20); - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_trains_import_train_number" - ON freight.trains (import_train_number) - WHERE import_train_number IS NOT NULL; - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_trains_export_train_number" - ON freight.trains (export_train_number) - WHERE export_train_number IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_trains_export_train_number";`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_trains_import_train_number";`); - await queryRunner.query(` - ALTER TABLE freight.trains - DROP COLUMN IF EXISTS export_train_number, - DROP COLUMN IF EXISTS import_train_number; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2210000000000-ScheduleScopedWagonPins.ts b/apps/edr-freight-api/src/migrations/2210000000000-ScheduleScopedWagonPins.ts deleted file mode 100644 index 42e8f1dc8..000000000 --- a/apps/edr-freight-api/src/migrations/2210000000000-ScheduleScopedWagonPins.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Schedule-scoped wagon pins. - * - * Wagon occupancy now lives ONLY on each schedule's own train_set_wagons slots - * (the per-schedule snapshot): pinning/releasing a wagon no longer mutates the - * Wagon entity, so the same physical wagon can serve many schedules (the July 17 - * and July 20 runs of one train both use its 50 wagons). The Wagon columns - * `current_train_schedule_id` / `train_set_wagon_id` keep only their physical - * meaning — "out on this DISPATCHED train right now" (stamped at dispatch, - * cleared at arrive/unload/cancel). - * - * This migration erases the legacy pin-time stamps left by the old flow: any - * wagon pointing at a schedule that is not currently DISPATCHED (or that no - * longer exists) gets its pointers cleared, and — when the old flow had parked - * it in ASSIGNED — its status returns to the pool semantics (ASSIGNED only - * while coupled to a built train, otherwise AVAILABLE). - */ -export class ScheduleScopedWagonPins2210000000000 implements MigrationInterface { - name = "ScheduleScopedWagonPins2210000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.wagons w - SET current_train_schedule_id = NULL, - train_set_wagon_id = NULL, - status = CASE - WHEN w.status = 'ASSIGNED' AND w.train_id IS NULL THEN 'AVAILABLE' - ELSE w.status - END - WHERE w.deleted_at IS NULL - AND w.current_train_schedule_id IS NOT NULL - AND NOT EXISTS ( - SELECT 1 - FROM freight.train_schedules ts - WHERE ts.id = w.current_train_schedule_id - AND ts.deleted_at IS NULL - AND ts.status = 'DISPATCHED' - ); - `); - } - - public async down(_queryRunner: QueryRunner): Promise { - // Pin-time stamps cannot be reconstructed (the data was the bug); the - // slots on train_set_wagons still hold every live pin, so down is a no-op. - } -} diff --git a/apps/edr-freight-api/src/migrations/2220000000000-AddContractDocumentSnapshot.ts b/apps/edr-freight-api/src/migrations/2220000000000-AddContractDocumentSnapshot.ts deleted file mode 100644 index 5a8cdd035..000000000 --- a/apps/edr-freight-api/src/migrations/2220000000000-AddContractDocumentSnapshot.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds freight.contracts.document_snapshot — a per-contract frozen copy of the - * contract-document template (articles + WHEREAS recitals) captured at staff - * accept. Staff can edit these articles for a single contract before generating - * its PDF; the edit never touches the shared six freight.contract_templates - * rows. Null on existing contracts → the PDF keeps rendering from the live - * template, so this is backward compatible. - */ -export class AddContractDocumentSnapshot2220000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.contracts - ADD COLUMN IF NOT EXISTS document_snapshot JSONB; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.contracts - DROP COLUMN IF EXISTS document_snapshot; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2230000000000-RenameWagonStatusRetiredToDetained.ts b/apps/edr-freight-api/src/migrations/2230000000000-RenameWagonStatusRetiredToDetained.ts deleted file mode 100644 index 2fe7c726d..000000000 --- a/apps/edr-freight-api/src/migrations/2230000000000-RenameWagonStatusRetiredToDetained.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Wagon status RETIRED is renamed DETAINED (wagons pulled from circulation). - * The column is a plain varchar, so this is a data-only rename. Vehicles keep - * their own RETIRED status — only freight.wagons rows are touched. - */ -export class RenameWagonStatusRetiredToDetained2230000000000 - implements MigrationInterface -{ - name = 'RenameWagonStatusRetiredToDetained2230000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.wagons SET status = 'DETAINED' WHERE status = 'RETIRED' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.wagons SET status = 'RETIRED' WHERE status = 'DETAINED' - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2240000000000-AddTransferRequestReason.ts b/apps/edr-freight-api/src/migrations/2240000000000-AddTransferRequestReason.ts deleted file mode 100644 index 76a59b0f7..000000000 --- a/apps/edr-freight-api/src/migrations/2240000000000-AddTransferRequestReason.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Every new wagon-transfer request must state WHY the wagons are needed; the - * reason is shown on the OCC request queue. Nullable in the DB — legacy rows - * predate the requirement; the DTO enforces it for new requests. - */ -export class AddTransferRequestReason2240000000000 implements MigrationInterface { - name = 'AddTransferRequestReason2240000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_transfer_requests - ADD COLUMN IF NOT EXISTS reason text NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_transfer_requests - DROP COLUMN IF EXISTS reason - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2250000000000-CreatePriorityRuleChangeRequests.ts b/apps/edr-freight-api/src/migrations/2250000000000-CreatePriorityRuleChangeRequests.ts deleted file mode 100644 index f93fc7c95..000000000 --- a/apps/edr-freight-api/src/migrations/2250000000000-CreatePriorityRuleChangeRequests.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Approval workflow for priority-rule changes: every create/update/delete of a - * priority config is filed here as a PENDING change request; an approver - * applies or rejects it. `payload` carries the proposed field values (null for - * DELETE), `priority_config_id` the target row (null for CREATE). - */ -export class CreatePriorityRuleChangeRequests2250000000000 - implements MigrationInterface -{ - name = 'CreatePriorityRuleChangeRequests2250000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.priority_rule_change_requests ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - action varchar(10) NOT NULL, - priority_config_id uuid NULL REFERENCES freight.priority_configs (id), - payload jsonb NULL, - status varchar(10) NOT NULL DEFAULT 'PENDING', - requested_by_user_id uuid NULL, - decided_by_user_id uuid NULL, - decided_at timestamptz NULL, - decision_note text NULL, - 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_prcr_status - ON freight.priority_rule_change_requests (status) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP TABLE IF EXISTS freight.priority_rule_change_requests`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2260000000000-AddClearanceFeePayment.ts b/apps/edr-freight-api/src/migrations/2260000000000-AddClearanceFeePayment.ts deleted file mode 100644 index c0dc2c818..000000000 --- a/apps/edr-freight-api/src/migrations/2260000000000-AddClearanceFeePayment.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Prepaid customs clearance service fee (Path B): - * - contract_rate_snapshots.is_clearance — flags the frozen CUSTOMS_CLEARANCE - * fee line so it is billed via its own clearance invoice and excluded from - * shipment booking totals; - * - contracts.clearance_fee_paid_at — when the ONE_TIME contract-level fee - * settled (gate: AWAITING_CLEARANCE_PAYMENT → AWAITING_CLEARANCE_DOCUMENTS); - * - bookings.clearance_fee_paid_at — when a GENERAL shipment-request instance's - * fee settled (gate: AWAITING_CLEARANCE_PAYMENT → AWAITING_DOCUMENTS). - * All nullable/defaulted — existing rows are untouched and keep today's flow. - */ -export class AddClearanceFeePayment2260000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.contract_rate_snapshots - ADD COLUMN IF NOT EXISTS is_clearance BOOLEAN NOT NULL DEFAULT FALSE; - `); - await queryRunner.query(` - ALTER TABLE freight.contracts - ADD COLUMN IF NOT EXISTS clearance_fee_paid_at TIMESTAMPTZ; - `); - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS clearance_fee_paid_at TIMESTAMPTZ; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS clearance_fee_paid_at; - `); - await queryRunner.query(` - ALTER TABLE freight.contracts - DROP COLUMN IF EXISTS clearance_fee_paid_at; - `); - await queryRunner.query(` - ALTER TABLE freight.contract_rate_snapshots - DROP COLUMN IF EXISTS is_clearance; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2260000000000-AddLastMileTruckArrivalDeparture.ts b/apps/edr-freight-api/src/migrations/2260000000000-AddLastMileTruckArrivalDeparture.ts deleted file mode 100644 index 052d46340..000000000 --- a/apps/edr-freight-api/src/migrations/2260000000000-AddLastMileTruckArrivalDeparture.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * EDR last-mile is multi-truck: a booking can be served by as many trucks as it - * has containers (bulk hauls until the tonnage is drawn down). Arrival/delivery - * were stamped once per `last_mile` record, so every truck shared one timestamp. - * These per-vehicle columns give each EDR truck its own arrival, leaving and - * weighed load — the same granularity self-haul trucks already have. - * - * Weights are TONNES (matching bookings.cargo_total_weight_vgm and the exit - * weighing UI). Named `*_tons` deliberately: the older - * customer_truck_assignments.gross_weight_kg is named kg but stores tonnes. - * All nullable — legacy rows predate per-truck tracking. - */ -export class AddLastMileTruckArrivalDeparture2260000000000 implements MigrationInterface { - name = 'AddLastMileTruckArrivalDeparture2260000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - ADD COLUMN IF NOT EXISTS arrived_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS departed_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS gross_weight_tons numeric(14, 3) NULL, - ADD COLUMN IF NOT EXISTS net_weight_tons numeric(14, 3) NULL - `); - - // A truck carries 1x40ft OR 2x20ft, so an EDR truck needs MORE than the one - // container the legacy scalar `container_number` can hold. Mirrors the - // self-haul customer_truck_containers child table. The scalar stays in place - // (synced to the first container) for backward compatibility. - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.last_mile_vehicle_containers ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - assignment_id uuid NOT NULL REFERENCES freight.last_mile_vehicle_assignments(id) ON DELETE CASCADE, - last_mile_id uuid NOT NULL, - container_number varchar(32) NOT NULL, - 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_last_mile_vehicle_containers_assignment" - ON freight.last_mile_vehicle_containers (assignment_id) - `); - // A container rides exactly one truck per delivery. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_last_mile_vehicle_container" - ON freight.last_mile_vehicle_containers (last_mile_id, container_number) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.last_mile_vehicle_containers`); - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - DROP COLUMN IF EXISTS arrived_at, - DROP COLUMN IF EXISTS departed_at, - DROP COLUMN IF EXISTS gross_weight_tons, - DROP COLUMN IF EXISTS net_weight_tons - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2260000000000-SeedEdrWagonFleetErNumbering.ts b/apps/edr-freight-api/src/migrations/2260000000000-SeedEdrWagonFleetErNumbering.ts deleted file mode 100644 index a651b8f60..000000000 --- a/apps/edr-freight-api/src/migrations/2260000000000-SeedEdrWagonFleetErNumbering.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Re-seed the EDR wagon fleet onto the official ER numbering. - * - * Supersedes SeedWagonsWithYardAssignment1784000000001, which seeded 500 wagons - * on a `-NNNN` scheme and wrote the status as 'Available' — mixed case - * that never matches WagonStatus.Available ('AVAILABLE'), so status filters - * silently returned nothing. This seed uses the enum value. - * - * Every wagon lands unassigned: current_yard_id NULL, status AVAILABLE. Wagon - * specs (capacity/length/tare) stay owned by wagon_types and are not touched — - * the types already exist and only the wagon↔type link is (re)established here. - */ -type FleetRow = { - code: string; - start: number; - end: number; - count: number; -}; - -/** Official fleet: 1100 wagons, ER0001–ER1100, contiguous across 10 types. */ -const FLEET: FleetRow[] = [ - { code: 'PW2', start: 1, end: 220, count: 220 }, - { code: 'CW4', start: 221, end: 330, count: 110 }, - { code: 'CW3', start: 331, end: 350, count: 20 }, - { code: 'KW2', start: 351, end: 370, count: 20 }, - { code: 'KW3', start: 371, end: 390, count: 20 }, - { code: 'NW5', start: 391, end: 940, count: 550 }, - { code: 'BW1', start: 941, end: 950, count: 10 }, - { code: 'GW2', start: 951, end: 1060, count: 110 }, - { code: 'NW6', start: 1061, end: 1080, count: 20 }, - { code: 'NW7', start: 1081, end: 1100, count: 20 }, -]; - -const wagonNumber = (sequence: number) => `ER${String(sequence).padStart(4, '0')}`; - -export class SeedEdrWagonFleetErNumbering2260000000000 implements MigrationInterface { - name = 'SeedEdrWagonFleetErNumbering2260000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Full replacement: the ER range is the fleet of record, so any wagon - // outside it is stale seed data. Safe to hard-delete — containers and - // train_set_wagons null their link, wagon_movements cascade. - await queryRunner.query(`DELETE FROM freight.wagons;`); - - // Deliberately does NOT create a unique index on wagon_number. It once did, - // to satisfy an ON CONFLICT clause that no longer exists (the DELETE above - // makes collisions impossible). Recreating the plain index here would undo - // WagonNumberPartialUnique2280000000000, which replaces it with a PARTIAL - // unique index so soft-deleted wagons stop reserving their number — this - // seeder is run directly by scripts/seed-edr-wagons.ts, which would - // otherwise resurrect the plain index on an already-migrated database. - - for (const row of FLEET) { - if (row.end - row.start + 1 !== row.count) { - throw new Error(`wagon_range_mismatch:${row.code}`); - } - - const [typeRecord] = await queryRunner.query( - `SELECT id FROM freight.wagon_types WHERE code = $1 AND deleted_at IS NULL LIMIT 1;`, - [row.code], - ); - - if (!typeRecord?.id) { - throw new Error(`wagon_type_missing:${row.code}`); - } - - // generate_series builds the range server-side — one round trip per type - // instead of 1100 individual INSERTs. No ON CONFLICT clause: every wagon - // was deleted above, so a plain INSERT cannot collide, and the clause would - // otherwise hard-require a unique index this table lacks on some envs. - await queryRunner.query( - ` - INSERT INTO freight.wagons ( - wagon_number, - wagon_type_id, - status, - current_yard_id, - train_id, - sequence_number, - notes, - train_set_wagon_id, - current_train_schedule_id - ) - SELECT - 'ER' || LPAD(seq::text, 4, '0'), - $1::uuid, - 'AVAILABLE', - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - FROM generate_series($2::int, $3::int) AS seq; - `, - [typeRecord.id, row.start, row.end], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM freight.wagons WHERE wagon_number BETWEEN $1 AND $2;`, - [wagonNumber(FLEET[0].start), wagonNumber(FLEET[FLEET.length - 1].end)], - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2270000000000-AddContainerReturnQuantity.ts b/apps/edr-freight-api/src/migrations/2270000000000-AddContainerReturnQuantity.ts deleted file mode 100644 index 4a37b5e98..000000000 --- a/apps/edr-freight-api/src/migrations/2270000000000-AddContainerReturnQuantity.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Adds freight.booking_container.return_quantity — how many units of a - * container line ship with the empty-container-return service (≤ quantity). - * Mirrors hazardous_quantity / reefer_quantity: captured per line at booking - * creation when the contract enables WITH_RETURN (container freight only) and - * drives the booking-level equipment_return flag that fires the WITH_RETURN - * pricing surcharge. - */ -export class AddContainerReturnQuantity2270000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_container - ADD COLUMN IF NOT EXISTS return_quantity SMALLINT NOT NULL DEFAULT 0; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_container - DROP COLUMN IF EXISTS return_quantity; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2270000000000-AddWagonTrainNumbers.ts b/apps/edr-freight-api/src/migrations/2270000000000-AddWagonTrainNumbers.ts deleted file mode 100644 index 7050c1c40..000000000 --- a/apps/edr-freight-api/src/migrations/2270000000000-AddWagonTrainNumbers.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-wagon EXPORT/IMPORT run numbers, editable from the wagon form. - * - * Nullable with no default: a wagon is not on a run until an operator says so. - * Mirrors the width of trains.export_train_number / trains.import_train_number - * (varchar 20) so the two stay comparable. - */ -export class AddWagonTrainNumbers2270000000000 implements MigrationInterface { - name = 'AddWagonTrainNumbers2270000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - ADD COLUMN IF NOT EXISTS export_train_number varchar(20), - ADD COLUMN IF NOT EXISTS import_train_number varchar(20); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagons - DROP COLUMN IF EXISTS export_train_number, - DROP COLUMN IF EXISTS import_train_number; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2280000000000-SeedWagonRunNumbers.ts b/apps/edr-freight-api/src/migrations/2280000000000-SeedWagonRunNumbers.ts deleted file mode 100644 index dae700883..000000000 --- a/apps/edr-freight-api/src/migrations/2280000000000-SeedWagonRunNumbers.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Assign EDR export/import run numbers to the wagon fleet. - * - * Runs AFTER SeedEdrWagonFleetErNumbering2260000000000, which recreates every - * wagon with NULL run numbers — so this must stay later in timestamp order. - * - * Source data below is the operator-supplied roster, kept verbatim rather than - * pre-resolved so its quirks stay visible: - * - ER0697 is listed twice under run 8101 (deduped here -> 49, not 50). - * - Four wagons are claimed by two runs each. A wagon holds a single run, so - * FIRST-LISTED WINS, which is why four runs land one short of their listed - * count: - * ER0484 8301 over 8401 - * ER0451 8401 over 8701 - * ER0887 8701 over 9001 - * ER0936 8801 over 8901 - * - * Wagons outside this roster (PW2 ER0001-0220 and ER0941-1100) keep NULL runs. - */ - -/** Odd EXPORT run (Ethiopia -> Djibouti) -> the wagons rostered to it. */ -const RUN_WAGONS: Record = { - '8001': [ - 'ER0744', 'ER0734', 'ER0791', 'ER0885', 'ER0410', 'ER0901', - 'ER0692', 'ER0784', 'ER0663', 'ER0547', 'ER0635', 'ER0840', - 'ER0660', 'ER0541', 'ER0850', 'ER0764', 'ER0786', 'ER0694', - 'ER0656', 'ER0432', 'ER0666', 'ER0879', 'ER0724', 'ER0868', - 'ER0835', 'ER0650', 'ER0926', 'ER0915', 'ER0858', 'ER0826', - 'ER0474', 'ER0539', 'ER0419', 'ER0695', 'ER0462', 'ER0825', - 'ER0820', 'ER0790', 'ER0905', 'ER0557', 'ER0712', 'ER0782', - 'ER0816', 'ER0447', 'ER0674', 'ER0424', 'ER0544', 'ER0519', - 'ER0479', 'ER0440', - ], - '8101': [ - 'ER0458', 'ER0600', 'ER0521', 'ER0559', 'ER0846', 'ER0459', - 'ER0863', 'ER0925', 'ER0746', 'ER0821', 'ER0914', 'ER0768', - 'ER0676', 'ER0470', 'ER0697', 'ER0697', 'ER0923', 'ER0937', - 'ER0431', 'ER0412', 'ER0254', 'ER0555', 'ER0527', 'ER0590', - 'ER0480', 'ER0723', 'ER0316', 'ER0800', 'ER0648', 'ER0435', - 'ER0844', 'ER0939', 'ER0747', 'ER0654', 'ER0752', 'ER0633', - 'ER0725', 'ER0567', 'ER0838', 'ER0920', 'ER0843', 'ER0520', - 'ER0646', 'ER0407', 'ER0515', 'ER0760', 'ER0703', 'ER0880', - 'ER0422', 'ER0852', - ], - '8201': [ - 'ER0322', 'ER0314', 'ER0274', 'ER0514', 'ER0505', 'ER0618', - 'ER0812', 'ER0776', 'ER0698', 'ER0662', 'ER0888', 'ER0625', - 'ER0568', 'ER0596', 'ER0918', 'ER0524', 'ER0684', 'ER0231', - 'ER0907', 'ER0445', 'ER0839', 'ER0430', 'ER0799', 'ER0464', - 'ER0491', 'ER0833', 'ER0855', 'ER0571', 'ER0452', 'ER0733', - 'ER0606', 'ER0822', 'ER0845', 'ER0771', 'ER0542', 'ER0588', - 'ER0443', 'ER0585', 'ER0624', 'ER0538', 'ER0642', 'ER0928', - 'ER0411', 'ER0794', 'ER0564', 'ER0906', 'ER0348', 'ER0236', - 'ER0933', 'ER0456', - ], - '8301': [ - 'ER0264', 'ER0691', 'ER0562', 'ER0686', 'ER0881', 'ER0780', - 'ER0400', 'ER0420', 'ER0475', 'ER0425', 'ER0396', 'ER0818', - 'ER0537', 'ER0917', 'ER0421', 'ER0766', 'ER0728', 'ER0485', - 'ER0830', 'ER0804', 'ER0935', 'ER0898', 'ER0577', 'ER0762', - 'ER0558', 'ER0612', 'ER0484', 'ER0566', 'ER0876', 'ER0528', - 'ER0292', 'ER0630', 'ER0761', 'ER0849', 'ER0578', 'ER0232', - 'ER0673', 'ER0870', 'ER0575', 'ER0250', 'ER0599', 'ER0622', - 'ER0801', 'ER0806', 'ER0594', 'ER0831', 'ER0513', - ], - '8401': [ - 'ER0616', 'ER0730', 'ER0415', 'ER0522', 'ER0454', 'ER0758', - 'ER0715', 'ER0658', 'ER0602', 'ER0649', 'ER0540', 'ER0434', - 'ER0678', 'ER0550', 'ER0402', 'ER0636', 'ER0500', 'ER0740', - 'ER0664', 'ER0397', 'ER0565', 'ER0704', 'ER0720', 'ER0787', - 'ER0884', 'ER0573', 'ER0755', 'ER0392', 'ER0739', 'ER0530', - 'ER0437', 'ER0484', 'ER0653', 'ER0502', 'ER0615', 'ER0563', - 'ER0641', 'ER0391', 'ER0789', 'ER0451', 'ER0819', 'ER0442', - 'ER0798', 'ER0729', 'ER0772', 'ER0940', 'ER0682', 'ER0614', - 'ER0561', 'ER0393', - ], - '8501': [ - 'ER0807', 'ER0289', 'ER0587', 'ER0902', 'ER0877', 'ER0748', - 'ER0837', 'ER0408', 'ER0307', 'ER0759', 'ER0847', 'ER0433', - 'ER0498', 'ER0492', 'ER0735', 'ER0503', 'ER0461', 'ER0508', - 'ER0243', 'ER0583', 'ER0924', 'ER0395', 'ER0707', 'ER0572', - 'ER0536', 'ER0796', 'ER0929', 'ER0713', 'ER0603', 'ER0814', - 'ER0756', 'ER0398', 'ER0853', 'ER0276', 'ER0405', 'ER0418', - 'ER0517', 'ER0919', 'ER0781', 'ER0516', 'ER0417', 'ER0702', - 'ER0857', 'ER0486', 'ER0637', 'ER0736', 'ER0859', 'ER0483', - 'ER0824', 'ER0640', 'ER0714', - ], - '8601': [ - 'ER0455', 'ER0930', 'ER0293', 'ER0294', 'ER0677', 'ER0808', - 'ER0785', 'ER0628', 'ER0545', 'ER0551', 'ER0644', 'ER0922', - 'ER0670', 'ER0864', 'ER0629', 'ER0306', 'ER0494', 'ER0496', - 'ER0679', 'ER0874', 'ER0921', 'ER0910', 'ER0621', 'ER0667', - 'ER0262', 'ER0774', 'ER0488', 'ER0300', 'ER0234', 'ER0711', - 'ER0605', 'ER0897', 'ER0841', 'ER0778', 'ER0769', 'ER0487', - 'ER0556', 'ER0526', 'ER0795', 'ER0268', 'ER0266', 'ER0257', - ], - '8701': [ - 'ER0263', 'ER0661', 'ER0282', 'ER0394', 'ER0423', 'ER0665', - 'ER0598', 'ER0909', 'ER0481', 'ER0854', 'ER0471', 'ER0582', - 'ER0671', 'ER0466', 'ER0788', 'ER0934', 'ER0683', 'ER0680', - 'ER0890', 'ER0531', 'ER0647', 'ER0823', 'ER0608', 'ER0900', - 'ER0467', 'ER0607', 'ER0554', 'ER0233', 'ER0911', 'ER0726', - 'ER0675', 'ER0291', 'ER0313', 'ER0619', 'ER0775', 'ER0705', - 'ER0548', 'ER0891', 'ER0560', 'ER0904', 'ER0429', 'ER0655', - 'ER0224', 'ER0700', 'ER0797', 'ER0706', 'ER0533', 'ER0861', - 'ER0580', 'ER0449', 'ER0409', 'ER0613', 'ER0645', 'ER0315', - 'ER0718', 'ER0553', 'ER0444', 'ER0593', 'ER0499', 'ER0693', - 'ER0525', 'ER0451', 'ER0634', 'ER0689', 'ER0878', 'ER0518', - 'ER0887', - ], - '8801': [ - 'ER0811', 'ER0652', 'ER0889', 'ER0886', 'ER0936', 'ER0476', - 'ER0832', 'ER0626', 'ER0669', 'ER0404', 'ER0546', 'ER0501', - 'ER0894', 'ER0460', 'ER0805', 'ER0465', 'ER0717', 'ER0601', - 'ER0751', 'ER0777', 'ER0504', 'ER0749', 'ER0827', 'ER0896', - 'ER0903', 'ER0591', 'ER0436', 'ER0552', 'ER0716', 'ER0895', - 'ER0463', 'ER0809', 'ER0473', 'ER0883', 'ER0569', 'ER0610', - 'ER0275', 'ER0333', 'ER0344', 'ER0469', - ], - '8901': [ - 'ER0913', 'ER0310', 'ER0873', 'ER0448', 'ER0763', 'ER0441', - 'ER0936', 'ER0767', 'ER0416', 'ER0413', 'ER0589', 'ER0453', - 'ER0507', 'ER0287', 'ER0414', 'ER0406', 'ER0584', 'ER0866', - 'ER0893', 'ER0627', 'ER0227', 'ER0403', 'ER0428', 'ER0908', - 'ER0349', 'ER0221', 'ER0271', 'ER0659', 'ER0765', 'ER0478', - 'ER0511', 'ER0506', 'ER0743', 'ER0512', 'ER0916', 'ER0497', - 'ER0643', 'ER0638', 'ER0468', 'ER0597', - ], - '9001': [ - 'ER0446', 'ER0802', 'ER0570', 'ER0836', 'ER0576', 'ER0672', - 'ER0631', 'ER0490', 'ER0851', 'ER0450', 'ER0872', 'ER0912', - 'ER0815', 'ER0882', 'ER0738', 'ER0899', 'ER0620', 'ER0399', - 'ER0685', 'ER0477', 'ER0842', 'ER0529', 'ER0617', 'ER0865', - 'ER0754', 'ER0737', 'ER0753', 'ER0732', 'ER0623', 'ER0574', - 'ER0803', 'ER0651', 'ER0489', 'ER0668', 'ER0741', 'ER0699', - 'ER0592', 'ER0225', 'ER0229', 'ER0298', 'ER0270', 'ER0259', - 'ER0337', 'ER0770', 'ER0327', 'ER0251', 'ER0285', 'ER0927', - 'ER0810', 'ER0681', 'ER0887', - ], -}; - -/** - * Even IMPORT run (Djibouti -> Ethiopia) for each export run. Listed rather - * than computed as export+1 so a run that ever breaks the convention stays - * correct. Run numbers are always 4 digits (8401, never 84001). - */ -const IMPORT_RUN: Record = { - '8001': '8002', - '8101': '8102', - '8201': '8202', - '8301': '8302', - '8401': '8402', - '8501': '8502', - '8601': '8602', - '8701': '8702', - '8801': '8802', - '8901': '8902', - '9001': '9002', -}; - -export class SeedWagonRunNumbers2280000000000 implements MigrationInterface { - name = 'SeedWagonRunNumbers2280000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Idempotent: clear the roster's runs first so a re-run cannot leave a - // wagon on a run it was since moved off of. - await queryRunner.query(` - UPDATE freight.wagons - SET export_train_number = NULL, import_train_number = NULL - WHERE export_train_number IS NOT NULL; - `); - - const claimed = new Set(); - - for (const [exportRun, wagons] of Object.entries(RUN_WAGONS)) { - const importRun = IMPORT_RUN[exportRun]; - if (!importRun) throw new Error(`import_run_missing:${exportRun}`); - - // First-listed wins — skip any wagon an earlier run already claimed. - const fresh = wagons.filter((w) => !claimed.has(w)); - fresh.forEach((w) => claimed.add(w)); - if (!fresh.length) continue; - - await queryRunner.query( - ` - UPDATE freight.wagons - SET export_train_number = $1, - import_train_number = $2, - updated_at = now() - WHERE wagon_number = ANY($3::text[]); - `, - [exportRun, importRun, fresh], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.wagons - SET export_train_number = NULL, import_train_number = NULL - WHERE export_train_number IS NOT NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2280000000000-WagonNumberPartialUnique.ts b/apps/edr-freight-api/src/migrations/2280000000000-WagonNumberPartialUnique.ts deleted file mode 100644 index f28c81317..000000000 --- a/apps/edr-freight-api/src/migrations/2280000000000-WagonNumberPartialUnique.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Wagons are now soft-deleted (deleted_at) instead of hard-deleted. The plain - * UNIQUE on wagon_number would keep a retired wagon's number reserved forever - * and block ever re-registering that number. Swap it for a PARTIAL unique index - * that only constrains live rows (deleted_at IS NULL); soft-deleted wagons no - * longer occupy their number. - * - * NOTE: the shared dev DB has no applied migration history, so this is also - * hand-applied there. The DO blocks + IF EXISTS/IF NOT EXISTS keep it - * idempotent whether the original uniqueness is the auto-named column - * constraint (wagons_wagon_number_key) or a TypeORM-named UQ_* constraint/index. - */ -export class WagonNumberPartialUnique2280000000000 implements MigrationInterface { - name = 'WagonNumberPartialUnique2280000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Drop any UNIQUE constraint on freight.wagons(wagon_number), whatever it is - // named (dropping the constraint also drops its backing index). - await queryRunner.query(` - DO $$ - DECLARE con_name text; - BEGIN - FOR con_name IN - SELECT conname - FROM pg_constraint - WHERE conrelid = 'freight.wagons'::regclass - AND contype = 'u' - AND pg_get_constraintdef(oid) ILIKE '%(wagon_number)%' - LOOP - EXECUTE format('ALTER TABLE freight.wagons DROP CONSTRAINT IF EXISTS %I', con_name); - END LOOP; - END $$; - `); - - // Drop any standalone (non-partial) unique index on wagon_number too. - await queryRunner.query(` - DO $$ - DECLARE idx_name text; - BEGIN - FOR idx_name IN - SELECT c.relname - FROM pg_index i - JOIN pg_class c ON c.oid = i.indexrelid - WHERE i.indrelid = 'freight.wagons'::regclass - AND i.indisunique - AND i.indpred IS NULL - AND c.relname <> 'UQ_wagons_wagon_number_active' - AND pg_get_indexdef(i.indexrelid) ILIKE '%(wagon_number)%' - LOOP - EXECUTE format('DROP INDEX IF EXISTS freight.%I', idx_name); - END LOOP; - END $$; - `); - - // Live wagon numbers stay unique; soft-deleted rows are exempt. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_wagons_wagon_number_active" - ON freight.wagons (wagon_number) - WHERE deleted_at IS NULL; - `); - } - - public async down(): Promise { - // No-op: re-adding a plain UNIQUE would fail whenever two soft-deleted - // wagons share a number, and the partial index is strictly safer. Left in - // place intentionally. - } -} diff --git a/apps/edr-freight-api/src/migrations/2290000000000-DropContainerWagonsPerUnit.ts b/apps/edr-freight-api/src/migrations/2290000000000-DropContainerWagonsPerUnit.ts deleted file mode 100644 index ed66c37d3..000000000 --- a/apps/edr-freight-api/src/migrations/2290000000000-DropContainerWagonsPerUnit.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * container_types.wagons_per_unit is no longer stored: the wagon fraction is - * derived from size_ft everywhere (40ft = 1.00 wagon, 20ft = 0.50 — two per - * wagon; see rule-engine/container-type.util.ts). The stored value duplicated - * that rule and could silently drift from it. - */ -export class DropContainerWagonsPerUnit2290000000000 implements MigrationInterface { - name = 'DropContainerWagonsPerUnit2290000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.container_types DROP COLUMN IF EXISTS wagons_per_unit; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.container_types - ADD COLUMN IF NOT EXISTS wagons_per_unit numeric(4,2); - `); - // Backfill from the same size rule the code now derives from. - await queryRunner.query(` - UPDATE freight.container_types - SET wagons_per_unit = CASE WHEN size_ft >= 40 THEN 1.00 ELSE 0.50 END; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2290000000000-SeedWagonYardDoraleh.ts b/apps/edr-freight-api/src/migrations/2290000000000-SeedWagonYardDoraleh.ts deleted file mode 100644 index 7e12efdbb..000000000 --- a/apps/edr-freight-api/src/migrations/2290000000000-SeedWagonYardDoraleh.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Stand the whole wagon fleet in Doraleh. - * - * Runs AFTER SeedEdrWagonFleetErNumbering2260000000000, which recreates every - * wagon with a NULL yard — so this must stay later in timestamp order. - * - * A wagon with no yard cannot be coupled to a train (the train builder only - * offers AVAILABLE wagons standing in the train's own yard), which left the - * seeded fleet unusable. Doraleh is the Djibouti-side port yard the import runs - * originate from. - * - * The yard is created when absent: environments disagree about which yards - * exist, so this cannot assume one is there. - */ -const YARD_CODE = 'DORALEH'; - -export class SeedWagonYardDoraleh2290000000000 implements MigrationInterface { - name = 'SeedWagonYardDoraleh2290000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Ensure the yard exists and is usable. Deliberately does NOT overwrite an - // existing label/country — a deployment that already calls this yard - // something else keeps its own naming. - await queryRunner.query( - ` - INSERT INTO freight.yards (code, label, country, is_active, display_order) - VALUES ($1, 'Doraleh', 'Djibouti', true, 12) - ON CONFLICT (code) DO UPDATE SET - is_active = true, - deleted_at = NULL, - updated_at = now(); - `, - [YARD_CODE], - ); - - const [yard] = await queryRunner.query( - `SELECT id FROM freight.yards WHERE code = $1 AND deleted_at IS NULL LIMIT 1;`, - [YARD_CODE], - ); - - if (!yard?.id) { - throw new Error(`yard_missing:${YARD_CODE}`); - } - - // Whole fleet — a wagon already coupled to a built train follows the train, - // so leave those where they stand. - await queryRunner.query( - ` - UPDATE freight.wagons - SET current_yard_id = $1::uuid, - updated_at = now() - WHERE train_id IS NULL; - `, - [yard.id], - ); - } - - public async down(queryRunner: QueryRunner): Promise { - // Back to the state SeedEdrWagonFleetErNumbering leaves them in. - await queryRunner.query(` - UPDATE freight.wagons - SET current_yard_id = NULL - WHERE train_id IS NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2290000000000-YardFacilities.ts b/apps/edr-freight-api/src/migrations/2290000000000-YardFacilities.ts deleted file mode 100644 index 620eebc14..000000000 --- a/apps/edr-freight-api/src/migrations/2290000000000-YardFacilities.ts +++ /dev/null @@ -1,85 +0,0 @@ -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 - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2300000000000-CreateRateChangeRequests.ts b/apps/edr-freight-api/src/migrations/2300000000000-CreateRateChangeRequests.ts deleted file mode 100644 index a3e36f0b9..000000000 --- a/apps/edr-freight-api/src/migrations/2300000000000-CreateRateChangeRequests.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Approval workflow for edits to LIVE rates. A LIVE rate is what pricing - * charges, so it is never edited in place: the edit is filed here as PENDING - * and the live row keeps its value until an approver applies it. - * - * `payload` holds the changed fields only; `previous_values` snapshots what - * they were at submit time so the approver sees a real before→after diff. - */ -export class CreateRateChangeRequests2300000000000 implements MigrationInterface { - name = 'CreateRateChangeRequests2300000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.rate_change_requests ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - rate_id uuid NOT NULL REFERENCES freight.rates (id), - payload jsonb NOT NULL, - previous_values jsonb NOT NULL, - status varchar(10) NOT NULL DEFAULT 'PENDING', - requested_by_user_id uuid NULL, - decided_by_user_id uuid NULL, - decided_at timestamptz NULL, - decision_note text NULL, - 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_rcr_status - ON freight.rate_change_requests (status) - `); - // At most one pending edit per rate — two racing requests would both pass - // validation and the second would silently overwrite the first on approval. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS uq_rcr_one_pending_per_rate - ON freight.rate_change_requests (rate_id) - WHERE status = 'PENDING' AND deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.rate_change_requests`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2300000000000-RepairGpsTrackingTables.ts b/apps/edr-freight-api/src/migrations/2300000000000-RepairGpsTrackingTables.ts deleted file mode 100644 index f4628db36..000000000 --- a/apps/edr-freight-api/src/migrations/2300000000000-RepairGpsTrackingTables.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Repair for environments missing the GPS tracking tables. - * - * AddGpsTracking2000000000000 creates freight.gps_devices / gps_positions, but - * some databases have it RECORDED in public.migrations without the tables ever - * landing. TypeORM never re-runs a recorded migration, so those environments - * stay broken through any number of restarts — the GT06 listener accepts tracker - * packets on its TCP port regardless of schema state and fails per packet with - * `relation "freight.gps_devices" does not exist`, dropping position fixes. - * - * This re-issues the same DDL under a new name so it is applied afresh. Every - * statement is IF NOT EXISTS, so it is a no-op where the tables already exist - * and safe on every environment. - * - * Kept byte-identical to the original DDL on purpose: this must converge on the - * schema the entities expect, not a variant of it. - */ -export class RepairGpsTrackingTables2300000000000 implements MigrationInterface { - name = "RepairGpsTrackingTables2300000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.gps_devices ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - imei varchar(20) NOT NULL UNIQUE, - name varchar, - vehicle_id uuid REFERENCES freight.vehicles(id), - status varchar(16) NOT NULL DEFAULT 'REGISTERED', - last_seen_at timestamptz, - last_lat numeric(10,6), - last_lng numeric(10,6), - last_speed numeric(6,2), - last_course int, - last_fix_at timestamptz, - voltage_level int, - gsm_level int, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_DEVICES_VEHICLE" - ON freight.gps_devices (vehicle_id) - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.gps_positions ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - device_id uuid NOT NULL, - imei varchar(20) NOT NULL, - vehicle_id uuid, - lat numeric(10,6) NOT NULL, - lng numeric(10,6) NOT NULL, - speed numeric(6,2) NOT NULL DEFAULT 0, - course int NOT NULL DEFAULT 0, - satellites int NOT NULL DEFAULT 0, - positioned boolean NOT NULL DEFAULT false, - gps_time timestamptz NOT NULL, - alarm int NOT NULL DEFAULT 0, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_POSITIONS_DEVICE_TIME" - ON freight.gps_positions (device_id, gps_time) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_GPS_POSITIONS_VEHICLE_TIME" - ON freight.gps_positions (vehicle_id, gps_time) - `); - } - - public async down(): Promise { - // No-op: dropping the tables would discard tracker history on environments - // where this migration was the one that created them. AddGpsTracking owns - // the teardown. - } -} diff --git a/apps/edr-freight-api/src/migrations/2310000000000-CreateSupportChat.ts b/apps/edr-freight-api/src/migrations/2310000000000-CreateSupportChat.ts deleted file mode 100644 index 17db8a4e1..000000000 --- a/apps/edr-freight-api/src/migrations/2310000000000-CreateSupportChat.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Customer-support chat. A `support_conversations` row is the single ongoing - * thread with a company; `support_messages` are its text messages. There is no - * lifecycle column — a thread is opened by whichever side speaks first and - * stays open. Enum-like columns are varchar (no PG enum churn). - * - * The unique index on `company_id` is load-bearing, not just an optimization: - * the get-or-create path depends on it to settle concurrent first-messages. - * It is partial on `deleted_at IS NULL` so a soft-deleted thread doesn't block - * a fresh one. - */ -export class CreateSupportChat2310000000000 implements MigrationInterface { - name = "CreateSupportChat2310000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.support_conversations ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - company_id uuid NOT NULL, - company_name varchar(200), - created_by_user_id uuid, - last_message_at timestamptz, - last_message_preview varchar(280), - last_message_author_role varchar(12), - customer_last_read_at timestamptz, - agent_last_read_at timestamptz, - 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_SUPPORT_CONV_COMPANY" - ON freight.support_conversations (company_id) - WHERE deleted_at IS NULL - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_SUPPORT_CONV_LASTMSG" - ON freight.support_conversations (last_message_at) - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.support_messages ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - conversation_id uuid NOT NULL, - author_user_id uuid NOT NULL, - author_role varchar(12) NOT NULL, - author_name varchar(200), - body text NOT NULL, - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz - ) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_SUPPORT_MSG_CONV_CREATED" - ON freight.support_messages (conversation_id, created_at) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_SUPPORT_MSG_CONV_CREATED"`, - ); - await queryRunner.query(`DROP TABLE IF EXISTS freight.support_messages`); - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_SUPPORT_CONV_LASTMSG"`, - ); - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_SUPPORT_CONV_COMPANY"`, - ); - await queryRunner.query( - `DROP TABLE IF EXISTS freight.support_conversations`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2320000000000-AddRateYardScope.ts b/apps/edr-freight-api/src/migrations/2320000000000-AddRateYardScope.ts deleted file mode 100644 index 8e693cf2a..000000000 --- a/apps/edr-freight-api/src/migrations/2320000000000-AddRateYardScope.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Scope base rail freight to a route (origin yard → destination yard). - * - * Until now a base-freight rate was keyed by direction + container/bulk scope - * only, so "container import" cost the same whether the box was railed to Dire - * Dawa or to Mojo. Rates now carry the yard pair the price is quoted for, which - * is what the business actually sells: `container import, Djibouti → Dire Dawa, - * 500 USD`. - * - * Existing base-freight rates predate the yard pair and cannot be backfilled — - * there is no way to know which route each was meant for. They are retired - * (SUPERSEDED + soft-deleted) rather than deleted, because booking_rate_snapshot - * and rate_change_requests hold FKs to them (RESTRICT) and those rows are price - * history. Retiring drops them out of pricing and the admin UI just the same; - * the yard-scoped replacements must be re-entered. - * - * Surcharges, first-mile and last-mile rates are untouched: they are not - * route-scoped and keep NULL yards. - */ -export class AddRateYardScope2320000000000 implements MigrationInterface { - name = 'AddRateYardScope2320000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // ── 1. Yard columns + FKs ────────────────────────────────────────────── - await queryRunner.query(` - ALTER TABLE freight.rates - ADD COLUMN IF NOT EXISTS origin_yard_id uuid NULL, - ADD COLUMN IF NOT EXISTS destination_yard_id uuid NULL; - `); - - await queryRunner.query(` - DO $$ BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'FK_rates_origin_yard_id') THEN - ALTER TABLE freight.rates - ADD CONSTRAINT "FK_rates_origin_yard_id" - FOREIGN KEY (origin_yard_id) REFERENCES freight.yards(id); - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'FK_rates_destination_yard_id') THEN - ALTER TABLE freight.rates - ADD CONSTRAINT "FK_rates_destination_yard_id" - FOREIGN KEY (destination_yard_id) REFERENCES freight.yards(id); - END IF; - END $$; - `); - - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_rates_origin_yard_id" ON freight.rates (origin_yard_id);`, - ); - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS "IDX_rates_destination_yard_id" ON freight.rates (destination_yard_id);`, - ); - - // ── 2. Retire route-less base freight ────────────────────────────────── - // Soft-delete, not DELETE: booking_rate_snapshot.rate_id is ON DELETE - // RESTRICT and those snapshots are what past bookings were charged. - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND "trigger" = 'ALWAYS' - AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY'); - `); - - // ── 3. Route is part of a rate's identity ────────────────────────────── - // Two rates may now share rateType + scope + unit as long as they price - // different legs, so the yard pair joins the uniqueness tuple. - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_rates_pattern";`); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_rates_pattern" - ON freight.rates ( - rate_type, - COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(trade_direction, ''), - COALESCE(origin_yard_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(destination_yard_id, '00000000-0000-0000-0000-000000000000'::uuid), - rate_unit - ) - WHERE deleted_at IS NULL AND status <> 'SUPERSEDED'; - `); - - // ── 4. Base freight must carry a route; nothing else may ─────────────── - // Retired rows are exempt — they are the route-less rates step 2 just - // superseded, and they must stay readable for snapshot history. - await queryRunner.query(` - DO $$ BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'CK_rates_yard_scope') THEN - ALTER TABLE freight.rates - ADD CONSTRAINT "CK_rates_yard_scope" CHECK ( - deleted_at IS NOT NULL - OR status = 'SUPERSEDED' - OR CASE - WHEN "trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY') - THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL - ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL - END - ); - END IF; - END $$; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // The retired rates are not un-superseded: which route each belonged to was - // never recorded, so reviving them would restore rates that price the wrong - // legs. Down only reverses the schema. - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";`, - ); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_rates_pattern";`); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_rates_pattern" - ON freight.rates ( - rate_type, - COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid), - COALESCE(trade_direction, ''), - rate_unit - ) - WHERE deleted_at IS NULL AND status <> 'SUPERSEDED'; - `); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_rates_destination_yard_id";`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_rates_origin_yard_id";`); - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "FK_rates_destination_yard_id";`, - ); - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "FK_rates_origin_yard_id";`, - ); - await queryRunner.query(` - ALTER TABLE freight.rates - DROP COLUMN IF EXISTS destination_yard_id, - DROP COLUMN IF EXISTS origin_yard_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2320000000000-SupportChatAttachments.ts b/apps/edr-freight-api/src/migrations/2320000000000-SupportChatAttachments.ts deleted file mode 100644 index 1f383f1da..000000000 --- a/apps/edr-freight-api/src/migrations/2320000000000-SupportChatAttachments.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Let a support message carry files instead of text. - * - * No new table: chat attachments reuse the polymorphic `freight.files` record - * with `resource = 'support_message'` and `resource_id = `, the same - * way bookings/contracts/companies already store theirs. - * - * The only schema change is dropping NOT NULL from `support_messages.body`, so - * an attachment-only message can say "there is no text" rather than smuggling - * that fact through an empty string. DROP NOT NULL is a catalog-only change in - * Postgres — no table rewrite, no long lock — so this is safe on a live table. - * - * The partial index on (resource, resource_id) is what makes hydrating a page of - * messages one indexed lookup instead of a scan of every file row in the system. - */ -export class SupportChatAttachments2320000000000 implements MigrationInterface { - name = "SupportChatAttachments2320000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.support_messages - ALTER COLUMN body DROP NOT NULL - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_FILES_RESOURCE_LOOKUP" - ON freight.files (resource, resource_id) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DROP INDEX IF EXISTS freight."IDX_FILES_RESOURCE_LOOKUP" - `); - - // Re-imposing NOT NULL would fail on any attachment-only message written - // while this migration was applied. Backfill those to '' first so the - // rollback is deterministic rather than dependent on production data. - await queryRunner.query(` - UPDATE freight.support_messages SET body = '' WHERE body IS NULL - `); - await queryRunner.query(` - ALTER TABLE freight.support_messages - ALTER COLUMN body SET NOT NULL - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2320000000000-YardFacilityFreightTypes.ts b/apps/edr-freight-api/src/migrations/2320000000000-YardFacilityFreightTypes.ts deleted file mode 100644 index d6e7ae273..000000000 --- a/apps/edr-freight-api/src/migrations/2320000000000-YardFacilityFreightTypes.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * A facility handles what its equipment can handle. Containers need a reach - * stacker or gantry, so only Indode, Modjo and Dire Dawa take them; bulk needs - * far less, so all five facilities load and unload it. - * - * Both default true — a facility handles everything unless someone says - * otherwise, which keeps existing rows working and makes the seeder the place - * where the real capability is stated. - */ -export class YardFacilityFreightTypes2320000000000 implements MigrationInterface { - name = 'YardFacilityFreightTypes2320000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.yard_facilities - ADD COLUMN IF NOT EXISTS handles_container boolean NOT NULL DEFAULT true, - ADD COLUMN IF NOT EXISTS handles_bulk boolean NOT NULL DEFAULT true - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.yard_facilities - DROP COLUMN IF EXISTS handles_container, - DROP COLUMN IF EXISTS handles_bulk - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2330000000000-AddBookingCloseOffset.ts b/apps/edr-freight-api/src/migrations/2330000000000-AddBookingCloseOffset.ts deleted file mode 100644 index b435e55ea..000000000 --- a/apps/edr-freight-api/src/migrations/2330000000000-AddBookingCloseOffset.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add a global "booking close offset" — how long BEFORE departure a schedule's - * booking window shuts — configurable separately for import and export. - * - * When an offset is set, the window's close instant is `departure − offset` - * (e.g. departure 17:00 with a 3-hour import offset closes at 14:00; departure - * Jul-10 16:00 with a 1-day export offset closes Jul-9 16:00). It caps the whole - * booking lifecycle: the first window close, every reopen cycle, and the export - * FCFS close all land at/at-or-before this cutoff instead of at departure. - * - * NULL / 0 preserves the previous behaviour exactly (import closes at - * open+duration clamped to departure; export closes at departure), so existing - * installs are unaffected until an offset is entered. - * - * `*_close_offset_minutes` on the global-rules singleton is the live config; the - * matching `rule_*_close_offset_minutes` snapshot on each schedule freezes it at - * creation so the batch board keeps drawing the window the customer was shown - * even after a later global-rules edit. Both are nullable with no backfill — - * absent means "no offset", the safe default. - */ -export class AddBookingCloseOffset2330000000000 implements MigrationInterface { - name = "AddBookingCloseOffset2330000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - ADD COLUMN IF NOT EXISTS import_close_offset_minutes integer, - ADD COLUMN IF NOT EXISTS export_close_offset_minutes integer; - `); - - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS rule_import_close_offset_minutes integer, - ADD COLUMN IF NOT EXISTS rule_export_close_offset_minutes integer; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS rule_import_close_offset_minutes, - DROP COLUMN IF EXISTS rule_export_close_offset_minutes; - `); - await queryRunner.query(` - ALTER TABLE freight.train_scheduling_global_rules - DROP COLUMN IF EXISTS import_close_offset_minutes, - DROP COLUMN IF EXISTS export_close_offset_minutes; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2340000000000-AddCargoTypeHasLashing.ts b/apps/edr-freight-api/src/migrations/2340000000000-AddCargoTypeHasLashing.ts deleted file mode 100644 index 6585cc842..000000000 --- a/apps/edr-freight-api/src/migrations/2340000000000-AddCargoTypeHasLashing.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add `has_lashing` to cargo types. - * - * When true, every booking of that cargo type incurs the flat LASHING - * surcharge (a rate with trigger = 'LASHING'). Defaults to false so existing - * cargo ships without the fee until the flag is turned on. - */ -export class AddCargoTypeHasLashing2340000000000 implements MigrationInterface { - name = "AddCargoTypeHasLashing2340000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.cargo_types - ADD COLUMN IF NOT EXISTS has_lashing boolean NOT NULL DEFAULT false; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.cargo_types - DROP COLUMN IF EXISTS has_lashing; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2340000000000-AddReverseWagonOrder.ts b/apps/edr-freight-api/src/migrations/2340000000000-AddReverseWagonOrder.ts deleted file mode 100644 index ad389e929..000000000 --- a/apps/edr-freight-api/src/migrations/2340000000000-AddReverseWagonOrder.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Add an opt-in "reverse wagon order" flag to a train schedule. - * - * When true, the built wagon plan is flipped at build time so the physically-last - * wagon sits at position 1. Only the order (sequence_no) changes — composition and - * booking allocations travel with their slot. The flag is frozen on the schedule - * at creation and re-applied every time the wagon plan is rebuilt, so the stored - * train order and the schedule order always match. - * - * Defaults to false; existing schedules keep their as-built order. - */ -export class AddReverseWagonOrder2340000000000 implements MigrationInterface { - name = "AddReverseWagonOrder2340000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - ADD COLUMN IF NOT EXISTS reverse_wagon_order boolean NOT NULL DEFAULT false; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.train_schedules - DROP COLUMN IF EXISTS reverse_wagon_order; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2350000000000-RefreshContractPricingArticles.ts b/apps/edr-freight-api/src/migrations/2350000000000-RefreshContractPricingArticles.ts deleted file mode 100644 index 95e007c8a..000000000 --- a/apps/edr-freight-api/src/migrations/2350000000000-RefreshContractPricingArticles.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -import { CONTRACT_TEMPLATE_DEFAULTS } from '../seed/data/contract-template-defaults'; - -/** - * Refresh the "pricing" article of each seeded contract template so it points - * at the live Rate Schedule instead of hardcoded price figures (USD 400/wagon, - * USD 919/40ft, …). The original CreateContractTemplates migration seeded the - * old prose with ON CONFLICT DO NOTHING, so those figures are frozen in the DB - * rows and would otherwise contradict the rate-config-driven schedule table now - * rendered under the pricing article. - * - * Only the article whose id = 'pricing' is touched, and only when its body - * still matches the originally-seeded prose — so any admin edit to the pricing - * article is left untouched. Idempotent: re-running is a no-op once refreshed. - */ -export class RefreshContractPricingArticles2350000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - for (const seed of CONTRACT_TEMPLATE_DEFAULTS) { - const pricing = seed.articles.find((article) => article.id === 'pricing'); - if (!pricing) continue; - - // jsonb_set the title + body of the element whose id = 'pricing', matched - // by array index. Guarded so admin-edited bodies are never overwritten. - await queryRunner.query( - ` - UPDATE freight.contract_templates ct - SET articles = ( - SELECT jsonb_agg( - CASE - WHEN elem->>'id' = 'pricing' - THEN elem || jsonb_build_object('title', $2::text, 'body', $3::text) - ELSE elem - END - ) - FROM jsonb_array_elements(ct.articles) elem - ) - WHERE ct.code = $1 - AND EXISTS ( - SELECT 1 FROM jsonb_array_elements(ct.articles) e - WHERE e->>'id' = 'pricing' - AND e->>'body' LIKE ANY (ARRAY[ - '%USD 59.4 per metric ton%', - '%USD 696 (six hundred ninety-six) per wagon%', - '%USD 400 (four hundred) per wagon%', - '%From SGTD to Dire Dawa dry port, the rate is USD 919%', - '%Railway transportation charges from GMP to SGTD: USD 819%', - '%prevailing EDR domestic container tariff, as set out in the commercial schedule%' - ]) - ); - `, - [seed.code, pricing.title, pricing.body], - ); - } - } - - public async down(): Promise { - // No-op: the refreshed pricing prose is the correct forward state; reverting - // to hardcoded figures would reintroduce the rate-schedule contradiction. - } -} diff --git a/apps/edr-freight-api/src/migrations/2360000000000-RefreshContractPricingArticles.ts b/apps/edr-freight-api/src/migrations/2360000000000-RefreshContractPricingArticles.ts deleted file mode 100644 index 566d0308e..000000000 --- a/apps/edr-freight-api/src/migrations/2360000000000-RefreshContractPricingArticles.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -import { CONTRACT_TEMPLATE_DEFAULTS } from '../seed/data/contract-template-defaults'; - -/** - * Refresh the `pricing` article body of the six seeded contract templates to - * the live-rate-schedule wording. The per-lane figures (e.g. "USD 400 per - * wagon") are now rendered from the LIVE rate config instead of frozen prose, - * so any template whose pricing article still carries a hardcoded price token - * is rewritten to the current seed text. - * - * The guard `body ~ '(USD|ETB) [0-9]'` identifies the auto-seeded original - * prose (which always quoted a currency + figure) and matches neither an - * already-migrated body nor a hand-edited one that adopted the schedule - * wording — so admin edits are preserved. Idempotent: after the rewrite the - * price token is gone, so a re-run is a no-op. Fresh databases seed the new - * text directly (CreateContractTemplates imports the same seed), making this - * a targeted backfill for databases seeded before the seed changed. - */ -const HARDCODED_PRICE_TOKEN = '(USD|ETB) [0-9]'; - -export class RefreshContractPricingArticles2360000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - for (const seed of CONTRACT_TEMPLATE_DEFAULTS) { - const pricing = seed.articles.find((a) => a.id === 'pricing'); - if (!pricing) continue; - - // Rewrite only the article whose id = 'pricing', in place, and only when - // its body still quotes a hardcoded currency figure. jsonb_agg keeps the - // rest of the article (id/title/order) and every other article intact. - await queryRunner.query( - ` - UPDATE freight.contract_templates AS t - SET articles = ( - SELECT jsonb_agg( - CASE - WHEN elem->>'id' = 'pricing' - THEN jsonb_set(elem, '{body}', to_jsonb($2::text), true) - ELSE elem - END - ORDER BY ord - ) - FROM jsonb_array_elements(t.articles) WITH ORDINALITY AS a(elem, ord) - ), - updated_at = now() - WHERE t.code = $1 - AND EXISTS ( - SELECT 1 - FROM jsonb_array_elements(t.articles) AS x - WHERE x->>'id' = 'pricing' - AND x->>'body' ~ $3 - ); - `, - [seed.code, pricing.body, HARDCODED_PRICE_TOKEN], - ); - } - } - - /** - * Irreversible in practice — the original per-lane figures are not restored. - * A no-op down keeps the migration reversible-by-contract without - * resurrecting stale hardcoded prices. - */ - public async down(): Promise { - // intentionally empty - } -} diff --git a/apps/edr-freight-api/src/migrations/2370000000000-AddContainerUnitReturnFlag.ts b/apps/edr-freight-api/src/migrations/2370000000000-AddContainerUnitReturnFlag.ts deleted file mode 100644 index 1971f6166..000000000 --- a/apps/edr-freight-api/src/migrations/2370000000000-AddContainerUnitReturnFlag.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-container handling opt-in: each physical container can now be marked - * hazardous / reefer / with-return individually, next to its VGM. The hazardous - * and reefer flags already existed on the unit row; only the return leg was - * missing, so a booking of 20 containers with 10 returning empty can bill the - * WITH_RETURN surcharge on 10 instead of all 20. - * - * Backfill: existing rows keep false. The line-level counts - * (booking_container.return_quantity etc.) stay authoritative for bookings made - * before this change — the rule engine falls back to them when no unit is flagged. - */ -export class AddContainerUnitReturnFlag2370000000000 implements MigrationInterface { - name = 'AddContainerUnitReturnFlag2370000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."booking_container_units" ADD COLUMN IF NOT EXISTS "is_return" boolean NOT NULL DEFAULT false`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."booking_container_units" DROP COLUMN IF EXISTS "is_return"`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2380000000000-AddTrainDeactivatedStatus.ts b/apps/edr-freight-api/src/migrations/2380000000000-AddTrainDeactivatedStatus.ts deleted file mode 100644 index 2c252f127..000000000 --- a/apps/edr-freight-api/src/migrations/2380000000000-AddTrainDeactivatedStatus.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * New built-train lifecycle status DEACTIVATED: staff park a train indefinitely - * (only allowed while it has no DRAFT/SCHEDULED/DISPATCHED schedule). Like - * UNDER_MAINTENANCE / OUT_OF_SERVICE it is staff-owned — the scheduler never - * overwrites it and refuses to schedule a deactivated train. - * - * Postgres cannot drop an enum value, so down() is a no-op. - */ -export class AddTrainDeactivatedStatus2380000000000 implements MigrationInterface { - name = 'AddTrainDeactivatedStatus2380000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TYPE "freight"."train_status" ADD VALUE IF NOT EXISTS 'DEACTIVATED'`, - ); - } - - public async down(): Promise { - // Enum values cannot be removed in Postgres; leaving the label is harmless. - } -} diff --git a/apps/edr-freight-api/src/migrations/2390000000000-SeedImportTrainNumbers.ts b/apps/edr-freight-api/src/migrations/2390000000000-SeedImportTrainNumbers.ts deleted file mode 100644 index 99c764806..000000000 --- a/apps/edr-freight-api/src/migrations/2390000000000-SeedImportTrainNumbers.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Admin-managed catalog of IMPORT run numbers (even, Djibouti → Ethiopia) - * selectable in the Train Builder. The paired EXPORT number is derived - * (import − 1), so only the import side is configured. Seeded with the runs - * historically hardcoded in the backoffice's trainRuns constants; admins add - * new runs from the Dropdown Settings editor. - */ -export class SeedImportTrainNumbers2390000000000 implements MigrationInterface { - name = 'SeedImportTrainNumbers2390000000000'; - private readonly code = 'import_train_numbers'; - private readonly options: string[] = [ - '8002', - '8102', - '8202', - '8302', - '8402', - '8502', - '8602', - '8702', - '8802', - '8902', - '9002', - ]; - - public async up(queryRunner: QueryRunner): Promise { - const existing = await queryRunner.query( - `SELECT id FROM freight.dropdown_settings WHERE code = $1 LIMIT 1;`, - [this.code], - ); - if (existing.length > 0) return; - - const inserted = await queryRunner.query( - `INSERT INTO freight.dropdown_settings (code, label, description, multiple, meta) - VALUES ($1, $2, $3, false, $4::jsonb) - RETURNING id;`, - [ - this.code, - 'Import train numbers', - 'Even IMPORT run numbers (Djibouti → Ethiopia) selectable when building a train. The paired export number is derived automatically (import − 1).', - JSON.stringify({ searchable: true, clearable: true }), - ], - ); - const settingId = inserted[0].id; - - for (let i = 0; i < this.options.length; i++) { - const value = this.options[i]; - await queryRunner.query( - `INSERT INTO freight.dropdown_options (setting_id, value, label, display_order) - VALUES ($1, $2, $3, $4);`, - [settingId, value, value, i], - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DELETE FROM freight.dropdown_settings WHERE code = $1;`, [ - this.code, - ]); - } -} diff --git a/apps/edr-freight-api/src/migrations/2390000000000-WidenYardCodeForSoftDeleteSuffix.ts b/apps/edr-freight-api/src/migrations/2390000000000-WidenYardCodeForSoftDeleteSuffix.ts deleted file mode 100644 index 31263f4b2..000000000 --- a/apps/edr-freight-api/src/migrations/2390000000000-WidenYardCodeForSoftDeleteSuffix.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Yard soft-delete now appends `@` to the unique code (SEBETA → - * SEBETA@1755612345678) so the name can be reused by a new yard while - * UQ_yards_code still spans soft-deleted rows. varchar(20) can't hold long - * codes plus the 14-char suffix, so widen to 40. - */ -export class WidenYardCodeForSoftDeleteSuffix2390000000000 implements MigrationInterface { - name = 'WidenYardCodeForSoftDeleteSuffix2390000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."yards" ALTER COLUMN "code" TYPE varchar(40)`, - ); - } - - public async down(): Promise { - // Narrowing would fail on suffixed codes; keep 40. - } -} diff --git a/apps/edr-freight-api/src/migrations/2400000000000-AddCustomerTruckExitWeights.ts b/apps/edr-freight-api/src/migrations/2400000000000-AddCustomerTruckExitWeights.ts deleted file mode 100644 index 6cddae23d..000000000 --- a/apps/edr-freight-api/src/migrations/2400000000000-AddCustomerTruckExitWeights.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-truck exit weights for customer self-haul, mirroring what - * `last_mile_vehicle_assignments` already carries for EDR trucks. - * - * A bulk booking is hauled away truck by truck until no tonnage is left, and the - * EDR side enforces that by summing `net_weight_tons` of departed trucks. The - * customer side had no net and no tare — only `gross_weight_kg`, which nothing - * in the live flow ever wrote (the release flow updated the EDR table only). So - * a self-haul bulk booking could take unlimited trucks: hauled tonnage always - * summed to zero. - * - * `gross_weight_kg` is left alone but note it holds TONNES despite its name — - * the weighing UI is in tonnes throughout. The new columns are named for the - * unit they actually hold. - */ -export class AddCustomerTruckExitWeights2400000000000 implements MigrationInterface { - name = 'AddCustomerTruckExitWeights2400000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.customer_truck_assignments - ADD COLUMN IF NOT EXISTS tare_weight_tons numeric(14,3) NULL, - ADD COLUMN IF NOT EXISTS net_weight_tons numeric(14,3) NULL - `); - - // Departed trucks are what the drawdown sums, so it reads this index. - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_customer_truck_departed" - ON freight.customer_truck_assignments (booking_id, departed_at) - WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_customer_truck_departed"`, - ); - await queryRunner.query(` - ALTER TABLE freight.customer_truck_assignments - DROP COLUMN IF EXISTS tare_weight_tons, - DROP COLUMN IF EXISTS net_weight_tons - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2400000000000-NormalizeCompanyRegions.ts b/apps/edr-freight-api/src/migrations/2400000000000-NormalizeCompanyRegions.ts deleted file mode 100644 index b3369b82d..000000000 --- a/apps/edr-freight-api/src/migrations/2400000000000-NormalizeCompanyRegions.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * `freight.companies.region` was free text until region became a closed set - * (see ETHIOPIAN_REGIONS in @edr/types). This normalizes the rows written under - * the old rules so they satisfy the new dropdown. - * - * Two classes of bad data exist, handled differently: - * - * - Unambiguous spelling/case drift ("Addis ababa", "oromoia") — rewritten to - * the canonical spelling. - * - Values that are not regions at all ("Arba Minch", a city), and rows whose - * region contradicts their own zone/woreda — set to NULL. These are NOT - * guessed at: inferring "Gurage/Meskan" means Central Ethiopia would silently - * overwrite what the customer actually submitted. NULL surfaces the gap and - * the required dropdown forces a deliberate pick on next edit. - */ -export class NormalizeCompanyRegions2400000000000 implements MigrationInterface { - name = 'NormalizeCompanyRegions2400000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Canonical spellings — case/whitespace insensitive, safe to re-run. - await queryRunner.query(` - UPDATE freight.companies - SET region = v.canonical - FROM (VALUES - ('addis ababa', 'Addis Ababa'), - ('addis abeba', 'Addis Ababa'), - ('addisababa', 'Addis Ababa'), - ('oromia', 'Oromia'), - ('oromoia', 'Oromia'), - ('oromiya', 'Oromia'), - ('amhara', 'Amhara'), - ('somali', 'Somali'), - ('afar', 'Afar'), - ('tigray', 'Tigray'), - ('tigrai', 'Tigray'), - ('sidama', 'Sidama'), - ('harari', 'Harari'), - ('gambela', 'Gambela'), - ('gambella', 'Gambela'), - ('dire dawa', 'Dire Dawa'), - ('benishangul-gumuz', 'Benishangul-Gumuz'), - ('benishangul gumuz', 'Benishangul-Gumuz'), - ('central ethiopia', 'Central Ethiopia'), - ('south ethiopia', 'South Ethiopia') - ) AS v(variant, canonical) - WHERE freight.companies.region IS NOT NULL - AND lower(regexp_replace(btrim(freight.companies.region), '\\s+', ' ', 'g')) = v.variant - AND freight.companies.region <> v.canonical - `); - - // Anything still outside the canonical set is unresolvable — null it. - await queryRunner.query(` - UPDATE freight.companies - SET region = NULL - WHERE region IS NOT NULL - AND region <> '' - AND region NOT IN ( - 'Addis Ababa','Afar','Amhara','Benishangul-Gumuz','Central Ethiopia', - 'Dire Dawa','Gambela','Harari','Oromia','Sidama','Somali', - 'South Ethiopia','South West Ethiopia Peoples''','Tigray' - ) - `); - - // Normalize empty string to NULL so "unset" has one representation. - await queryRunner.query(` - UPDATE freight.companies SET region = NULL WHERE region = '' - `); - } - - public async down(): Promise { - // Irreversible by design: the original free-text values are not retained - // anywhere, so there is nothing to restore. Rolling back the code is safe — - // the column is still a nullable varchar(100) and accepts free text again. - } -} diff --git a/apps/edr-freight-api/src/migrations/2410000000000-DropBookingApprovalWidenRoles.ts b/apps/edr-freight-api/src/migrations/2410000000000-DropBookingApprovalWidenRoles.ts deleted file mode 100644 index 1b4674b05..000000000 --- a/apps/edr-freight-api/src/migrations/2410000000000-DropBookingApprovalWidenRoles.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Bookings no longer run an approval chain — accepting an intake approves the - * booking outright and generates its contract. The approval chain is now a - * contract-only concern, so `freight.approval_rules` is read by contracts alone. - * - * Also widens the role columns: chain steps now reference IAM position-type - * keys (`iam.position_types.key`), and real keys run past the old varchar(30) - * (e.g. '-marketing-manager-/-general-manager' is 38 chars), which would fail - * on insert. - */ -export class DropBookingApprovalWidenRoles2410000000000 - implements MigrationInterface -{ - name = 'DropBookingApprovalWidenRoles2410000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP TABLE IF EXISTS freight.booking_approval_step;`, - ); - - for (const [table, column] of [ - ['approval_rules', 'required_role'], - ['approval_rules', 'blocks_role'], - ['contract_approval_steps', 'required_role'], - ['contract_approval_steps', 'blocks_role'], - ] as const) { - await queryRunner.query( - `ALTER TABLE freight.${table} ALTER COLUMN ${column} TYPE varchar(64);`, - ); - } - } - - /** - * No-op: the booking approval chain is retired, so re-creating the table - * would leave dead schema behind. Narrowing the role columns again would - * truncate any position-type key already stored. - */ - public async down(): Promise { - // intentionally empty - } -} diff --git a/apps/edr-freight-api/src/migrations/2420000000000-CreateContractDocumentRevisions.ts b/apps/edr-freight-api/src/migrations/2420000000000-CreateContractDocumentRevisions.ts deleted file mode 100644 index db06b2ba2..000000000 --- a/apps/edr-freight-api/src/migrations/2420000000000-CreateContractDocumentRevisions.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Audit trail for contract document edits. The document stays editable through - * the whole approval chain (each approver may edit on their turn), so the - * contract itself only ever holds the current snapshot — this table records who - * changed which article, and when. - */ -export class CreateContractDocumentRevisions2420000000000 - implements MigrationInterface -{ - name = 'CreateContractDocumentRevisions2420000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.contract_document_revisions ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now(), - deleted_at timestamptz, - contract_id uuid NOT NULL REFERENCES freight.contracts(id) ON DELETE CASCADE, - actor_id uuid, - actor_role varchar(64), - step_id uuid, - summary varchar(255), - changes jsonb NOT NULL DEFAULT '[]'::jsonb - ); - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS idx_contract_document_revisions_contract - ON freight.contract_document_revisions (contract_id, created_at DESC); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP TABLE IF EXISTS freight.contract_document_revisions;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2430000000000-AddFileReviewStatus.ts b/apps/edr-freight-api/src/migrations/2430000000000-AddFileReviewStatus.ts deleted file mode 100644 index 833d49fea..000000000 --- a/apps/edr-freight-api/src/migrations/2430000000000-AddFileReviewStatus.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-document review state, so a backoffice reviewer can request a correction - * on one specific onboarding document instead of rejecting the whole role. - * - * Until now `freight.files` carried no status at all: the `pending_add` / - * `pending_remove` badges the portal shows are derived by diffing live rows - * against an open company change request, which says nothing about whether a - * reviewer is happy with a given document. `review_status` is that missing - * verdict — NULL means never reviewed, which is the state every existing row - * correctly starts in, so no backfill is needed. - * - * The partial index serves the approval gate, which asks "does this company (or - * profile) still have any document with an open change request?" on every - * role-status write. - */ -export class AddFileReviewStatus2430000000000 implements MigrationInterface { - name = 'AddFileReviewStatus2430000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.files - ADD COLUMN IF NOT EXISTS review_status varchar(32) NULL, - ADD COLUMN IF NOT EXISTS review_note text NULL, - ADD COLUMN IF NOT EXISTS reviewed_by uuid NULL, - ADD COLUMN IF NOT EXISTS reviewed_at timestamptz NULL - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_files_open_change_request" - ON freight.files (resource, resource_id) - WHERE review_status = 'change_requested' AND deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."IDX_files_open_change_request"`, - ); - await queryRunner.query(` - ALTER TABLE freight.files - DROP COLUMN IF EXISTS review_status, - DROP COLUMN IF EXISTS review_note, - DROP COLUMN IF EXISTS reviewed_by, - DROP COLUMN IF EXISTS reviewed_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2430000000000-UniqueLocomotiveName.ts b/apps/edr-freight-api/src/migrations/2430000000000-UniqueLocomotiveName.ts deleted file mode 100644 index 5468e2207..000000000 --- a/apps/edr-freight-api/src/migrations/2430000000000-UniqueLocomotiveName.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Locomotive names must be unique so staff can identify a unit by name alone - * (the card view leads with `name`, falling back to `code`). Uniqueness is: - * - * - case/whitespace-insensitive — "MTL1", "mtl1" and " MTL1 " are one name; - * - scoped to live rows — a decommissioned (soft-deleted) locomotive must not - * hold its name hostage, matching how the fleet reuses yard codes; - * - skipped for blank names — `name` stays optional, and NULL/'' rows are - * excluded rather than colliding with each other. - * - * A partial expression index gives all three; a plain UNIQUE column cannot. - */ -export class UniqueLocomotiveName2430000000000 implements MigrationInterface { - name = 'UniqueLocomotiveName2430000000000'; - - public async up(queryRunner: QueryRunner): Promise { - // Pre-existing duplicates would abort CREATE UNIQUE INDEX. Suffix every - // copy after the oldest (…-2, …-3) so the index can build; the oldest row - // keeps the original name. Deterministic on created_at, then id. - await queryRunner.query(` - WITH ranked AS ( - SELECT - id, - name, - row_number() OVER ( - PARTITION BY lower(btrim(name)) - ORDER BY created_at, id - ) AS rn - FROM "freight"."locomotives" - WHERE deleted_at IS NULL - AND name IS NOT NULL - AND btrim(name) <> '' - ) - UPDATE "freight"."locomotives" AS l - SET name = btrim(ranked.name) || '-' || ranked.rn - FROM ranked - WHERE l.id = ranked.id - AND ranked.rn > 1 - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_locomotives_name_active" - ON "freight"."locomotives" (lower(btrim("name"))) - WHERE "deleted_at" IS NULL - AND "name" IS NOT NULL - AND btrim("name") <> '' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS "freight"."UQ_locomotives_name_active"`, - ); - // The de-duplicating renames are not reversed: the original names are no - // longer recoverable, and restoring them would re-introduce the conflict. - } -} diff --git a/apps/edr-freight-api/src/migrations/2440000000000-AddHandoverEdrAssignment.ts b/apps/edr-freight-api/src/migrations/2440000000000-AddHandoverEdrAssignment.ts deleted file mode 100644 index c8f48af05..000000000 --- a/apps/edr-freight-api/src/migrations/2440000000000-AddHandoverEdrAssignment.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-truck EDR last-mile handovers. `truck_assignment_id` FKs - * customer_truck_assignments (self-haul only), so EDR trucks need their own - * link to the last-mile vehicle assignment that hauled the goods. Generated - * when the EDR truck exits the warehouse (with its exit paper) and signed by - * the customer in the portal — one per truck, or booking-level (both ids null) - * when the truck cannot be resolved. - */ -export class AddHandoverEdrAssignment2440000000000 implements MigrationInterface { - name = 'AddHandoverEdrAssignment2440000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.booking_handovers - ADD COLUMN IF NOT EXISTS edr_assignment_id uuid - REFERENCES freight.last_mile_vehicle_assignments(id) ON DELETE SET NULL; - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_booking_handovers_booking_edr_truck" - ON freight.booking_handovers (booking_id, edr_assignment_id) - WHERE deleted_at IS NULL AND edr_assignment_id IS NOT NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."UQ_booking_handovers_booking_edr_truck";`, - ); - await queryRunner.query( - `ALTER TABLE freight.booking_handovers DROP COLUMN IF EXISTS edr_assignment_id;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2450000000000-DropActiveProfileTypeFromExternalProfiles.ts b/apps/edr-freight-api/src/migrations/2450000000000-DropActiveProfileTypeFromExternalProfiles.ts deleted file mode 100644 index d8119930f..000000000 --- a/apps/edr-freight-api/src/migrations/2450000000000-DropActiveProfileTypeFromExternalProfiles.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Drop the `active_profile_type` "active mode" column. A booking/contract now - * resolves its company_profile from the trade direction at creation time (with - * a forwarder passing an explicit companyProfileId), so no per-user active mode - * is stored. `onboarding_step` / `onboarding_completed` are unaffected. - */ -export class DropActiveProfileTypeFromExternalProfiles2450000000000 - implements MigrationInterface -{ - name = 'DropActiveProfileTypeFromExternalProfiles2450000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.external_profiles - DROP COLUMN IF EXISTS active_profile_type; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.external_profiles - ADD COLUMN IF NOT EXISTS active_profile_type varchar(32); - `); - // Rebuild the mode the same way the original column was backfilled: - // importer first, then exporter, then whichever profile the company has. - await queryRunner.query(` - UPDATE freight.external_profiles ep - SET active_profile_type = cp.type - FROM ( - SELECT DISTINCT ON (company_id) company_id, type - FROM freight.company_profiles - ORDER BY company_id, - CASE type - WHEN 'importer' THEN 0 - WHEN 'exporter' THEN 1 - ELSE 2 - END - ) cp - WHERE ep.company_id = cp.company_id - AND ep.active_profile_type IS NULL; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2460000000000-AddCacBankPaymentMethod.ts b/apps/edr-freight-api/src/migrations/2460000000000-AddCacBankPaymentMethod.ts deleted file mode 100644 index e6cfe70c3..000000000 --- a/apps/edr-freight-api/src/migrations/2460000000000-AddCacBankPaymentMethod.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddCacBankPaymentMethod2460000000000 implements MigrationInterface { - name = "AddCacBankPaymentMethod2460000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // The entity + frontend already list 'cac-bank' as a valid method, but the - // DB enum was never extended. Filtering payments by 'cac-bank' cast the - // literal to the enum and errored (invalid input value for enum). EDRFREIGHT-301. - await queryRunner.query(`ALTER TYPE freight.payments_method_enum ADD VALUE IF NOT EXISTS 'cac-bank';`); - } - - public async down(_queryRunner: QueryRunner): Promise { - // PostgreSQL does not support removing enum values directly. - // To roll back, recreate the type without the added value and update the column. - } -} diff --git a/apps/edr-freight-api/src/migrations/2470000000000-AddAcquisitionItemName.ts b/apps/edr-freight-api/src/migrations/2470000000000-AddAcquisitionItemName.ts deleted file mode 100644 index fadacda69..000000000 --- a/apps/edr-freight-api/src/migrations/2470000000000-AddAcquisitionItemName.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Acquisitions describe WHAT was acquired (vehicle, parts, equipment…) — the - * vehicle link is optional and only for acquisitions that ARE a fleet vehicle. - */ -export class AddAcquisitionItemName2470000000000 implements MigrationInterface { - name = 'AddAcquisitionItemName2470000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.asset_acquisitions - ADD COLUMN IF NOT EXISTS item_name varchar(200) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.asset_acquisitions - DROP COLUMN IF EXISTS item_name - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2480000000000-AddMaintenanceDueNotifiedAt.ts b/apps/edr-freight-api/src/migrations/2480000000000-AddMaintenanceDueNotifiedAt.ts deleted file mode 100644 index 61431c5bc..000000000 --- a/apps/edr-freight-api/src/migrations/2480000000000-AddMaintenanceDueNotifiedAt.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Dedup stamp for the km/date-due maintenance alert — without it the daily - * cron would re-notify every day a schedule stays due. - */ -export class AddMaintenanceDueNotifiedAt2480000000000 implements MigrationInterface { - name = 'AddMaintenanceDueNotifiedAt2480000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.maintenance_schedules - ADD COLUMN IF NOT EXISTS due_notified_at timestamptz NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.maintenance_schedules DROP COLUMN IF EXISTS due_notified_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2800000000000-AddMaintenanceIntervals.ts b/apps/edr-freight-api/src/migrations/2800000000000-AddMaintenanceIntervals.ts deleted file mode 100644 index f4f125eaf..000000000 --- a/apps/edr-freight-api/src/migrations/2800000000000-AddMaintenanceIntervals.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * KM-based maintenance scheduling: per-vehicle service intervals (by km - * and/or days) driving the maintenance due engine. Raw schema-qualified SQL — - * the builder API resolved bare table names against the default schema and - * failed on boot ("Table maintenance_intervals does not exist"). - */ -export class AddMaintenanceIntervals2800000000000 implements MigrationInterface { - name = 'AddMaintenanceIntervals2800000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.maintenance_intervals ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - vehicle_id uuid NOT NULL REFERENCES freight.vehicles(id) ON DELETE CASCADE, - maintenance_type varchar NOT NULL, - interval_km numeric(14,2), - interval_days integer, - description text, - 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 INDEX IF NOT EXISTS "IDX_maintenance_intervals_vehicle_type" - ON freight.maintenance_intervals (vehicle_id, maintenance_type); - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_maintenance_intervals_vehicle_type" - ON freight.maintenance_intervals (vehicle_id, maintenance_type); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.maintenance_intervals;`); - } -} diff --git a/apps/edr-freight-api/src/migrations/2800000000001-AddSignatureToHandover.ts b/apps/edr-freight-api/src/migrations/2800000000001-AddSignatureToHandover.ts deleted file mode 100644 index 679846484..000000000 --- a/apps/edr-freight-api/src/migrations/2800000000001-AddSignatureToHandover.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Persist the signer's saved-signature image on the handover record, so the - * signed handover document can render the actual signature (not just the - * typed name) — parity with the booking-contract signing flow. - */ -export class AddSignatureToHandover2800000000001 implements MigrationInterface { - name = 'AddSignatureToHandover2800000000001'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_handovers ADD COLUMN IF NOT EXISTS signature_image_url text;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_handovers DROP COLUMN IF EXISTS signature_image_url;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2810000000000-AddMaintenanceServiceItem.ts b/apps/edr-freight-api/src/migrations/2810000000000-AddMaintenanceServiceItem.ts deleted file mode 100644 index 983aa6e64..000000000 --- a/apps/edr-freight-api/src/migrations/2810000000000-AddMaintenanceServiceItem.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Named service items for KM-based maintenance ("oil change", "tires", …). - * The coarse maintenance_type enum (PREVENTIVE/…) allowed only one interval - * per type per vehicle, so oil and tire intervals could not coexist. Interval - * identity becomes (vehicle, maintenance_type, service_item); schedules carry - * the item so completion re-finds the right interval for auto-scheduling. - */ -export class AddMaintenanceServiceItem2810000000000 implements MigrationInterface { - name = 'AddMaintenanceServiceItem2810000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.maintenance_intervals ADD COLUMN IF NOT EXISTS service_item varchar(120);`, - ); - await queryRunner.query( - `ALTER TABLE freight.maintenance_schedules ADD COLUMN IF NOT EXISTS service_item varchar(120);`, - ); - // Re-key interval uniqueness on (vehicle, type, item). COALESCE folds the - // item-less legacy rows into one slot; soft-deleted rows are ignored. - await queryRunner.query( - `DROP INDEX IF EXISTS freight."UQ_maintenance_intervals_vehicle_type";`, - ); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_maintenance_intervals_vehicle_type_item" - ON freight.maintenance_intervals (vehicle_id, maintenance_type, COALESCE(service_item, '')) - WHERE deleted_at IS NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight."UQ_maintenance_intervals_vehicle_type_item";`, - ); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_maintenance_intervals_vehicle_type" - ON freight.maintenance_intervals (vehicle_id, maintenance_type); - `); - await queryRunner.query( - `ALTER TABLE freight.maintenance_schedules DROP COLUMN IF EXISTS service_item;`, - ); - await queryRunner.query( - `ALTER TABLE freight.maintenance_intervals DROP COLUMN IF EXISTS service_item;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2820000000000-AddMileTonsQuantity.ts b/apps/edr-freight-api/src/migrations/2820000000000-AddMileTonsQuantity.ts deleted file mode 100644 index e1e02c418..000000000 --- a/apps/edr-freight-api/src/migrations/2820000000000-AddMileTonsQuantity.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Bulk tonnage at assignment time. First-mile trucks and export self-haul - * trucks carry a planned load (tonnes + optional item count) so bulk bookings - * draw down as vehicles are assigned — not only at the weighbridge. - */ -export class AddMileTonsQuantity2820000000000 implements MigrationInterface { - name = 'AddMileTonsQuantity2820000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.first_mile_vehicle_assignments ADD COLUMN IF NOT EXISTS tons numeric(14,3);`, - ); - await queryRunner.query( - `ALTER TABLE freight.first_mile_vehicle_assignments ADD COLUMN IF NOT EXISTS quantity integer;`, - ); - await queryRunner.query( - `ALTER TABLE freight.customer_truck_assignments ADD COLUMN IF NOT EXISTS planned_tons numeric(14,3);`, - ); - await queryRunner.query( - `ALTER TABLE freight.customer_truck_assignments ADD COLUMN IF NOT EXISTS planned_quantity integer;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.customer_truck_assignments DROP COLUMN IF EXISTS planned_quantity;`, - ); - await queryRunner.query( - `ALTER TABLE freight.customer_truck_assignments DROP COLUMN IF EXISTS planned_tons;`, - ); - await queryRunner.query( - `ALTER TABLE freight.first_mile_vehicle_assignments DROP COLUMN IF EXISTS quantity;`, - ); - await queryRunner.query( - `ALTER TABLE freight.first_mile_vehicle_assignments DROP COLUMN IF EXISTS tons;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2820000000000-CustomsClearanceRouteScope.ts b/apps/edr-freight-api/src/migrations/2820000000000-CustomsClearanceRouteScope.ts deleted file mode 100644 index 17902ff0d..000000000 --- a/apps/edr-freight-api/src/migrations/2820000000000-CustomsClearanceRouteScope.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Scope the customs clearance service fee to a direction + route. - * - * The fee was a single global flat rate; the business sells it per lane — - * "import clearance, Djibouti → Adama, 300 USD". CUSTOMS_CLEARANCE rates now - * carry trade_direction + the yard pair, and contract pricing matches on them - * strictly (no route-less fallback). - * - * Existing route-less clearance rates cannot be backfilled (no way to know - * which lane each was meant for) — retired exactly like the base-freight - * retirement in AddRateYardScope: SUPERSEDED + soft-deleted, kept for - * snapshot history. - */ -export class CustomsClearanceRouteScope2820000000000 implements MigrationInterface { - name = 'CustomsClearanceRouteScope2820000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND rate_type = 'CUSTOMS_CLEARANCE' - AND (origin_yard_id IS NULL OR destination_yard_id IS NULL); - `); - - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";`, - ); - await queryRunner.query(` - ALTER TABLE freight.rates - ADD CONSTRAINT "CK_rates_yard_scope" CHECK ( - deleted_at IS NOT NULL - OR status = 'SUPERSEDED' - OR CASE - WHEN ("trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY')) - OR "trigger" = 'CUSTOMS_CLEARANCE' - THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL - ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL - END - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Retired rates stay retired (their lanes were never recorded); down only - // restores the pre-customs constraint shape. - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";`, - ); - await queryRunner.query(` - ALTER TABLE freight.rates - ADD CONSTRAINT "CK_rates_yard_scope" CHECK ( - deleted_at IS NOT NULL - OR status = 'SUPERSEDED' - OR CASE - WHEN "trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY') - THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL - ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL - END - ); - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2830000000000-ReturnSurchargeRouteScope.ts b/apps/edr-freight-api/src/migrations/2830000000000-ReturnSurchargeRouteScope.ts deleted file mode 100644 index 26c512cfc..000000000 --- a/apps/edr-freight-api/src/migrations/2830000000000-ReturnSurchargeRouteScope.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Scope the empty-container return surcharge to a direction + route + - * container type, like base freight (import-only for now — the box only goes - * back to the port on imports). - * - * Existing route-less RETURN_SURCHARGE rates cannot be backfilled — retired - * (SUPERSEDED + soft-deleted) exactly like base freight and customs clearance - * were, kept readable for snapshot history. Route-scoped replacements must be - * re-entered; a booking that asks for return with no matching rate hard-blocks. - */ -export class ReturnSurchargeRouteScope2830000000000 implements MigrationInterface { - name = 'ReturnSurchargeRouteScope2830000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND rate_type = 'RETURN_SURCHARGE' - AND (origin_yard_id IS NULL OR destination_yard_id IS NULL); - `); - - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";`, - ); - await queryRunner.query(` - ALTER TABLE freight.rates - ADD CONSTRAINT "CK_rates_yard_scope" CHECK ( - deleted_at IS NOT NULL - OR status = 'SUPERSEDED' - OR CASE - WHEN ("trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY')) - OR "trigger" IN ('CUSTOMS_CLEARANCE', 'WITH_RETURN') - THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL - ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL - END - ); - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Retired rates stay retired; down only restores the customs-era shape. - await queryRunner.query( - `ALTER TABLE freight.rates DROP CONSTRAINT IF EXISTS "CK_rates_yard_scope";`, - ); - await queryRunner.query(` - ALTER TABLE freight.rates - ADD CONSTRAINT "CK_rates_yard_scope" CHECK ( - deleted_at IS NOT NULL - OR status = 'SUPERSEDED' - OR CASE - WHEN ("trigger" = 'ALWAYS' AND applies_to IN ('BULK', 'CONTAINER', 'INTERCITY')) - OR "trigger" = 'CUSTOMS_CLEARANCE' - THEN origin_yard_id IS NOT NULL AND destination_yard_id IS NOT NULL - ELSE origin_yard_id IS NULL AND destination_yard_id IS NULL - END - ); - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2840000000000-AddTruckTypes.ts b/apps/edr-freight-api/src/migrations/2840000000000-AddTruckTypes.ts deleted file mode 100644 index fb22cbee9..000000000 --- a/apps/edr-freight-api/src/migrations/2840000000000-AddTruckTypes.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Truck types become back-office data instead of a hardcoded `VehicleType` enum, - * so EDR can add a configuration without a code change. - * - * `vehicles.vehicle_type` is deliberately LEFT IN PLACE as a denormalised code. - * Truck-detention billing groups trucks with raw SQL over that column - * (`SELECT v.vehicle_type ... GROUP BY`, warehouse-fee.service.ts) and matches - * the result against `warehouse_fee_rules.vehicle_type`. Swapping it for the FK - * outright would silently drop detention charges, so the FK is additive and the - * service writes the type's code through on every save. - * - * Raw SQL, `freight.`-qualified, IF NOT EXISTS throughout — the TypeORM builder - * API resolves bare names against `public` and crash-loops boot. - */ -export class AddTruckTypes2840000000000 implements MigrationInterface { - name = "AddTruckTypes2840000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.truck_types ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - code varchar(32) NOT NULL, - name varchar(100) NOT NULL, - capacity_tons numeric(10,3), - has_trailer boolean NOT NULL DEFAULT false, - description text, - 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 ux_truck_types_code - ON freight.truck_types (code) - `); - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS ix_truck_types_is_active - ON freight.truck_types (is_active) - `); - - // Seed one row per legacy enum value so vehicles already carrying that code - // keep resolving, plus CASONI as the first rigid (no-trailer) configuration. - // has_trailer is true only for the articulated configurations. - await queryRunner.query(` - INSERT INTO freight.truck_types (code, name, has_trailer) - VALUES - ('TRUCK', 'Truck', true), - ('TRAILER', 'Trailer', true), - ('TANKER', 'Tanker', true), - ('FLATBED', 'Flatbed', true), - ('VAN', 'Van', false), - ('CAR', 'Car', false), - ('BUS', 'Bus', false), - ('CASONI', 'Casoni (rigid, no trailer)', false) - ON CONFLICT (code) DO NOTHING - `); - - await queryRunner.query(` - ALTER TABLE freight.vehicles - ADD COLUMN IF NOT EXISTS truck_type_id uuid - `); - - // Separate DO block: ADD CONSTRAINT has no IF NOT EXISTS in Postgres. - await queryRunner.query(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'fk_vehicles_truck_type' - ) THEN - ALTER TABLE freight.vehicles - ADD CONSTRAINT fk_vehicles_truck_type - FOREIGN KEY (truck_type_id) REFERENCES freight.truck_types (id) - ON DELETE SET NULL; - END IF; - END $$ - `); - - // Backfill the FK from the code already stored on each vehicle. - await queryRunner.query(` - UPDATE freight.vehicles v - SET truck_type_id = t.id - FROM freight.truck_types t - WHERE v.truck_type_id IS NULL - AND upper(trim(v.vehicle_type)) = t.code - `); - - // Truck-type codes are varchar(32); the fee-rule column they are matched - // against was varchar(20) and would truncate/reject longer codes. - await queryRunner.query(` - ALTER TABLE freight.warehouse_fee_rules - ALTER COLUMN vehicle_type TYPE varchar(32) - `); - - // A VIN identifies exactly one vehicle worldwide. Partial index so the many - // existing rows without a VIN do not collide. - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS ux_vehicles_vin - ON freight.vehicles (vin) - WHERE vin IS NOT NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight.ux_vehicles_vin`); - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP CONSTRAINT IF EXISTS fk_vehicles_truck_type - `); - await queryRunner.query(` - ALTER TABLE freight.vehicles - DROP COLUMN IF EXISTS truck_type_id - `); - await queryRunner.query(`DROP TABLE IF EXISTS freight.truck_types`); - // warehouse_fee_rules.vehicle_type is left widened: narrowing it back would - // fail on any row that stored a code longer than 20 characters. - } -} diff --git a/apps/edr-freight-api/src/migrations/2850000000000-AddBookingDoubleHandling.ts b/apps/edr-freight-api/src/migrations/2850000000000-AddBookingDoubleHandling.ts deleted file mode 100644 index be98729e7..000000000 --- a/apps/edr-freight-api/src/migrations/2850000000000-AddBookingDoubleHandling.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Double handling becomes an explicit per-booking decision instead of an - * implicit "every import" charge. Warehouse staff record Yes/No after - * unloading (whether the goods actually had to be re-handled); the - * DOUBLE_HANDLING_FEE rule only bills when the answer is Yes. - * - * NULL = not decided yet → no charge, and the UI shows "not set" so the - * operator is prompted. Existing rows stay NULL deliberately: back-billing a - * fee nobody confirmed would be wrong. - */ -export class AddBookingDoubleHandling2850000000000 implements MigrationInterface { - name = 'AddBookingDoubleHandling2850000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS double_handling boolean;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS double_handling_set_at timestamptz;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS double_handling_set_by varchar(160);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS double_handling_set_by;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS double_handling_set_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS double_handling;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2860000000000-AddPerTruckDetentionWindow.ts b/apps/edr-freight-api/src/migrations/2860000000000-AddPerTruckDetentionWindow.ts deleted file mode 100644 index 710ad12ad..000000000 --- a/apps/edr-freight-api/src/migrations/2860000000000-AddPerTruckDetentionWindow.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Per-truck detention clocks. Detention was timed once per last-mile leg - * (last_mile.arrived_at / delivered_at), so every truck on a multi-truck - * delivery shared one window and was billed identical days — wrong the moment - * two trucks arrive or return at different times. - * - * Deliberately NEW columns rather than reusing the existing per-truck - * arrived_at / departed_at on this table: those are WAREHOUSE gate-in/gate-out - * events stamped by release(), whereas detention runs from arrival at the - * DESTINATION until the truck is released/returned. - * - * Both nullable — a truck without its own window falls back to the leg-level - * timestamps, so legacy legs keep billing exactly as before. - */ -export class AddPerTruckDetentionWindow2860000000000 implements MigrationInterface { - name = 'AddPerTruckDetentionWindow2860000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - ADD COLUMN IF NOT EXISTS destination_arrived_at timestamptz, - ADD COLUMN IF NOT EXISTS returned_at timestamptz; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.last_mile_vehicle_assignments - DROP COLUMN IF EXISTS returned_at, - DROP COLUMN IF EXISTS destination_arrived_at; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2860000000000-DropClearanceFeePrepay.ts b/apps/edr-freight-api/src/migrations/2860000000000-DropClearanceFeePrepay.ts deleted file mode 100644 index 9fd854b94..000000000 --- a/apps/edr-freight-api/src/migrations/2860000000000-DropClearanceFeePrepay.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * The customs clearance service fee is no longer prepaid via its own - * `clearance`-source invoice — it is billed as a CUSTOMS_CLEARANCE line on the - * booking invoice, together with the freight (see BookingPricingService). - * - * - Contracts/bookings parked at the payment gate move straight to the - * document step (the gate no longer exists — nothing could ever pay them). - * - Open (unpaid) clearance invoices are expired; PAID ones stay as history. - * NOTE: a ONE_TIME customs contract that already PAID its prepaid fee but - * has not booked yet will be billed the fee again on its booking invoice — - * accepted for dev data; reverses the old AddClearanceFeePayment migration. - * - clearance_fee_paid_at columns are dropped from contracts and bookings. - */ -export class DropClearanceFeePrepay2860000000000 implements MigrationInterface { - name = 'DropClearanceFeePrepay2860000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.contracts - SET status = 'AWAITING_CLEARANCE_DOCUMENTS', updated_at = now() - WHERE status = 'AWAITING_CLEARANCE_PAYMENT'; - `); - await queryRunner.query(` - UPDATE freight.contracts - SET clearance_status = 'AWAITING_DOCUMENTS', updated_at = now() - WHERE clearance_status = 'AWAITING_PAYMENT'; - `); - await queryRunner.query(` - UPDATE freight.bookings - SET status = 'AWAITING_DOCUMENTS', updated_at = now() - WHERE status = 'AWAITING_CLEARANCE_PAYMENT'; - `); - await queryRunner.query(` - UPDATE freight.invoices - SET status = 'EXPIRED', updated_at = now() - WHERE source = 'clearance' - AND status IN ('DRAFT', 'ISSUED', 'PENDING', 'PARTIALLY_PAID', 'OVERDUE'); - `); - await queryRunner.query( - `ALTER TABLE freight.contracts DROP COLUMN IF EXISTS clearance_fee_paid_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS clearance_fee_paid_at;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - // Moved rows and expired invoices stay — only the columns come back. - await queryRunner.query( - `ALTER TABLE freight.contracts ADD COLUMN IF NOT EXISTS clearance_fee_paid_at timestamptz;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS clearance_fee_paid_at timestamptz;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2870000000000-CustomsClearancePerKind.ts b/apps/edr-freight-api/src/migrations/2870000000000-CustomsClearancePerKind.ts deleted file mode 100644 index be01e7825..000000000 --- a/apps/edr-freight-api/src/migrations/2870000000000-CustomsClearancePerKind.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Customs clearance fees are now sold per cargo kind: container fees name a - * container type (billed PER_CONTAINER / PER_WAGON), bulk fees carry no type - * (billed PER_TON / PER_WAGON). The old one-FLAT-fee-per-route shape cannot be - * mapped to a kind — retired (SUPERSEDED + soft-deleted) exactly like the - * base-freight and return-surcharge reshapes, kept readable for snapshot - * history. Per-kind replacements must be re-entered; a customs contract or - * booking without a matching fee hard-blocks. Contracts that already froze a - * FLAT snapshot keep billing it (legacy honoured at booking pricing). - */ -export class CustomsClearancePerKind2870000000000 implements MigrationInterface { - name = 'CustomsClearancePerKind2870000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND rate_type = 'CUSTOMS_CLEARANCE' - AND rate_unit = 'FLAT'; - `); - } - - public async down(): Promise { - // Retired rates stay retired — re-enter per-kind rates instead. - } -} diff --git a/apps/edr-freight-api/src/migrations/2880000000000-LashingPerKind.ts b/apps/edr-freight-api/src/migrations/2880000000000-LashingPerKind.ts deleted file mode 100644 index 9d311c60f..000000000 --- a/apps/edr-freight-api/src/migrations/2880000000000-LashingPerKind.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Lashing is now sold per cargo kind, like the customs clearance fee: - * container rates name a container type (PER_CONTAINER / PER_WAGON), bulk - * rates carry no type (PER_TON / PER_WAGON). The old flat-per-booking shape - * cannot be mapped to a kind — retired (SUPERSEDED + soft-deleted), kept - * readable for snapshot history. Per-kind replacements must be re-entered; - * an unconfigured lashing rate simply bills nothing (lenient, like - * hazard/reefer). Matched on trigger, not rate_type — CONSOLIDATION rates - * share the LASHING rate_type and must survive. - */ -export class LashingPerKind2880000000000 implements MigrationInterface { - name = 'LashingPerKind2880000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND "trigger" = 'LASHING' - AND rate_unit = 'FLAT'; - `); - } - - public async down(): Promise { - // Retired rates stay retired — re-enter per-kind rates instead. - } -} diff --git a/apps/edr-freight-api/src/migrations/2890000000000-LashingBulkOnlyPerDirection.ts b/apps/edr-freight-api/src/migrations/2890000000000-LashingBulkOnlyPerDirection.ts deleted file mode 100644 index 8904c6194..000000000 --- a/apps/edr-freight-api/src/migrations/2890000000000-LashingBulkOnlyPerDirection.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Lashing is now BULK-only and sold per trade direction (IMPORT / EXPORT), - * optionally narrowed to one leaf commodity. Rates that no longer fit — - * container-scoped, or carrying no direction — cannot be mapped and are - * retired (SUPERSEDED + soft-deleted), kept readable for snapshot history. - * Matched on trigger, not rate_type (CONSOLIDATION shares rate_type LASHING). - */ -export class LashingBulkOnlyPerDirection2890000000000 implements MigrationInterface { - name = 'LashingBulkOnlyPerDirection2890000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.rates - SET status = 'SUPERSEDED', - deleted_at = now(), - updated_at = now() - WHERE deleted_at IS NULL - AND "trigger" = 'LASHING' - AND (container_type_id IS NOT NULL - OR trade_direction IS NULL - OR trade_direction NOT IN ('IMPORT', 'EXPORT')); - `); - } - - public async down(): Promise { - // Retired rates stay retired — re-enter per-direction bulk rates instead. - } -} diff --git a/apps/edr-freight-api/src/migrations/2900000000000-LivestockPerItem.ts b/apps/edr-freight-api/src/migrations/2900000000000-LivestockPerItem.ts deleted file mode 100644 index ce05a7ce1..000000000 --- a/apps/edr-freight-api/src/migrations/2900000000000-LivestockPerItem.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Livestock is billed and counted per head, not per ton — line it up with the - * other break-bulk cargo types (Machinery, Truck, Automobile) so bulk - * storage/demurrage fees charge per item instead of per ton for it. - */ -export class LivestockPerItem2900000000000 implements MigrationInterface { - name = "LivestockPerItem2900000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.cargo_types - SET unit_of_measure = 'PER_ITEM' - WHERE code = 'LIVESTOCK' - AND unit_of_measure IS DISTINCT FROM 'PER_ITEM' - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - UPDATE freight.cargo_types - SET unit_of_measure = 'PER_TON' - WHERE code = 'LIVESTOCK' - AND unit_of_measure IS DISTINCT FROM 'PER_TON' - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2910000000000-AddContractSignatureStamp.ts b/apps/edr-freight-api/src/migrations/2910000000000-AddContractSignatureStamp.ts deleted file mode 100644 index e28748cb7..000000000 --- a/apps/edr-freight-api/src/migrations/2910000000000-AddContractSignatureStamp.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Company stamp (seal) attached alongside the drawn signature, for both the - * client and the EDR side. Stored the same way the signature image is: a - * FileRecord on the contract (`resource: 'contracts'`, `code: 'stamp_'`) - * referenced from the signature row. - * - * Nullable — existing signature rows predate the stamp requirement. The - * "both stamps recorded" gate lives in ContractTransitionService.counterSign, - * not in a NOT NULL constraint, so historical rows stay readable. - */ -export class AddContractSignatureStamp2910000000000 implements MigrationInterface { - name = 'AddContractSignatureStamp2910000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_signatures ADD COLUMN IF NOT EXISTS stamp_file_id uuid;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_signatures DROP COLUMN IF EXISTS stamp_file_id;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2920000000000-AddRevisionActorName.ts b/apps/edr-freight-api/src/migrations/2920000000000-AddRevisionActorName.ts deleted file mode 100644 index 2263d78fc..000000000 --- a/apps/edr-freight-api/src/migrations/2920000000000-AddRevisionActorName.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Store WHO made a contract edit as a name, not just an id. Denormalised on - * purpose: an audit trail must still read correctly after the user is renamed, - * deactivated or deleted, and `iam.users` lives outside this module's schema. - */ -export class AddRevisionActorName2920000000000 implements MigrationInterface { - name = 'AddRevisionActorName2920000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_document_revisions ADD COLUMN IF NOT EXISTS actor_name varchar(200);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contract_document_revisions DROP COLUMN IF EXISTS actor_name;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2930000000000-AddWagonTransferPartialFulfilment.ts b/apps/edr-freight-api/src/migrations/2930000000000-AddWagonTransferPartialFulfilment.ts deleted file mode 100644 index a9cc5e74d..000000000 --- a/apps/edr-freight-api/src/migrations/2930000000000-AddWagonTransferPartialFulfilment.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Partial wagon-transfer fulfilment. - * - * A request for 50 wagons no longer has to be met in one go: OCC moves what the - * source yard can spare, whenever it can, and the request stays open until the - * full count is met (FULFILLED) or OCC ends it short (CLOSED_SHORT) so the - * requester can ask another yard for the rest. - * - * Existing rows are back-filled so history keeps reading correctly: a FULFILLED - * request delivered its whole quantity; anything else delivered nothing. - */ -export class AddWagonTransferPartialFulfilment2930000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_transfer_requests - ADD COLUMN IF NOT EXISTS fulfilled_quantity integer NOT NULL DEFAULT 0, - ADD COLUMN IF NOT EXISTS closed_short_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS closed_short_by_user_id uuid NULL - `); - await queryRunner.query(` - UPDATE freight.wagon_transfer_requests - SET fulfilled_quantity = quantity - WHERE status = 'FULFILLED' - AND fulfilled_quantity = 0 - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.wagon_transfer_requests - DROP COLUMN IF EXISTS fulfilled_quantity, - DROP COLUMN IF EXISTS closed_short_at, - DROP COLUMN IF EXISTS closed_short_by_user_id - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2940000000000-AddFileVersionHistory.ts b/apps/edr-freight-api/src/migrations/2940000000000-AddFileVersionHistory.ts deleted file mode 100644 index ad9bae99c..000000000 --- a/apps/edr-freight-api/src/migrations/2940000000000-AddFileVersionHistory.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Keep every version of a stored document. - * - * Replacing a file used to DELETE the previous row outright, so a staff - * correction erased the customer's original upload with no trail. Superseded - * versions are now soft-deleted (already excluded from every read by TypeORM's - * soft-delete filter) and stamped with who replaced them and why, which is what - * the document's version history reads back. - */ -export class AddFileVersionHistory2940000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.files - ADD COLUMN IF NOT EXISTS replaced_by_user_id uuid NULL, - ADD COLUMN IF NOT EXISTS replace_reason text NULL - `); - // History reads walk one document's versions, deleted rows included. - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS "IDX_files_version_history" - ON freight.files (resource, resource_id, code, created_at DESC) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_files_version_history"`); - await queryRunner.query(` - ALTER TABLE freight.files - DROP COLUMN IF EXISTS replaced_by_user_id, - DROP COLUMN IF EXISTS replace_reason - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2950000000000-AddTransitAssigneeHandshake.ts b/apps/edr-freight-api/src/migrations/2950000000000-AddTransitAssigneeHandshake.ts deleted file mode 100644 index bd9647d44..000000000 --- a/apps/edr-freight-api/src/migrations/2950000000000-AddTransitAssigneeHandshake.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Transit-assignee handshake before the customs declaration. - * - * GL Ethiopia must ask GL Djibouti who will handle the shipment in transit, and - * Djibouti answers with a name, before the declaration can be filed. The whole - * exchange lives on the clearance cycle so it repeats naturally with each cycle - * of a GENERAL contract. - */ -export class AddTransitAssigneeHandshake2950000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.contract_clearance_cycles - ADD COLUMN IF NOT EXISTS transit_assignee_requested_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_requested_by_user_id uuid NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_request_note text NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_name text NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_assigned_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_assigned_by_user_id uuid NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.contract_clearance_cycles - DROP COLUMN IF EXISTS transit_assignee_requested_at, - DROP COLUMN IF EXISTS transit_assignee_requested_by_user_id, - DROP COLUMN IF EXISTS transit_assignee_request_note, - DROP COLUMN IF EXISTS transit_assignee_name, - DROP COLUMN IF EXISTS transit_assignee_assigned_at, - DROP COLUMN IF EXISTS transit_assignee_assigned_by_user_id - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/2960000000000-AddContractHazardDeclaration.ts b/apps/edr-freight-api/src/migrations/2960000000000-AddContractHazardDeclaration.ts deleted file mode 100644 index 810f59a07..000000000 --- a/apps/edr-freight-api/src/migrations/2960000000000-AddContractHazardDeclaration.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Hazardous contracts now declare WHAT the dangerous good is, not just that it - * exists: the UN/ADR class (CLASS_1..CLASS_9) and the shipment's UN number. Both - * are captured in the portal alongside the hazard documents and reviewed by the - * two hazardous approval desks. - * - * Nullable — non-hazardous contracts leave both null, and contracts created - * before this change have no declaration to backfill. - */ -export class AddContractHazardDeclaration2960000000000 - implements MigrationInterface -{ - name = 'AddContractHazardDeclaration2960000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts ADD COLUMN IF NOT EXISTS hazard_class varchar(16);`, - ); - await queryRunner.query( - `ALTER TABLE freight.contracts ADD COLUMN IF NOT EXISTS un_number varchar(16);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts DROP COLUMN IF EXISTS un_number;`, - ); - await queryRunner.query( - `ALTER TABLE freight.contracts DROP COLUMN IF EXISTS hazard_class;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2970000000000-AddDoCollectionDates.ts b/apps/edr-freight-api/src/migrations/2970000000000-AddDoCollectionDates.ts deleted file mode 100644 index 90b3a9298..000000000 --- a/apps/edr-freight-api/src/migrations/2970000000000-AddDoCollectionDates.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Djibouti GL must record WHEN the vessel arrived and WHEN the Delivery Order - * was collected, not just attach the DO file. Both are mandatory on DO upload - * (enforced in the clearance services), so the columns are new and nullable — - * DOs uploaded before this change have no dates to backfill. - * - * `vessel_departure_date` is the EXPORT Release-Order date and stays as-is; the - * import arrival date gets its own column rather than overloading it. - */ -export class AddDoCollectionDates2970000000000 implements MigrationInterface { - name = 'AddDoCollectionDates2970000000000'; - - public async up(queryRunner: QueryRunner): Promise { - for (const table of [ - 'freight.contract_clearance_cycles', - 'freight.bookings', - ]) { - await queryRunner.query( - `ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS vessel_arrival_date date;`, - ); - await queryRunner.query( - `ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS do_collected_date date;`, - ); - } - } - - public async down(queryRunner: QueryRunner): Promise { - for (const table of [ - 'freight.contract_clearance_cycles', - 'freight.bookings', - ]) { - await queryRunner.query( - `ALTER TABLE ${table} DROP COLUMN IF EXISTS do_collected_date;`, - ); - await queryRunner.query( - `ALTER TABLE ${table} DROP COLUMN IF EXISTS vessel_arrival_date;`, - ); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/2980000000000-AddBookingRequestCurrency.ts b/apps/edr-freight-api/src/migrations/2980000000000-AddBookingRequestCurrency.ts deleted file mode 100644 index 5f92cff68..000000000 --- a/apps/edr-freight-api/src/migrations/2980000000000-AddBookingRequestCurrency.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Currency moved from the contract to the shipment: a contract now quotes in - * USD and the customer picks the billing currency per booking. On a customs - * contract GL books on the customer's behalf, so the shipment request is where - * the customer states the currency — GL reads it when creating the booking. - * - * Nullable: requests submitted before this change fall back to the contract's - * own currency, which is exactly what their bookings already used. - */ -export class AddBookingRequestCurrency2980000000000 implements MigrationInterface { - name = 'AddBookingRequestCurrency2980000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_requests ADD COLUMN IF NOT EXISTS payment_currency varchar(5);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.booking_requests DROP COLUMN IF EXISTS payment_currency;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/2990000000000-IndodeYardsAndCargoRouting.ts b/apps/edr-freight-api/src/migrations/2990000000000-IndodeYardsAndCargoRouting.ts deleted file mode 100644 index d89e0c04b..000000000 --- a/apps/edr-freight-api/src/migrations/2990000000000-IndodeYardsAndCargoRouting.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Indode's real 11-yard layout, plus the plumbing to auto-route a booking to - * the right yard by cargo type (and, for container yards, trade direction): - * - * - `warehouse_yards.direction` — IMPORT | EXPORT | BOTH | null. Only - * meaningful for CONTAINER_YARD, where import and export stacks are - * physically separate (Yard 5 vs Yard 6). Everything else takes cargo - * either way. A CONTAINER_YARD left at null/BOTH is a signal too: it means - * "not a customer cargo yard" — Yards 10/11 (service/equipment) are - * CONTAINER_YARD structurally but must never be offered for ordinary - * import/export cargo, so the frontend match requires an EXACT IMPORT/ - * EXPORT direction hit for container freight rather than treating BOTH as - * a wildcard. - * - `warehouse_yard_cargo_types` — which cargo types a yard accepts (mirrors - * the existing `cargo_type_wagon_types` join table). Empty = open to any - * cargo type of the yard's structural type (additive, never restrictive - * by default), so this cannot break a yard nobody has configured yet. - * - * Three cargo types didn't exist yet (Fertilizer, Coffee, Tea) — added here - * so Yards 1 and 9 have a real mapping ready for when they reopen. - */ -export class IndodeYardsAndCargoRouting2990000000000 implements MigrationInterface { - name = "IndodeYardsAndCargoRouting2990000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.warehouse_yards - ADD COLUMN IF NOT EXISTS direction varchar(10) - `); - - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.warehouse_yard_cargo_types ( - yard_id uuid NOT NULL REFERENCES freight.warehouse_yards (id) ON DELETE CASCADE, - cargo_type_id uuid NOT NULL REFERENCES freight.cargo_types (id) ON DELETE CASCADE, - PRIMARY KEY (yard_id, cargo_type_id) - ) - `); - - // New cargo types Indode's yard list names but the catalog didn't have yet. - await queryRunner.query(` - INSERT INTO freight.cargo_types (code, cargo_type_name, unit_of_measure, is_active) - VALUES - ('FERTILIZER', 'Fertilizer', 'PER_TON', true), - ('COFFEE', 'Coffee', 'PER_TON', true), - ('TEA', 'Tea', 'PER_TON', true) - ON CONFLICT (code) DO NOTHING - `); - - // The 11 real yards at Indode Open Warehouse (code 'IOW'). - await queryRunner.query(` - INSERT INTO freight.warehouse_yards - (warehouse_id, name, code, type, direction, status, is_active) - SELECT w.id, y.name, y.code, y.type, y.direction, y.status, y.status = 'ACTIVE' - FROM freight.warehouses w - CROSS JOIN (VALUES - ('Y1', 'Bagged Cargo Discharge - Fertilizer', 'BULK_YARD', NULL, 'INACTIVE'), - ('Y2', 'Break Bulk', 'GENERAL_CARGO_YARD', NULL, 'ACTIVE'), - ('Y3', 'Ro-Ro / Pac', 'GENERAL_CARGO_YARD', NULL, 'ACTIVE'), - ('Y4', 'Dry Bulk', 'BULK_YARD', NULL, 'INACTIVE'), - ('Y5', 'Container Terminal - Import (Stack Area)', 'CONTAINER_YARD', 'IMPORT', 'ACTIVE'), - ('Y6', 'Container Terminal - Export', 'CONTAINER_YARD', 'EXPORT', 'ACTIVE'), - ('Y7', 'Cold Chain', 'COLD_STORAGE_YARD', NULL, 'INACTIVE'), - ('Y8', 'Chemical', 'HAZARDOUS_YARD', NULL, 'INACTIVE'), - ('Y9', 'Coffee and Tea', 'GENERAL_CARGO_YARD', NULL, 'INACTIVE'), - ('Y10', 'Container Service Yard - Maintenance', 'CONTAINER_YARD', 'BOTH', 'ACTIVE'), - ('Y11', 'Equipment (Empty Container)', 'CONTAINER_YARD', 'BOTH', 'ACTIVE') - ) AS y(code, name, type, direction, status) - WHERE w.code = 'IOW' - ON CONFLICT (warehouse_id, code) DO NOTHING - `); - - // One default zone per new yard, matching its yard's type — every existing - // yard (CY-1, CY-A) already follows this one-zone-per-yard shape. - await queryRunner.query(` - INSERT INTO freight.warehouse_zones (yard_id, name, code, type, status, is_active) - SELECT y.id, y.name || ' Zone 1', 'Z1', - CASE y.type - WHEN 'CONTAINER_YARD' THEN 'CONTAINER_ZONE' - WHEN 'COLD_STORAGE_YARD' THEN 'COLD_STORAGE_ZONE' - WHEN 'HAZARDOUS_YARD' THEN 'HAZARDOUS_ZONE' - WHEN 'BULK_YARD' THEN 'BULK_ZONE' - ELSE 'GENERAL_CARGO_ZONE' - END, - y.status, y.status = 'ACTIVE' - FROM freight.warehouse_yards y - JOIN freight.warehouses w ON w.id = y.warehouse_id - WHERE w.code = 'IOW' AND y.code LIKE 'Y%' - ON CONFLICT (yard_id, code) DO NOTHING - `); - - // Cargo-type routing. Yards 5/6/10/11 (CONTAINER_YARD) are intentionally - // left with no rows — direction alone decides those, per the entity comment. - await queryRunner.query(` - INSERT INTO freight.warehouse_yard_cargo_types (yard_id, cargo_type_id) - SELECT y.id, ct.id - FROM freight.warehouses w - JOIN freight.warehouse_yards y ON y.warehouse_id = w.id - JOIN (VALUES - ('Y1', 'FERTILIZER'), - ('Y2', 'STEEL_BILLET'), ('Y2', 'PLASTIC_BARREL'), ('Y2', 'MACHINERY'), ('Y2', 'LIVESTOCK'), - ('Y3', 'AUTOMOBILE'), ('Y3', 'TRUCK'), - ('Y4', 'BARLY'), ('Y4', 'BEANS'), ('Y4', 'BULK'), ('Y4', 'CEREAL'), - ('Y4', 'EDIBLE_OIL'), ('Y4', 'RICE'), ('Y4', 'SUGAR'), ('Y4', 'WHEAT'), - ('Y7', 'PERISHABLE'), - ('Y9', 'COFFEE'), ('Y9', 'TEA') - ) AS m(yard_code, cargo_code) ON m.yard_code = y.code - JOIN freight.cargo_types ct ON ct.code = m.cargo_code - WHERE w.code = 'IOW' - ON CONFLICT (yard_id, cargo_type_id) DO NOTHING - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DELETE FROM freight.warehouse_zones z - USING freight.warehouse_yards y, freight.warehouses w - WHERE z.yard_id = y.id AND y.warehouse_id = w.id - AND w.code = 'IOW' AND y.code LIKE 'Y%' - `); - await queryRunner.query(` - DELETE FROM freight.warehouse_yards y - USING freight.warehouses w - WHERE y.warehouse_id = w.id AND w.code = 'IOW' AND y.code LIKE 'Y%' - `); - // Cargo types and the join table are left in place — other data may have - // started referencing them since; dropping columns/tables is not reversible - // once real rows exist, and leaving them is harmless. - } -} diff --git a/apps/edr-freight-api/src/migrations/3000000000000-AddContractSuspension.ts b/apps/edr-freight-api/src/migrations/3000000000000-AddContractSuspension.ts deleted file mode 100644 index 0e0484345..000000000 --- a/apps/edr-freight-api/src/migrations/3000000000000-AddContractSuspension.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Backoffice contract suspension (reversible freeze at any post-signature step) - * and customer-initiated contract cancellation. - * - * Only one new column is needed: the status to restore when the suspension is - * lifted. The reason and the actor already have a home — contract_review_notes - * rows with note_type SUSPENSION / SUSPENSION_LIFTED / CANCELLATION. - */ -export class AddContractSuspension3000000000000 implements MigrationInterface { - name = 'AddContractSuspension3000000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts ADD COLUMN IF NOT EXISTS status_before_suspension varchar(40);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts DROP COLUMN IF EXISTS status_before_suspension;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3010000000000-AddBookingTransitAssignee.ts b/apps/edr-freight-api/src/migrations/3010000000000-AddBookingTransitAssignee.ts deleted file mode 100644 index 50fb9db2b..000000000 --- a/apps/edr-freight-api/src/migrations/3010000000000-AddBookingTransitAssignee.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Transit-assignee handshake on the SHIPMENT, not the contract. - * - * Clearance runs per booking now, so the ask GL Ethiopia raises before filing a - * customs declaration ("who handles this shipment in Djibouti?") and Djibouti's - * answer belong on the booking. The contract-cycle columns added by - * 2950000000000 stay for the legacy contract-level cycles. - */ -export class AddBookingTransitAssignee3010000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - ADD COLUMN IF NOT EXISTS transit_assignee_requested_at timestamptz NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_request_note text NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_name text NULL, - ADD COLUMN IF NOT EXISTS transit_assignee_assigned_at timestamptz NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.bookings - DROP COLUMN IF EXISTS transit_assignee_requested_at, - DROP COLUMN IF EXISTS transit_assignee_request_note, - DROP COLUMN IF EXISTS transit_assignee_name, - DROP COLUMN IF EXISTS transit_assignee_assigned_at - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3020000000000-AddContractSubmittedAt.ts b/apps/edr-freight-api/src/migrations/3020000000000-AddContractSubmittedAt.ts deleted file mode 100644 index f2c579f6b..000000000 --- a/apps/edr-freight-api/src/migrations/3020000000000-AddContractSubmittedAt.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * A contract's `created_at` is the DRAFT row's insert time, not when the - * customer actually submitted it for review — a DRAFT can sit edited for days - * first. `submitted_at` is stamped by ContractTransitionService.submit / - * confirmSubmit so the history UI can show a real submission time. - */ -export class AddContractSubmittedAt3020000000000 implements MigrationInterface { - name = 'AddContractSubmittedAt3020000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts ADD COLUMN IF NOT EXISTS submitted_at timestamptz;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.contracts DROP COLUMN IF EXISTS submitted_at;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3030000000000-AddGlExchangeDocumentFields.ts b/apps/edr-freight-api/src/migrations/3030000000000-AddGlExchangeDocumentFields.ts deleted file mode 100644 index 2958f5406..000000000 --- a/apps/edr-freight-api/src/migrations/3030000000000-AddGlExchangeDocumentFields.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * GL Ethiopia ↔ GL Djibouti document exchange. The documents are ordinary - * `freight.files` rows (resource `gl_exchange`), so they only need the metadata - * a free-form upload has and a catalog-driven one does not: the uploader's own - * title, who uploaded it (the only user allowed to change it afterwards) and - * whether the customer may see it in the portal. - */ -export class AddGlExchangeDocumentFields3030000000000 - implements MigrationInterface -{ - name = 'AddGlExchangeDocumentFields3030000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.files - ADD COLUMN IF NOT EXISTS title varchar(300), - ADD COLUMN IF NOT EXISTS visible_to_customer boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS uploaded_by_user_id uuid, - ADD COLUMN IF NOT EXISTS uploaded_by_name varchar(200);`, - ); - // Every read of a thread is "all files of one resource" — index the pair. - await queryRunner.query( - `CREATE INDEX IF NOT EXISTS idx_files_resource_lookup - ON freight.files (resource, resource_id);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DROP INDEX IF EXISTS freight.idx_files_resource_lookup;`, - ); - await queryRunner.query( - `ALTER TABLE freight.files - DROP COLUMN IF EXISTS title, - DROP COLUMN IF EXISTS visible_to_customer, - DROP COLUMN IF EXISTS uploaded_by_user_id, - DROP COLUMN IF EXISTS uploaded_by_name;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3040000000000-AddTransitAgents.ts b/apps/edr-freight-api/src/migrations/3040000000000-AddTransitAgents.ts deleted file mode 100644 index f587af9a7..000000000 --- a/apps/edr-freight-api/src/migrations/3040000000000-AddTransitAgents.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddTransitAgents3040000000000 implements MigrationInterface { - name = "AddTransitAgents3040000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE IF NOT EXISTS freight.transit_agents ( - id uuid PRIMARY KEY DEFAULT gen_random_uuid(), - name varchar(150) NOT NULL, - valid_from date NOT NULL, - valid_to date NOT 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 - ) - `); - - await queryRunner.query(` - CREATE INDEX IF NOT EXISTS ix_transit_agents_is_active - ON freight.transit_agents (is_active) - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE IF EXISTS freight.transit_agents`); - } -} diff --git a/apps/edr-freight-api/src/migrations/3050000000000-AddCbeBillPaymentMethod.ts b/apps/edr-freight-api/src/migrations/3050000000000-AddCbeBillPaymentMethod.ts deleted file mode 100644 index 449f3cebe..000000000 --- a/apps/edr-freight-api/src/migrations/3050000000000-AddCbeBillPaymentMethod.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddCbeBillPaymentMethod3050000000000 implements MigrationInterface { - name = "AddCbeBillPaymentMethod3050000000000"; - - public async up(queryRunner: QueryRunner): Promise { - // CBE Unified Bill Payment (docs/cbe/CBE_IMPLEMENTATION_PLAN.md §4.3) — lowercase-hyphen - // per the local convention (see 2460000000000-AddCacBankPaymentMethod). - await queryRunner.query(`ALTER TYPE freight.payments_method_enum ADD VALUE IF NOT EXISTS 'cbe-bill';`); - } - - public async down(_queryRunner: QueryRunner): Promise { - // PostgreSQL does not support removing enum values directly. - } -} diff --git a/apps/edr-freight-api/src/migrations/3050000000000-MergeDuplicateSebetaYards.ts b/apps/edr-freight-api/src/migrations/3050000000000-MergeDuplicateSebetaYards.ts deleted file mode 100644 index c8a2c5722..000000000 --- a/apps/edr-freight-api/src/migrations/3050000000000-MergeDuplicateSebetaYards.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Two active "Sebeta" yards existed (code LEGACY_DEST label "Sebeta", and code - * SEBETA label "sebeta") — rates and routes pointed at one or the other, so a - * rate configured against one never matched a contract routed via the other. - * Merge them: keep the row all rates/distances/facilities reference - * (LEGACY_DEST), repoint every yard reference from the duplicate to it, retire - * the duplicate, and give the survivor the clean SEBETA code. Then make - * duplicate active yard labels/codes impossible at the DB level. - */ -export class MergeDuplicateSebetaYards3050000000000 implements MigrationInterface { - name = "MergeDuplicateSebetaYards3050000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ - DECLARE - survivor uuid; - dupe uuid; - col record; - BEGIN - SELECT id INTO survivor FROM freight.yards - WHERE code = 'LEGACY_DEST' AND lower(trim(label)) = 'sebeta' AND deleted_at IS NULL; - SELECT id INTO dupe FROM freight.yards - WHERE code = 'SEBETA' AND deleted_at IS NULL; - IF survivor IS NULL OR dupe IS NULL OR survivor = dupe THEN - RETURN; - END IF; - - -- Every yard-referencing column in the schema, so rows created between - -- authoring and running this migration are repointed too. - FOR col IN - SELECT table_name, column_name FROM information_schema.columns - WHERE table_schema = 'freight' - AND table_name <> 'yards' - AND (column_name LIKE '%yard_id%' OR column_name LIKE '%station_id%') - LOOP - EXECUTE format( - 'UPDATE freight.%I SET %I = $1 WHERE %I = $2', - col.table_name, col.column_name, col.column_name - ) USING survivor, dupe; - END LOOP; - - UPDATE freight.yards - SET code = 'SEBETA@merged', label = 'sebeta@merged', deleted_at = now() - WHERE id = dupe; - UPDATE freight.yards SET code = 'SEBETA', label = 'Sebeta' WHERE id = survivor; - END $$; - `); - - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_yards_label_active" - ON freight.yards (lower(trim(label))) WHERE deleted_at IS NULL - `); - await queryRunner.query(` - CREATE UNIQUE INDEX IF NOT EXISTS "UQ_yards_code_active" - ON freight.yards (lower(trim(code))) WHERE deleted_at IS NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - // Data repair — not reversible. The uniqueness indexes are the new invariant. - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_yards_label_active"`); - await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_yards_code_active"`); - } -} diff --git a/apps/edr-freight-api/src/migrations/3060000000000-AddExportPaymentWindow.ts b/apps/edr-freight-api/src/migrations/3060000000000-AddExportPaymentWindow.ts deleted file mode 100644 index c55745126..000000000 --- a/apps/edr-freight-api/src/migrations/3060000000000-AddExportPaymentWindow.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Export bookings get their own pay window, separately tunable from import: - * - global_rules.export_payment_window_minutes — global default for EXPORT - * (payment_window_minutes keeps governing IMPORT/DOMESTIC). - * - train_schedules.rule_payment_window_minutes — per-schedule override; until - * now the DTO accepted paymentWindowMinutes but only folded it into the - * reopen-delay sum, so the override never reached the actual pay window. - * - bookings.requested_train_schedule_id — the export train the customer picked - * at day-commit; pickExportSchedule honors it instead of earliest-first. - * - bookings.payment_reminder_sent_at — marks the one pre-deadline pay - * reminder so the 10s window tick doesn't re-send it. - */ -export class AddExportPaymentWindow3060000000000 implements MigrationInterface { - name = 'AddExportPaymentWindow3060000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.train_scheduling_global_rules ADD COLUMN IF NOT EXISTS export_payment_window_minutes int NOT NULL DEFAULT 60;`, - ); - await queryRunner.query( - `ALTER TABLE freight.train_schedules ADD COLUMN IF NOT EXISTS rule_payment_window_minutes int;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS requested_train_schedule_id uuid;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS payment_reminder_sent_at timestamptz;`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS payment_reminder_sent_at;`, - ); - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS requested_train_schedule_id;`, - ); - await queryRunner.query( - `ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS rule_payment_window_minutes;`, - ); - await queryRunner.query( - `ALTER TABLE freight.train_scheduling_global_rules DROP COLUMN IF EXISTS export_payment_window_minutes;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3070000000000-AddBulkTotalWeightTons.ts b/apps/edr-freight-api/src/migrations/3070000000000-AddBulkTotalWeightTons.ts deleted file mode 100644 index f2c50ec8d..000000000 --- a/apps/edr-freight-api/src/migrations/3070000000000-AddBulkTotalWeightTons.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Break-bulk (PER_ITEM) bookings store their item count in - * cargo_total_weight_vgm, so the actual tonnage was never captured — wagon - * allocation divided an item COUNT by a tons capacity and under-allocated - * (400 machines ÷ 69T wagon read as 6 wagons instead of 12). New column holds - * the real total weight in tons for PER_ITEM cargo; null for PER_TON bulk and - * container bookings. - */ -export class AddBulkTotalWeightTons3070000000000 implements MigrationInterface { - name = 'AddBulkTotalWeightTons3070000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings ADD COLUMN IF NOT EXISTS bulk_total_weight_tons numeric(12,3);`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.bookings DROP COLUMN IF EXISTS bulk_total_weight_tons;`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3080000000000-BackfillDireDawaMilestone.ts b/apps/edr-freight-api/src/migrations/3080000000000-BackfillDireDawaMilestone.ts deleted file mode 100644 index 78c44c0ce..000000000 --- a/apps/edr-freight-api/src/migrations/3080000000000-BackfillDireDawaMilestone.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Several DCT (DORALEH) → GMP (KALITY) routes are missing the Dire Dawa stop - * in their milestone list. The corridor budget builds its per-leg edges from - * route_milestones, so on those routes a DCT→Dire Dawa or Dire Dawa→GMP - * booking cannot resolve its own leg and conservatively occupies the WHOLE - * route — per-leg wagon reuse (a wagon freed at Dire Dawa reloading for GMP) - * silently degrades to train-wide accounting. - * - * Insert the Dire Dawa milestone at sequence 2 on every active DORALEH→KALITY - * route with a stop list that lacks it, shifting later stops down. Matched by - * yard CODE so the repair is portable across environments. Idempotent: routes - * already carrying Dire Dawa are untouched. - */ -export class BackfillDireDawaMilestone3080000000000 implements MigrationInterface { - name = "BackfillDireDawaMilestone3080000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - DO $$ - DECLARE - dire uuid; - r record; - BEGIN - SELECT id INTO dire FROM freight.yards - WHERE code = 'DIRE_DAWA' AND deleted_at IS NULL; - IF dire IS NULL THEN - RETURN; - END IF; - - FOR r IN - SELECT rt.id - FROM freight.routes rt - JOIN freight.yards o ON o.id = rt.origin_yard_id AND o.code = 'DORALEH' - JOIN freight.yards d ON d.id = rt.destination_yard_id AND d.code = 'KALITY' - WHERE rt.deleted_at IS NULL - AND EXISTS (SELECT 1 FROM freight.route_milestones m - WHERE m.route_id = rt.id AND m.deleted_at IS NULL) - AND NOT EXISTS (SELECT 1 FROM freight.route_milestones m - WHERE m.route_id = rt.id AND m.yard_id = dire - AND m.deleted_at IS NULL) - LOOP - -- Two-phase shift: uq_route_milestones_route_sequence isn't deferrable, - -- so a direct +1 UPDATE can collide mid-scan (seq 2 -> 3 while seq 3 still live). - -- Route through negative sequence_no first to avoid any interim collision. - -- Soft-deleted rows shift too: the constraint counts them, so a dead row - -- left at a target sequence would still collide. - UPDATE freight.route_milestones - SET sequence_no = -sequence_no - WHERE route_id = r.id AND sequence_no >= 2; - UPDATE freight.route_milestones - SET sequence_no = -sequence_no + 1 - WHERE route_id = r.id AND sequence_no < 0; - INSERT INTO freight.route_milestones (route_id, yard_id, sequence_no) - VALUES (r.id, dire, 2); - END LOOP; - END $$; - `); - } - - public async down(): Promise { - // Data repair — not reversible. - } -} diff --git a/apps/edr-freight-api/src/migrations/3090000000000-AddSavedSignatureStamp.ts b/apps/edr-freight-api/src/migrations/3090000000000-AddSavedSignatureStamp.ts deleted file mode 100644 index 3beafb6bf..000000000 --- a/apps/edr-freight-api/src/migrations/3090000000000-AddSavedSignatureStamp.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSavedSignatureStamp3090000000000 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.saved_signatures - ADD COLUMN IF NOT EXISTS stamp_file_id UUID NULL; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.saved_signatures - DROP COLUMN IF EXISTS stamp_file_id; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3100000000000-PromoteDraftSchedulesToScheduled.ts b/apps/edr-freight-api/src/migrations/3100000000000-PromoteDraftSchedulesToScheduled.ts deleted file mode 100644 index f5a916bd3..000000000 --- a/apps/edr-freight-api/src/migrations/3100000000000-PromoteDraftSchedulesToScheduled.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * The draft/finalize phase is abolished: train schedules are created SCHEDULED - * and the Finalize button is gone from the backoffice. Promote every surviving - * DRAFT schedule so it stays reachable (dispatch requires SCHEDULED and there - * is no manual promotion path anymore). Idempotent; one-way — the original - * DRAFT set is not recorded, so down() cannot restore it. - */ -export class PromoteDraftSchedulesToScheduled3100000000000 implements MigrationInterface { - name = "PromoteDraftSchedulesToScheduled3100000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE freight.train_schedules - SET status = 'SCHEDULED' - WHERE status = 'DRAFT' - AND deleted_at IS NULL`, - ); - } - - public async down(): Promise { - // One-way data promotion — nothing to restore. - } -} diff --git a/apps/edr-freight-api/src/migrations/3110000000000-AddYardToScheduleWagonAdjustmentLogs.ts b/apps/edr-freight-api/src/migrations/3110000000000-AddYardToScheduleWagonAdjustmentLogs.ts deleted file mode 100644 index 0e1d13175..000000000 --- a/apps/edr-freight-api/src/migrations/3110000000000-AddYardToScheduleWagonAdjustmentLogs.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Consist adjustments can now happen mid-route (train standing at a stop), so - * each history row records WHERE it happened. Nullable — rows written before - * this column simply have no yard. - */ -export class AddYardToScheduleWagonAdjustmentLogs3110000000000 implements MigrationInterface { - name = "AddYardToScheduleWagonAdjustmentLogs3110000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.schedule_wagon_adjustment_logs - ADD COLUMN IF NOT EXISTS yard_id uuid`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.schedule_wagon_adjustment_logs - DROP COLUMN IF EXISTS yard_id`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3120000000000-AddApprovedAtToCompanies.ts b/apps/edr-freight-api/src/migrations/3120000000000-AddApprovedAtToCompanies.ts deleted file mode 100644 index 976aca798..000000000 --- a/apps/edr-freight-api/src/migrations/3120000000000-AddApprovedAtToCompanies.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * Pending→Active is the only company-level approval event; `updatedAt` can't - * stand in for it since any field edit bumps that too. Nullable — existing - * companies (approved before this column existed) have no recorded moment. - */ -export class AddApprovedAtToCompanies3120000000000 implements MigrationInterface { - name = "AddApprovedAtToCompanies3120000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.companies - ADD COLUMN IF NOT EXISTS approved_at timestamptz`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE freight.companies - DROP COLUMN IF EXISTS approved_at`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3120000000000-AddCargoTypeItemsPerWagonMap.ts b/apps/edr-freight-api/src/migrations/3120000000000-AddCargoTypeItemsPerWagonMap.ts deleted file mode 100644 index 153928b04..000000000 --- a/apps/edr-freight-api/src/migrations/3120000000000-AddCargoTypeItemsPerWagonMap.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Break-bulk (PER_ITEM) cargo needs a physical items-fit per allowed wagon - * type (e.g. cars → NW5: 4, NW7: 6): a wagon runs out of floor space before it - * runs out of rated tonnage, so allocation must respect BOTH limits. Stored as - * a jsonb map { [wagonTypeId]: itemsFit } on cargo_types — keys mirror the - * cargo_type_wagon_types join rows, kept in sync by the cargo-types service. - */ -export class AddCargoTypeItemsPerWagonMap3120000000000 implements MigrationInterface { - name = 'AddCargoTypeItemsPerWagonMap3120000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."cargo_types" ADD COLUMN IF NOT EXISTS "items_per_wagon_map" jsonb`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."cargo_types" DROP COLUMN IF EXISTS "items_per_wagon_map"`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3130000000000-CreateCompanyRevisions.ts b/apps/edr-freight-api/src/migrations/3130000000000-CreateCompanyRevisions.ts deleted file mode 100644 index 01c1c6991..000000000 --- a/apps/edr-freight-api/src/migrations/3130000000000-CreateCompanyRevisions.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Append-only audit of company edits made before the company reaches Active - * (the onboarding phase) — that write path has no approval gate and, until - * now, left no trace of what changed (e.g. a phone number or a document). - */ -export class CreateCompanyRevisions3130000000000 implements MigrationInterface { - name = 'CreateCompanyRevisions3130000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'company_revisions', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'company_id', type: 'uuid' }, - { name: 'actor_id', type: 'uuid', isNullable: true }, - { name: 'summary', type: 'varchar', length: '255' }, - { name: 'changes', type: 'jsonb', default: "'[]'::jsonb" }, - { name: 'created_at', type: 'timestamptz', default: 'now()' }, - { name: 'updated_at', type: 'timestamptz', default: 'now()' }, - { name: 'deleted_at', type: 'timestamptz', isNullable: true }, - ], - foreignKeys: [ - { - columnNames: ['company_id'], - referencedSchema: 'freight', - referencedTableName: 'companies', - referencedColumnNames: ['id'], - onDelete: 'CASCADE', - }, - ], - }), - true, - ); - - await queryRunner.createIndex( - 'freight.company_revisions', - new TableIndex({ name: 'idx_company_revisions_company', columnNames: ['company_id'] }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.company_revisions', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/3140000000000-SyncBulkRateUnitsToCargoUom.ts b/apps/edr-freight-api/src/migrations/3140000000000-SyncBulkRateUnitsToCargoUom.ts deleted file mode 100644 index b2a931542..000000000 --- a/apps/edr-freight-api/src/migrations/3140000000000-SyncBulkRateUnitsToCargoUom.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Rates created before their commodity's unit_of_measure was flipped kept the - * old bulk-quantity unit, so bookings of a PER_ITEM commodity (e.g. Machinery) - * quoted "per ton". PER_TON and PER_ITEM bill the same stored quantity — only - * the name differs — so renaming is safe. Going forward the cargo-types - * service syncs rates on every uom change; this backfills the drift. - */ -export class SyncBulkRateUnitsToCargoUom3140000000000 implements MigrationInterface { - name = 'SyncBulkRateUnitsToCargoUom3140000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `UPDATE "freight"."rates" r - SET "rate_unit" = 'PER_ITEM' - FROM "freight"."cargo_types" ct - WHERE ct."id" = r."cargo_type_id" - AND ct."unit_of_measure" = 'PER_ITEM' - AND r."rate_unit" = 'PER_TON'`, - ); - await queryRunner.query( - `UPDATE "freight"."rates" r - SET "rate_unit" = 'PER_TON' - FROM "freight"."cargo_types" ct - WHERE ct."id" = r."cargo_type_id" - AND ct."unit_of_measure" = 'PER_TON' - AND r."rate_unit" = 'PER_ITEM'`, - ); - } - - public async down(): Promise { - // Irreversible rename-by-join: the pre-sync unit is not recorded. Both - // units bill identically, so rolling back the code needs no data change. - } -} diff --git a/apps/edr-freight-api/src/migrations/3150000000000-CreateUserTradeAccess.ts b/apps/edr-freight-api/src/migrations/3150000000000-CreateUserTradeAccess.ts deleted file mode 100644 index 9e7cba924..000000000 --- a/apps/edr-freight-api/src/migrations/3150000000000-CreateUserTradeAccess.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; - -/** - * Per-backoffice-user trade-direction scope (import / export / intercity). - * A user with no row (or all three directions) is unrestricted. Admins - * (super_admin / organization_admin) bypass the scope entirely. - */ -export class CreateUserTradeAccess3150000000000 implements MigrationInterface { - name = 'CreateUserTradeAccess3150000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'user_trade_access', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - // IAM user id (iam.users) — no FK, iam schema is externally owned. - { name: 'user_id', type: 'uuid', isUnique: true }, - // Comma-separated subset of IMPORT,EXPORT,DOMESTIC (simple-array). - { name: 'directions', type: 'text', default: "''" }, - { name: 'updated_by_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.createIndex( - 'freight.user_trade_access', - new TableIndex({ - name: 'idx_user_trade_access_user_id', - columnNames: ['user_id'], - }), - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.user_trade_access', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/3150000000000-FixFaydaAddressShape.ts b/apps/edr-freight-api/src/migrations/3150000000000-FixFaydaAddressShape.ts deleted file mode 100644 index 7a8923f3c..000000000 --- a/apps/edr-freight-api/src/migrations/3150000000000-FixFaydaAddressShape.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * A normalizeUserInfo bug in VerifaydaService read the raw `address#en` / - * `address#am` claim objects (e.g. `{ "zone#en": "...", "region#en": "...", - * "woreda#en": "..." }`) straight through as if they were strings, so any - * company verified before the fix has `attributes.ownerAddress` / - * `poaAddress` stored as that raw object instead of a formatted string — - * which crashes the portal when it tries to render it as text. - * - * Reformats every affected row's ownerAddress/poaAddress into - * "woreda, zone, region" (falling back to whatever #en fields are present, - * in that preferred order, then any leftover fields), mirroring - * VerifaydaService.formatFaydaAddress. Only touches rows where the field is - * still a jsonb object, so it's idempotent and a no-op once repaired. - */ -export class FixFaydaAddressShape3150000000000 implements MigrationInterface { - name = "FixFaydaAddressShape3150000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE OR REPLACE FUNCTION pg_temp.format_fayda_address(addr jsonb) - RETURNS text AS $$ - DECLARE - field_order text[] := ARRAY['houseNumber','kebele','woreda','city','subCity','zone','region','postalCode','country']; - f text; - v text; - parts text[] := '{}'; - used_keys text[] := '{}'; - kv record; - BEGIN - IF addr IS NULL OR jsonb_typeof(addr) != 'object' THEN - RETURN NULL; - END IF; - - FOREACH f IN ARRAY field_order LOOP - v := addr ->> (f || '#en'); - IF v IS NOT NULL AND trim(v) != '' THEN - parts := array_append(parts, trim(v)); - used_keys := array_append(used_keys, f || '#en'); - END IF; - END LOOP; - - FOR kv IN SELECT * FROM jsonb_each_text(addr) LOOP - IF kv.key LIKE '%#en' AND NOT (kv.key = ANY(used_keys)) - AND kv.value IS NOT NULL AND trim(kv.value) != '' THEN - parts := array_append(parts, trim(kv.value)); - END IF; - END LOOP; - - IF array_length(parts, 1) IS NULL THEN - RETURN NULL; - END IF; - RETURN array_to_string(parts, ', '); - END; - $$ LANGUAGE plpgsql; - - UPDATE freight.companies - SET attributes = jsonb_set( - attributes, - '{ownerAddress}', - to_jsonb(pg_temp.format_fayda_address(attributes -> 'ownerAddress')) - ) - WHERE jsonb_typeof(attributes -> 'ownerAddress') = 'object'; - - UPDATE freight.companies - SET attributes = jsonb_set( - attributes, - '{poaAddress}', - to_jsonb(pg_temp.format_fayda_address(attributes -> 'poaAddress')) - ) - WHERE jsonb_typeof(attributes -> 'poaAddress') = 'object'; - - DROP FUNCTION pg_temp.format_fayda_address(jsonb); - `); - } - - public async down(): Promise { - // Data repair — not reversible (the original malformed shape isn't worth restoring). - } -} diff --git a/apps/edr-freight-api/src/migrations/3160000000000-FixPaymentPaidAtType.ts b/apps/edr-freight-api/src/migrations/3160000000000-FixPaymentPaidAtType.ts deleted file mode 100644 index 35ccdc658..000000000 --- a/apps/edr-freight-api/src/migrations/3160000000000-FixPaymentPaidAtType.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -/** - * `freight.payments.paid_at` was created as `date` (CreatePaymentTable) and never - * migrated to `timestamp` alongside its siblings `refunded_at`/`expires_at` - * (UpdatePaymentTimestamp). TypeORM's postgres driver hydrates `date` columns as a - * plain "YYYY-MM-DD" string, not a `Date` — so `PaymentEntity.paidAt` (typed `Date`) - * was actually a string once read back from the DB, and - * `intent.paidAt?.toISOString()` in PaymentService.formatIntentStatus threw - * `TypeError: intent.paidAt.toISOString is not a function`. This hit every - * OTP-confirm response (CAC Bank) because confirmOtp always re-reads the intent - * before formatting the response. - */ -export class FixPaymentPaidAtType3160000000000 implements MigrationInterface { - name = "FixPaymentPaidAtType3160000000000"; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN paid_at TYPE timestamp - USING paid_at::timestamp; - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.payments - ALTER COLUMN paid_at TYPE date - USING paid_at::date; - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3170000000000-YardFacilityOriginDestination.ts b/apps/edr-freight-api/src/migrations/3170000000000-YardFacilityOriginDestination.ts deleted file mode 100644 index fb361b702..000000000 --- a/apps/edr-freight-api/src/migrations/3170000000000-YardFacilityOriginDestination.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Handling a freight type is not the same as handling it in both directions. A - * facility can be equipped to load containers onto a train but have no yard - * space to receive and stage inbound ones, so the origin and destination sides - * are stated independently per freight type. - * - * Backfilled from `handles_container` / `handles_bulk` so every existing row - * keeps its current behaviour: a facility that handles a type today handles it - * on both sides until someone narrows it in the backoffice. New rows default - * false — an unconfigured facility offers nothing rather than silently - * offering everything. - */ -export class YardFacilityOriginDestination3170000000000 implements MigrationInterface { - name = 'YardFacilityOriginDestination3170000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.yard_facilities - ADD COLUMN IF NOT EXISTS has_container_facility_origin boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS has_bulk_facility_origin boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS has_container_facility_destination boolean NOT NULL DEFAULT false, - ADD COLUMN IF NOT EXISTS has_bulk_facility_destination boolean NOT NULL DEFAULT false - `); - - await queryRunner.query(` - UPDATE freight.yard_facilities - SET has_container_facility_origin = handles_container, - has_container_facility_destination = handles_container, - has_bulk_facility_origin = handles_bulk, - has_bulk_facility_destination = handles_bulk - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.yard_facilities - DROP COLUMN IF EXISTS has_container_facility_origin, - DROP COLUMN IF EXISTS has_bulk_facility_origin, - DROP COLUMN IF EXISTS has_container_facility_destination, - DROP COLUMN IF EXISTS has_bulk_facility_destination - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3180000000000-PortYardFacilityRecords.ts b/apps/edr-freight-api/src/migrations/3180000000000-PortYardFacilityRecords.ts deleted file mode 100644 index f07252959..000000000 --- a/apps/edr-freight-api/src/migrations/3180000000000-PortYardFacilityRecords.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * 3170 backfilled the per-side facility flags onto EXISTING yard_facilities - * rows, but the Djibouti port yards (Negad, the Doraleh terminals) are flagged - * `has_facility` without ever getting a facility record — the seeder only - * covers the inland intercity facilities. With the contract route picker now - * gating on the per-side flags, those yards report false on every side and - * vanish: import contracts lose all origin options, exports all destinations. - * - * Give every facility-flagged yard that has no live record one with both - * freight types open on both sides — exactly the offerability these yards had - * before the gate existed. Ops can narrow a port from the backoffice yards - * page, which now edits these flags. - */ -export class PortYardFacilityRecords3180000000000 implements MigrationInterface { - name = 'PortYardFacilityRecords3180000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - INSERT INTO freight.yard_facilities - (yard_id, has_warehouse, handles_container, handles_bulk, - has_container_facility_origin, has_bulk_facility_origin, - has_container_facility_destination, has_bulk_facility_destination) - SELECT y.id, false, true, true, true, true, true, true - FROM freight.yards y - WHERE y.deleted_at IS NULL - AND y.has_facility = true - AND NOT EXISTS ( - SELECT 1 FROM freight.yard_facilities f - WHERE f.yard_id = y.id AND f.deleted_at IS NULL - ) - `); - } - - public async down(): Promise { - // Data seed — the inserted rows are indistinguishable from operator edits - // afterwards, so reversing would risk deleting real configuration. - } -} diff --git a/apps/edr-freight-api/src/migrations/3190000000000-AddCargoTypeTonsPerWagonMap.ts b/apps/edr-freight-api/src/migrations/3190000000000-AddCargoTypeTonsPerWagonMap.ts deleted file mode 100644 index 04fb6c1aa..000000000 --- a/apps/edr-freight-api/src/migrations/3190000000000-AddCargoTypeTonsPerWagonMap.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * PER_TON (bulk) cargo can have a loading limit BELOW the wagon's rated - * capacity: sugar rides 50T on a 70T wagon (density/stowage/policy), so 200T - * needs 4 wagons, not the 3 that raw capacity implies. Stored as a jsonb map - * { [wagonTypeId]: maxTons } on cargo_types — the PER_TON mirror of - * items_per_wagon_map. Unset (or no key) means the wagon's full rated capacity, - * so existing cargo types keep their current behaviour with no backfill. - */ -export class AddCargoTypeTonsPerWagonMap3190000000000 implements MigrationInterface { - name = 'AddCargoTypeTonsPerWagonMap3190000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."cargo_types" ADD COLUMN IF NOT EXISTS "tons_per_wagon_map" jsonb`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."cargo_types" DROP COLUMN IF EXISTS "tons_per_wagon_map"`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3200000000000-AddScheduleWindowRuleCustom.ts b/apps/edr-freight-api/src/migrations/3200000000000-AddScheduleWindowRuleCustom.ts deleted file mode 100644 index 821c67135..000000000 --- a/apps/edr-freight-api/src/migrations/3200000000000-AddScheduleWindowRuleCustom.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -/** - * Marks a train schedule whose booking-window rule was configured by staff at - * creation rather than inherited from the live global rules. - * - * Without this flag `restampPendingWindows` — which re-derives EVERY still - * PRE_WINDOW schedule from the current global config after a global-rules edit — - * would silently overwrite those hand-picked settings, which is precisely what - * the per-schedule configuration exists to prevent. - * - * Defaults false, so every existing schedule keeps following the global rules. - */ -export class AddScheduleWindowRuleCustom3200000000000 implements MigrationInterface { - name = 'AddScheduleWindowRuleCustom3200000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."train_schedules" ADD COLUMN IF NOT EXISTS "window_rule_custom" boolean NOT NULL DEFAULT false`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "freight"."train_schedules" DROP COLUMN IF EXISTS "window_rule_custom"`, - ); - } -} diff --git a/apps/edr-freight-api/src/migrations/3210000000000-EmptyContainerReturnedBy.ts b/apps/edr-freight-api/src/migrations/3210000000000-EmptyContainerReturnedBy.ts deleted file mode 100644 index b6f23b19e..000000000 --- a/apps/edr-freight-api/src/migrations/3210000000000-EmptyContainerReturnedBy.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class EmptyContainerReturnedBy3210000000000 implements MigrationInterface { - name = 'EmptyContainerReturnedBy3210000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.empty_container_returns - ADD COLUMN IF NOT EXISTS returned_by varchar(20) NULL - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.empty_container_returns - DROP COLUMN IF EXISTS returned_by - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3220000000000-EmptyContainerReturnStatusHistory.ts b/apps/edr-freight-api/src/migrations/3220000000000-EmptyContainerReturnStatusHistory.ts deleted file mode 100644 index da9267713..000000000 --- a/apps/edr-freight-api/src/migrations/3220000000000-EmptyContainerReturnStatusHistory.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class EmptyContainerReturnStatusHistory3220000000000 implements MigrationInterface { - name = 'EmptyContainerReturnStatusHistory3220000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.empty_container_returns - ADD COLUMN IF NOT EXISTS status_history jsonb NOT NULL DEFAULT '[]'::jsonb - `); - await queryRunner.query(` - UPDATE freight.empty_container_returns - SET status_history = jsonb_build_array( - jsonb_build_object('status', status, 'changedAt', created_at, 'performedBy', performed_by) - ) - WHERE status_history = '[]'::jsonb - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE freight.empty_container_returns - DROP COLUMN IF EXISTS status_history - `); - } -} diff --git a/apps/edr-freight-api/src/migrations/3230000000000-SplitContractTemplatesByCustoms.ts b/apps/edr-freight-api/src/migrations/3230000000000-SplitContractTemplatesByCustoms.ts deleted file mode 100644 index 88e715b05..000000000 --- a/apps/edr-freight-api/src/migrations/3230000000000-SplitContractTemplatesByCustoms.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -import { CONTRACT_TEMPLATE_DEFAULTS } from '../seed/data/contract-template-defaults'; - -/** - * The codes that gain a customs variant. Intercity is deliberately absent: it - * is a domestic Ethiopian movement that crosses no border, so it has no customs - * leg and keeps its single unsuffixed template. - */ -const SPLIT_CODES = [ - 'IMPORT_BULK', - 'EXPORT_BULK', - 'IMPORT_CONTAINER', - 'EXPORT_CONTAINER', -]; - -/** - * Split the four cross-border contract templates into eight — one `_CUSTOMS` - * and one `_NO_CUSTOMS` variant each — so the generated contract document - * reflects whether EDR clears customs on the Client's behalf. Together with the - * two untouched intercity templates the table ends up with ten rows. - * - * The four existing rows are RENAMED to `_NO_CUSTOMS` rather than - * replaced, so any article text staff already edited through the template - * editor survives. The four `_CUSTOMS` rows are then inserted from the seed - * (the same base pack plus the customs-clearing articles). - * - * Idempotent: the rename is guarded on the legacy code still existing, and the - * insert is ON CONFLICT (code) DO NOTHING. - */ -export class SplitContractTemplatesByCustoms3230000000000 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - // 1. Carry each legacy row over to its _NO_CUSTOMS code, preserving edits. - // Guarded so a re-run (or a DB already holding the new code) is a no-op. - for (const legacy of SPLIT_CODES) { - await queryRunner.query( - ` - UPDATE freight.contract_templates - SET code = $2, updated_at = now() - WHERE code = $1 - AND NOT EXISTS ( - SELECT 1 FROM freight.contract_templates WHERE code = $2 - ); - `, - [legacy, `${legacy}_NO_CUSTOMS`], - ); - } - - // 2. Seed anything still missing — the six _CUSTOMS rows on an existing DB, - // or all twelve on a database that never held the legacy codes. - for (const seed of CONTRACT_TEMPLATE_DEFAULTS) { - const articles = seed.articles.map((article, index) => ({ - ...article, - order: index + 1, - })); - await queryRunner.query( - ` - INSERT INTO freight.contract_templates - (code, name, description, document_title, whereas_clauses, articles) - VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb) - ON CONFLICT (code) DO NOTHING; - `, - [ - seed.code, - seed.name, - seed.description, - seed.documentTitle, - JSON.stringify(seed.whereasClauses), - JSON.stringify(articles), - ], - ); - } - } - - /** - * Drop the _CUSTOMS rows and fold the _NO_CUSTOMS rows back onto the legacy - * codes, returning the table to six templates. The two intercity rows were - * never touched by up(), so they need no reversal. - */ - public async down(queryRunner: QueryRunner): Promise { - for (const legacy of SPLIT_CODES) { - await queryRunner.query( - `DELETE FROM freight.contract_templates WHERE code = $1;`, - [`${legacy}_CUSTOMS`], - ); - await queryRunner.query( - ` - UPDATE freight.contract_templates - SET code = $1, updated_at = now() - WHERE code = $2 - AND NOT EXISTS ( - SELECT 1 FROM freight.contract_templates WHERE code = $1 - ); - `, - [legacy, `${legacy}_NO_CUSTOMS`], - ); - } - } -} diff --git a/apps/edr-freight-api/src/migrations/3240000000000-CreateExchangeSettings.ts b/apps/edr-freight-api/src/migrations/3240000000000-CreateExchangeSettings.ts deleted file mode 100644 index 68ad4f49b..000000000 --- a/apps/edr-freight-api/src/migrations/3240000000000-CreateExchangeSettings.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MigrationInterface, QueryRunner, Table } from 'typeorm'; - -/** - * Single-row store for the USD→ETB fallback used when the CBE exchange-rate - * endpoint is unreachable. The live CBE rate always wins; every successful - * fetch overwrites this row, so it holds the last known good rate rather than - * a constant that drifts. Operators can also set it by hand during an outage. - * - * Seeded with the CBE USD transactional selling rate on 2026-08-04, so the - * fallback is usable before the first successful fetch. - */ -export class CreateExchangeSettings3240000000000 implements MigrationInterface { - name = 'CreateExchangeSettings3240000000000'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - schema: 'freight', - name: 'exchange_settings', - columns: [ - { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'gen_random_uuid()' }, - { name: 'fallback_rate', type: 'numeric', precision: 18, scale: 6 }, - // AUTO when written by the CBE sync, MANUAL when set in the backoffice. - { name: 'fallback_source', type: 'varchar', length: '16', default: "'AUTO'" }, - { name: 'last_synced_at', type: 'timestamptz', isNullable: true }, - // IAM user id (iam.users) — no FK, iam schema is externally owned. - { name: 'updated_by_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.query(` - INSERT INTO freight.exchange_settings (fallback_rate, fallback_source) - VALUES (162.416500, 'AUTO') - `); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('freight.exchange_settings', true); - } -} diff --git a/apps/edr-freight-api/src/migrations/3250000000000-FreightBaseline.ts b/apps/edr-freight-api/src/migrations/3250000000000-FreightBaseline.ts new file mode 100644 index 000000000..5e39b3974 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/3250000000000-FreightBaseline.ts @@ -0,0 +1,5561 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +/** + * Squashed baseline for the whole `freight` schema. + * + * Replaces the 299 incremental migrations that preceded it. The SQL below is a + * `pg_dump` of a database built by running those 299 in order, so a fresh + * database ends up byte-identical to one migrated the long way — including the + * reference/seed rows the old migrations inserted (wagon fleet, wagon types, + * cargo types, yards, approval rules, dropdown settings, contract templates, + * truck types, gov companies, exchange settings). + * + * On a database that already ran the old migrations this is a no-op: `up()` + * returns early when the schema is already there, and the row is recorded so the + * history stays linear. It is therefore safe to deploy to dev/prod as-is. + * + * Order matters: structure → seed rows → foreign keys. The FK constraints are + * applied last so the dumped INSERTs never depend on table ordering. + * + * Regenerate (never hand-edit): run every migration into an empty database, then + * `pg_dump --schema-only -n freight -T freight.migrations` plus a + * `--data-only --column-inserts` dump of the non-empty tables. + * + * ONE deliberate deviation from that dump, which a regeneration would silently + * undo — reapply it: `freight.otp_verifications` carries the constraint names + * `pk_otp_verifications` / `uq_otp_verifications_phone` rather than TypeORM's + * generated `PK_91d17…` / `UQ_5121c…`. Prod built that table through + * `1870000000000-RepairSynchronizeDrift` (which names its constraints by hand) + * while a fresh run builds it through `1810000000003-CreateOtpVerifications` + * (which lets TypeORM hash them). Same columns either way; matching prod's names + * keeps `sql/adopt-split-migration-history.sql` strict. + */ + +const STRUCTURE_SQL = ` +CREATE SCHEMA IF NOT EXISTS freight; + +CREATE TYPE freight.consignments_cargo_type_enum AS ENUM ( + 'CONTAINER', + 'BULK_LIQUID', + 'BULK_DRY', + 'GENERAL', + 'REFRIGERATED', + 'HAZARDOUS' +); + +CREATE TYPE freight.consignments_status_enum AS ENUM ( + 'PENDING', + 'LOADED', + 'IN_TRANSIT', + 'AT_DESTINATION', + 'DELIVERED', + 'RETURNED' +); + +CREATE TYPE freight.invoices_status_enum AS ENUM ( + 'DRAFT', + 'ISSUED', + 'PENDING', + 'PARTIALLY_PAID', + 'PAID', + 'OVERDUE', + 'CANCELLED', + 'REFUNDED', + 'EXPIRED' +); + +CREATE TYPE freight.payment_webhook_method_enum AS ENUM ( + 'telebirr', + 'cbe-birr', + 'ebirr' +); + +CREATE TYPE freight.payments_currency_enum AS ENUM ( + 'ETB', + 'USD' +); + +CREATE TYPE freight.payments_method_enum AS ENUM ( + 'telebirr', + 'cbe-birr', + 'ebirr', + 'waafi', + 'card', + 'dmoney', + 'cac-bank', + 'cbe-bill' +); + +CREATE TYPE freight.payments_status_enum AS ENUM ( + 'action-required', + 'processing', + 'success', + 'failed', + 'canceled', + 'refunded' +); + +CREATE TYPE freight.priority_rules_priority_type_enum AS ENUM ( + 'USD_PAYER', + 'RAIL_AND_FORWARDING', + 'GOVERNMENT_ACCOUNT', + 'HIGH_VOLUME_SHIPMENT' +); + +CREATE TYPE freight.surcharges_calculation_method_enum AS ENUM ( + 'PER_TON', + 'FLAT_FEE', + 'PERCENTAGE' +); + +CREATE TYPE freight.tracking_events_status_enum AS ENUM ( + 'PENDING', + 'LOADED', + 'IN_TRANSIT', + 'AT_DESTINATION', + 'DELIVERED', + 'RETURNED' +); + +CREATE TYPE freight.train_status AS ENUM ( + 'AVAILABLE', + 'SCHEDULED', + 'IN_SERVICE', + 'UNDER_MAINTENANCE', + 'OUT_OF_SERVICE', + 'DEACTIVATED' +); + +CREATE TYPE freight.vehicles_status_enum AS ENUM ( + 'ACTIVE', + 'FREE', + 'BUSY', + 'MAINTENANCE', + 'RETIRED', + 'OUT_OF_SERVICE' +); + +CREATE TYPE freight.weight_limit_rules_exceeded_action_enum AS ENUM ( + 'WARNING_ONLY', + 'HARD_BLOCK' +); + +CREATE TYPE freight.weight_limit_rules_trade_direction_enum AS ENUM ( + 'IMPORT', + 'EXPORT', + 'BOTH', + 'DOMESTIC' +); + +CREATE TABLE freight.approval_rules ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + requires_director_approval boolean NOT NULL, + step_order smallint NOT NULL, + required_role character varying(64) NOT NULL, + action_label character varying(50) NOT NULL, + blocks_role character varying(64), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.asset_acquisitions ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + vehicle_id uuid, + vendor_id uuid, + acquisition_type character varying NOT NULL, + acquisition_date date NOT NULL, + cost numeric(14,2), + useful_life_months integer, + salvage_value numeric(14,2), + lease_start date, + lease_end date, + monthly_payment numeric(14,2), + status character varying DEFAULT 'ACTIVE'::character varying NOT NULL, + notes text, + item_name character varying(200) +); + +CREATE TABLE freight.asset_disposals ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + vehicle_id uuid NOT NULL, + disposal_date date NOT NULL, + method character varying NOT NULL, + sale_price numeric(14,2), + buyer character varying, + notes text +); + +CREATE TABLE freight.booking_batch_offers ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + train_schedule_id uuid NOT NULL, + offered_wagons integer NOT NULL, + total_wagons integer NOT NULL, + offered_lines jsonb, + offered_weight_tons numeric(12,3) NOT NULL, + offered_amount numeric(14,2) NOT NULL, + offered_pricing_breakdown jsonb, + invoice_id uuid, + payment_deadline timestamp with time zone NOT NULL, + status character varying(10) DEFAULT 'OFFERED'::character varying NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.booking_cargo_modifier ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + booking_id uuid NOT NULL, + trigger_value numeric(14,4), + calculated_amount numeric(14,2) NOT NULL, + rate_snapshot_id uuid NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + rate_id uuid NOT NULL +); + +CREATE TABLE freight.booking_container ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + booking_id uuid NOT NULL, + container_type_id uuid, + quantity smallint NOT NULL, + vgm_per_unit_tons numeric(10,3) NOT NULL, + total_vgm_tons numeric(12,3) NOT NULL, + wagons_required numeric(6,2) NOT NULL, + weight_limit_rule_id uuid, + is_overweight boolean DEFAULT false NOT NULL, + overweight_excess_tons numeric(10,3), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + container_number character varying(64), + container_size character varying(10), + hazardous_quantity smallint DEFAULT 0, + reefer_quantity smallint DEFAULT 0, + return_quantity smallint DEFAULT 0 NOT NULL +); + +CREATE TABLE freight.booking_container_allocations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + container_id uuid NOT NULL, + vehicle_id uuid, + container_type text NOT NULL, + quantity integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.booking_container_units ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_container_id uuid NOT NULL, + container_number character varying(64) NOT NULL, + seal_number character varying(64), + vgm_tons numeric(10,3) NOT NULL, + is_hazardous boolean DEFAULT false, + is_reefer boolean DEFAULT false, + sort_order smallint DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + received_to_port boolean DEFAULT false NOT NULL, + received_at timestamp with time zone, + grn_number character varying(100), + is_return boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.booking_contract_signatures ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + signer_role character varying(20) NOT NULL, + signer_user_id uuid, + signer_display_name character varying(200) NOT NULL, + signed_at timestamp with time zone DEFAULT now() NOT NULL, + signature_file_id uuid, + consent_text text, + ip_address character varying(64), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.booking_document_review ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + setting_code character varying(128) NOT NULL, + file_key character varying(128) NOT NULL, + file_record_id uuid, + status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + note text, + reviewed_by_staff_id uuid, + reviewed_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + contract_id uuid +); + +CREATE TABLE freight.booking_handovers ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + truck_assignment_id uuid, + truck_plate character varying(32), + mile_type character varying(20) NOT NULL, + reference character varying(100) NOT NULL, + generated_at timestamp with time zone DEFAULT now() NOT NULL, + signed_at timestamp with time zone, + signed_by_user_id uuid, + delivered_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + signer_name character varying(160), + edr_assignment_id uuid, + signature_image_url text +); + +CREATE TABLE freight.booking_rate_snapshot ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + booking_id uuid NOT NULL, + rate_id uuid NOT NULL, + rate_type character varying(50) NOT NULL, + rate_value numeric(14,4) NOT NULL, + rate_unit character varying(30) NOT NULL, + currency character varying(5) NOT NULL, + snapshotted_at timestamp with time zone NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.booking_requests ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + reference character varying(40) DEFAULT ''::character varying NOT NULL, + contract_id uuid NOT NULL, + requested_by_user_id uuid, + contract_route_id uuid, + scheduled_date timestamp with time zone, + status character varying(16) DEFAULT 'PENDING'::character varying NOT NULL, + requested_lines jsonb DEFAULT '{}'::jsonb NOT NULL, + notes text, + created_booking_id uuid, + reviewed_by_staff_id uuid, + reviewed_at timestamp with time zone, + review_note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + payment_currency character varying(5) +); + +CREATE TABLE freight.booking_review_note ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + author_id uuid, + note text NOT NULL, + type character varying(30) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.bookings ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + reference character varying(64) NOT NULL, + customer_id uuid, + train_id uuid, + status character varying(40) DEFAULT 'DRAFT'::character varying NOT NULL, + scheduled_date timestamp with time zone DEFAULT now(), + total_amount numeric(14,2) DEFAULT 0 NOT NULL, + payment_status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + contract_type character varying(20) DEFAULT 'SPOT'::character varying NOT NULL, + trade_direction character varying(10) DEFAULT 'IMPORT'::character varying NOT NULL, + equipment_return character varying(20) DEFAULT 'RETURN'::character varying NOT NULL, + first_mile_pickup_address text, + last_mile_delivery_address text, + cargo_total_weight_vgm numeric(12,3) DEFAULT 0 NOT NULL, + is_hazardous boolean DEFAULT false NOT NULL, + payment_currency character varying(5) DEFAULT 'USD'::character varying NOT NULL, + start_date date, + end_date date, + financial_terms text, + version_number integer DEFAULT 1 NOT NULL, + approved_by_staff_id uuid, + approved_by_staff_at timestamp with time zone, + signed_by_director_id uuid, + signed_by_director_at timestamp with time zone, + signed_by_ceo_id uuid, + signed_by_ceo_at timestamp with time zone, + priority_score integer DEFAULT 0 NOT NULL, + consolidation_partner_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + origin_yard_id uuid NOT NULL, + destination_yard_id uuid NOT NULL, + service_type_id uuid NOT NULL, + cargo_type_id uuid, + cargo_free_text character varying(200), + shipping_line_id uuid, + pnr_code character varying(50), + customer_signed_at timestamp with time zone, + fully_executed_at timestamp with time zone, + marketing_approved_by_id uuid, + marketing_approved_at timestamp with time zone, + contract_summary text, + locked_at timestamp with time zone, + freight_type character varying(20) NOT NULL, + contract_template_key character varying(80), + contract_generated_at timestamp with time zone, + pricing_breakdown jsonb, + company_id uuid NOT NULL, + wagons_required numeric(6,2), + scheduling_status character varying(30) DEFAULT 'NOT_SCHEDULED'::character varying NOT NULL, + hold_started_at timestamp with time zone, + hold_expires_at timestamp with time zone, + scheduled_at timestamp with time zone, + is_government boolean DEFAULT false NOT NULL, + government_institution character varying(255), + train_schedule_id uuid, + payment_deadline timestamp with time zone, + selected_for_batch_at timestamp with time zone, + company_profile_id uuid NOT NULL, + expires_at timestamp with time zone, + adjusted_total_amount numeric(14,2), + adjusted_by_staff_id uuid, + adjusted_at timestamp with time zone, + adjustment_reason text, + contract_validity_days integer, + contract_valid_from timestamp with time zone, + contract_valid_until timestamp with time zone, + first_mile_pickup_lat numeric(10,7), + first_mile_pickup_lng numeric(10,7), + last_mile_delivery_lat numeric(10,7), + last_mile_delivery_lng numeric(10,7), + customs_clearing_enabled boolean DEFAULT false NOT NULL, + customs_clearing_agent character varying(200), + is_reefer boolean DEFAULT false NOT NULL, + estimated_shipment_date timestamp with time zone, + contract_id uuid, + contract_route_id uuid, + created_by_role character varying(20) DEFAULT 'CUSTOMER'::character varying, + created_by_user_id uuid, + contract_kind character varying(20), + gl_station_yard_id uuid, + gl_assigned_staff_id uuid, + gl_assigned_at timestamp with time zone, + bulk_hazardous_quantity numeric(12,3) DEFAULT 0 NOT NULL, + bulk_reefer_quantity numeric(12,3) DEFAULT 0 NOT NULL, + clearance_current_phase character varying(40), + duty_required boolean, + vessel_departure_date date, + ro_amendment_requested_at timestamp with time zone, + ro_hold_reason text, + pre_clearance_finalized_at timestamp with time zone, + customer_truck_plate_number character varying(32), + customer_truck_driver_name character varying(120), + customer_truck_type character varying(60), + customer_truck_container_number character varying(16), + customer_truck_assigned_at timestamp with time zone, + customer_truck_arrived_at timestamp with time zone, + booking_type character varying(20) DEFAULT 'ONE_TIME'::character varying NOT NULL, + loaded_at timestamp with time zone, + loaded_by_user_id uuid, + arrived_at timestamp with time zone, + arrived_by_user_id uuid, + consolidation_resume_status character varying(40), + is_split boolean DEFAULT false NOT NULL, + pre_split_quantities jsonb, + double_handling boolean, + double_handling_set_at timestamp with time zone, + double_handling_set_by character varying(160), + vessel_arrival_date date, + do_collected_date date, + transit_assignee_requested_at timestamp with time zone, + transit_assignee_request_note text, + transit_assignee_name text, + transit_assignee_assigned_at timestamp with time zone, + requested_train_schedule_id uuid, + payment_reminder_sent_at timestamp with time zone, + bulk_total_weight_tons numeric(12,3), + CONSTRAINT chk_bookings_freight_type CHECK (((freight_type)::text = ANY ((ARRAY['CONTAINER'::character varying, 'BULK'::character varying])::text[]))) +); + +CREATE TABLE freight.cargo_type_wagon_types ( + cargo_type_id uuid NOT NULL, + wagon_type_id uuid NOT NULL +); + +CREATE TABLE freight.cargo_types ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + cargo_type_name character varying(255) NOT NULL, + parent_group_id uuid, + requires_director_approval boolean DEFAULT false NOT NULL, + is_active boolean DEFAULT true NOT NULL, + display_order integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + code character varying(50) NOT NULL, + unit_of_measure character varying(16), + has_lashing boolean DEFAULT false NOT NULL, + items_per_wagon_map jsonb, + tons_per_wagon_map jsonb +); + +CREATE TABLE freight.cargoes ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + cargo_reference character varying NOT NULL, + shipment_id uuid NOT NULL, + container_id uuid, + cargo_type_id uuid, + description text, + quantity numeric(12,3) NOT NULL, + weight numeric(10,2) NOT NULL, + volume numeric(10,2), + status character varying DEFAULT 'PENDING'::character varying NOT NULL, + loaded_at timestamp without time zone, + unloaded_at timestamp without time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + wagon_booking_allocation_id uuid, + booking_id uuid, + load_type character varying(20), + receiver_name character varying, + delivered_at timestamp without time zone, + delivery_remarks text +); + +CREATE TABLE freight.clearance_incidents ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + incident_type character varying(32) NOT NULL, + description text NOT NULL, + photo_file_ids jsonb DEFAULT '[]'::jsonb NOT NULL, + reported_by_user_id uuid, + reported_at timestamp with time zone DEFAULT now() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.clearance_milestones ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid, + contract_id uuid, + clearance_cycle_id uuid, + milestone_code character varying(64) NOT NULL, + milestone_label character varying(255) NOT NULL, + status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + owner_region character varying(5), + triggered_by_doc boolean DEFAULT false, + triggered_at timestamp with time zone, + triggered_by_user_id uuid, + note text, + sort_order smallint DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + metadata jsonb +); + +CREATE TABLE freight.companies ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + name character varying(200) NOT NULL, + type character varying(32) NOT NULL, + status character varying(32) DEFAULT 'pending'::character varying NOT NULL, + tin character varying(10) NOT NULL, + vat_number character varying(50), + fan_number character varying(16), + country character varying(32) DEFAULT 'Ethiopia'::character varying NOT NULL, + address text, + phone character varying(20), + email character varying(150), + website character varying(200), + attributes jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + contact_person_name character varying(100), + contact_person_phone character varying(20), + general_manager_name character varying(100), + general_manager_email character varying(150), + general_manager_phone character varying(20), + nationality character varying(32), + licence_number character varying(100), + status_description text, + date_registered character varying(50), + renewed_from character varying(50), + renewal_date character varying(50), + renewed_to character varying(50), + region character varying(100), + zone character varying(100), + woreda character varying(100), + kebele character varying(100), + house_no character varying(100), + etrade_phone character varying(20), + kind character varying(20) DEFAULT 'commercial'::character varying NOT NULL, + approved_at timestamp with time zone +); + +CREATE TABLE freight.company_change_request ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + company_id uuid NOT NULL, + snapshot jsonb NOT NULL, + documents jsonb, + status character varying(20) DEFAULT 'pending'::character varying NOT NULL, + note text, + submitted_by uuid, + submitted_at timestamp with time zone, + reviewed_by uuid, + reviewed_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.company_profiles ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + company_id uuid NOT NULL, + type character varying(32) NOT NULL, + reference character varying(20), + status character varying(32) DEFAULT 'pending'::character varying NOT NULL, + business_license character varying(100), + attributes jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + business_license_files jsonb, + review_note text, + reviewed_by uuid, + reviewed_at timestamp with time zone +); + +CREATE TABLE freight.company_revisions ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + company_id uuid NOT NULL, + actor_id uuid, + summary character varying(255) NOT NULL, + changes jsonb DEFAULT '[]'::jsonb NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.compliance_records ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + type character varying NOT NULL, + document_number character varying, + issued_date date, + expiry_date date NOT NULL, + status character varying DEFAULT 'VALID'::character varying NOT NULL, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.consignments ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + tracking_number character varying(64) NOT NULL, + cargo_type freight.consignments_cargo_type_enum NOT NULL, + weight_kg numeric(12,2) NOT NULL, + status freight.consignments_status_enum DEFAULT 'PENDING'::freight.consignments_status_enum NOT NULL, + origin_station character varying(128) NOT NULL, + destination_station character varying(128) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.container_type_wagon_types ( + container_type_id uuid NOT NULL, + wagon_type_id uuid NOT NULL +); + +CREATE TABLE freight.container_types ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + code character varying(20) NOT NULL, + label character varying(100), + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + size_ft smallint, + is_reefer boolean DEFAULT false NOT NULL, + is_open_top boolean DEFAULT false NOT NULL, + display_order integer DEFAULT 1 NOT NULL +); + +CREATE TABLE freight.containers ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + container_number character varying NOT NULL, + container_type_id uuid NOT NULL, + wagon_id uuid, + "position" integer, + tare_weight numeric(10,2) NOT NULL, + max_gross_weight numeric(10,2) NOT NULL, + seal_number character varying, + status character varying DEFAULT 'AVAILABLE'::character varying NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + booking_id uuid, + wagon_booking_allocation_id uuid, + booking_container_id uuid +); + +CREATE TABLE freight.contract_approval_steps ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + step_order smallint DEFAULT 0 NOT NULL, + required_role character varying(64) NOT NULL, + blocks_role character varying(64), + status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + acted_by_staff_id uuid, + acted_at timestamp with time zone, + note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.contract_cargo_scope ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + container_size character varying(10), + cargo_type_id uuid, + cargo_free_text character varying(200), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + quantity_cap numeric(12,2) +); + +CREATE TABLE freight.contract_clearance_cycles ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + cycle_number integer NOT NULL, + status character varying(40) DEFAULT 'AWAITING_DOCUMENTS'::character varying NOT NULL, + booking_id uuid, + started_at timestamp with time zone DEFAULT now() NOT NULL, + clearance_ready_at timestamp with time zone, + completed_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + duty_required boolean, + vessel_departure_date date, + ro_amendment_requested_at timestamp with time zone, + ro_hold_reason text, + current_phase character varying(40), + pre_clearance_finalized_at timestamp with time zone, + transit_assignee_requested_at timestamp with time zone, + transit_assignee_requested_by_user_id uuid, + transit_assignee_request_note text, + transit_assignee_name text, + transit_assignee_assigned_at timestamp with time zone, + transit_assignee_assigned_by_user_id uuid, + vessel_arrival_date date, + do_collected_date date +); + +CREATE TABLE freight.contract_document_review ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + clearance_cycle_id uuid, + setting_code character varying(128) NOT NULL, + file_key character varying(128) NOT NULL, + file_record_id uuid, + status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + note text, + uploaded_by_role character varying(20) DEFAULT 'CUSTOMER'::character varying NOT NULL, + reviewed_by_staff_id uuid, + reviewed_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.contract_document_revisions ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + contract_id uuid NOT NULL, + actor_id uuid, + actor_role character varying(64), + step_id uuid, + summary character varying(255), + changes jsonb DEFAULT '[]'::jsonb NOT NULL, + actor_name character varying(200) +); + +CREATE TABLE freight.contract_rate_snapshots ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + rate_id uuid, + rate_code character varying(64) NOT NULL, + description character varying(255), + unit_price numeric(14,2) NOT NULL, + unit_of_measure character varying(32) NOT NULL, + currency character varying(5) NOT NULL, + container_size character varying(10), + is_surcharge boolean DEFAULT false, + conditional_on character varying(32), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + is_clearance boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.contract_review_notes ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + note_type character varying(40) NOT NULL, + body text NOT NULL, + author_role character varying(20), + author_user_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.contract_routes ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + origin_yard_id uuid NOT NULL, + destination_yard_id uuid NOT NULL, + km numeric(10,2), + sort_order smallint DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.contract_signatures ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + contract_id uuid NOT NULL, + role character varying(20) NOT NULL, + signer_display_name character varying(255) NOT NULL, + signature_file_id uuid, + consent_text text, + signed_at timestamp with time zone DEFAULT now() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + stamp_file_id uuid +); + +CREATE TABLE freight.contract_templates ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(40) NOT NULL, + name character varying(200) NOT NULL, + description text, + document_title character varying(300) NOT NULL, + whereas_clauses jsonb DEFAULT '[]'::jsonb NOT NULL, + articles jsonb DEFAULT '[]'::jsonb NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.contracts ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + reference character varying(64) NOT NULL, + company_id uuid, + company_profile_id uuid, + is_government boolean DEFAULT false NOT NULL, + government_institution character varying(255), + contract_kind character varying(20) NOT NULL, + renewal_of_id uuid, + trade_direction character varying(10) NOT NULL, + freight_type character varying(20) NOT NULL, + service_type_id uuid NOT NULL, + payment_currency character varying(5) NOT NULL, + customs_clearing_enabled boolean DEFAULT false NOT NULL, + customs_clearing_agent character varying(200), + equipment_return character varying(20), + first_mile_pickup_address text, + first_mile_pickup_lat numeric(10,7), + first_mile_pickup_lng numeric(10,7), + last_mile_delivery_address text, + last_mile_delivery_lat numeric(10,7), + last_mile_delivery_lng numeric(10,7), + is_hazardous boolean DEFAULT false NOT NULL, + is_reefer boolean DEFAULT false NOT NULL, + estimated_shipment_date timestamp with time zone, + contract_validity_days integer, + contract_valid_from timestamp with time zone, + contract_valid_until timestamp with time zone, + expires_at timestamp with time zone, + status character varying(40) DEFAULT 'DRAFT'::character varying NOT NULL, + clearance_status character varying(40) DEFAULT 'NOT_APPLICABLE'::character varying NOT NULL, + clearance_cycle_number integer DEFAULT 0 NOT NULL, + pricing_breakdown jsonb, + pricing_display_mode character varying(20) DEFAULT 'UNIT_RATES'::character varying, + contract_type character varying(20), + contract_template_key character varying(128), + contract_generated_at timestamp with time zone, + contract_summary text, + version_number integer DEFAULT 1 NOT NULL, + financial_terms jsonb, + approved_by_staff_id uuid, + approved_by_staff_at timestamp with time zone, + signed_by_director_id uuid, + signed_by_director_at timestamp with time zone, + signed_by_ceo_id uuid, + signed_by_ceo_at timestamp with time zone, + customer_signed_at timestamp with time zone, + fully_executed_at timestamp with time zone, + locked_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + document_snapshot jsonb, + hazard_class character varying(16), + un_number character varying(16), + status_before_suspension character varying(40), + submitted_at timestamp with time zone +); + +CREATE TABLE freight.customer_truck_assignments ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + plate_number character varying(32) NOT NULL, + driver_name character varying(120) NOT NULL, + truck_type character varying(60) NOT NULL, + assigned_at timestamp with time zone DEFAULT now() NOT NULL, + arrived_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + gross_weight_kg numeric(14,2), + departed_at timestamp with time zone, + tare_weight_tons numeric(14,3), + net_weight_tons numeric(14,3), + planned_tons numeric(14,3), + planned_quantity integer +); + +CREATE TABLE freight.customer_truck_containers ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + assignment_id uuid NOT NULL, + booking_id uuid NOT NULL, + container_number character varying(64) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + loaded_at timestamp with time zone +); + +CREATE TABLE freight.customers ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + user_id uuid NOT NULL, + first_name character varying(100) NOT NULL, + last_name character varying(100) NOT NULL, + email character varying(150) NOT NULL, + phone character varying(20) NOT NULL, + company_name character varying(200) NOT NULL, + company_email character varying(150) NOT NULL, + company_phone character varying(20) NOT NULL, + company_location character varying(100) NOT NULL, + company_address text NOT NULL, + customer_type character varying(32), + status character varying(32), + contact_person_name character varying(100) NOT NULL, + contact_person_phone character varying(20) NOT NULL, + tin_number character varying(10) NOT NULL, + vat_number character varying(50), + fan_number character varying(16) NOT NULL, + general_manager_name character varying(100) NOT NULL, + general_manager_email character varying(150) NOT NULL, + general_manager_phone character varying(20) NOT NULL, + poa_name character varying(100), + poa_phone character varying(20), + poa_address text, + poa_email character varying(150), + poa_location character varying(100), + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.djibouti_import_incidents ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + booking_id uuid NOT NULL, + container_number character varying(80), + cargo_id uuid, + facility character varying(120), + station character varying(120), + incident_type character varying(40) NOT NULL, + description text NOT NULL, + photos jsonb DEFAULT '[]'::jsonb NOT NULL, + reported_by character varying(120), + reported_at timestamp with time zone NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.drivers ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + license_number character varying NOT NULL, + first_name character varying NOT NULL, + last_name character varying NOT NULL, + email character varying NOT NULL, + phone_number character varying NOT NULL, + date_of_birth date NOT NULL, + license_expiry_date date NOT NULL, + status character varying DEFAULT 'ACTIVE'::character varying NOT NULL, + vehicle_types_authorized character varying[], + address text, + emergency_contact character varying, + notes text, + total_trips integer DEFAULT 0, + rating numeric(3,2), + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted_at timestamp without time zone, + fayda_verified boolean DEFAULT false, + fayda_sub character varying, + gender character varying +); + +CREATE TABLE freight.dropdown_options ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + setting_id uuid NOT NULL, + value character varying(256) NOT NULL, + label character varying(256) NOT NULL, + note text, + is_disabled boolean DEFAULT false NOT NULL, + display_order integer DEFAULT 0 NOT NULL, + meta jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.dropdown_settings ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(128) NOT NULL, + label character varying(256) NOT NULL, + description text, + multiple boolean DEFAULT false NOT NULL, + meta jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.empty_container_returns ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + container_number character varying(80) NOT NULL, + booking_id uuid, + customer_id uuid, + return_date timestamp with time zone NOT NULL, + facility character varying(120), + yard character varying(120), + zone character varying(120), + condition text, + handover_note text, + status character varying(40) DEFAULT 'RETURNED'::character varying NOT NULL, + wagon_allocation_reference character varying(120), + performed_by character varying(120), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + returned_by character varying(20), + status_history jsonb DEFAULT '[]'::jsonb NOT NULL +); + +CREATE TABLE freight.exchange_settings ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + fallback_rate numeric(18,6) NOT NULL, + fallback_source character varying(16) DEFAULT 'AUTO'::character varying NOT NULL, + last_synced_at timestamp with time zone, + updated_by_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.external_profiles ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + user_id uuid NOT NULL, + company_id uuid NOT NULL, + first_name character varying(100) NOT NULL, + last_name character varying(100) NOT NULL, + national_id character varying(50), + job_title character varying(100), + is_primary_contact boolean DEFAULT false NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + onboarding_step character varying(40), + onboarding_completed boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.facilities ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(40) NOT NULL, + name character varying(160) NOT NULL, + description text, + facility_type character varying(32) NOT NULL, + facility_status character varying(32) DEFAULT 'ACTIVE'::character varying NOT NULL, + location_name character varying(200), + country character varying(100), + city character varying(100), + address text, + latitude numeric(10,8), + longitude numeric(11,8), + capacity numeric(14,3), + is_active boolean DEFAULT true NOT NULL, + notes text, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted_at timestamp without time zone +); + +CREATE TABLE freight.facility_handling_events ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + yard_id uuid NOT NULL, + train_schedule_id uuid, + event_type character varying(10) NOT NULL, + grn_number character varying(60), + quantity numeric(14,3), + weight_tons numeric(14,3), + inventory_id uuid, + performed_by character varying(120), + occurred_at timestamp with time zone DEFAULT now() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.fayda_verification_sessions ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + state character varying NOT NULL, + code_verifier character varying NOT NULL, + purpose character varying DEFAULT 'VERIFY'::character varying NOT NULL, + platform character varying DEFAULT 'WEB'::character varying NOT NULL, + save_to_account boolean DEFAULT false NOT NULL, + status character varying DEFAULT 'PENDING'::character varying NOT NULL, + error_code character varying, + error_description text, + iam_user_id uuid, + expires_at timestamp with time zone NOT NULL, + completed_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.ff_clients ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + forwarder_company_id uuid NOT NULL, + client_company_id uuid NOT NULL, + relationship_type character varying(32) DEFAULT 'managed_account'::character varying NOT NULL, + can_book_on_behalf boolean DEFAULT true NOT NULL, + can_view_documents boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.file_upload_fields ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + setting_id uuid NOT NULL, + file_key character varying(128) NOT NULL, + file_label character varying(256) NOT NULL, + help_text text, + is_required boolean DEFAULT false NOT NULL, + is_multiple boolean DEFAULT false NOT NULL, + max_files integer DEFAULT 1 NOT NULL, + allowed_extensions text[] DEFAULT '{}'::text[] NOT NULL, + max_size_mb integer DEFAULT 10 NOT NULL, + display_order integer DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + phase character varying(40), + owner_region character varying(5), + trade_direction character varying(10), + triggers_milestone_code character varying(64), + CONSTRAINT "CHK_file_upload_fields_max_files" CHECK ((max_files > 0)), + CONSTRAINT "CHK_file_upload_fields_max_size_mb" CHECK ((max_size_mb > 0)) +); + +CREATE TABLE freight.file_upload_settings ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + code character varying(128) NOT NULL, + label character varying(256) NOT NULL, + description text, + entity character varying(32) DEFAULT 'other'::character varying NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.files ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + resource_id uuid NOT NULL, + resource character varying(100) NOT NULL, + code character varying(100) NOT NULL, + name character varying(500) NOT NULL, + url text NOT NULL, + size integer NOT NULL, + mime_type character varying(255) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + review_status character varying(32), + review_note text, + reviewed_by uuid, + reviewed_at timestamp with time zone, + replaced_by_user_id uuid, + replace_reason text, + title character varying(300), + visible_to_customer boolean DEFAULT false NOT NULL, + uploaded_by_user_id uuid, + uploaded_by_name character varying(200) +); + +CREATE TABLE freight.first_mile ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + status character varying(30) DEFAULT 'PAYMENT_PENDING'::character varying NOT NULL, + advanced_payment numeric(14,2) DEFAULT 0 NOT NULL, + remaining_payment numeric(14,2) DEFAULT 0 NOT NULL, + estimated_km numeric(10,2), + exact_km numeric(10,2), + vehicle_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + paid boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.first_mile_container_allocations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + first_mile_id uuid NOT NULL, + container_id uuid NOT NULL, + vehicle_id uuid, + container_type text NOT NULL, + quantity integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.first_mile_vehicle_assignments ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + first_mile_id uuid NOT NULL, + vehicle_id uuid NOT NULL, + container_number character varying, + distance_km numeric(10,2), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + tons numeric(14,3), + quantity integer +); + +CREATE TABLE freight.fleet_events ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + event_type character varying NOT NULL, + vehicle_id uuid, + driver_id uuid, + first_mile_id uuid, + last_mile_id uuid, + from_value character varying, + to_value character varying, + label character varying, + metadata jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.fuel_consumption ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + month date NOT NULL, + total_liters numeric(10,2) NOT NULL, + total_cost numeric(14,2) NOT NULL, + total_distance_km numeric(10,2) NOT NULL, + fuel_efficiency_km_per_l numeric(10,2), + number_of_purchases integer DEFAULT 0, + average_cost_per_liter numeric(10,2), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.fuel_purchases ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + purchase_date timestamp with time zone NOT NULL, + liters numeric(10,2) NOT NULL, + cost_per_liter numeric(10,2) NOT NULL, + total_cost numeric(14,2) NOT NULL, + fuel_station character varying(255), + payment_method character varying(50) DEFAULT 'CASH'::character varying, + odometer_reading numeric(10,2), + driver_id uuid, + receipt_number character varying(255), + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.gps_devices ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + imei character varying(20) NOT NULL, + name character varying, + vehicle_id uuid, + status character varying(16) DEFAULT 'REGISTERED'::character varying NOT NULL, + last_seen_at timestamp with time zone, + last_lat numeric(10,6), + last_lng numeric(10,6), + last_speed numeric(6,2), + last_course integer, + last_fix_at timestamp with time zone, + voltage_level integer, + gsm_level integer, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.gps_positions ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + device_id uuid NOT NULL, + imei character varying(20) NOT NULL, + vehicle_id uuid, + lat numeric(10,6) NOT NULL, + lng numeric(10,6) NOT NULL, + speed numeric(6,2) DEFAULT 0 NOT NULL, + course integer DEFAULT 0 NOT NULL, + satellites integer DEFAULT 0 NOT NULL, + positioned boolean DEFAULT false NOT NULL, + gps_time timestamp with time zone NOT NULL, + alarm integer DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.import_customs_finalizations ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + booking_id uuid NOT NULL, + documents jsonb DEFAULT '{}'::jsonb NOT NULL, + declaration_serial_number character varying(120), + duties_taxes_notified_at timestamp with time zone, + duties_taxes_paid_at timestamp with time zone, + customs_risk character varying(12), + import_release_permitted_at timestamp with time zone, + completed_at timestamp with time zone, + performed_by character varying(120), + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.import_djibouti_operations ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + train_schedule_id uuid NOT NULL, + documents jsonb DEFAULT '{}'::jsonb NOT NULL, + gatepass_granted_at timestamp with time zone, + ready_for_loading_at timestamp with time zone, + loaded_on_train_at timestamp with time zone, + departed_from_djibouti_at timestamp with time zone, + load_list_generated_at timestamp with time zone, + performed_by character varying(120), + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.incidents ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + vehicle_id uuid, + driver_id uuid, + booking_id uuid, + type character varying NOT NULL, + severity character varying NOT NULL, + occurred_at timestamp with time zone NOT NULL, + location character varying, + description text NOT NULL, + damage_estimate numeric(14,2), + status character varying DEFAULT 'REPORTED'::character varying NOT NULL, + insurance_claim_number character varying, + reported_by character varying +); + +CREATE TABLE freight.interchange_document_items ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + interchange_document_id uuid NOT NULL, + booking_id uuid, + booking_reference character varying(64), + item_type character varying(20) NOT NULL, + booking_container_id uuid, + booking_cargo_id uuid, + container_number character varying(64), + seal_number character varying(100), + cargo_id uuid, + cargo_type character varying(255), + cargo_description text, + weight numeric(14,3), + quantity numeric(12,3), + package_count integer, + wagon_number character varying(80), + condition_status character varying(20) DEFAULT 'GOOD'::character varying NOT NULL, + damage_description text, + remarks text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.interchange_documents ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + document_no character varying(40) NOT NULL, + direction character varying(10) NOT NULL, + schedule_id uuid, + train_no character varying(40), + route_id uuid, + origin_facility_id uuid, + destination_facility_id uuid, + handover_location character varying(255) NOT NULL, + handover_from character varying(255) NOT NULL, + handover_to character varying(255) NOT NULL, + operator_name character varying(255), + port_operator_name character varying(255), + shipping_line_name character varying(255), + customs_reference character varying(120), + manifest_reference character varying(120), + status character varying(20) DEFAULT 'DRAFT'::character varying NOT NULL, + generated_at timestamp with time zone, + acknowledged_at timestamp with time zone, + generated_by character varying(120), + acknowledged_by character varying(120), + remarks text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.invoice_lines ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + invoice_id uuid NOT NULL, + charge_type character varying NOT NULL, + description character varying(255), + quantity numeric(12,2) DEFAULT 1 NOT NULL, + unit_rate numeric(14,2) DEFAULT 0 NOT NULL, + amount numeric(14,2) NOT NULL, + currency character varying(8) DEFAULT 'ETB'::character varying NOT NULL, + metadata jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.invoices ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + invoice_number character varying(64) NOT NULL, + company_id uuid NOT NULL, + company_profile_id uuid NOT NULL, + total_amount numeric(14,2) NOT NULL, + currency character varying(8) DEFAULT 'ETB'::character varying NOT NULL, + status freight.invoices_status_enum DEFAULT 'DRAFT'::freight.invoices_status_enum NOT NULL, + source character varying(255) NOT NULL, + source_id character varying(255) NOT NULL, + type character varying(255) NOT NULL, + issued_at timestamp with time zone, + payment_id uuid, + due_at timestamp with time zone NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + subtotal_amount numeric(14,2) DEFAULT 0 NOT NULL, + tax_amount numeric(14,2) DEFAULT 0 NOT NULL, + paid_amount numeric(14,2) DEFAULT 0 NOT NULL, + balance_amount numeric(14,2) DEFAULT 0 NOT NULL, + paid_at timestamp with time zone, + payments jsonb DEFAULT '[]'::jsonb NOT NULL +); + +CREATE TABLE freight.last_mile ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + booking_id uuid NOT NULL, + status character varying(30) DEFAULT 'PAYMENT_PENDING'::character varying NOT NULL, + advanced_payment numeric(14,2) DEFAULT 0 NOT NULL, + remaining_payment numeric(14,2) DEFAULT 0 NOT NULL, + estimated_km numeric(10,2), + exact_km numeric(10,2), + vehicle_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + paid boolean DEFAULT false NOT NULL, + arrived_at timestamp with time zone, + delivered_at timestamp with time zone, + pod_recipient_name character varying(160), + pod_signature_file_id uuid, + pod_photo_file_ids text[] DEFAULT '{}'::text[] NOT NULL, + pod_notes text, + pod_captured_at timestamp with time zone +); + +CREATE TABLE freight.last_mile_container_allocations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + last_mile_id uuid NOT NULL, + container_id uuid NOT NULL, + vehicle_id uuid, + container_type text NOT NULL, + quantity integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.last_mile_vehicle_assignments ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + last_mile_id uuid NOT NULL, + vehicle_id uuid NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + container_number character varying, + distance_km numeric(10,2), + arrived_at timestamp with time zone, + departed_at timestamp with time zone, + gross_weight_tons numeric(14,3), + net_weight_tons numeric(14,3), + destination_arrived_at timestamp with time zone, + returned_at timestamp with time zone +); + +CREATE TABLE freight.last_mile_vehicle_containers ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + assignment_id uuid NOT NULL, + last_mile_id uuid NOT NULL, + container_number character varying(32) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.locomotives ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(32) NOT NULL, + name character varying(100), + max_pull_weight_tons numeric(10,3) NOT NULL, + status character varying(20) DEFAULT 'AVAILABLE'::character varying NOT NULL, + available_from timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + locomotive_type character varying(20) DEFAULT 'DIESEL'::character varying NOT NULL, + max_train_length_meters numeric(10,3) DEFAULT 760 NOT NULL, + power_kw numeric(10,3), + traction_force_kn numeric(10,3), + max_speed_kmh numeric(10,3), + current_yard_id uuid, + overage_tolerance_tons numeric(10,3), + overage_tolerance_meters numeric(10,3) +); + +CREATE TABLE freight.maintenance_costs ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + maintenance_schedule_id uuid, + incurred_date timestamp with time zone NOT NULL, + cost_amount numeric(14,2) NOT NULL, + cost_type character varying NOT NULL, + description character varying NOT NULL, + service_provider character varying, + invoice_number character varying, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.maintenance_intervals ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + maintenance_type character varying NOT NULL, + interval_km numeric(14,2), + interval_days integer, + description text, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + service_item character varying(120) +); + +CREATE TABLE freight.maintenance_schedules ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + maintenance_type character varying NOT NULL, + description character varying NOT NULL, + scheduled_date timestamp with time zone NOT NULL, + completed_date timestamp with time zone, + estimated_cost numeric(14,2), + actual_cost numeric(14,2), + status character varying DEFAULT 'SCHEDULED'::character varying NOT NULL, + odometer_reading numeric, + service_provider character varying, + notes text, + next_due_km numeric, + next_due_date timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + due_notified_at timestamp with time zone, + service_item character varying(120) +); + +CREATE TABLE freight.notifications ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + recipient_user_id uuid NOT NULL, + audience character varying(20) NOT NULL, + type character varying(48) DEFAULT 'GENERIC'::character varying NOT NULL, + title character varying(200) NOT NULL, + body text NOT NULL, + link character varying, + data jsonb, + priority character varying(12) DEFAULT 'NORMAL'::character varying NOT NULL, + is_read boolean DEFAULT false NOT NULL, + read_at timestamp with time zone, + channels_sent jsonb, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.otp_verifications ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + phone character varying, + otp character varying NOT NULL, + verified boolean DEFAULT false NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + email character varying +); + +CREATE TABLE freight.parts ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + name character varying NOT NULL, + sku character varying, + category character varying, + quantity_in_stock integer DEFAULT 0 NOT NULL, + reorder_level integer DEFAULT 0 NOT NULL, + unit_cost numeric(14,2), + location character varying, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.payment_refunds ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + payment_id uuid NOT NULL, + amount_minor integer NOT NULL, + reason character varying(255), + provider_refund_id character varying(255), + status character varying(50) NOT NULL, + created_at timestamp without time zone DEFAULT now() NOT NULL +); + +CREATE TABLE freight.payment_webhook_events ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + provider freight.payment_webhook_method_enum NOT NULL, + external_event_id character varying(255) NOT NULL, + merchant_order_id character varying(255), + provider_txn_id character varying(255), + signature_valid boolean NOT NULL, + status character varying(100) NOT NULL, + payload jsonb NOT NULL, + received_at timestamp without time zone DEFAULT now() NOT NULL, + processed_at timestamp without time zone, + processing_error text +); + +CREATE TABLE freight.payments ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + ref_id character varying(255) NOT NULL, + type character varying(50) NOT NULL, + method freight.payments_method_enum NOT NULL, + currency freight.payments_currency_enum NOT NULL, + amount numeric NOT NULL, + raw_initiation jsonb DEFAULT '{}'::jsonb NOT NULL, + client_action jsonb, + merchant_order_id character varying(255) NOT NULL, + transaction_id character varying(255), + status freight.payments_status_enum DEFAULT 'action-required'::freight.payments_status_enum NOT NULL, + paid_at timestamp without time zone, + refunded_at timestamp without time zone, + expires_at timestamp without time zone, + failer_code character varying(30), + failer_message character varying(255), + reason character varying(255), + created_at timestamp without time zone DEFAULT now() NOT NULL, + reference_type character varying(40) +); + +CREATE TABLE freight.priority_configs ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + type character varying(20) NOT NULL, + label character varying(100) NOT NULL, + currency character varying(5), + min_wagon_count integer NOT NULL, + max_wagon_count integer NOT NULL, + score_points integer DEFAULT 0 NOT NULL, + is_active boolean DEFAULT false NOT NULL, + display_order integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + CONSTRAINT chk_currency_for_type CHECK (((((type)::text = 'WAGON'::text) AND (currency IS NULL)) OR (((type)::text = 'CURRENCY'::text) AND (currency IS NOT NULL)) OR (((type)::text = 'CUSTOMS'::text) AND (currency IS NULL)))), + CONSTRAINT chk_wagon_range CHECK ((min_wagon_count <= max_wagon_count)), + CONSTRAINT priority_configs_type_check CHECK (((type)::text = ANY ((ARRAY['WAGON'::character varying, 'CURRENCY'::character varying, 'CUSTOMS'::character varying])::text[]))) +); + +CREATE TABLE freight.priority_rule_change_requests ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + action character varying(10) NOT NULL, + priority_config_id uuid, + payload jsonb, + status character varying(10) DEFAULT 'PENDING'::character varying NOT NULL, + requested_by_user_id uuid, + decided_by_user_id uuid, + decided_at timestamp with time zone, + decision_note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.priority_rules ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + is_active boolean DEFAULT false NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + code character varying(40) NOT NULL, + label character varying(100) NOT NULL, + score integer DEFAULT 0 NOT NULL, + condition_currency character varying(5) +); + +CREATE TABLE freight.rate_change_requests ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + rate_id uuid NOT NULL, + payload jsonb NOT NULL, + previous_values jsonb NOT NULL, + status character varying(10) DEFAULT 'PENDING'::character varying NOT NULL, + requested_by_user_id uuid, + decided_by_user_id uuid, + decided_at timestamp with time zone, + decision_note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.rates ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + rate_type character varying(50) NOT NULL, + container_type_id uuid, + trade_direction character varying(10), + currency character varying(5) NOT NULL, + rate_value numeric(14,4) NOT NULL, + rate_unit character varying(30) NOT NULL, + status character varying(20) DEFAULT 'DRAFT'::character varying NOT NULL, + proposed_by_staff_id uuid NOT NULL, + approved_by_ceo_id uuid, + approved_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + applies_to character varying(20) DEFAULT 'OTHER'::character varying NOT NULL, + trigger character varying(20) DEFAULT 'ALWAYS'::character varying NOT NULL, + cargo_type_id uuid, + origin_yard_id uuid, + destination_yard_id uuid, + CONSTRAINT "CK_rates_yard_scope" CHECK (((deleted_at IS NOT NULL) OR ((status)::text = 'SUPERSEDED'::text) OR +CASE + WHEN ((((trigger)::text = 'ALWAYS'::text) AND ((applies_to)::text = ANY ((ARRAY['BULK'::character varying, 'CONTAINER'::character varying, 'INTERCITY'::character varying])::text[]))) OR ((trigger)::text = ANY ((ARRAY['CUSTOMS_CLEARANCE'::character varying, 'WITH_RETURN'::character varying])::text[]))) THEN ((origin_yard_id IS NOT NULL) AND (destination_yard_id IS NOT NULL)) + ELSE ((origin_yard_id IS NULL) AND (destination_yard_id IS NULL)) +END)) +); + +CREATE TABLE freight.route_milestones ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + route_id uuid NOT NULL, + yard_id uuid NOT NULL, + sequence_no integer NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + distance_km numeric(10,2) +); + +CREATE TABLE freight.routes ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + origin_yard_id uuid NOT NULL, + destination_yard_id uuid NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + status character varying(32) DEFAULT 'AVAILABLE'::character varying NOT NULL, + direction character varying(10) NOT NULL, + CONSTRAINT chk_routes_direction CHECK (((direction)::text = ANY ((ARRAY['IMPORT'::character varying, 'EXPORT'::character varying, 'DOMESTIC'::character varying])::text[]))) +); + +CREATE TABLE freight.saved_signatures ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + user_id uuid NOT NULL, + signer_display_name character varying(200) NOT NULL, + signature_file_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + stamp_file_id uuid +); + +CREATE TABLE freight.schedule_wagon_adjustment_logs ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + train_schedule_id uuid NOT NULL, + train_id uuid NOT NULL, + action character varying(10) NOT NULL, + wagon_id uuid NOT NULL, + wagon_number character varying(50) NOT NULL, + adjusted_by_user_id uuid, + occurred_at timestamp with time zone DEFAULT now() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + yard_id uuid +); + +CREATE TABLE freight.scheduling_events ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_schedule_id uuid NOT NULL, + trigger character varying(40) NOT NULL, + actor_user_id uuid, + reason text, + plan_snapshot jsonb DEFAULT '{}'::jsonb NOT NULL, + displaced_booking_ids jsonb DEFAULT '[]'::jsonb NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE SEQUENCE freight.seq_company_profile_ex + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE SEQUENCE freight.seq_company_profile_ffe + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE SEQUENCE freight.seq_company_profile_fwj + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE SEQUENCE freight.seq_company_profile_im + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE SEQUENCE freight.seq_company_profile_tr + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +CREATE TABLE freight.service_types ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + service_name character varying(255) NOT NULL, + description text, + can_be_booked_alone boolean DEFAULT true NOT NULL, + includes_first_mile boolean DEFAULT false NOT NULL, + includes_last_mile boolean DEFAULT false NOT NULL, + includes_customs boolean DEFAULT false NOT NULL, + is_active boolean DEFAULT true NOT NULL, + display_order integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + code character varying(50) NOT NULL +); + +CREATE TABLE freight.shipping_lines ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + code character varying(20) NOT NULL, + label character varying(100) NOT NULL, + mapped_to_code character varying(20), + show_extra_fee_notice boolean DEFAULT false NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.support_conversations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + company_id uuid NOT NULL, + company_name character varying(200), + created_by_user_id uuid, + last_message_at timestamp with time zone, + last_message_preview character varying(280), + last_message_author_role character varying(12), + customer_last_read_at timestamp with time zone, + agent_last_read_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.support_messages ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + conversation_id uuid NOT NULL, + author_user_id uuid NOT NULL, + author_role character varying(12) NOT NULL, + author_name character varying(200), + body text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.tracking_events ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + consignment_id uuid NOT NULL, + location character varying(256) NOT NULL, + status freight.tracking_events_status_enum NOT NULL, + occurred_at timestamp with time zone NOT NULL, + description text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.train_checkpoint_events ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_schedule_id uuid NOT NULL, + yard_id uuid NOT NULL, + sequence_no integer NOT NULL, + kind character varying(20) NOT NULL, + occurred_at timestamp with time zone DEFAULT now() NOT NULL, + note text, + recorded_by_user_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.train_composition_removal_logs ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + schedule_id uuid NOT NULL, + booking_id uuid NOT NULL, + booking_reference character varying(64), + removed_by_user_id uuid, + removed_at timestamp with time zone DEFAULT now() NOT NULL, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.train_locomotives ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + train_id uuid NOT NULL, + locomotive_id uuid NOT NULL, + sequence_no integer DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.train_schedule_bookings ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_schedule_id uuid NOT NULL, + booking_id uuid NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + loading_status character varying(20) DEFAULT 'UNLOADED'::character varying NOT NULL +); + +CREATE TABLE freight.train_schedules ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_set_id uuid NOT NULL, + origin_station_id uuid NOT NULL, + destination_station_id uuid NOT NULL, + scheduled_departure_date timestamp with time zone NOT NULL, + scheduled_arrival_date timestamp with time zone, + status character varying(20) DEFAULT 'DRAFT'::character varying NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + route_id uuid, + train_number character varying(20), + direction character varying(10), + actual_departure_at timestamp with time zone, + actual_arrival_at timestamp with time zone, + prepared_by_user_id uuid, + checked_by_user_id uuid, + max_wagons integer DEFAULT 53 NOT NULL, + booking_window_status character varying(10) DEFAULT 'OPEN'::character varying NOT NULL, + window_phase character varying(20), + window_opens_at timestamp with time zone, + window_closes_at timestamp with time zone, + doc_review_ends_at timestamp with time zone, + doc_review_completed_at timestamp with time zone, + payment_phase_ends_at timestamp with time zone, + booking_cycle_no integer DEFAULT 0 NOT NULL, + rule_window_open_hour integer, + rule_window_duration_hours numeric(6,4), + rule_reopen_delay_minutes integer, + rule_import_window_lead_days integer, + rule_export_booking_lead_hours integer, + rule_window_close_hour integer, + reference character varying(20), + wagon_allocation_snapshot jsonb, + rule_import_close_offset_minutes integer, + rule_export_close_offset_minutes integer, + reverse_wagon_order boolean DEFAULT false NOT NULL, + rule_payment_window_minutes integer, + window_rule_custom boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.train_scheduling_global_rules ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + max_train_length_meters numeric(10,2) DEFAULT 760 NOT NULL, + max_train_weight_tons numeric(10,3) DEFAULT 3500 NOT NULL, + max_wagons_per_train integer DEFAULT 53 NOT NULL, + max_20ft_container_weight_tons numeric(8,3) DEFAULT 30 NOT NULL, + max_20ft_pair_weight_diff_tons numeric(8,3) DEFAULT 10 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + import_window_lead_days integer DEFAULT 3 NOT NULL, + export_booking_lead_hours integer DEFAULT 24 NOT NULL, + window_open_hour integer DEFAULT 8 NOT NULL, + window_duration_hours numeric(6,4) DEFAULT 3 NOT NULL, + doc_review_minutes integer DEFAULT 30 NOT NULL, + payment_window_minutes integer DEFAULT 60 NOT NULL, + window_close_hour integer DEFAULT 17 NOT NULL, + import_close_offset_minutes integer, + export_close_offset_minutes integer, + export_payment_window_minutes integer DEFAULT 60 NOT NULL +); + +CREATE TABLE freight.train_set_locomotives ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + train_set_id uuid NOT NULL, + locomotive_id uuid NOT NULL, + sequence_no integer DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.train_set_wagons ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_set_id uuid NOT NULL, + wagon_type_id uuid NOT NULL, + sequence_no integer NOT NULL, + capacity_tons numeric(10,3) NOT NULL, + length_meters numeric(10,3) NOT NULL, + assigned_weight_tons numeric(10,3) DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + physical_wagon_id uuid, + status character varying(20) DEFAULT 'PLANNED'::character varying NOT NULL, + board_yard_id uuid, + alight_yard_id uuid +); + +CREATE TABLE freight.train_sets ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + locomotive_id uuid NOT NULL, + total_weight_tons numeric(10,3) NOT NULL, + total_length_meters numeric(10,3) NOT NULL, + wagon_count integer NOT NULL, + status character varying(20) DEFAULT 'DRAFT'::character varying NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + train_id uuid +); + +CREATE TABLE freight.trains ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + code character varying(32) NOT NULL, + capacity_tons numeric(10,2) DEFAULT 0 NOT NULL, + status freight.train_status DEFAULT 'AVAILABLE'::freight.train_status NOT NULL, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + train_number character varying(20), + train_name character varying(100), + route_id uuid, + origin_station_id uuid, + destination_station_id uuid, + departure_time timestamp with time zone, + arrival_time timestamp with time zone, + locomotive_number character varying(50), + remarks text, + current_yard_id uuid, + import_train_number character varying(20), + export_train_number character varying(20) +); + +CREATE TABLE freight.transit_agents ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + name character varying(150) NOT NULL, + valid_from date NOT NULL, + valid_to date NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.truck_types ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(32) NOT NULL, + name character varying(100) NOT NULL, + capacity_tons numeric(10,3), + has_trailer boolean DEFAULT false NOT NULL, + description text, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.user_trade_access ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + user_id uuid NOT NULL, + directions text DEFAULT ''::text NOT NULL, + updated_by_id uuid, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.vehicles ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + plate_number character varying NOT NULL, + registration_number character varying NOT NULL, + vehicle_type character varying NOT NULL, + manufacturer character varying NOT NULL, + model character varying NOT NULL, + year integer NOT NULL, + fuel_type character varying NOT NULL, + capacity numeric NOT NULL, + status character varying DEFAULT 'ACTIVE'::character varying NOT NULL, + description text, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted_at timestamp without time zone, + assigned_driver_id uuid, + assigned_driver_name character varying, + code character varying, + power_plate_no character varying, + trailer_plate_no character varying, + estimated_distance_km numeric, + actual_distance_km numeric, + location_id uuid, + availability character varying DEFAULT 'FREE'::character varying, + vin character varying, + ownership character varying, + insurance_expiry date, + registration_expiry date, + next_inspection_date date, + price_per_km numeric(14,2), + currency character varying(8) DEFAULT 'ETB'::character varying NOT NULL, + truck_type_id uuid +); + +CREATE TABLE freight.vendors ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + name character varying NOT NULL, + type character varying, + contact_person character varying, + phone character varying, + email character varying, + address character varying, + is_active boolean DEFAULT true NOT NULL +); + +CREATE TABLE freight.wagon_allocation_bulk_loads ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + wagon_booking_allocation_id uuid NOT NULL, + booking_id uuid NOT NULL, + cargo_type_id uuid, + cargo_description text, + pricing_unit character varying(20) DEFAULT 'PER_TON'::character varying NOT NULL, + quantity numeric(12,3) DEFAULT 0 NOT NULL, + weight_tons numeric(10,3) DEFAULT 0 NOT NULL, + truck_plate_number character varying(32), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.wagon_allocation_container_items ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + wagon_booking_allocation_id uuid NOT NULL, + booking_container_id uuid, + container_id uuid, + container_number character varying(64), + container_type_id uuid, + position_on_wagon smallint, + seal_number character varying(64), + chassis_number character varying(64), + gross_weight_tons numeric(10,3), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.wagon_booking_allocations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + train_set_wagon_id uuid NOT NULL, + booking_id uuid NOT NULL, + allocated_weight_tons numeric(10,3) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + load_type character varying(20), + status character varying(20) DEFAULT 'PLANNED'::character varying NOT NULL, + confirmed_at timestamp with time zone, + confirmed_by_user_id uuid +); + +CREATE TABLE freight.wagon_movements ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + wagon_id uuid NOT NULL, + from_yard_id uuid, + to_yard_id uuid NOT NULL, + train_schedule_id uuid, + booking_id uuid, + kind character varying(30) NOT NULL, + moved_by_user_id uuid, + occurred_at timestamp with time zone DEFAULT now() NOT NULL, + note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + transfer_request_id uuid +); + +CREATE TABLE freight.wagon_transfer_requests ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + from_yard_id uuid NOT NULL, + to_yard_id uuid NOT NULL, + wagon_type_id uuid NOT NULL, + quantity integer NOT NULL, + status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL, + requested_by_user_id uuid, + fulfilled_by_user_id uuid, + fulfilled_at timestamp with time zone, + note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + reason text, + fulfilled_quantity integer DEFAULT 0 NOT NULL, + closed_short_at timestamp with time zone, + closed_short_by_user_id uuid, + CONSTRAINT chk_wtr_quantity CHECK ((quantity > 0)) +); + +CREATE TABLE freight.wagon_types ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + code character varying(32) NOT NULL, + name character varying(100) NOT NULL, + capacity_tons numeric(10,3) NOT NULL, + length_meters numeric(10,3) NOT NULL, + supported_load_types text[] DEFAULT '{}'::text[] NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + equated_length_m numeric(10,3), + tare_weight_tons numeric(10,3) NOT NULL, + supports_container boolean DEFAULT false NOT NULL, + max_container_gross_t numeric(10,3) +); + +CREATE TABLE freight.wagons ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + wagon_number character varying NOT NULL, + wagon_type_id uuid NOT NULL, + train_id uuid, + sequence_number integer, + status character varying DEFAULT 'AVAILABLE'::character varying NOT NULL, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + current_location_yard_id uuid, + train_set_wagon_id uuid, + current_train_schedule_id uuid, + current_yard_id uuid, + export_train_number character varying(20), + import_train_number character varying(20) +); + +CREATE TABLE freight.warehouse_accrual_acks ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + inventory_id uuid NOT NULL, + acknowledged_by uuid, + acknowledged_at timestamp with time zone DEFAULT now() NOT NULL, + snooze_until timestamp with time zone, + note text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL +); + +CREATE TABLE freight.warehouse_activity_log ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + inventory_id uuid, + warehouse_id uuid, + activity_type character varying(40) NOT NULL, + description text, + performed_by character varying(120), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.warehouse_allocation_rules ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + name character varying(160) NOT NULL, + priority integer DEFAULT 100 NOT NULL, + freight_type character varying(16), + trade_direction character varying(16), + cargo_type_code character varying(50), + container_status character varying(24), + requires_inspection boolean, + target_facility_code character varying(40), + target_yard_code character varying(40) NOT NULL, + target_warehouse_code character varying(40), + target_zone_code character varying(40), + storage_type character varying(80), + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.warehouse_fee_rules ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + name character varying(160) NOT NULL, + rule_type character varying(20) NOT NULL, + priority integer DEFAULT 100 NOT NULL, + freight_type character varying(16), + trade_direction character varying(16), + cargo_type_code character varying(50), + container_type character varying(40), + facility_id uuid, + warehouse_id uuid, + yard_id uuid, + zone_id uuid, + free_days integer DEFAULT 0 NOT NULL, + rate_per_day numeric(14,2) DEFAULT 0 NOT NULL, + tiers jsonb DEFAULT '[]'::jsonb NOT NULL, + currency character varying(8) DEFAULT 'USD'::character varying NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + basis character varying(20), + free_hours integer, + vehicle_type character varying(32) +); + +CREATE TABLE freight.warehouse_inspection_reports ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + inventory_id uuid NOT NULL, + booking_id uuid, + customer_id uuid, + report_type character varying(32) DEFAULT 'INSPECTION'::character varying NOT NULL, + inspection_status character varying(20) DEFAULT 'NEEDS_REVIEW'::character varying NOT NULL, + has_damage boolean DEFAULT false NOT NULL, + damage_description text, + has_weight_loss boolean DEFAULT false NOT NULL, + expected_weight numeric(14,3), + actual_weight numeric(14,3), + weight_loss numeric(14,3), + weight_loss_unit character varying(12), + has_missing_items boolean DEFAULT false NOT NULL, + missing_items_description text, + remarks text, + inspected_by_id uuid, + inspected_at timestamp with time zone, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.warehouse_inventory ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + warehouse_id uuid NOT NULL, + yard_id uuid NOT NULL, + zone_id uuid NOT NULL, + booking_id uuid, + cargo_id uuid, + container_id uuid, + goods_id uuid, + quantity numeric(12,3) DEFAULT 0 NOT NULL, + weight numeric(14,3) DEFAULT 0 NOT NULL, + volume numeric(12,3), + status character varying(32) DEFAULT 'RECEIVED'::character varying NOT NULL, + inspection_status character varying(20), + arrived_at timestamp with time zone, + inspected_at timestamp with time zone, + ready_for_loading_at timestamp with time zone, + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + stored_at timestamp with time zone, + reserved_at timestamp with time zone, + loaded_at timestamp with time zone, + dispatched_at timestamp with time zone, + inspection_started_at timestamp with time zone, + inspection_completed_at timestamp with time zone, + ready_for_pickup_at timestamp with time zone, + release_date timestamp with time zone, + gate_cleared_at timestamp with time zone, + release_order_reference character varying(100), + delivered_at timestamp with time zone, + unloaded_at timestamp with time zone, + grn_number character varying(100) +); + +CREATE TABLE freight.warehouse_inventory_movement ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + inventory_id uuid NOT NULL, + from_warehouse_id uuid NOT NULL, + from_yard_id uuid NOT NULL, + from_zone_id uuid NOT NULL, + to_warehouse_id uuid NOT NULL, + to_yard_id uuid NOT NULL, + to_zone_id uuid NOT NULL, + remarks text, + moved_by character varying(120), + moved_at timestamp with time zone DEFAULT now() NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.warehouse_loadings ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + warehouse_inventory_id uuid NOT NULL, + booking_id uuid, + wagon_id uuid, + loaded_at timestamp with time zone DEFAULT now() NOT NULL, + loaded_by character varying(120), + loaded_weight numeric(14,3), + notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + train_schedule_id uuid +); + +CREATE TABLE freight.warehouse_yard_cargo_types ( + yard_id uuid NOT NULL, + cargo_type_id uuid NOT NULL +); + +CREATE TABLE freight.warehouse_yards ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + warehouse_id uuid NOT NULL, + name character varying(160) NOT NULL, + code character varying(40) NOT NULL, + type character varying(32) NOT NULL, + capacity_weight numeric(14,3), + capacity_containers integer, + current_weight numeric(14,3) DEFAULT 0 NOT NULL, + current_containers integer DEFAULT 0 NOT NULL, + status character varying(16) DEFAULT 'ACTIVE'::character varying NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + max_weight numeric(14,3), + max_volume numeric(14,3), + current_volume numeric(14,3) DEFAULT 0 NOT NULL, + direction character varying(10) +); + +CREATE TABLE freight.warehouse_zones ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + yard_id uuid NOT NULL, + name character varying(160) NOT NULL, + code character varying(40) NOT NULL, + type character varying(32) NOT NULL, + capacity_weight numeric(14,3), + capacity_containers integer, + current_weight numeric(14,3) DEFAULT 0 NOT NULL, + current_containers integer DEFAULT 0 NOT NULL, + status character varying(16) DEFAULT 'ACTIVE'::character varying NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + max_weight numeric(14,3), + max_volume numeric(14,3), + current_volume numeric(14,3) DEFAULT 0 NOT NULL +); + +CREATE TABLE freight.warehouses ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + name character varying(160) NOT NULL, + code character varying(40) NOT NULL, + type character varying(32) NOT NULL, + station_id uuid, + location_name character varying(200), + capacity_weight numeric(14,3), + capacity_containers integer, + current_weight numeric(14,3) DEFAULT 0 NOT NULL, + current_containers integer DEFAULT 0 NOT NULL, + status character varying(16) DEFAULT 'ACTIVE'::character varying NOT NULL, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + max_weight numeric(14,3), + max_volume numeric(14,3), + current_volume numeric(14,3) DEFAULT 0 NOT NULL, + facility_id uuid +); + +CREATE TABLE freight.warranties ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + component character varying NOT NULL, + provider character varying, + start_date date, + expiry_date date NOT NULL, + coverage_notes text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.weight_limit_rules ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + container_type_id uuid NOT NULL, + trade_direction freight.weight_limit_rules_trade_direction_enum NOT NULL, + max_vgm_tons numeric(8,3) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + max_capacity_tons numeric(8,3) +); + +CREATE TABLE freight.work_orders ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + vehicle_id uuid NOT NULL, + title character varying NOT NULL, + description text, + status character varying DEFAULT 'OPEN'::character varying NOT NULL, + priority character varying DEFAULT 'MEDIUM'::character varying NOT NULL, + assigned_to character varying, + opened_at timestamp with time zone DEFAULT now() NOT NULL, + closed_at timestamp with time zone, + labor_cost numeric(14,2), + parts_cost numeric(14,2), + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.yard_distances ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + from_yard_id uuid NOT NULL, + to_yard_id uuid NOT NULL, + distance_km numeric(10,2) NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone +); + +CREATE TABLE freight.yard_facilities ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + yard_id uuid NOT NULL, + has_warehouse boolean DEFAULT false NOT NULL, + equipment_notes text, + is_active boolean DEFAULT true NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + handles_container boolean DEFAULT true NOT NULL, + handles_bulk boolean DEFAULT true NOT NULL, + has_container_facility_origin boolean DEFAULT false NOT NULL, + has_bulk_facility_origin boolean DEFAULT false NOT NULL, + has_container_facility_destination boolean DEFAULT false NOT NULL, + has_bulk_facility_destination boolean DEFAULT false NOT NULL +); + +CREATE TABLE freight.yards ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + code character varying(40) NOT NULL, + label character varying(100) NOT NULL, + country character varying(50) NOT NULL, + is_active boolean DEFAULT true NOT NULL, + display_order integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT now() NOT NULL, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + deleted_at timestamp with time zone, + has_facility boolean DEFAULT false NOT NULL, + CONSTRAINT chk_yards_country CHECK (((country)::text = ANY ((ARRAY['Ethiopia'::character varying, 'Djibouti'::character varying])::text[]))) +); + +ALTER TABLE ONLY freight.approval_rules + ADD CONSTRAINT "PK_048d2ffdf7169337b4cc237d772" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.company_change_request + ADD CONSTRAINT "PK_0a57bba5aaf77b376e7fee5fcf8" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.interchange_document_items + ADD CONSTRAINT "PK_163803862ca83ef98678e39a43b" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.company_profiles + ADD CONSTRAINT "PK_1980200b310bd1e2ac86aa1ae4a" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.service_types + ADD CONSTRAINT "PK_1dc93417a097cdee3491f39d7cc" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_composition_removal_logs + ADD CONSTRAINT "PK_29f7cdb5e0ae32ef1b96155fc9a" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.rates + ADD CONSTRAINT "PK_2c804ed4019b80ce48eedba5cec" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.facilities + ADD CONSTRAINT "PK_2e6c685b2e1195e6d6394a22bc7" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_allocation_rules + ADD CONSTRAINT "PK_2e7632f009769d4da579c14f151" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.shipping_lines + ADD CONSTRAINT "PK_336306f24563d798ec54eedca0c" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.import_djibouti_operations + ADD CONSTRAINT "PK_3456f58d03f6719b38c70018ab6" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.yards + ADD CONSTRAINT "PK_3aa7dacb4c4fb065b1e2f8dfb5a" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_document_review + ADD CONSTRAINT "PK_3d7705ea54a01cb4d6db5b743cd" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.exchange_settings + ADD CONSTRAINT "PK_48f5730ce6881caf75f279d0a5d" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.container_types + ADD CONSTRAINT "PK_50e6b62fcd07ba58bdb6415d47c" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_inspection_reports + ADD CONSTRAINT "PK_625df1e3a62e5aa4c3f14e7172e" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_requests + ADD CONSTRAINT "PK_62c29ee249979fe0bcdcde33dae" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.first_mile + ADD CONSTRAINT "PK_72bc92607db5356f03c2aaeb6ec" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.first_mile_container_allocations + ADD CONSTRAINT "PK_8be4b0df481f8a1555a4fb9d05d" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.last_mile + ADD CONSTRAINT "PK_8be9fbd78fd39e78b6d30ab119b" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_rate_snapshot + ADD CONSTRAINT "PK_8ca5cf692c4c3e95d91a7343117" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.otp_verifications + ADD CONSTRAINT pk_otp_verifications PRIMARY KEY (id); + +ALTER TABLE ONLY freight.user_trade_access + ADD CONSTRAINT "PK_94e21d7bfb20e57940e3255df87" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.priority_rules + ADD CONSTRAINT "PK_95c73e8a6e80f29d81edf66dbe2" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.interchange_documents + ADD CONSTRAINT "PK_95e5a5484c57ecc6f4a2927ddb4" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.last_mile_container_allocations + ADD CONSTRAINT "PK_9d5180799a6dd494156ec980dfb" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_container + ADD CONSTRAINT "PK_c1805410bccc51530297b2960ef" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.company_revisions + ADD CONSTRAINT "PK_c8ed8b5e0e0d93edffd43c8c024" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.cargo_type_wagon_types + ADD CONSTRAINT "PK_cargo_type_wagon_types" PRIMARY KEY (cargo_type_id, wagon_type_id); + +ALTER TABLE ONLY freight.djibouti_import_incidents + ADD CONSTRAINT "PK_cf3871f27f8bd0db9176f09bf95" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.container_type_wagon_types + ADD CONSTRAINT "PK_container_type_wagon_types" PRIMARY KEY (container_type_id, wagon_type_id); + +ALTER TABLE ONLY freight.warehouse_fee_rules + ADD CONSTRAINT "PK_d24f444e0cb6841c1b19342e134" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.companies + ADD CONSTRAINT "PK_d4bc3e82a314fa9e29f652c2c22" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.weight_limit_rules + ADD CONSTRAINT "PK_d82c70fa7e878ca301e2aaff709" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_cargo_modifier + ADD CONSTRAINT "PK_d949ef8f1b862135ad7e4afdbf1" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.cargo_types + ADD CONSTRAINT "PK_db1aa5f07b0c5ea996eaea03394" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.dropdown_options + ADD CONSTRAINT "PK_dropdown_options" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.dropdown_settings + ADD CONSTRAINT "PK_dropdown_settings" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.ff_clients + ADD CONSTRAINT "PK_eb91bf3ee74a361acee369dbda2" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.external_profiles + ADD CONSTRAINT "PK_f01bade59a434fa68039620ccb9" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.import_customs_finalizations + ADD CONSTRAINT "PK_f67c60e65b732153fc050dd166c" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.empty_container_returns + ADD CONSTRAINT "PK_f82bda09e0ff411811193579948" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_container_allocations + ADD CONSTRAINT "PK_fb0dee3634a65d2ebd734ff46e3" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.schedule_wagon_adjustment_logs + ADD CONSTRAINT "PK_schedule_wagon_adjustment_logs" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_locomotives + ADD CONSTRAINT "PK_train_locomotives" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_set_locomotives + ADD CONSTRAINT "PK_train_set_locomotives" PRIMARY KEY (id); + +ALTER TABLE ONLY freight.companies + ADD CONSTRAINT "UQ_1b3738f728d42fc9aca8d4ac19b" UNIQUE (tin); + +ALTER TABLE ONLY freight.ff_clients + ADD CONSTRAINT "UQ_4107fef2abf7128f890ef276244" UNIQUE (forwarder_company_id, client_company_id); + +ALTER TABLE ONLY freight.otp_verifications + ADD CONSTRAINT uq_otp_verifications_phone UNIQUE (phone); + +ALTER TABLE ONLY freight.company_profiles + ADD CONSTRAINT "UQ_539ff8f8225951adb2ef76b0313" UNIQUE (reference); + +ALTER TABLE ONLY freight.import_djibouti_operations + ADD CONSTRAINT "UQ_6c3e3046300b152a13505bf8ffd" UNIQUE (train_schedule_id); + +ALTER TABLE ONLY freight.first_mile_vehicle_assignments + ADD CONSTRAINT "UQ_FIRST_MILE_VEHICLE" UNIQUE (first_mile_id, vehicle_id); + +ALTER TABLE ONLY freight.last_mile_vehicle_assignments + ADD CONSTRAINT "UQ_LAST_MILE_VEHICLE" UNIQUE (last_mile_id, vehicle_id); + +ALTER TABLE ONLY freight.import_customs_finalizations + ADD CONSTRAINT "UQ_ad87af234cc0068a05fa7bd2335" UNIQUE (booking_id); + +ALTER TABLE ONLY freight.approval_rules + ADD CONSTRAINT "UQ_approval_rules_chain_step" UNIQUE (requires_director_approval, step_order); + +ALTER TABLE ONLY freight.interchange_documents + ADD CONSTRAINT "UQ_b44369ad5b13e0d897487fc4284" UNIQUE (document_no); + +ALTER TABLE ONLY freight.facilities + ADD CONSTRAINT "UQ_bf808b325b190fb9049254ba55e" UNIQUE (code); + +ALTER TABLE ONLY freight.user_trade_access + ADD CONSTRAINT "UQ_e54889f850f4db112a77b9e8431" UNIQUE (user_id); + +ALTER TABLE ONLY freight.asset_acquisitions + ADD CONSTRAINT asset_acquisitions_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.asset_disposals + ADD CONSTRAINT asset_disposals_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_batch_offers + ADD CONSTRAINT booking_batch_offers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_container_units + ADD CONSTRAINT booking_container_units_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_contract_signatures + ADD CONSTRAINT booking_contract_signatures_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_handovers + ADD CONSTRAINT booking_handovers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_review_note + ADD CONSTRAINT booking_review_note_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT bookings_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT bookings_reference_key UNIQUE (reference); + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT cargoes_cargo_reference_key UNIQUE (cargo_reference); + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT cargoes_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.clearance_incidents + ADD CONSTRAINT clearance_incidents_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.clearance_milestones + ADD CONSTRAINT clearance_milestones_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.compliance_records + ADD CONSTRAINT compliance_records_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT containers_container_number_key UNIQUE (container_number); + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT containers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_approval_steps + ADD CONSTRAINT contract_approval_steps_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_cargo_scope + ADD CONSTRAINT contract_cargo_scope_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_clearance_cycles + ADD CONSTRAINT contract_clearance_cycles_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_document_review + ADD CONSTRAINT contract_document_review_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_document_revisions + ADD CONSTRAINT contract_document_revisions_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_rate_snapshots + ADD CONSTRAINT contract_rate_snapshots_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_review_notes + ADD CONSTRAINT contract_review_notes_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_routes + ADD CONSTRAINT contract_routes_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_signatures + ADD CONSTRAINT contract_signatures_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contract_templates + ADD CONSTRAINT contract_templates_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contracts + ADD CONSTRAINT contracts_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.contracts + ADD CONSTRAINT contracts_reference_key UNIQUE (reference); + +ALTER TABLE ONLY freight.customer_truck_assignments + ADD CONSTRAINT customer_truck_assignments_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.customer_truck_containers + ADD CONSTRAINT customer_truck_containers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.customers + ADD CONSTRAINT customers_email_key UNIQUE (email); + +ALTER TABLE ONLY freight.customers + ADD CONSTRAINT customers_fan_number_key UNIQUE (fan_number); + +ALTER TABLE ONLY freight.customers + ADD CONSTRAINT customers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.customers + ADD CONSTRAINT customers_tin_number_key UNIQUE (tin_number); + +ALTER TABLE ONLY freight.drivers + ADD CONSTRAINT drivers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.facility_handling_events + ADD CONSTRAINT facility_handling_events_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.fayda_verification_sessions + ADD CONSTRAINT fayda_verification_sessions_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.fayda_verification_sessions + ADD CONSTRAINT fayda_verification_sessions_state_key UNIQUE (state); + +ALTER TABLE ONLY freight.file_upload_fields + ADD CONSTRAINT file_upload_fields_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.file_upload_settings + ADD CONSTRAINT file_upload_settings_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.files + ADD CONSTRAINT files_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.first_mile_vehicle_assignments + ADD CONSTRAINT first_mile_vehicle_assignments_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.fleet_events + ADD CONSTRAINT fleet_events_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.gps_devices + ADD CONSTRAINT gps_devices_imei_key UNIQUE (imei); + +ALTER TABLE ONLY freight.gps_devices + ADD CONSTRAINT gps_devices_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.gps_positions + ADD CONSTRAINT gps_positions_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.incidents + ADD CONSTRAINT incidents_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.last_mile_vehicle_assignments + ADD CONSTRAINT last_mile_vehicle_assignments_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.last_mile_vehicle_containers + ADD CONSTRAINT last_mile_vehicle_containers_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.locomotives + ADD CONSTRAINT locomotives_code_key UNIQUE (code); + +ALTER TABLE ONLY freight.locomotives + ADD CONSTRAINT locomotives_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.maintenance_costs + ADD CONSTRAINT maintenance_costs_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.maintenance_intervals + ADD CONSTRAINT maintenance_intervals_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.maintenance_schedules + ADD CONSTRAINT maintenance_schedules_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.otp_verifications + ADD CONSTRAINT otp_verifications_email_key UNIQUE (email); + +ALTER TABLE ONLY freight.parts + ADD CONSTRAINT parts_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.consignments + ADD CONSTRAINT pk_consignments PRIMARY KEY (id); + +ALTER TABLE ONLY freight.fuel_consumption + ADD CONSTRAINT pk_fuel_consumption PRIMARY KEY (id); + +ALTER TABLE ONLY freight.fuel_purchases + ADD CONSTRAINT pk_fuel_purchases PRIMARY KEY (id); + +ALTER TABLE ONLY freight.invoice_lines + ADD CONSTRAINT pk_invoice_lines PRIMARY KEY (id); + +ALTER TABLE ONLY freight.invoices + ADD CONSTRAINT pk_invoices PRIMARY KEY (id); + +ALTER TABLE ONLY freight.payment_refunds + ADD CONSTRAINT pk_payment_refunds PRIMARY KEY (id); + +ALTER TABLE ONLY freight.payment_webhook_events + ADD CONSTRAINT pk_payment_webhook_events PRIMARY KEY (id); + +ALTER TABLE ONLY freight.payments + ADD CONSTRAINT pk_payments PRIMARY KEY (id); + +ALTER TABLE ONLY freight.tracking_events + ADD CONSTRAINT pk_tracking_events PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_transfer_requests + ADD CONSTRAINT pk_wagon_transfer_requests PRIMARY KEY (id); + +ALTER TABLE ONLY freight.priority_configs + ADD CONSTRAINT priority_configs_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.priority_rule_change_requests + ADD CONSTRAINT priority_rule_change_requests_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.rate_change_requests + ADD CONSTRAINT rate_change_requests_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.route_milestones + ADD CONSTRAINT route_milestones_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.routes + ADD CONSTRAINT routes_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.saved_signatures + ADD CONSTRAINT saved_signatures_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.scheduling_events + ADD CONSTRAINT scheduling_events_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.support_conversations + ADD CONSTRAINT support_conversations_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.support_messages + ADD CONSTRAINT support_messages_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_checkpoint_events + ADD CONSTRAINT train_checkpoint_events_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_schedule_bookings + ADD CONSTRAINT train_schedule_bookings_booking_id_key UNIQUE (booking_id); + +ALTER TABLE ONLY freight.train_schedule_bookings + ADD CONSTRAINT train_schedule_bookings_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT train_schedules_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT train_schedules_train_set_id_key UNIQUE (train_set_id); + +ALTER TABLE ONLY freight.train_scheduling_global_rules + ADD CONSTRAINT train_scheduling_global_rules_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT train_set_wagons_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.train_sets + ADD CONSTRAINT train_sets_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.trains + ADD CONSTRAINT trains_code_key UNIQUE (code); + +ALTER TABLE ONLY freight.trains + ADD CONSTRAINT trains_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.transit_agents + ADD CONSTRAINT transit_agents_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.truck_types + ADD CONSTRAINT truck_types_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.booking_container_units + ADD CONSTRAINT uq_booking_container_unit_number UNIQUE (booking_container_id, container_number); + +ALTER TABLE ONLY freight.booking_contract_signatures + ADD CONSTRAINT uq_booking_contract_signatures_role UNIQUE (booking_id, signer_role); + +ALTER TABLE ONLY freight.consignments + ADD CONSTRAINT uq_consignments_tracking_number UNIQUE (tracking_number); + +ALTER TABLE ONLY freight.contract_clearance_cycles + ADD CONSTRAINT uq_contract_clearance_cycle UNIQUE (contract_id, cycle_number); + +ALTER TABLE ONLY freight.contract_cargo_scope + ADD CONSTRAINT uq_contract_container_size UNIQUE NULLS NOT DISTINCT (contract_id, container_size); + +ALTER TABLE ONLY freight.contract_document_review + ADD CONSTRAINT uq_contract_document_review_doc UNIQUE NULLS NOT DISTINCT (contract_id, clearance_cycle_id, setting_code, file_key); + +ALTER TABLE ONLY freight.contract_routes + ADD CONSTRAINT uq_contract_route UNIQUE (contract_id, origin_yard_id, destination_yard_id); + +ALTER TABLE ONLY freight.contract_templates + ADD CONSTRAINT uq_contract_templates_code UNIQUE (code); + +ALTER TABLE ONLY freight.fuel_consumption + ADD CONSTRAINT uq_fuel_consumption_vehicle_month UNIQUE (vehicle_id, month); + +ALTER TABLE ONLY freight.invoices + ADD CONSTRAINT uq_invoices_invoice_number UNIQUE (invoice_number); + +ALTER TABLE ONLY freight.payment_webhook_events + ADD CONSTRAINT uq_payment_webhook_events_provider_event UNIQUE (provider, external_event_id); + +ALTER TABLE ONLY freight.payments + ADD CONSTRAINT uq_payments_merchant_order_id UNIQUE (merchant_order_id); + +ALTER TABLE ONLY freight.payments + ADD CONSTRAINT uq_payments_transaction_id UNIQUE (transaction_id); + +ALTER TABLE ONLY freight.route_milestones + ADD CONSTRAINT uq_route_milestones_route_sequence UNIQUE (route_id, sequence_no); + +ALTER TABLE ONLY freight.saved_signatures + ADD CONSTRAINT uq_saved_signatures_user_id UNIQUE (user_id); + +ALTER TABLE ONLY freight.train_schedule_bookings + ADD CONSTRAINT uq_train_schedule_booking UNIQUE (train_schedule_id, booking_id); + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT uq_train_set_wagons_sequence UNIQUE (train_set_id, sequence_no); + +ALTER TABLE ONLY freight.warehouse_yards + ADD CONSTRAINT uq_warehouse_yards_code UNIQUE (warehouse_id, code); + +ALTER TABLE ONLY freight.warehouse_zones + ADD CONSTRAINT uq_warehouse_zones_code UNIQUE (yard_id, code); + +ALTER TABLE ONLY freight.vehicles + ADD CONSTRAINT vehicles_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.vehicles + ADD CONSTRAINT vehicles_plate_number_key UNIQUE (plate_number); + +ALTER TABLE ONLY freight.vehicles + ADD CONSTRAINT vehicles_registration_number_key UNIQUE (registration_number); + +ALTER TABLE ONLY freight.vendors + ADD CONSTRAINT vendors_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_allocation_bulk_loads + ADD CONSTRAINT wagon_allocation_bulk_loads_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_allocation_bulk_loads + ADD CONSTRAINT wagon_allocation_bulk_loads_wagon_booking_allocation_id_key UNIQUE (wagon_booking_allocation_id); + +ALTER TABLE ONLY freight.wagon_allocation_container_items + ADD CONSTRAINT wagon_allocation_container_items_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_booking_allocations + ADD CONSTRAINT wagon_booking_allocations_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagon_types + ADD CONSTRAINT wagon_types_code_key UNIQUE (code); + +ALTER TABLE ONLY freight.wagon_types + ADD CONSTRAINT wagon_types_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT wagons_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_accrual_acks + ADD CONSTRAINT warehouse_accrual_acks_inventory_id_key UNIQUE (inventory_id); + +ALTER TABLE ONLY freight.warehouse_accrual_acks + ADD CONSTRAINT warehouse_accrual_acks_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_activity_log + ADD CONSTRAINT warehouse_activity_log_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_inventory_movement + ADD CONSTRAINT warehouse_inventory_movement_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_inventory + ADD CONSTRAINT warehouse_inventory_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_loadings + ADD CONSTRAINT warehouse_loadings_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_yard_cargo_types + ADD CONSTRAINT warehouse_yard_cargo_types_pkey PRIMARY KEY (yard_id, cargo_type_id); + +ALTER TABLE ONLY freight.warehouse_yards + ADD CONSTRAINT warehouse_yards_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouse_zones + ADD CONSTRAINT warehouse_zones_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warehouses + ADD CONSTRAINT warehouses_code_key UNIQUE (code); + +ALTER TABLE ONLY freight.warehouses + ADD CONSTRAINT warehouses_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.warranties + ADD CONSTRAINT warranties_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.work_orders + ADD CONSTRAINT work_orders_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.yard_distances + ADD CONSTRAINT yard_distances_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY freight.yard_facilities + ADD CONSTRAINT yard_facilities_pkey PRIMARY KEY (id); + +CREATE INDEX "IDX_1101fbe8e745d91b6bd0747b58" ON freight.ff_clients USING btree (forwarder_company_id); + +CREATE INDEX "IDX_1b3738f728d42fc9aca8d4ac19" ON freight.companies USING btree (tin); + +CREATE INDEX "IDX_1e57cd6c6afae8f303847f159d" ON freight.companies USING btree (type); + +CREATE INDEX "IDX_26d2a16e263ab4fe0a4c8e9195" ON freight.external_profiles USING btree (company_id); + +CREATE INDEX "IDX_30228dd283a0f14486346e1db9" ON freight.company_profiles USING btree (company_id); + +CREATE INDEX "IDX_CARGO_TYPES_DISPLAY_ORDER" ON freight.cargo_types USING btree (display_order); + +CREATE INDEX "IDX_CARGO_TYPES_IS_ACTIVE" ON freight.cargo_types USING btree (is_active); + +CREATE INDEX "IDX_CARGO_TYPES_PARENT_GROUP_ID" ON freight.cargo_types USING btree (parent_group_id); + +CREATE INDEX "IDX_FAYDA_SESSIONS_EXPIRES_AT" ON freight.fayda_verification_sessions USING btree (expires_at); + +CREATE INDEX "IDX_FAYDA_SESSIONS_IAM_USER_ID" ON freight.fayda_verification_sessions USING btree (iam_user_id); + +CREATE INDEX "IDX_FILES_RESOURCE_LOOKUP" ON freight.files USING btree (resource, resource_id) WHERE (deleted_at IS NULL); + +CREATE INDEX "IDX_FLEET_EVENTS_DRIVER" ON freight.fleet_events USING btree (driver_id, created_at); + +CREATE INDEX "IDX_FLEET_EVENTS_VEHICLE" ON freight.fleet_events USING btree (vehicle_id, created_at); + +CREATE INDEX "IDX_FM_VEHICLE_ASSIGNMENTS_VEHICLE" ON freight.first_mile_vehicle_assignments USING btree (vehicle_id); + +CREATE INDEX "IDX_GPS_DEVICES_VEHICLE" ON freight.gps_devices USING btree (vehicle_id); + +CREATE INDEX "IDX_GPS_POSITIONS_DEVICE_TIME" ON freight.gps_positions USING btree (device_id, gps_time); + +CREATE INDEX "IDX_GPS_POSITIONS_VEHICLE_TIME" ON freight.gps_positions USING btree (vehicle_id, gps_time); + +CREATE INDEX "IDX_INCIDENTS_DRIVER" ON freight.incidents USING btree (driver_id, occurred_at); + +CREATE INDEX "IDX_INCIDENTS_VEHICLE" ON freight.incidents USING btree (vehicle_id, occurred_at); + +CREATE INDEX "IDX_LM_VEHICLE_ASSIGNMENTS_VEHICLE" ON freight.last_mile_vehicle_assignments USING btree (vehicle_id); + +CREATE INDEX "IDX_NOTIFICATIONS_RECIPIENT_CREATED" ON freight.notifications USING btree (recipient_user_id, created_at); + +CREATE INDEX "IDX_NOTIFICATIONS_RECIPIENT_UNREAD" ON freight.notifications USING btree (recipient_user_id, is_read); + +CREATE INDEX "IDX_SERVICE_TYPES_DISPLAY_ORDER" ON freight.service_types USING btree (display_order); + +CREATE INDEX "IDX_SERVICE_TYPES_IS_ACTIVE" ON freight.service_types USING btree (is_active); + +CREATE UNIQUE INDEX "IDX_SUPPORT_CONV_COMPANY" ON freight.support_conversations USING btree (company_id) WHERE (deleted_at IS NULL); + +CREATE INDEX "IDX_SUPPORT_CONV_LASTMSG" ON freight.support_conversations USING btree (last_message_at); + +CREATE INDEX "IDX_SUPPORT_MSG_CONV_CREATED" ON freight.support_messages USING btree (conversation_id, created_at); + +CREATE INDEX "IDX_af4d6bac2844d39095b2056e97" ON freight.ff_clients USING btree (client_company_id); + +CREATE INDEX "IDX_b658cd8f6876645a05c0366a56" ON freight.external_profiles USING btree (user_id); + +CREATE INDEX "IDX_booking_cargo_modifier_rate_id" ON freight.booking_cargo_modifier USING btree (rate_id); + +CREATE INDEX "IDX_booking_container_allocations_booking_id" ON freight.booking_container_allocations USING btree (booking_id); + +CREATE INDEX "IDX_booking_container_allocations_vehicle_id" ON freight.booking_container_allocations USING btree (vehicle_id); + +CREATE INDEX "IDX_booking_container_units_grn" ON freight.booking_container_units USING btree (grn_number); + +CREATE INDEX "IDX_booking_handovers_booking" ON freight.booking_handovers USING btree (booking_id); + +CREATE UNIQUE INDEX "IDX_cargo_types_code" ON freight.cargo_types USING btree (code); + +CREATE INDEX "IDX_cargoes_container_id" ON freight.cargoes USING btree (container_id); + +CREATE INDEX "IDX_companies_kind" ON freight.companies USING btree (kind); + +CREATE INDEX "IDX_container_types_is_active" ON freight.container_types USING btree (is_active); + +CREATE UNIQUE INDEX "IDX_container_types_size_code" ON freight.container_types USING btree (code); + +CREATE INDEX "IDX_containers_wagon_id" ON freight.containers USING btree (wagon_id); + +CREATE INDEX "IDX_customer_truck_assignments_booking" ON freight.customer_truck_assignments USING btree (booking_id); + +CREATE INDEX "IDX_customer_truck_containers_assignment" ON freight.customer_truck_containers USING btree (assignment_id); + +CREATE INDEX "IDX_customer_truck_departed" ON freight.customer_truck_assignments USING btree (booking_id, departed_at) WHERE (deleted_at IS NULL); + +CREATE INDEX "IDX_dc808839c3d64c763cc7f6ff68" ON freight.company_profiles USING btree (type); + +CREATE INDEX "IDX_e669a91069a3aa982b2c99c256" ON freight.train_composition_removal_logs USING btree (schedule_id); + +CREATE INDEX "IDX_facility_handling_events_booking" ON freight.facility_handling_events USING btree (booking_id); + +CREATE INDEX "IDX_facility_handling_events_grn" ON freight.facility_handling_events USING btree (grn_number) WHERE (grn_number IS NOT NULL); + +CREATE INDEX "IDX_facility_handling_events_yard" ON freight.facility_handling_events USING btree (yard_id); + +CREATE INDEX "IDX_files_open_change_request" ON freight.files USING btree (resource, resource_id) WHERE (((review_status)::text = 'change_requested'::text) AND (deleted_at IS NULL)); + +CREATE INDEX "IDX_files_version_history" ON freight.files USING btree (resource, resource_id, code, created_at DESC); + +CREATE INDEX "IDX_first_mile_booking_id" ON freight.first_mile USING btree (booking_id); + +CREATE INDEX "IDX_first_mile_container_allocations_first_mile_id" ON freight.first_mile_container_allocations USING btree (first_mile_id); + +CREATE INDEX "IDX_first_mile_container_allocations_vehicle_id" ON freight.first_mile_container_allocations USING btree (vehicle_id); + +CREATE INDEX "IDX_first_mile_status" ON freight.first_mile USING btree (status); + +CREATE INDEX "IDX_first_mile_vehicle_id" ON freight.first_mile USING btree (vehicle_id); + +CREATE INDEX "IDX_freight_customers_email" ON freight.customers USING btree (email); + +CREATE INDEX "IDX_freight_files_resource" ON freight.files USING btree (resource_id, resource); + +CREATE INDEX "IDX_freight_files_resource_code" ON freight.files USING btree (resource_id, resource, code); + +CREATE INDEX "IDX_last_mile_booking_id" ON freight.last_mile USING btree (booking_id); + +CREATE INDEX "IDX_last_mile_container_allocations_last_mile_id" ON freight.last_mile_container_allocations USING btree (last_mile_id); + +CREATE INDEX "IDX_last_mile_container_allocations_vehicle_id" ON freight.last_mile_container_allocations USING btree (vehicle_id); + +CREATE INDEX "IDX_last_mile_status" ON freight.last_mile USING btree (status); + +CREATE INDEX "IDX_last_mile_vehicle_containers_assignment" ON freight.last_mile_vehicle_containers USING btree (assignment_id); + +CREATE INDEX "IDX_last_mile_vehicle_id" ON freight.last_mile USING btree (vehicle_id); + +CREATE INDEX "IDX_locomotive_current_yard_id" ON freight.locomotives USING btree (current_yard_id); + +CREATE INDEX "IDX_maintenance_intervals_vehicle_type" ON freight.maintenance_intervals USING btree (vehicle_id, maintenance_type); + +CREATE INDEX "IDX_parts_category" ON freight.parts USING btree (category); + +CREATE INDEX "IDX_priority_rules_is_active" ON freight.priority_rules USING btree (is_active); + +CREATE INDEX "IDX_rates_destination_yard_id" ON freight.rates USING btree (destination_yard_id); + +CREATE INDEX "IDX_rates_origin_yard_id" ON freight.rates USING btree (origin_yard_id); + +CREATE INDEX "IDX_rates_trigger" ON freight.rates USING btree (trigger); + +CREATE INDEX "IDX_routes_status" ON freight.routes USING btree (status); + +CREATE UNIQUE INDEX "IDX_service_types_code" ON freight.service_types USING btree (code); + +CREATE INDEX "IDX_swal_train_id" ON freight.schedule_wagon_adjustment_logs USING btree (train_id); + +CREATE INDEX "IDX_swal_train_schedule_id" ON freight.schedule_wagon_adjustment_logs USING btree (train_schedule_id); + +CREATE INDEX "IDX_train_sets_train_id" ON freight.train_sets USING btree (train_id); + +CREATE INDEX "IDX_trains_current_yard_id" ON freight.trains USING btree (current_yard_id); + +CREATE INDEX "IDX_wagon_current_yard_id" ON freight.wagons USING btree (current_yard_id); + +CREATE INDEX "IDX_wagon_movements_schedule" ON freight.wagon_movements USING btree (train_schedule_id); + +CREATE INDEX "IDX_wagon_movements_wagon_occurred" ON freight.wagon_movements USING btree (wagon_id, occurred_at); + +CREATE INDEX "IDX_wagons_current_location_yard_id" ON freight.wagons USING btree (current_location_yard_id); + +CREATE INDEX "IDX_wagons_train_id" ON freight.wagons USING btree (train_id); + +CREATE INDEX "IDX_warranties_vehicle_id_expiry_date" ON freight.warranties USING btree (vehicle_id, expiry_date); + +CREATE INDEX "IDX_weight_limit_rules_container_type_id" ON freight.weight_limit_rules USING btree (container_type_id); + +CREATE INDEX "IDX_work_orders_vehicle_id_status" ON freight.work_orders USING btree (vehicle_id, status); + +CREATE UNIQUE INDEX "UQ_DRIVERS_EMAIL_ACTIVE" ON freight.drivers USING btree (email) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_DRIVERS_FAYDA_SUB_ACTIVE" ON freight.drivers USING btree (fayda_sub) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_DRIVERS_LICENSE_ACTIVE" ON freight.drivers USING btree (license_number) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_DRIVERS_PHONE_ACTIVE" ON freight.drivers USING btree (phone_number) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_booking_handovers_booking_edr_truck" ON freight.booking_handovers USING btree (booking_id, edr_assignment_id) WHERE ((deleted_at IS NULL) AND (edr_assignment_id IS NOT NULL)); + +CREATE UNIQUE INDEX "UQ_booking_handovers_booking_truck" ON freight.booking_handovers USING btree (booking_id, truck_assignment_id) WHERE ((deleted_at IS NULL) AND (truck_assignment_id IS NOT NULL)); + +CREATE UNIQUE INDEX "UQ_customer_truck_containers_booking_number" ON freight.customer_truck_containers USING btree (booking_id, container_number) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_dropdown_options_setting_value" ON freight.dropdown_options USING btree (setting_id, value); + +CREATE UNIQUE INDEX "UQ_dropdown_settings_code" ON freight.dropdown_settings USING btree (code); + +CREATE UNIQUE INDEX "UQ_file_upload_fields_setting_file_key" ON freight.file_upload_fields USING btree (setting_id, file_key); + +CREATE UNIQUE INDEX "UQ_file_upload_settings_code" ON freight.file_upload_settings USING btree (code); + +CREATE UNIQUE INDEX "UQ_last_mile_vehicle_container" ON freight.last_mile_vehicle_containers USING btree (last_mile_id, container_number) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_locomotives_name_active" ON freight.locomotives USING btree (lower(btrim((name)::text))) WHERE ((deleted_at IS NULL) AND (name IS NOT NULL) AND (btrim((name)::text) <> ''::text)); + +CREATE UNIQUE INDEX "UQ_maintenance_intervals_vehicle_type_item" ON freight.maintenance_intervals USING btree (vehicle_id, maintenance_type, COALESCE(service_item, ''::character varying)) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_priority_rules_code" ON freight.priority_rules USING btree (code); + +CREATE UNIQUE INDEX "UQ_rates_pattern" ON freight.rates USING btree (rate_type, COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(trade_direction, ''::character varying), COALESCE(origin_yard_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(destination_yard_id, '00000000-0000-0000-0000-000000000000'::uuid), rate_unit) WHERE ((deleted_at IS NULL) AND ((status)::text <> 'SUPERSEDED'::text)); + +CREATE UNIQUE INDEX "UQ_shipping_lines_code" ON freight.shipping_lines USING btree (code); + +CREATE UNIQUE INDEX "UQ_train_locomotives_train_loco" ON freight.train_locomotives USING btree (train_id, locomotive_id); + +CREATE UNIQUE INDEX "UQ_train_set_locomotives_set_loco" ON freight.train_set_locomotives USING btree (train_set_id, locomotive_id); + +CREATE UNIQUE INDEX "UQ_trains_export_train_number" ON freight.trains USING btree (export_train_number) WHERE (export_train_number IS NOT NULL); + +CREATE UNIQUE INDEX "UQ_trains_import_train_number" ON freight.trains USING btree (import_train_number) WHERE (import_train_number IS NOT NULL); + +CREATE UNIQUE INDEX "UQ_trains_train_number" ON freight.trains USING btree (train_number) WHERE (train_number IS NOT NULL); + +CREATE UNIQUE INDEX "UQ_wagons_wagon_number_active" ON freight.wagons USING btree (wagon_number) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_weight_limit_rules_pattern" ON freight.weight_limit_rules USING btree (container_type_id, trade_direction) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_yard_facility_yard" ON freight.yard_facilities USING btree (yard_id) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_yards_code" ON freight.yards USING btree (code); + +CREATE UNIQUE INDEX "UQ_yards_code_active" ON freight.yards USING btree (lower(TRIM(BOTH FROM code))) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX "UQ_yards_label_active" ON freight.yards USING btree (lower(TRIM(BOTH FROM label))) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_asset_acquisitions_vehicle_date ON freight.asset_acquisitions USING btree (vehicle_id, acquisition_date); + +CREATE INDEX idx_asset_disposals_vehicle_date ON freight.asset_disposals USING btree (vehicle_id, disposal_date); + +CREATE INDEX idx_booking_batch_offers_booking ON freight.booking_batch_offers USING btree (booking_id); + +CREATE INDEX idx_booking_batch_offers_schedule ON freight.booking_batch_offers USING btree (train_schedule_id); + +CREATE INDEX idx_booking_batch_offers_status ON freight.booking_batch_offers USING btree (status); + +CREATE INDEX idx_booking_contract_signatures_booking_id ON freight.booking_contract_signatures USING btree (booking_id); + +CREATE INDEX idx_booking_document_review_booking ON freight.booking_document_review USING btree (booking_id); + +CREATE INDEX idx_booking_document_review_status ON freight.booking_document_review USING btree (status); + +CREATE INDEX idx_booking_requests_contract ON freight.booking_requests USING btree (contract_id); + +CREATE INDEX idx_booking_requests_contract_status ON freight.booking_requests USING btree (contract_id, status); + +CREATE INDEX idx_booking_requests_status ON freight.booking_requests USING btree (status); + +CREATE INDEX idx_booking_review_note_booking_id ON freight.booking_review_note USING btree (booking_id); + +CREATE INDEX idx_bookings_booking_type ON freight.bookings USING btree (booking_type); + +CREATE INDEX idx_bookings_company_id ON freight.bookings USING btree (company_id); + +CREATE INDEX idx_bookings_company_profile_id ON freight.bookings USING btree (company_profile_id); + +CREATE INDEX idx_bookings_contract ON freight.bookings USING btree (contract_id); + +CREATE INDEX idx_bookings_is_government ON freight.bookings USING btree (is_government) WHERE ((is_government = true) AND (deleted_at IS NULL)); + +CREATE INDEX idx_bookings_route_day ON freight.bookings USING btree (origin_yard_id, destination_yard_id, scheduled_date, status) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_bookings_scheduling_status ON freight.bookings USING btree (scheduling_status); + +CREATE INDEX idx_bookings_train_schedule_id ON freight.bookings USING btree (train_schedule_id) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_clearance_incidents_booking ON freight.clearance_incidents USING btree (booking_id); + +CREATE INDEX idx_clearance_milestones_booking ON freight.clearance_milestones USING btree (booking_id); + +CREATE INDEX idx_clearance_milestones_contract ON freight.clearance_milestones USING btree (contract_id); + +CREATE INDEX idx_clearance_milestones_region ON freight.clearance_milestones USING btree (owner_region, status); + +CREATE INDEX idx_company_change_request_company ON freight.company_change_request USING btree (company_id); + +CREATE INDEX idx_company_change_request_status ON freight.company_change_request USING btree (status); + +CREATE INDEX idx_company_revisions_company ON freight.company_revisions USING btree (company_id); + +CREATE INDEX idx_compliance_records_expiry_date ON freight.compliance_records USING btree (expiry_date); + +CREATE INDEX idx_compliance_records_type ON freight.compliance_records USING btree (type); + +CREATE INDEX idx_compliance_records_vehicle_id ON freight.compliance_records USING btree (vehicle_id); + +CREATE INDEX idx_contract_approval_steps_contract ON freight.contract_approval_steps USING btree (contract_id); + +CREATE INDEX idx_contract_cargo_scope_contract ON freight.contract_cargo_scope USING btree (contract_id); + +CREATE INDEX idx_contract_clearance_cycles_contract ON freight.contract_clearance_cycles USING btree (contract_id); + +CREATE INDEX idx_contract_doc_review_contract ON freight.contract_document_review USING btree (contract_id); + +CREATE INDEX idx_contract_doc_review_status ON freight.contract_document_review USING btree (status); + +CREATE INDEX idx_contract_document_revisions_contract ON freight.contract_document_revisions USING btree (contract_id, created_at DESC); + +CREATE INDEX idx_contract_rate_snapshots_contract ON freight.contract_rate_snapshots USING btree (contract_id); + +CREATE INDEX idx_contract_review_notes_contract ON freight.contract_review_notes USING btree (contract_id); + +CREATE INDEX idx_contract_routes_contract ON freight.contract_routes USING btree (contract_id); + +CREATE INDEX idx_contract_signatures_contract ON freight.contract_signatures USING btree (contract_id); + +CREATE INDEX idx_contracts_company ON freight.contracts USING btree (company_id); + +CREATE INDEX idx_contracts_kind ON freight.contracts USING btree (contract_kind); + +CREATE INDEX idx_contracts_status ON freight.contracts USING btree (status); + +CREATE INDEX idx_contracts_valid_until ON freight.contracts USING btree (contract_valid_until); + +CREATE INDEX idx_djibouti_incidents_booking ON freight.djibouti_import_incidents USING btree (booking_id); + +CREATE INDEX idx_djibouti_incidents_container ON freight.djibouti_import_incidents USING btree (container_number); + +CREATE INDEX idx_djibouti_incidents_type ON freight.djibouti_import_incidents USING btree (incident_type); + +CREATE INDEX idx_drivers_email ON freight.drivers USING btree (email); + +CREATE INDEX idx_drivers_license_number ON freight.drivers USING btree (license_number); + +CREATE INDEX idx_drivers_phone_number ON freight.drivers USING btree (phone_number); + +CREATE INDEX idx_drivers_status ON freight.drivers USING btree (status); + +CREATE INDEX idx_empty_returns_booking ON freight.empty_container_returns USING btree (booking_id); + +CREATE INDEX idx_empty_returns_container ON freight.empty_container_returns USING btree (container_number); + +CREATE INDEX idx_empty_returns_status ON freight.empty_container_returns USING btree (status); + +CREATE UNIQUE INDEX idx_facilities_code ON freight.facilities USING btree (code); + +CREATE INDEX idx_facilities_status ON freight.facilities USING btree (facility_status); + +CREATE INDEX idx_files_resource_lookup ON freight.files USING btree (resource, resource_id); + +CREATE INDEX idx_fuel_consumption_vehicle_month ON freight.fuel_consumption USING btree (vehicle_id, month); + +CREATE INDEX idx_fuel_purchases_date ON freight.fuel_purchases USING btree (purchase_date); + +CREATE INDEX idx_fuel_purchases_vehicle ON freight.fuel_purchases USING btree (vehicle_id); + +CREATE INDEX idx_import_customs_booking ON freight.import_customs_finalizations USING btree (booking_id); + +CREATE INDEX idx_import_customs_risk ON freight.import_customs_finalizations USING btree (customs_risk); + +CREATE INDEX idx_import_djibouti_operations_schedule ON freight.import_djibouti_operations USING btree (train_schedule_id); + +CREATE INDEX idx_interchange_documents_direction ON freight.interchange_documents USING btree (direction); + +CREATE INDEX idx_interchange_documents_schedule ON freight.interchange_documents USING btree (schedule_id); + +CREATE INDEX idx_interchange_documents_status ON freight.interchange_documents USING btree (status); + +CREATE INDEX idx_interchange_items_booking ON freight.interchange_document_items USING btree (booking_id); + +CREATE INDEX idx_interchange_items_document ON freight.interchange_document_items USING btree (interchange_document_id); + +CREATE INDEX idx_invoice_lines_invoice ON freight.invoice_lines USING btree (invoice_id); + +CREATE INDEX idx_invoices_company ON freight.invoices USING btree (company_id); + +CREATE INDEX idx_invoices_company_profile ON freight.invoices USING btree (company_profile_id); + +CREATE INDEX idx_invoices_source ON freight.invoices USING btree (source, source_id); + +CREATE INDEX idx_invoices_status ON freight.invoices USING btree (status); + +CREATE INDEX idx_locomotives_status ON freight.locomotives USING btree (status); + +CREATE INDEX idx_maintenance_costs_vehicle_date ON freight.maintenance_costs USING btree (vehicle_id, incurred_date); + +CREATE INDEX idx_maintenance_schedules_vehicle_date ON freight.maintenance_schedules USING btree (vehicle_id, scheduled_date); + +CREATE INDEX idx_payment_webhook_events_merchant_order_id ON freight.payment_webhook_events USING btree (merchant_order_id); + +CREATE INDEX idx_prcr_status ON freight.priority_rule_change_requests USING btree (status); + +CREATE INDEX idx_priority_configs_currency_type ON freight.priority_configs USING btree (currency, type); + +CREATE INDEX idx_priority_configs_type_active ON freight.priority_configs USING btree (type, is_active); + +CREATE INDEX idx_rcr_status ON freight.rate_change_requests USING btree (status); + +CREATE INDEX idx_route_milestones_route_id ON freight.route_milestones USING btree (route_id); + +CREATE INDEX idx_route_milestones_yard_id ON freight.route_milestones USING btree (yard_id); + +CREATE INDEX idx_routes_destination_yard_id ON freight.routes USING btree (destination_yard_id); + +CREATE INDEX idx_routes_origin_yard_id ON freight.routes USING btree (origin_yard_id); + +CREATE INDEX idx_scheduling_events_train_schedule_id ON freight.scheduling_events USING btree (train_schedule_id) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_train_checkpoint_events_schedule ON freight.train_checkpoint_events USING btree (train_schedule_id, sequence_no) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_train_schedules_booking_window_status ON freight.train_schedules USING btree (booking_window_status) WHERE (deleted_at IS NULL); + +CREATE INDEX idx_train_schedules_departure_status ON freight.train_schedules USING btree (scheduled_departure_date, status); + +CREATE INDEX idx_train_schedules_route_id ON freight.train_schedules USING btree (route_id); + +CREATE INDEX idx_train_schedules_train_number ON freight.train_schedules USING btree (train_number); + +CREATE INDEX idx_train_schedules_window_phase ON freight.train_schedules USING btree (window_phase) WHERE (window_phase IS NOT NULL); + +CREATE INDEX idx_train_set_wagons_physical_wagon ON freight.train_set_wagons USING btree (physical_wagon_id); + +CREATE INDEX idx_train_sets_status ON freight.train_sets USING btree (status); + +CREATE INDEX idx_user_trade_access_user_id ON freight.user_trade_access USING btree (user_id); + +CREATE INDEX idx_vehicles_manufacturer ON freight.vehicles USING btree (manufacturer); + +CREATE INDEX idx_vehicles_plate_number ON freight.vehicles USING btree (plate_number); + +CREATE INDEX idx_vehicles_registration_number ON freight.vehicles USING btree (registration_number); + +CREATE INDEX idx_vehicles_status ON freight.vehicles USING btree (status); + +CREATE INDEX idx_vehicles_vehicle_type ON freight.vehicles USING btree (vehicle_type); + +CREATE INDEX idx_wabl_booking ON freight.wagon_allocation_bulk_loads USING btree (booking_id); + +CREATE INDEX idx_waci_allocation ON freight.wagon_allocation_container_items USING btree (wagon_booking_allocation_id); + +CREATE INDEX idx_wagon_booking_allocations_booking ON freight.wagon_booking_allocations USING btree (booking_id); + +CREATE INDEX idx_wagons_current_train_schedule_id ON freight.wagons USING btree (current_train_schedule_id); + +CREATE INDEX idx_wagons_train_set_wagon_id ON freight.wagons USING btree (train_set_wagon_id); + +CREATE INDEX idx_war_active ON freight.warehouse_allocation_rules USING btree (is_active); + +CREATE INDEX idx_war_priority ON freight.warehouse_allocation_rules USING btree (priority); + +CREATE INDEX idx_warehouse_activity_log_activity_type ON freight.warehouse_activity_log USING btree (activity_type); + +CREATE INDEX idx_warehouse_activity_log_inventory_id ON freight.warehouse_activity_log USING btree (inventory_id); + +CREATE INDEX idx_warehouse_activity_log_warehouse_id ON freight.warehouse_activity_log USING btree (warehouse_id); + +CREATE INDEX idx_warehouse_inventory_booking_id ON freight.warehouse_inventory USING btree (booking_id); + +CREATE INDEX idx_warehouse_inventory_cargo_id ON freight.warehouse_inventory USING btree (cargo_id); + +CREATE INDEX idx_warehouse_inventory_container_id ON freight.warehouse_inventory USING btree (container_id); + +CREATE INDEX idx_warehouse_inventory_goods_id ON freight.warehouse_inventory USING btree (goods_id); + +CREATE INDEX idx_warehouse_inventory_grn_number ON freight.warehouse_inventory USING btree (grn_number) WHERE (grn_number IS NOT NULL); + +CREATE INDEX idx_warehouse_inventory_inspection_status ON freight.warehouse_inventory USING btree (inspection_status); + +CREATE INDEX idx_warehouse_inventory_movement_inventory_id ON freight.warehouse_inventory_movement USING btree (inventory_id); + +CREATE INDEX idx_warehouse_inventory_status ON freight.warehouse_inventory USING btree (status); + +CREATE INDEX idx_warehouse_inventory_warehouse_id ON freight.warehouse_inventory USING btree (warehouse_id); + +CREATE INDEX idx_warehouse_inventory_yard_id ON freight.warehouse_inventory USING btree (yard_id); + +CREATE INDEX idx_warehouse_inventory_zone_id ON freight.warehouse_inventory USING btree (zone_id); + +CREATE INDEX idx_warehouse_loadings_booking_id ON freight.warehouse_loadings USING btree (booking_id); + +CREATE INDEX idx_warehouse_loadings_inventory_id ON freight.warehouse_loadings USING btree (warehouse_inventory_id); + +CREATE INDEX idx_warehouse_loadings_train_schedule ON freight.warehouse_loadings USING btree (train_schedule_id) WHERE (train_schedule_id IS NOT NULL); + +CREATE INDEX idx_warehouse_loadings_wagon_id ON freight.warehouse_loadings USING btree (wagon_id); + +CREATE INDEX idx_warehouse_yards_status ON freight.warehouse_yards USING btree (status); + +CREATE INDEX idx_warehouse_yards_type ON freight.warehouse_yards USING btree (type); + +CREATE INDEX idx_warehouse_yards_warehouse_id ON freight.warehouse_yards USING btree (warehouse_id); + +CREATE INDEX idx_warehouse_zones_status ON freight.warehouse_zones USING btree (status); + +CREATE INDEX idx_warehouse_zones_type ON freight.warehouse_zones USING btree (type); + +CREATE INDEX idx_warehouse_zones_yard_id ON freight.warehouse_zones USING btree (yard_id); + +CREATE INDEX idx_warehouses_station_id ON freight.warehouses USING btree (station_id); + +CREATE INDEX idx_warehouses_status ON freight.warehouses USING btree (status); + +CREATE INDEX idx_warehouses_type ON freight.warehouses USING btree (type); + +CREATE INDEX idx_wfr_active ON freight.warehouse_fee_rules USING btree (is_active); + +CREATE INDEX idx_wfr_type ON freight.warehouse_fee_rules USING btree (rule_type); + +CREATE INDEX idx_wir_booking ON freight.warehouse_inspection_reports USING btree (booking_id); + +CREATE INDEX idx_wir_inventory ON freight.warehouse_inspection_reports USING btree (inventory_id); + +CREATE INDEX idx_wir_status ON freight.warehouse_inspection_reports USING btree (inspection_status); + +CREATE INDEX idx_wm_moved_by ON freight.wagon_movements USING btree (moved_by_user_id); + +CREATE INDEX idx_wm_transfer_request ON freight.wagon_movements USING btree (transfer_request_id); + +CREATE INDEX idx_wtr_status_from_yard ON freight.wagon_transfer_requests USING btree (status, from_yard_id); + +CREATE INDEX idx_yard_distances_from_yard ON freight.yard_distances USING btree (from_yard_id); + +CREATE INDEX idx_yard_distances_to_yard ON freight.yard_distances USING btree (to_yard_id); + +CREATE INDEX ix_transit_agents_is_active ON freight.transit_agents USING btree (is_active); + +CREATE INDEX ix_truck_types_is_active ON freight.truck_types USING btree (is_active); + +CREATE UNIQUE INDEX uq_booking_document_review_doc ON freight.booking_document_review USING btree (booking_id, setting_code, file_key); + +CREATE UNIQUE INDEX uq_clearance_milestone_booking ON freight.clearance_milestones USING btree (booking_id, milestone_code) WHERE (booking_id IS NOT NULL); + +CREATE UNIQUE INDEX uq_clearance_milestone_cycle ON freight.clearance_milestones USING btree (clearance_cycle_id, milestone_code) WHERE (clearance_cycle_id IS NOT NULL); + +CREATE UNIQUE INDEX uq_interchange_active_schedule_direction ON freight.interchange_documents USING btree (schedule_id, direction) WHERE ((schedule_id IS NOT NULL) AND ((status)::text <> 'CANCELLED'::text) AND (deleted_at IS NULL)); + +CREATE UNIQUE INDEX uq_one_active_booking_per_one_time_contract ON freight.bookings USING btree (contract_id) WHERE (((status)::text <> ALL ((ARRAY['EXPIRED'::character varying, 'CANCELLED'::character varying, 'COMPLETED'::character varying, 'REJECTED'::character varying])::text[])) AND (contract_id IS NOT NULL) AND ((contract_kind)::text = 'ONE_TIME'::text)); + +CREATE UNIQUE INDEX uq_rcr_one_pending_per_rate ON freight.rate_change_requests USING btree (rate_id) WHERE (((status)::text = 'PENDING'::text) AND (deleted_at IS NULL)); + +CREATE UNIQUE INDEX uq_yard_distances_pair ON freight.yard_distances USING btree (from_yard_id, to_yard_id) WHERE (deleted_at IS NULL); + +CREATE UNIQUE INDEX ux_train_schedules_reference ON freight.train_schedules USING btree (reference) WHERE (reference IS NOT NULL); + +CREATE UNIQUE INDEX ux_truck_types_code ON freight.truck_types USING btree (code); + +CREATE UNIQUE INDEX ux_vehicles_vin ON freight.vehicles USING btree (vin) WHERE (vin IS NOT NULL); +`; + +/** + * Reference/seed rows, keyed by table. Exported so a targeted re-seed (see + * `scripts/seed-edr-wagons.ts`) can replay a single table without the rest. + * Insertion order is irrelevant — the FK constraints below are added afterwards. + */ +export const FREIGHT_SEED_SQL: Record = { + approval_rules: ` +INSERT INTO freight.approval_rules (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at, deleted_at) VALUES ('dd31712c-25ef-4ca1-a4d2-435e219fcd7e', false, 1, 'LINE_STAFF', 'Review & Approve', NULL, '2026-08-05 07:31:05.116257+00', '2026-08-05 07:31:05.116257+00', NULL); +INSERT INTO freight.approval_rules (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at, deleted_at) VALUES ('3e1d0f06-65cb-467e-bf16-a43d47e546bd', false, 2, 'DIRECTOR', 'Final Signature', 'LINE_STAFF', '2026-08-05 07:31:05.116257+00', '2026-08-05 07:31:05.116257+00', NULL); +INSERT INTO freight.approval_rules (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at, deleted_at) VALUES ('8f818e32-4c51-4e74-859b-9268e39e320c', true, 1, 'DIRECTOR', 'Review & Approve', 'LINE_STAFF', '2026-08-05 07:31:05.116257+00', '2026-08-05 07:31:05.116257+00', NULL); +INSERT INTO freight.approval_rules (id, requires_director_approval, step_order, required_role, action_label, blocks_role, created_at, updated_at, deleted_at) VALUES ('8c55dcfd-607a-4f86-be71-f3b81c4bc044', true, 2, 'CEO', 'Final Signature', NULL, '2026-08-05 07:31:05.116257+00', '2026-08-05 07:31:05.116257+00', NULL); +`, + cargo_types: ` +INSERT INTO freight.cargo_types (id, cargo_type_name, parent_group_id, requires_director_approval, is_active, display_order, created_at, updated_at, deleted_at, code, unit_of_measure, has_lashing, items_per_wagon_map, tons_per_wagon_map) VALUES ('8ed5e27a-44e8-4448-ba73-b435788b0a51', 'General Cargo', NULL, false, true, 1, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, 'GENERAL', NULL, false, NULL, NULL); +INSERT INTO freight.cargo_types (id, cargo_type_name, parent_group_id, requires_director_approval, is_active, display_order, created_at, updated_at, deleted_at, code, unit_of_measure, has_lashing, items_per_wagon_map, tons_per_wagon_map) VALUES ('d529f2c1-b7b4-406c-9d40-16bfdffdd26c', 'Fertilizer', NULL, false, true, 1, '2026-08-05 07:31:09.200884+00', '2026-08-05 07:31:09.200884+00', NULL, 'FERTILIZER', 'PER_TON', false, NULL, NULL); +INSERT INTO freight.cargo_types (id, cargo_type_name, parent_group_id, requires_director_approval, is_active, display_order, created_at, updated_at, deleted_at, code, unit_of_measure, has_lashing, items_per_wagon_map, tons_per_wagon_map) VALUES ('ca196126-7b3b-4879-ab40-5ee7953d9ec5', 'Coffee', NULL, false, true, 1, '2026-08-05 07:31:09.200884+00', '2026-08-05 07:31:09.200884+00', NULL, 'COFFEE', 'PER_TON', false, NULL, NULL); +INSERT INTO freight.cargo_types (id, cargo_type_name, parent_group_id, requires_director_approval, is_active, display_order, created_at, updated_at, deleted_at, code, unit_of_measure, has_lashing, items_per_wagon_map, tons_per_wagon_map) VALUES ('9edeb30b-bca0-49bf-abe5-4ed26e6b9353', 'Tea', NULL, false, true, 1, '2026-08-05 07:31:09.200884+00', '2026-08-05 07:31:09.200884+00', NULL, 'TEA', 'PER_TON', false, NULL, NULL); +`, + companies: ` +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0001-0000-4000-8000-000000000001', 'Federal Government of Ethiopia', 'customer', 'active', '0000000001', NULL, NULL, 'Ethiopia', NULL, '+251111000001', 'procurement@gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0002-0000-4000-8000-000000000002', 'Ministry of National Defense', 'customer', 'active', '0000000002', NULL, NULL, 'Ethiopia', NULL, '+251111000002', 'logistics@mod.gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0003-0000-4000-8000-000000000003', 'Ethiopian Roads Administration', 'customer', 'active', '0000000003', NULL, NULL, 'Ethiopia', NULL, '+251111000003', 'supply@era.gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0004-0000-4000-8000-000000000004', 'Ministry of Agriculture', 'customer', 'active', '0000000004', NULL, NULL, 'Ethiopia', NULL, '+251111000004', 'imports@moa.gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0005-0000-4000-8000-000000000005', 'Ministry of Trade and Regional Integration', 'customer', 'active', '0000000005', NULL, NULL, 'Ethiopia', NULL, '+251111000005', 'trade@motri.gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +INSERT INTO freight.companies (id, name, type, status, tin, vat_number, fan_number, country, address, phone, email, website, attributes, created_at, updated_at, deleted_at, contact_person_name, contact_person_phone, general_manager_name, general_manager_email, general_manager_phone, nationality, licence_number, status_description, date_registered, renewed_from, renewal_date, renewed_to, region, zone, woreda, kebele, house_no, etrade_phone, kind, approved_at) VALUES ('0a1b0006-0000-4000-8000-000000000006', 'Ethiopian Disaster Risk Management Commission', 'customer', 'active', '0000000006', NULL, NULL, 'Ethiopia', NULL, '+251111000006', 'relief@edrmc.gov.et', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'government', NULL); +`, + company_profiles: ` +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0001-0000-4000-8000-000000000001', '0a1b0001-0000-4000-8000-000000000001', 'importer', 'IM-90001', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0001-0000-4000-8000-000000000002', '0a1b0001-0000-4000-8000-000000000001', 'exporter', 'EX-90001', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0002-0000-4000-8000-000000000001', '0a1b0002-0000-4000-8000-000000000002', 'importer', 'IM-90002', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0002-0000-4000-8000-000000000002', '0a1b0002-0000-4000-8000-000000000002', 'exporter', 'EX-90002', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0003-0000-4000-8000-000000000001', '0a1b0003-0000-4000-8000-000000000003', 'importer', 'IM-90003', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0003-0000-4000-8000-000000000002', '0a1b0003-0000-4000-8000-000000000003', 'exporter', 'EX-90003', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0004-0000-4000-8000-000000000001', '0a1b0004-0000-4000-8000-000000000004', 'importer', 'IM-90004', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0004-0000-4000-8000-000000000002', '0a1b0004-0000-4000-8000-000000000004', 'exporter', 'EX-90004', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0005-0000-4000-8000-000000000001', '0a1b0005-0000-4000-8000-000000000005', 'importer', 'IM-90005', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0005-0000-4000-8000-000000000002', '0a1b0005-0000-4000-8000-000000000005', 'exporter', 'EX-90005', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0006-0000-4000-8000-000000000001', '0a1b0006-0000-4000-8000-000000000006', 'importer', 'IM-90006', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +INSERT INTO freight.company_profiles (id, company_id, type, reference, status, business_license, attributes, created_at, updated_at, deleted_at, business_license_files, review_note, reviewed_by, reviewed_at) VALUES ('0b1c0006-0000-4000-8000-000000000002', '0a1b0006-0000-4000-8000-000000000006', 'exporter', 'EX-90006', 'active', NULL, NULL, '2026-08-05 07:31:07.431166+00', '2026-08-05 07:31:07.431166+00', NULL, NULL, NULL, NULL, NULL); +`, + contract_templates: ` +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('6bc99976-d5f7-4b4d-82a0-f0340f3e7cf7', 'IMPORT_BULK_CUSTOMS', 'Bulk Import Contract (with customs clearing)', 'Import of bulk cargo (e.g. steel billets) from Djibouti (DMP/Nagad) to Galaan Multipurpose Port with customs clearance and optional last-mile delivery. Customs clearing is performed by the Service Provider.', 'Bulk Cargo Transportation and Customs Clearance Services', '["The Client has agreed to engage the Service Provider for transportation and customs clearance services for bulk cargo, including first-mile transport to the railway station at Djibouti, loading at either DMP or Nagad Railway Station (Djibouti), port/rail terminal handling, loading onto the train, railway transport to Galaan Multipurpose Port (GMP) in Ethiopia, unloading at the destination port from train to load directly on truck, onward transportation to the Client''s site (excluding truck loading at Djibouti and truck unloading at the Client destination where last-mile service is undertaken by the Service Provider), and all related documentation.", "The Service Provider has agreed to provide the requested services in accordance with the terms and conditions of this Agreement."]', '[{"id": "objective", "body": "The objective of this contract is to provide the Client with integrated logistics services for the transportation of bulk cargo, including:\\n- First-mile transportation in Djibouti from the Client''s designated cargo location to the selected railway station (DMP or Nagad).\\n- Port handling and loading onto railway wagons.\\n- Railway transport from DMP and/or Nagad Railway freight station (Djibouti) to Galaan Multipurpose Port.\\n- Customs clearance in Djibouti and Ethiopia.\\n- Unloading from train at the destination port to load directly on truck.\\n- Last-mile delivery by truck to the Client''s delivery site where the last-mile service is undertaken by the Service Provider.\\nThe truck loading at Djibouti and the truck unloading at the Client''s delivery site shall be the responsibility of the Client.", "order": 1, "title": "Objective of the Services"}, {"id": "client-obligations", "body": "Provide written/email/electronic instructions specifying the cargo volume and the selected loading station (DMP or Nagad) for each shipment.\\nPrepare and submit all necessary documents and permits to enable smooth service execution.\\nEnsure cargo readiness in compliance with specifications (including weight, size, and contour restrictions).\\nHandle truck loading at Djibouti Free Zone/Old Port/DMP and any other designated cargo location at Djibouti, and truck unloading at the delivery site.\\nEnsure safety and proper securing of cargo during truck handling.\\nSubmit all required documents necessary for customs clearance and cargo release within one (1) calendar day from the date of request or notification by the Service Provider.\\nUpon receipt of the wagon allocation list and train schedule from the Service Provider, ensure that the cargo is transferred to the designated loading freight station and made ready for loading within two (2) days prior to wagon arrival. Any delay beyond this period resulting from Client-related issues shall be subject to a charge of USD 56 per wagon per day, or part thereof, until the cargo is made available for loading.\\nUpon arrival of the train at Galaan Multipurpose Port (GMP), offload cargo from wagons within twenty-four (24) hours of train arrival. Where the Client undertakes last-mile transportation, the Client may arrange sufficient trucks at the time of train arrival to enable direct loading of cargo from wagons to trucks.\\nIn the event the Client is unable to provide trucks for the collection of cargo within twenty-four (24) hours of train arrival, the Service Provider shall have the right to handle and reposition the cargo to any location it deems appropriate, and shall not be held responsible for any loss, shortage, or damage arising from such repositioning.\\nAny additional handling, re-handling, or repeated loading operations performed by the Service Provider shall be charged as double handling fees at a rate of USD 4 per ton, payable by the Client.\\nIf stored, the full cargo must be collected from the Galaan Multipurpose Port compound within three (3) days from the time of train arrival at the port.\\nIf the Client fails to collect the cargo within the specified period, the Client shall be liable to pay demurrage charges of USD 2 per day per ton, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nWhere the last-mile service is provided by the Service Provider, unload the cargo from the truck at the delivery site within the agreed time frame.\\nDesignate authorized representatives (with valid power of attorney) for handover at origin and destination.\\nSettle demurrage payments within ten (10) calendar days from the date the Service Provider issues a claim.\\nPay the Service Provider one hundred percent (100%) of the contract price in advance for each train set in accordance with the pricing article of this Agreement.\\nContact the Service Provider to obtain confirmation prior to booking and proceeding with payment.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Provide first-mile transportation in Djibouti from the Client''s designated location to the selected railway station (DMP or Nagad).\\nCarry out port handling and loading onto railway wagons.\\nProvide railway transportation from DMP/Nagad (Djibouti) railway freight station to Galaan Multipurpose Port.\\nPerform unloading at Galaan Multipurpose Port (GMP) to load directly on truck.\\nPerform customs clearance in Djibouti and Ethiopia, including border station procedures.\\nPrepare and submit all required transport documentation.\\nProvide cargo insurance coverage for each supplied wagon.\\nNotify the Client of train schedules, wagon numbers, and expected arrival times in advance.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "liability", "body": "The Service Provider shall be fully responsible for any loss, shortage, or damage to cargo that occurs after it has been taken over until delivery to the Client''s delivery site.\\nCompensation shall be based on the market value of the cargo, in accordance with applicable laws.", "order": 5, "title": "Liabilities Related to Damages and Losses"}, {"id": "pricing", "body": "The applicable railway freight, Djibouti handling, and any additional service and surcharge rates for this contract are set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per service.\\nEach wagon shall be loaded up to a maximum of seventy (70) metric tons; for billing purposes one full wagon shall be deemed equivalent to this volume.\\nWhere lashing materials and wood are provided by the Service Provider, they shall be charged at the applicable rate set out in the Rate Schedule; the provision continues until the cargo reaches and is fully unloaded at the designated destination station.\\nThe price for last-mile delivery, where not listed in the Rate Schedule, shall be determined once the cargo departs from the loading point and shall be communicated to the Client by official email upon the Client''s request.\\nPayments shall be made 100% in advance in USD.", "order": 6, "title": "Contract Price and Payment Terms"}, {"id": "contract-documents", "body": "The following documents form part of this contract:\\n- This Contract Agreement.\\n- Any amendments made to this Agreement.\\n- Minutes of negotiation (if any).", "order": 7, "title": "Contract Documents"}, {"id": "documentation", "body": "The Service Provider shall deliver the following to the Client:\\n- Freight Carriage Acceptance Sheet of the Addis Ababa–Djibouti Railway.\\n- Notice of transportation and miscellaneous charges.\\n- Summary of payment request as per the agreed tariff, if required.", "order": 8, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider shall certify the taking over of goods in the Freight Carriage Acceptance Sheet.\\nThis document shall serve as prima facie evidence of receipt of the cargo.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 9, "title": "Consignment Notes"}, {"id": "termination", "body": "This contract may be terminated:\\n- By mutual consent.\\n- Upon completion of the agreed contract period or cargo volume.\\n- For breach of fundamental provisions, with one-week prior written notice.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "This Agreement becomes effective on the date it is signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "The contract is valid until August 31, {{contractYear}} from the date of effectiveness, extendable by mutual agreement.", "order": 12, "title": "Duration"}, {"id": "disputes", "body": "Disputes shall first be settled amicably.\\nIf unresolved, disputes shall be referred to the competent Federal Court of Ethiopia in Addis Ababa.\\nThe governing law shall be the laws of the Federal Democratic Republic of Ethiopia.", "order": 13, "title": "Settlement of Disputes"}, {"id": "customs-clearing", "body": "The Service Provider shall carry out customs clearing on behalf of the Client for the cargo covered by this Agreement, including declaration, lodgement, and follow-up at the customs stations of Djibouti and Ethiopia as applicable to the agreed corridor.\\nThe Service Provider shall act only within the authority granted by the Client and shall not amend a declaration without the Client''s written instruction.\\nCustoms duties, taxes, and any government charges assessed on the cargo remain payable by the Client and are not included in the freight price; the Service Provider shall settle them on the Client''s behalf only where the Client has placed the corresponding funds in advance.\\nThe Service Provider shall hand over all customs documents obtained in the course of clearing to the Client upon completion of each shipment.", "order": 14, "title": "Customs Clearing Services"}, {"id": "customs-client-duties", "body": "Grant the Service Provider a duly signed and stamped power of attorney authorising it to act as the Client''s customs agent for the duration of this Agreement.\\nSubmit every document required for declaration (commercial invoice, packing list, bill of lading or airway bill, permits, certificates of origin, and any authority-specific licence) within one (1) calendar day of the Service Provider''s request.\\nWarrant that the declared description, quantity, value, and tariff classification of the cargo are complete and accurate.\\nBear any penalty, demurrage, storage, or re-inspection cost arising from incorrect, incomplete, or late Client-supplied information or documentation.\\nSettle assessed duties and taxes within the period notified by the Service Provider, failing which the Service Provider may suspend clearing and the cargo shall remain at the Client''s risk and cost.", "order": 15, "title": "Client Obligations for Customs Clearing"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('b4dcb3fb-43f9-47f1-a97d-a7af210f05eb', 'IMPORT_BULK_NO_CUSTOMS', 'Bulk Import Contract (without customs clearing)', 'Import of bulk cargo (e.g. steel billets) from Djibouti (DMP/Nagad) to Galaan Multipurpose Port with customs clearance and optional last-mile delivery. Customs clearing is handled by the Client.', 'Bulk Cargo Transportation and Customs Clearance Services', '["The Client has agreed to engage the Service Provider for transportation and customs clearance services for bulk cargo, including first-mile transport to the railway station at Djibouti, loading at either DMP or Nagad Railway Station (Djibouti), port/rail terminal handling, loading onto the train, railway transport to Galaan Multipurpose Port (GMP) in Ethiopia, unloading at the destination port from train to load directly on truck, onward transportation to the Client''s site (excluding truck loading at Djibouti and truck unloading at the Client destination where last-mile service is undertaken by the Service Provider), and all related documentation.", "The Service Provider has agreed to provide the requested services in accordance with the terms and conditions of this Agreement."]', '[{"id": "objective", "body": "The objective of this contract is to provide the Client with integrated logistics services for the transportation of bulk cargo, including:\\n- First-mile transportation in Djibouti from the Client''s designated cargo location to the selected railway station (DMP or Nagad).\\n- Port handling and loading onto railway wagons.\\n- Railway transport from DMP and/or Nagad Railway freight station (Djibouti) to Galaan Multipurpose Port.\\n- Customs clearance in Djibouti and Ethiopia.\\n- Unloading from train at the destination port to load directly on truck.\\n- Last-mile delivery by truck to the Client''s delivery site where the last-mile service is undertaken by the Service Provider.\\nThe truck loading at Djibouti and the truck unloading at the Client''s delivery site shall be the responsibility of the Client.", "order": 1, "title": "Objective of the Services"}, {"id": "client-obligations", "body": "Provide written/email/electronic instructions specifying the cargo volume and the selected loading station (DMP or Nagad) for each shipment.\\nPrepare and submit all necessary documents and permits to enable smooth service execution.\\nEnsure cargo readiness in compliance with specifications (including weight, size, and contour restrictions).\\nHandle truck loading at Djibouti Free Zone/Old Port/DMP and any other designated cargo location at Djibouti, and truck unloading at the delivery site.\\nEnsure safety and proper securing of cargo during truck handling.\\nSubmit all required documents necessary for customs clearance and cargo release within one (1) calendar day from the date of request or notification by the Service Provider.\\nUpon receipt of the wagon allocation list and train schedule from the Service Provider, ensure that the cargo is transferred to the designated loading freight station and made ready for loading within two (2) days prior to wagon arrival. Any delay beyond this period resulting from Client-related issues shall be subject to a charge of USD 56 per wagon per day, or part thereof, until the cargo is made available for loading.\\nUpon arrival of the train at Galaan Multipurpose Port (GMP), offload cargo from wagons within twenty-four (24) hours of train arrival. Where the Client undertakes last-mile transportation, the Client may arrange sufficient trucks at the time of train arrival to enable direct loading of cargo from wagons to trucks.\\nIn the event the Client is unable to provide trucks for the collection of cargo within twenty-four (24) hours of train arrival, the Service Provider shall have the right to handle and reposition the cargo to any location it deems appropriate, and shall not be held responsible for any loss, shortage, or damage arising from such repositioning.\\nAny additional handling, re-handling, or repeated loading operations performed by the Service Provider shall be charged as double handling fees at a rate of USD 4 per ton, payable by the Client.\\nIf stored, the full cargo must be collected from the Galaan Multipurpose Port compound within three (3) days from the time of train arrival at the port.\\nIf the Client fails to collect the cargo within the specified period, the Client shall be liable to pay demurrage charges of USD 2 per day per ton, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nWhere the last-mile service is provided by the Service Provider, unload the cargo from the truck at the delivery site within the agreed time frame.\\nDesignate authorized representatives (with valid power of attorney) for handover at origin and destination.\\nSettle demurrage payments within ten (10) calendar days from the date the Service Provider issues a claim.\\nPay the Service Provider one hundred percent (100%) of the contract price in advance for each train set in accordance with the pricing article of this Agreement.\\nContact the Service Provider to obtain confirmation prior to booking and proceeding with payment.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Provide first-mile transportation in Djibouti from the Client''s designated location to the selected railway station (DMP or Nagad).\\nCarry out port handling and loading onto railway wagons.\\nProvide railway transportation from DMP/Nagad (Djibouti) railway freight station to Galaan Multipurpose Port.\\nPerform unloading at Galaan Multipurpose Port (GMP) to load directly on truck.\\nPerform customs clearance in Djibouti and Ethiopia, including border station procedures.\\nPrepare and submit all required transport documentation.\\nProvide cargo insurance coverage for each supplied wagon.\\nNotify the Client of train schedules, wagon numbers, and expected arrival times in advance.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "liability", "body": "The Service Provider shall be fully responsible for any loss, shortage, or damage to cargo that occurs after it has been taken over until delivery to the Client''s delivery site.\\nCompensation shall be based on the market value of the cargo, in accordance with applicable laws.", "order": 5, "title": "Liabilities Related to Damages and Losses"}, {"id": "pricing", "body": "The applicable railway freight, Djibouti handling, and any additional service and surcharge rates for this contract are set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per service.\\nEach wagon shall be loaded up to a maximum of seventy (70) metric tons; for billing purposes one full wagon shall be deemed equivalent to this volume.\\nWhere lashing materials and wood are provided by the Service Provider, they shall be charged at the applicable rate set out in the Rate Schedule; the provision continues until the cargo reaches and is fully unloaded at the designated destination station.\\nThe price for last-mile delivery, where not listed in the Rate Schedule, shall be determined once the cargo departs from the loading point and shall be communicated to the Client by official email upon the Client''s request.\\nPayments shall be made 100% in advance in USD.", "order": 6, "title": "Contract Price and Payment Terms"}, {"id": "contract-documents", "body": "The following documents form part of this contract:\\n- This Contract Agreement.\\n- Any amendments made to this Agreement.\\n- Minutes of negotiation (if any).", "order": 7, "title": "Contract Documents"}, {"id": "documentation", "body": "The Service Provider shall deliver the following to the Client:\\n- Freight Carriage Acceptance Sheet of the Addis Ababa–Djibouti Railway.\\n- Notice of transportation and miscellaneous charges.\\n- Summary of payment request as per the agreed tariff, if required.", "order": 8, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider shall certify the taking over of goods in the Freight Carriage Acceptance Sheet.\\nThis document shall serve as prima facie evidence of receipt of the cargo.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 9, "title": "Consignment Notes"}, {"id": "termination", "body": "This contract may be terminated:\\n- By mutual consent.\\n- Upon completion of the agreed contract period or cargo volume.\\n- For breach of fundamental provisions, with one-week prior written notice.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "This Agreement becomes effective on the date it is signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "The contract is valid until August 31, {{contractYear}} from the date of effectiveness, extendable by mutual agreement.", "order": 12, "title": "Duration"}, {"id": "disputes", "body": "Disputes shall first be settled amicably.\\nIf unresolved, disputes shall be referred to the competent Federal Court of Ethiopia in Addis Ababa.\\nThe governing law shall be the laws of the Federal Democratic Republic of Ethiopia.", "order": 13, "title": "Settlement of Disputes"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('23cc0059-6258-4f16-8c84-6670751cfbc6', 'EXPORT_BULK_CUSTOMS', 'Bulk Export Contract (with customs clearing)', 'Export of bulk cargo (e.g. livestock) by railway from Ethiopian loading stations to Nagad railway freight yard, Djibouti. Customs clearing is performed by the Service Provider.', 'Bulk Cargo Transportation Service by Railway', '["The Client has agreed to deliver bulk cargo to the Service Provider for transport from the agreed Ethiopian loading station to Nagad railway freight yard using the Addis Ababa–Djibouti railway line.", "The Service Provider has agreed to provide the service to transport the bulk cargo from the agreed loading station to Nagad railway freight yard."]', '[{"id": "objective", "body": "To undertake the railway transportation of bulk cargo from the agreed Ethiopian loading station to Nagad railway freight yard.", "order": 1, "title": "Objective of the Service"}, {"id": "client-obligations", "body": "Give written instruction to the Service Provider to transport a minimum of one wagon of cargo; the wagon request shall be made at least five (5) days in advance for each wagon.\\nMaintain detailed information incorporating type, weight, and destination of the cargo ready for shipment, and notify the Service Provider or its nominated agent by notice, email, or fax.\\nPrepare the necessary documents and facilities to make the cargo ready for transport.\\nNote the allowable transport period of the cargo: the maximum time range during which the goods maintain their condition without any problem. The allowable transport period must be at least two (2) days longer than the delivery period.\\nEnsure cargo is properly loaded and fastened in the wagons, provide the necessary lashing and barriers for loading as per the instruction of the departure station, and bear responsibility for the condition of the cargo during the transport period.\\nSupply the necessary provisions for the cargo for each wagon and assign a responsible person to travel with the train to check the status of the cargo during transport, where the nature of the cargo so requires.\\nSupply the minimum amount of cargo available for at least one wagon.\\nExecute loading, lashing, and preparing barriers on wagons at the loading station and provide the complete documents/bill to the Service Provider within one (1) calendar day.\\nFor each extra calendar day used for loading cargo and completing documents at the loading station, pay the wagon-occupied fee per the pricing article; the fee shall be paid within ten (10) calendar days from the date the Service Provider claims it, failing which compensation is payable calculated on the basis of the Commercial Bank of Ethiopia interest rate for the delay period.\\nBe responsible for safety matters, and indemnify and hold the Service Provider harmless against all consequences resulting from accidents arising from or associated with the loading and unloading process.\\nExecute and cover the cost of loading and unloading of cargo at both the loading station and Nagad railway freight yard.\\nFollow up that the cargo is loaded and unloaded on time.\\nDelegate representatives at both ends to consign and receive cargo with signature and stamp. Representatives shall hold a duly signed and stamped power of attorney and shall produce their ID or passport when consigning or receiving the cargo.\\nPrepare the necessary facilities to take over the transported cargo at Nagad freight yard upon arrival by issuing handover documents.\\nTake the transported cargo out of the wagons at Nagad freight yard within one (1) calendar day starting from the day following the notice of arrival.\\nPay the wagon-occupied fee per the pricing article for delays of more than one (1) calendar day at Nagad railway freight yard due to the fault of the Client in resolving customs or third-party claims or any other causes.\\nAfter the wagon list is submitted to the Client, if a wagon is not loaded due to the fault of the Client, pay 100% of the transportation price per wagon for each unloaded wagon.\\nPay the Service Provider 100% of the contract price in advance for each wagon.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Provide the list and identification numbers of wagons with sequence and locomotives at least twenty-four (24) hours in advance to the Client, with any correction at least twelve (12) hours before arrival at destination.\\nTransport the cargo from the loading station to Nagad railway freight yard.\\nProvide safe transportation of the cargo throughout the transit.\\nPresent customs clearance documents and mobilize the rolling stock as needed.\\nProvide the wagons assigned for the freight at the agreed place and time, and follow up that the cargo is loaded on time.\\nTransport and deliver the cargo taken over, in the condition received, within two (2) calendar days to Nagad railway freight yard.\\nWhere a wagon carrying cargo stops due to accident or mechanical problem, promptly notify the nearby customs station, police office, and the Client. A wagon stopped in Ethiopia due to mechanical defect shall be maintained within four (4) calendar days; within Nagad (Djibouti) territory within twelve (12) calendar days. In case of accident where the problem cannot be solved within one (1) calendar day and the wagon is not operational, the Service Provider shall have the cargo carried and delivered by another wagon, and shall provide an accident or defect report issued by the local police office regarding the sustained damage.\\nBuy a cargo liability insurance policy for each supplied wagon.\\nProvide wagon cleaning service and charge the cleaning fee based on actual expenditure.\\nIf the Client fails or refuses to receive the cargo beyond the allowable transport period, the Service Provider has the right to handle the cargo.\\nNeither party shall be liable for any indirect or consequential loss sustained by the other in connection with this Agreement.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "The parties have no obligation to pay demurrage or any other compensation if they have failed to discharge their obligations due to force majeure.\\nForce majeure shall be deemed to exist when the contract is not performed due to any event beyond the reasonable control of a party which prevents that party from complying with its obligations under this Agreement, including but not limited to:\\n- Acts of God (such as, but not limited to, fires, explosions, earthquakes, drought, tidal waves, and floods).\\n- War, hostilities (whether war is declared or not), invasion, acts of foreign enemies, mobilization, requisition, or embargo.\\n- Rebellion, revolution, insurrection, military or usurped power, or civil war.\\n- Contamination by radioactivity from any nuclear fuel or nuclear waste.\\n- Riot, commotion, strikes, go-slows, lockouts, or disorder.\\n- Acts of terrorism.\\nA party wishing to claim protection in respect of a force majeure event shall, as soon as possible following the occurrence or commencement of the event, notify the other party of its nature and expected duration, and shall thereafter keep the other party informed until it is able to perform its obligations under this Agreement.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The price of bulk cargo transportation from the loading station to Nagad, together with any applicable demurrage and surcharge rates, is set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per wagon.\\nPayment for transport services shall be made in Birr based on the selling price of USD to Birr on the date of payment set by the Commercial Bank of Ethiopia.\\nIf there is an increment or decrement of the USD exchange rate to Birr between the date of payment and the date the wagon/train number is provided to the Client, either the Client shall make the additional payment to the Service Provider or the Service Provider shall refund the difference from the initial payment to the Client.\\nThe cost of loading at the loading station and unloading at Nagad shall be covered by the Client and is not part of this contract agreement.\\nThe Client shall pay 100% of the contract price in advance.\\nThe Client shall pay a demurrage fee for occupied wagons at the rate set out in the Rate Schedule for the applicable occupancy band.\\nDemurrage payment shall be made in Birr based on the selling price of USD to Birr set by the Commercial Bank of Ethiopia on the date of the demurrage occurrence.", "order": 5, "title": "Contract Price and Terms of Payment"}, {"id": "contract-documents", "body": "The following documents shall constitute the contract between the Client and the Service Provider:\\n- Amendments made to this contract (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "The following documents shall be delivered to the Client upon request for settlement:\\n- Consignment Note (cargo handover document to the Client).\\n- Summary of payment request of the Service Provider prepared as per the agreed tariff.", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over of the goods on the duplicates of the consignment note in an appropriate manner and return the duplicate to the Client.\\nA consignment note shall be prima facie evidence of the receipt of the goods by the Service Provider and of the kind, number, and weight of the goods.", "order": 8, "title": "Consignment Notes"}, {"id": "termination", "body": "The contract may be terminated:\\n- Upon mutual consent of the parties.\\n- Upon completion of the contract period.\\n- If either or both parties breach a fundamental provision of the contract, upon prior legal notice delivered by either party.", "order": 9, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract shall come into full force and effect on the date when all of the following are accomplished:\\n- The contract is signed by the Client and the Service Provider.\\n- The Service Provider has received the advance payment of 100% of the contract price for each train set of cargo.", "order": 10, "title": "Contract Effectiveness"}, {"id": "cargo-amount", "body": "The minimum cargo to be transported shall be one wagon.", "order": 11, "title": "Cargo Amount"}, {"id": "duration", "body": "The contract shall last for three (3) months starting from the date of contract signing, with possible extension upon mutual agreement.", "order": 12, "title": "Duration of Contract"}, {"id": "disputes", "body": "If a dispute arises between the parties, they shall exert efforts to settle their differences amicably.\\nIf the parties fail to settle their disputes amicably, the case shall be taken to the competent Federal Court of law presiding in Addis Ababa.\\nThe governing law shall be the laws of the Federal Democratic Republic of Ethiopia.", "order": 13, "title": "Settlement of Disputes"}, {"id": "customs-clearing", "body": "The Service Provider shall carry out customs clearing on behalf of the Client for the cargo covered by this Agreement, including declaration, lodgement, and follow-up at the customs stations of Djibouti and Ethiopia as applicable to the agreed corridor.\\nThe Service Provider shall act only within the authority granted by the Client and shall not amend a declaration without the Client''s written instruction.\\nCustoms duties, taxes, and any government charges assessed on the cargo remain payable by the Client and are not included in the freight price; the Service Provider shall settle them on the Client''s behalf only where the Client has placed the corresponding funds in advance.\\nThe Service Provider shall hand over all customs documents obtained in the course of clearing to the Client upon completion of each shipment.", "order": 14, "title": "Customs Clearing Services"}, {"id": "customs-client-duties", "body": "Grant the Service Provider a duly signed and stamped power of attorney authorising it to act as the Client''s customs agent for the duration of this Agreement.\\nSubmit every document required for declaration (commercial invoice, packing list, bill of lading or airway bill, permits, certificates of origin, and any authority-specific licence) within one (1) calendar day of the Service Provider''s request.\\nWarrant that the declared description, quantity, value, and tariff classification of the cargo are complete and accurate.\\nBear any penalty, demurrage, storage, or re-inspection cost arising from incorrect, incomplete, or late Client-supplied information or documentation.\\nSettle assessed duties and taxes within the period notified by the Service Provider, failing which the Service Provider may suspend clearing and the cargo shall remain at the Client''s risk and cost.", "order": 15, "title": "Client Obligations for Customs Clearing"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('87b640a0-dd01-46bf-a20f-7859ff77d4d3', 'EXPORT_BULK_NO_CUSTOMS', 'Bulk Export Contract (without customs clearing)', 'Export of bulk cargo (e.g. livestock) by railway from Ethiopian loading stations to Nagad railway freight yard, Djibouti. Customs clearing is handled by the Client.', 'Bulk Cargo Transportation Service by Railway', '["The Client has agreed to deliver bulk cargo to the Service Provider for transport from the agreed Ethiopian loading station to Nagad railway freight yard using the Addis Ababa–Djibouti railway line.", "The Service Provider has agreed to provide the service to transport the bulk cargo from the agreed loading station to Nagad railway freight yard."]', '[{"id": "objective", "body": "To undertake the railway transportation of bulk cargo from the agreed Ethiopian loading station to Nagad railway freight yard.", "order": 1, "title": "Objective of the Service"}, {"id": "client-obligations", "body": "Give written instruction to the Service Provider to transport a minimum of one wagon of cargo; the wagon request shall be made at least five (5) days in advance for each wagon.\\nMaintain detailed information incorporating type, weight, and destination of the cargo ready for shipment, and notify the Service Provider or its nominated agent by notice, email, or fax.\\nPrepare the necessary documents and facilities to make the cargo ready for transport.\\nNote the allowable transport period of the cargo: the maximum time range during which the goods maintain their condition without any problem. The allowable transport period must be at least two (2) days longer than the delivery period.\\nEnsure cargo is properly loaded and fastened in the wagons, provide the necessary lashing and barriers for loading as per the instruction of the departure station, and bear responsibility for the condition of the cargo during the transport period.\\nSupply the necessary provisions for the cargo for each wagon and assign a responsible person to travel with the train to check the status of the cargo during transport, where the nature of the cargo so requires.\\nSupply the minimum amount of cargo available for at least one wagon.\\nExecute loading, lashing, and preparing barriers on wagons at the loading station and provide the complete documents/bill to the Service Provider within one (1) calendar day.\\nFor each extra calendar day used for loading cargo and completing documents at the loading station, pay the wagon-occupied fee per the pricing article; the fee shall be paid within ten (10) calendar days from the date the Service Provider claims it, failing which compensation is payable calculated on the basis of the Commercial Bank of Ethiopia interest rate for the delay period.\\nBe responsible for safety matters, and indemnify and hold the Service Provider harmless against all consequences resulting from accidents arising from or associated with the loading and unloading process.\\nExecute and cover the cost of loading and unloading of cargo at both the loading station and Nagad railway freight yard.\\nFollow up that the cargo is loaded and unloaded on time.\\nDelegate representatives at both ends to consign and receive cargo with signature and stamp. Representatives shall hold a duly signed and stamped power of attorney and shall produce their ID or passport when consigning or receiving the cargo.\\nPrepare the necessary facilities to take over the transported cargo at Nagad freight yard upon arrival by issuing handover documents.\\nTake the transported cargo out of the wagons at Nagad freight yard within one (1) calendar day starting from the day following the notice of arrival.\\nPay the wagon-occupied fee per the pricing article for delays of more than one (1) calendar day at Nagad railway freight yard due to the fault of the Client in resolving customs or third-party claims or any other causes.\\nAfter the wagon list is submitted to the Client, if a wagon is not loaded due to the fault of the Client, pay 100% of the transportation price per wagon for each unloaded wagon.\\nPay the Service Provider 100% of the contract price in advance for each wagon.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Provide the list and identification numbers of wagons with sequence and locomotives at least twenty-four (24) hours in advance to the Client, with any correction at least twelve (12) hours before arrival at destination.\\nTransport the cargo from the loading station to Nagad railway freight yard.\\nProvide safe transportation of the cargo throughout the transit.\\nPresent customs clearance documents and mobilize the rolling stock as needed.\\nProvide the wagons assigned for the freight at the agreed place and time, and follow up that the cargo is loaded on time.\\nTransport and deliver the cargo taken over, in the condition received, within two (2) calendar days to Nagad railway freight yard.\\nWhere a wagon carrying cargo stops due to accident or mechanical problem, promptly notify the nearby customs station, police office, and the Client. A wagon stopped in Ethiopia due to mechanical defect shall be maintained within four (4) calendar days; within Nagad (Djibouti) territory within twelve (12) calendar days. In case of accident where the problem cannot be solved within one (1) calendar day and the wagon is not operational, the Service Provider shall have the cargo carried and delivered by another wagon, and shall provide an accident or defect report issued by the local police office regarding the sustained damage.\\nBuy a cargo liability insurance policy for each supplied wagon.\\nProvide wagon cleaning service and charge the cleaning fee based on actual expenditure.\\nIf the Client fails or refuses to receive the cargo beyond the allowable transport period, the Service Provider has the right to handle the cargo.\\nNeither party shall be liable for any indirect or consequential loss sustained by the other in connection with this Agreement.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "The parties have no obligation to pay demurrage or any other compensation if they have failed to discharge their obligations due to force majeure.\\nForce majeure shall be deemed to exist when the contract is not performed due to any event beyond the reasonable control of a party which prevents that party from complying with its obligations under this Agreement, including but not limited to:\\n- Acts of God (such as, but not limited to, fires, explosions, earthquakes, drought, tidal waves, and floods).\\n- War, hostilities (whether war is declared or not), invasion, acts of foreign enemies, mobilization, requisition, or embargo.\\n- Rebellion, revolution, insurrection, military or usurped power, or civil war.\\n- Contamination by radioactivity from any nuclear fuel or nuclear waste.\\n- Riot, commotion, strikes, go-slows, lockouts, or disorder.\\n- Acts of terrorism.\\nA party wishing to claim protection in respect of a force majeure event shall, as soon as possible following the occurrence or commencement of the event, notify the other party of its nature and expected duration, and shall thereafter keep the other party informed until it is able to perform its obligations under this Agreement.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The price of bulk cargo transportation from the loading station to Nagad, together with any applicable demurrage and surcharge rates, is set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per wagon.\\nPayment for transport services shall be made in Birr based on the selling price of USD to Birr on the date of payment set by the Commercial Bank of Ethiopia.\\nIf there is an increment or decrement of the USD exchange rate to Birr between the date of payment and the date the wagon/train number is provided to the Client, either the Client shall make the additional payment to the Service Provider or the Service Provider shall refund the difference from the initial payment to the Client.\\nThe cost of loading at the loading station and unloading at Nagad shall be covered by the Client and is not part of this contract agreement.\\nThe Client shall pay 100% of the contract price in advance.\\nThe Client shall pay a demurrage fee for occupied wagons at the rate set out in the Rate Schedule for the applicable occupancy band.\\nDemurrage payment shall be made in Birr based on the selling price of USD to Birr set by the Commercial Bank of Ethiopia on the date of the demurrage occurrence.", "order": 5, "title": "Contract Price and Terms of Payment"}, {"id": "contract-documents", "body": "The following documents shall constitute the contract between the Client and the Service Provider:\\n- Amendments made to this contract (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "The following documents shall be delivered to the Client upon request for settlement:\\n- Consignment Note (cargo handover document to the Client).\\n- Summary of payment request of the Service Provider prepared as per the agreed tariff.", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over of the goods on the duplicates of the consignment note in an appropriate manner and return the duplicate to the Client.\\nA consignment note shall be prima facie evidence of the receipt of the goods by the Service Provider and of the kind, number, and weight of the goods.", "order": 8, "title": "Consignment Notes"}, {"id": "termination", "body": "The contract may be terminated:\\n- Upon mutual consent of the parties.\\n- Upon completion of the contract period.\\n- If either or both parties breach a fundamental provision of the contract, upon prior legal notice delivered by either party.", "order": 9, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract shall come into full force and effect on the date when all of the following are accomplished:\\n- The contract is signed by the Client and the Service Provider.\\n- The Service Provider has received the advance payment of 100% of the contract price for each train set of cargo.", "order": 10, "title": "Contract Effectiveness"}, {"id": "cargo-amount", "body": "The minimum cargo to be transported shall be one wagon.", "order": 11, "title": "Cargo Amount"}, {"id": "duration", "body": "The contract shall last for three (3) months starting from the date of contract signing, with possible extension upon mutual agreement.", "order": 12, "title": "Duration of Contract"}, {"id": "disputes", "body": "If a dispute arises between the parties, they shall exert efforts to settle their differences amicably.\\nIf the parties fail to settle their disputes amicably, the case shall be taken to the competent Federal Court of law presiding in Addis Ababa.\\nThe governing law shall be the laws of the Federal Democratic Republic of Ethiopia.", "order": 13, "title": "Settlement of Disputes"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('c6051eea-ae34-49aa-9c42-6d9bc6e30d85', 'INTERCITY_BULK', 'Bulk Intercity Contract', 'Domestic (intercity) bulk cargo transportation by railway between Ethiopian freight yards, e.g. Dire Dawa to Sebeta.', 'Bulk Cargo Transportation Service by Railway (Intercity)', '["The Client has requested the Service Provider to transport bulk cargo between the agreed Ethiopian railway freight yards using the Ethio–Djibouti Railway.", "The Service Provider has accepted the Client''s request to render the said transportation service."]', '[{"id": "objective", "body": "The Service Provider shall undertake the railway transportation of bulk cargo from the agreed origin railway freight yard to the agreed destination railway freight yard.", "order": 1, "title": "Objective of the Contract"}, {"id": "client-obligations", "body": "Provide written instructions to the Service Provider to transport a minimum of sixteen (16) wagons of cargo per consignment.\\nPrepare all necessary documents, including laboratory tests from the pertinent organ and off-taking contract where applicable, and the facilities required to sign the contract and make the cargo ready for transport.\\nAssign representatives at the origin yard and other stations, as required, to hand over the cargo to the Service Provider and handle transit clearance if required.\\nTransport the cargo to the designated loading points at the origin yard.\\nBe responsible for cargo handling: loading at the origin yard and unloading at the destination yard, in accordance with the standards set by the EDR operations and technical terms.\\nMake advance payment to the Service Provider for services in accordance with the payment terms and conditions of this contract.\\nFollow up to ensure that the cargo is loaded and unloaded on time.\\nDelegate representatives at the cargo destination to immediately receive the transported cargo.\\nEnsure representatives are duly authorized with a power of attorney, signed and stamped by the Client, and present valid identification (ID or passport) when consigning or receiving cargo.\\nMaintain detailed information including item, weight, and destination of the cargo, and communicate the same to the Service Provider or its nominated agent via written notice, email, or fax.\\nPrepare the necessary facilities to immediately take over the transported cargo at the destination upon arrival and provide sufficient trucks at the destination freight yard for unloading from railway wagons.\\nUpon arrival of the train/wagon at the unloading site, sign the train arrival confirmation sheet to acknowledge the arrival time.\\nInspect the loaded wagons jointly with the Service Provider and EDR at the loading yard, and again with the customs agent (if required) and the Service Provider at the destination yard.\\nAfter receiving the cargo, sign the Freight Carriage Acceptance Sheet (copies II, III, and IV) immediately to confirm delivery.\\nCompensate the Service Provider or any third party for actual loss or damage caused to persons, property, or wagons during unloading where such damage is attributable to the Client''s fault.\\nEach consignment (train) shall be granted three (3) hours of free time at the loading station and one (1) day at the unloading station. For each additional 3 hours of loading or parking the Client shall pay ETB 5,000 (five thousand) per wagon, and for each additional day of unloading ETB 5,000 (five thousand) per wagon per day.\\nBear demurrage charges of ETB 5,000 (five thousand) per wagon per 3 hours for delays exceeding three (3) hours at any station resulting from the Client''s failure to resolve customs or third-party claims.\\nPay 100% of the transport price in advance. Any additional charges or fees shall be paid within ten (10) calendar days after submission of the Service Provider''s payment request.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Provide the necessary train(s) to execute the transportation service under this contract, and furnish the Client with the list and identification numbers of wagons and locomotives at least 24 hours in advance, with corrections (if any) communicated at least 12 hours before the expected time of arrival at destination.\\nProvide pre-arrival notification including the train number to the discharging terminal and customs at least 24/12 hours before train arrival.\\nTransport the cargo from origin to destination within two (2) days from completion of loading (time counting starts upon completion of documentation and loading).\\nProvide safe transportation of the cargo throughout transit.\\nDeliver the cargo to the Client at the destination railway freight yard in the same condition as received.\\nPurchase a cargo liability insurance policy for each wagon transported.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable due to a force majeure event.\\nFor the purposes of this contract, force majeure shall mean any unforeseeable event or circumstance beyond the reasonable control of the affected party which absolutely prevents the performance of the contract, including but not limited to natural disasters, war, civil commotion, strikes, government actions, epidemics, or interruption of railway operations due to accidents or infrastructure failure.\\nThe affected party shall notify the other party in writing within a reasonable period not exceeding two (2) hours after the occurrence of the force majeure event, providing evidence and details of the impact on performance and the mitigating steps taken.", "order": 4, "title": "Force Majeure"}, {"id": "liability", "body": "The Service Provider will be responsible for any loss, shortage, or damage occurring to the cargo it has received.", "order": 5, "title": "Liabilities Related to Damages and Losses"}, {"id": "pricing", "body": "The price for transporting cargo from the origin freight yard to the destination freight yard is set out in the Rate Schedule immediately below, expressed as a unit price per origin → destination lane and per wagon.\\nEach wagon shall be loaded with a maximum of 70 (seventy) metric tons.\\nPayment for transport services may be made in Ethiopian Birr, based on the Commercial Bank of Ethiopia''s official selling exchange rate of USD to Birr on the date of payment.\\nIf the exchange rate changes between the payment and the wagon assignment date, payment adjustments will be made accordingly.\\nThe contract price shall include the cost of railway transportation from the origin freight yard to the destination freight yard.\\nExcluded cost: cargo handling (loading and unloading) is not included in the contract price and shall remain the sole responsibility of the Client.", "order": 6, "title": "Contract Price"}, {"id": "contract-documents", "body": "The following documents shall constitute the contract between the Client and the Service Provider:\\n- Amendments made to this contract (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 7, "title": "Contract Documents"}, {"id": "documentation", "body": "The following documents shall be delivered to the Client by the Service Provider to collect and settle payment:\\n- Freight Carriage Acceptance Sheet of the Ethio-Djibouti Railway.\\n- Notice of collecting transportation and miscellaneous charges of the Ethio-Djibouti Railway (if any).\\n- Summary of payment request of the Service Provider prepared as per the agreed tariff.\\n- Railway Waybill.", "order": 8, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over of the goods on copy III (kept by the consignee for future reference) of the Freight Carriage Acceptance Sheet of the Ethio-Djibouti Railway in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the goods by the Service Provider and of the kind, number, and weight of the goods.", "order": 9, "title": "Consignment Notes"}, {"id": "termination", "body": "The contract may be terminated:\\n- Upon mutual consent of the parties.\\n- Upon completion of the contract period or amount of cargo, whichever comes first.\\n- If either or both parties breach a fundamental provision of the contract, upon one-week prior legal notice delivered by either party.", "order": 10, "title": "Termination of Contract"}, {"id": "duration", "body": "The contract duration shall be three (3) months from the date of effectiveness of the contract, with possible extension upon mutual agreement of the parties.", "order": 11, "title": "Duration of Contract"}, {"id": "disputes", "body": "If a dispute arises between the parties, they shall exert efforts to settle their differences amicably.\\nIf the parties fail to settle their dispute amicably, the case shall be taken to the competent Federal Court of law presiding in Addis Ababa.\\nThe governing law shall be the laws of the Federal Democratic Republic of Ethiopia.", "order": 12, "title": "Settlement of Disputes"}, {"id": "effectiveness", "body": "The contract shall come into full force and effect on the date when the contract is signed by both parties.", "order": 13, "title": "Contract Effectiveness"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('5fba1daf-4e75-407d-855c-73c0545e7b46', 'IMPORT_CONTAINER_CUSTOMS', 'Container Import Contract (with customs clearing)', 'Import container transport by railway from SGTD (Djibouti) to Dire Dawa, Modjo dry port, or Galaan Multipurpose Port, with empty-container return. Customs clearing is performed by the Service Provider.', 'Import Container Transport Service by Railway', '["The Client has requested and agreed to the transportation of container cargo from SGTD railway freight station at Djibouti to Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP), and the return of empty containers from Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP) to SGTD railway freight station using the Addis Ababa–Djibouti railway line.", "The Service Provider has agreed to transport the container cargo as per the terms of this contract."]', '[{"id": "objective", "body": "To provide railway transportation services for 40ft and/or 20ft full containers from SGTD to Dire Dawa, Modjo dry port, and/or Galaan Multipurpose Port (GMP), and empty container return from Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP) to SGTD.\\nThe scope of the services comprises:\\n- Railway transport service.\\n- Cargo handling at Galaan Multipurpose Port (GMP).", "order": 1, "title": "Objective and Scope of the Services"}, {"id": "client-obligations", "body": "Give written/email/electronic shipment instructions to the Service Provider for transportation of container cargo from SGTD to Dire Dawa, Modjo dry port, and/or Galaan Multipurpose Port (GMP).\\nPrepare all necessary documents and facilities for shipment.\\nEnsure the following minimum supply of containers per shipment based on the loading terminal and destination:\\n- Minimum of twenty-five (25) 40ft containers or fifty (50) 20ft containers to Modjo dry port.\\n- Minimum of ten (10) 40ft containers or twenty (20) 20ft containers to Dire Dawa dry port.\\n- Minimum of one (1) 40ft container or two (2) TEU to Galaan Multipurpose Port (GMP).\\nOne flat wagon must carry either one 40ft container or two 20ft containers.\\nIf two 20ft containers are loaded on one flat wagon, their weight difference must not exceed 10 tons.\\nEnsure timely loading and unloading of cargo.\\nAssign representatives at both ends to oversee container handover and ensure the necessary arrangements for cargo reception at the destination upon arrival.\\nMaintain and provide detailed cargo information (type, weight, destination, etc.).\\nBe responsible for cargo handling, loading, and unloading of both empty and full containers at Modjo, Dire Dawa dry port, and SGTD.\\nBook wagons at least five (5) days in advance.\\nEnsure containers are ready one day before the planned loading date.\\nSubmit all required documents to the Djibouti Nagad station at least 24 hours in advance before starting to load. Failure to submit the documents within the stipulated time shall result in the following demurrage charges, calculated as a percentage of the booked wagon price:\\n- Delay of up to twelve (12) hours: 20% of the booked wagon price.\\n- Delay exceeding twelve (12) hours but not more than one (1) day: 50% of the booked wagon price.\\n- Delay of more than one (1) day: 100% of the booked wagon price.\\nCollect the full container from Galaan Multipurpose Port (GMP) within three (3) calendar days from the day following the arrival notice.\\nIf the Client fails to collect the container within the specified period, the Service Provider shall have the right to reposition the container to any location it deems appropriate; in such case, the Service Provider shall not be held responsible for any damage or loss arising from such repositioning.\\nIf the Client fails to collect the container from Galaan Multipurpose Port within the specified period, the Client shall be liable to pay demurrage charges of 15 USD per day per 20ft container and 27 USD per day per 40ft container, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nIn the event the Client fails to collect the container(s) within the specified period, the Client shall be liable to pay double handling charges of 27 USD per 20ft container per handling or 40 USD per 40ft container per handling, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nIf empty containers cannot be offloaded from the train upon arrival at SGTD due to any Client-related issue, the Client shall be liable for the applicable penalty charges.\\nPenalty charges for delay at SGTD/Nagad upon train arrival: 20 USD per day per 20ft container; 33 USD per day per 40ft container.\\nCollect the containers within one day at Dire Dawa and Modjo dry port, or make the necessary payment to the dry port as per the standard of the dry port.\\nFor returning empty containers, deliver to Dire Dawa dry port, Modjo dry port, or Galaan Multipurpose Port.\\nOnce the empty containers are returned from the Client''s premises and stored at Dire Dawa/Modjo dry port while awaiting train allocation for return to SGTD, any demurrage and/or storage charges incurred from the dry port thereafter shall not be the responsibility or liability of the Service Provider; the Client shall be solely responsible for settling such charges.\\nProvide clean empty containers that meet SGTD standards. If the port refuses to take over an empty container because of inside cleanliness problems, additional cleaning costs incurred due to non-compliance will be borne by the Client.\\nEnsure containers are structurally intact and meet weight distribution requirements.\\nProhibited cargo: cargo covered with tarpaulin is not allowed due to safety risks.\\nNotify the Service Provider forty-eight (48) hours in advance before wagon booking if transporting hazardous or valuable goods.\\nIf a booked wagon is not loaded due to Client-related issues, including but not limited to a damaged container, missing lock, unpaid demurrage, port system errors, or incomplete documentation and submission, the Client shall be charged 100% of the total price of the reserved wagon.\\nRefund requests before wagon booking require an official request, with a 3% administrative fee deducted. If the refund is due to the Service Provider, the Client shall receive a full refund. Refunds not requested and completed within six months shall be considered waived.\\nPay 100% of the transportation fee in advance for each train set.\\nSettle additional penalties due to non-compliance within ten (10) days of invoice issuance.\\nLate payment incurs a penalty of an additional 10%.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Assign the necessary voyage based on the operational schedule and cargo demand, and notify the train schedule 48 hours in advance.\\nProvide a list of wagons/voyage or train number 24 hours in advance and update corrections 12 hours before arrival.\\nProvide safe transportation of the containers.\\nDeliver the cargo within two (2) days after train departure, provided that all required documents are submitted on time and no unforeseen circumstances or events occur.\\nReturn empty containers from Dire Dawa, Modjo, and Galaan Multipurpose Port to SGTD within seven (7) calendar days of receipt.\\nIn the event of export cargo operations, the Service Provider may prioritize the loading of export containers during the loading of empty containers and the unloading of import containers from the train at Galaan Multipurpose Port.\\nThe Service Provider reserves the right to refuse the transportation of any cargo classified as dangerous goods.\\nIf any operational, technical, or mechanical problem occurs throughout the transit, notify customs and arrange cargo transfer within 4 days if the incident occurs in Ethiopia, or within 6 days if it occurs in Djibouti.\\nProvide accident or defect reports if needed.\\nBuy cargo liability insurance for each wagon.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The railway transportation rate for each corridor (per one 40ft container or per two 20ft containers, with or without empty return where applicable) is set out in the Rate Schedule immediately below, expressed as a unit price per origin → destination lane and per container.\\nIf cargo exceeds 40 tons per two 20ft containers of gross weight, additional charges apply proportionally.\\nGross weight shall be the total sum of cargo, packing, and container tare weight.\\nPayment for any additional tonnage shall be made in advance before the container is loaded onto the wagon.\\nThe price of loading and unloading and container handling at Modjo, Dire Dawa dry port, and SGTD container railway freight yard is not part of this contract; it is the Client''s responsibility.\\nAdditional costs (if applicable):\\n- Last-mile delivery service by truck from Galaan Multipurpose Port or Modjo to Addis Ababa or Modjo and surrounding areas shall incur an additional cost, fully covered by the Client.\\n- For clients utilizing EDR''s last-mile logistics services, the applicable charges shall vary based on the cargo movement route.\\n- The charge for last-mile delivery from Galaan Multipurpose Port and Modjo dry port shall be communicated to the Client by the Service Provider after receiving the necessary details regarding the cargo destination, type, and weight.\\nAll payments shall be made one hundred percent (100%) in advance in United States Dollars (USD).", "order": 5, "title": "Contract Price and Terms of Payment"}, {"id": "contract-documents", "body": "The following documents constitute this contract:\\n- Amendments (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "Equipment Interchange Receipt of SGTD, Railway Waybill, Container Carriage Acceptance Sheet, and incidental charges (if any).\\nPayment summary as per the agreed contract price (if required).", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over and handing over of the container cargo on the Freight Carriage Acceptance Sheet of EDR in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the container cargo by the Service Provider and of the kind, number, and weight of the goods.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 8, "title": "Consignment Notes"}, {"id": "amendment", "body": "This contract can be amended by mutual agreement.\\nNotwithstanding the above, the Service Provider may revise transport tariffs due to operational and regulatory changes by providing at least five (5) working days'' prior written notice to the Client.", "order": 9, "title": "Amendment"}, {"id": "termination", "body": "The contract may be terminated:\\n- By mutual agreement.\\n- Upon completion of the contract period or agreed cargo shipments.\\n- If either party breaches fundamental terms.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract is valid once signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "Valid until August 31, {{contractYear}}, with a possible extension upon mutual agreement.", "order": 12, "title": "Contract Period"}, {"id": "disputes", "body": "Disputes shall be settled amicably.\\nIf unresolved, disputes shall be taken to the Federal Court in Addis Ababa.", "order": 13, "title": "Settlement of Disputes"}, {"id": "customs-clearing", "body": "The Service Provider shall carry out customs clearing on behalf of the Client for the cargo covered by this Agreement, including declaration, lodgement, and follow-up at the customs stations of Djibouti and Ethiopia as applicable to the agreed corridor.\\nThe Service Provider shall act only within the authority granted by the Client and shall not amend a declaration without the Client''s written instruction.\\nCustoms duties, taxes, and any government charges assessed on the cargo remain payable by the Client and are not included in the freight price; the Service Provider shall settle them on the Client''s behalf only where the Client has placed the corresponding funds in advance.\\nThe Service Provider shall hand over all customs documents obtained in the course of clearing to the Client upon completion of each shipment.", "order": 14, "title": "Customs Clearing Services"}, {"id": "customs-client-duties", "body": "Grant the Service Provider a duly signed and stamped power of attorney authorising it to act as the Client''s customs agent for the duration of this Agreement.\\nSubmit every document required for declaration (commercial invoice, packing list, bill of lading or airway bill, permits, certificates of origin, and any authority-specific licence) within one (1) calendar day of the Service Provider''s request.\\nWarrant that the declared description, quantity, value, and tariff classification of the cargo are complete and accurate.\\nBear any penalty, demurrage, storage, or re-inspection cost arising from incorrect, incomplete, or late Client-supplied information or documentation.\\nSettle assessed duties and taxes within the period notified by the Service Provider, failing which the Service Provider may suspend clearing and the cargo shall remain at the Client''s risk and cost.", "order": 15, "title": "Client Obligations for Customs Clearing"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('8cd8e805-178a-4faa-bdbb-2e7ac5f75e7c', 'IMPORT_CONTAINER_NO_CUSTOMS', 'Container Import Contract (without customs clearing)', 'Import container transport by railway from SGTD (Djibouti) to Dire Dawa, Modjo dry port, or Galaan Multipurpose Port, with empty-container return. Customs clearing is handled by the Client.', 'Import Container Transport Service by Railway', '["The Client has requested and agreed to the transportation of container cargo from SGTD railway freight station at Djibouti to Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP), and the return of empty containers from Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP) to SGTD railway freight station using the Addis Ababa–Djibouti railway line.", "The Service Provider has agreed to transport the container cargo as per the terms of this contract."]', '[{"id": "objective", "body": "To provide railway transportation services for 40ft and/or 20ft full containers from SGTD to Dire Dawa, Modjo dry port, and/or Galaan Multipurpose Port (GMP), and empty container return from Dire Dawa, Modjo dry port, and Galaan Multipurpose Port (GMP) to SGTD.\\nThe scope of the services comprises:\\n- Railway transport service.\\n- Cargo handling at Galaan Multipurpose Port (GMP).", "order": 1, "title": "Objective and Scope of the Services"}, {"id": "client-obligations", "body": "Give written/email/electronic shipment instructions to the Service Provider for transportation of container cargo from SGTD to Dire Dawa, Modjo dry port, and/or Galaan Multipurpose Port (GMP).\\nPrepare all necessary documents and facilities for shipment.\\nEnsure the following minimum supply of containers per shipment based on the loading terminal and destination:\\n- Minimum of twenty-five (25) 40ft containers or fifty (50) 20ft containers to Modjo dry port.\\n- Minimum of ten (10) 40ft containers or twenty (20) 20ft containers to Dire Dawa dry port.\\n- Minimum of one (1) 40ft container or two (2) TEU to Galaan Multipurpose Port (GMP).\\nOne flat wagon must carry either one 40ft container or two 20ft containers.\\nIf two 20ft containers are loaded on one flat wagon, their weight difference must not exceed 10 tons.\\nEnsure timely loading and unloading of cargo.\\nAssign representatives at both ends to oversee container handover and ensure the necessary arrangements for cargo reception at the destination upon arrival.\\nMaintain and provide detailed cargo information (type, weight, destination, etc.).\\nBe responsible for cargo handling, loading, and unloading of both empty and full containers at Modjo, Dire Dawa dry port, and SGTD.\\nBook wagons at least five (5) days in advance.\\nEnsure containers are ready one day before the planned loading date.\\nSubmit all required documents to the Djibouti Nagad station at least 24 hours in advance before starting to load. Failure to submit the documents within the stipulated time shall result in the following demurrage charges, calculated as a percentage of the booked wagon price:\\n- Delay of up to twelve (12) hours: 20% of the booked wagon price.\\n- Delay exceeding twelve (12) hours but not more than one (1) day: 50% of the booked wagon price.\\n- Delay of more than one (1) day: 100% of the booked wagon price.\\nCollect the full container from Galaan Multipurpose Port (GMP) within three (3) calendar days from the day following the arrival notice.\\nIf the Client fails to collect the container within the specified period, the Service Provider shall have the right to reposition the container to any location it deems appropriate; in such case, the Service Provider shall not be held responsible for any damage or loss arising from such repositioning.\\nIf the Client fails to collect the container from Galaan Multipurpose Port within the specified period, the Client shall be liable to pay demurrage charges of 15 USD per day per 20ft container and 27 USD per day per 40ft container, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nIn the event the Client fails to collect the container(s) within the specified period, the Client shall be liable to pay double handling charges of 27 USD per 20ft container per handling or 40 USD per 40ft container per handling, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nIf empty containers cannot be offloaded from the train upon arrival at SGTD due to any Client-related issue, the Client shall be liable for the applicable penalty charges.\\nPenalty charges for delay at SGTD/Nagad upon train arrival: 20 USD per day per 20ft container; 33 USD per day per 40ft container.\\nCollect the containers within one day at Dire Dawa and Modjo dry port, or make the necessary payment to the dry port as per the standard of the dry port.\\nFor returning empty containers, deliver to Dire Dawa dry port, Modjo dry port, or Galaan Multipurpose Port.\\nOnce the empty containers are returned from the Client''s premises and stored at Dire Dawa/Modjo dry port while awaiting train allocation for return to SGTD, any demurrage and/or storage charges incurred from the dry port thereafter shall not be the responsibility or liability of the Service Provider; the Client shall be solely responsible for settling such charges.\\nProvide clean empty containers that meet SGTD standards. If the port refuses to take over an empty container because of inside cleanliness problems, additional cleaning costs incurred due to non-compliance will be borne by the Client.\\nEnsure containers are structurally intact and meet weight distribution requirements.\\nProhibited cargo: cargo covered with tarpaulin is not allowed due to safety risks.\\nNotify the Service Provider forty-eight (48) hours in advance before wagon booking if transporting hazardous or valuable goods.\\nIf a booked wagon is not loaded due to Client-related issues, including but not limited to a damaged container, missing lock, unpaid demurrage, port system errors, or incomplete documentation and submission, the Client shall be charged 100% of the total price of the reserved wagon.\\nRefund requests before wagon booking require an official request, with a 3% administrative fee deducted. If the refund is due to the Service Provider, the Client shall receive a full refund. Refunds not requested and completed within six months shall be considered waived.\\nPay 100% of the transportation fee in advance for each train set.\\nSettle additional penalties due to non-compliance within ten (10) days of invoice issuance.\\nLate payment incurs a penalty of an additional 10%.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Assign the necessary voyage based on the operational schedule and cargo demand, and notify the train schedule 48 hours in advance.\\nProvide a list of wagons/voyage or train number 24 hours in advance and update corrections 12 hours before arrival.\\nProvide safe transportation of the containers.\\nDeliver the cargo within two (2) days after train departure, provided that all required documents are submitted on time and no unforeseen circumstances or events occur.\\nReturn empty containers from Dire Dawa, Modjo, and Galaan Multipurpose Port to SGTD within seven (7) calendar days of receipt.\\nIn the event of export cargo operations, the Service Provider may prioritize the loading of export containers during the loading of empty containers and the unloading of import containers from the train at Galaan Multipurpose Port.\\nThe Service Provider reserves the right to refuse the transportation of any cargo classified as dangerous goods.\\nIf any operational, technical, or mechanical problem occurs throughout the transit, notify customs and arrange cargo transfer within 4 days if the incident occurs in Ethiopia, or within 6 days if it occurs in Djibouti.\\nProvide accident or defect reports if needed.\\nBuy cargo liability insurance for each wagon.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The railway transportation rate for each corridor (per one 40ft container or per two 20ft containers, with or without empty return where applicable) is set out in the Rate Schedule immediately below, expressed as a unit price per origin → destination lane and per container.\\nIf cargo exceeds 40 tons per two 20ft containers of gross weight, additional charges apply proportionally.\\nGross weight shall be the total sum of cargo, packing, and container tare weight.\\nPayment for any additional tonnage shall be made in advance before the container is loaded onto the wagon.\\nThe price of loading and unloading and container handling at Modjo, Dire Dawa dry port, and SGTD container railway freight yard is not part of this contract; it is the Client''s responsibility.\\nAdditional costs (if applicable):\\n- Last-mile delivery service by truck from Galaan Multipurpose Port or Modjo to Addis Ababa or Modjo and surrounding areas shall incur an additional cost, fully covered by the Client.\\n- For clients utilizing EDR''s last-mile logistics services, the applicable charges shall vary based on the cargo movement route.\\n- The charge for last-mile delivery from Galaan Multipurpose Port and Modjo dry port shall be communicated to the Client by the Service Provider after receiving the necessary details regarding the cargo destination, type, and weight.\\nAll payments shall be made one hundred percent (100%) in advance in United States Dollars (USD).", "order": 5, "title": "Contract Price and Terms of Payment"}, {"id": "contract-documents", "body": "The following documents constitute this contract:\\n- Amendments (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "Equipment Interchange Receipt of SGTD, Railway Waybill, Container Carriage Acceptance Sheet, and incidental charges (if any).\\nPayment summary as per the agreed contract price (if required).", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over and handing over of the container cargo on the Freight Carriage Acceptance Sheet of EDR in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the container cargo by the Service Provider and of the kind, number, and weight of the goods.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 8, "title": "Consignment Notes"}, {"id": "amendment", "body": "This contract can be amended by mutual agreement.\\nNotwithstanding the above, the Service Provider may revise transport tariffs due to operational and regulatory changes by providing at least five (5) working days'' prior written notice to the Client.", "order": 9, "title": "Amendment"}, {"id": "termination", "body": "The contract may be terminated:\\n- By mutual agreement.\\n- Upon completion of the contract period or agreed cargo shipments.\\n- If either party breaches fundamental terms.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract is valid once signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "Valid until August 31, {{contractYear}}, with a possible extension upon mutual agreement.", "order": 12, "title": "Contract Period"}, {"id": "disputes", "body": "Disputes shall be settled amicably.\\nIf unresolved, disputes shall be taken to the Federal Court in Addis Ababa.", "order": 13, "title": "Settlement of Disputes"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('9b2636ec-3ad4-4f26-9133-6a6c9fc3f798', 'EXPORT_CONTAINER_CUSTOMS', 'Container Export Contract (with customs clearing)', 'Export container transport, freight forwarding, and customs clearing from Galaan Multipurpose Port or Modjo dry port to SGTD container freight station (Djibouti). Customs clearing is performed by the Service Provider.', 'Export Container Transport, Freight Forwarding and Customs Clearing Service', '["The parties have agreed on the following services: rail transport, customs clearance, transit work, freight forwarding, and handling of container cargo."]', '[{"id": "objective", "body": "Customs clearance (Ethiopia side):\\n- Processing of export declarations.\\n- Coordination with the Ethiopian Customs Authority for clearance.\\n- Ensuring compliance with all export regulations.\\nRail transport:\\n- Transportation of containers from Galaan Multipurpose Port (GMP) or Modjo dry port to SGTD container freight station.\\nDjibouti transit and handling:\\n- Customs clearance in Djibouti.\\n- Coordination with Djibouti port and transit authorities.\\n- Freight forwarding and last-mile facilitation as required.\\nExcluded costs:\\n- Shore handling.\\n- Shifting of containers from SGTD to DMP or DMP to SGTD port.", "order": 1, "title": "Objective and Scope of the Services"}, {"id": "client-obligations", "body": "Give written/email instructions to the Service Provider for transportation of containers from Galaan Multipurpose Port (GMP) and/or Modjo to Djibouti.\\nSupply a minimum of two (2) 20ft containers (or an equivalent load to fill one flat wagon).\\nSubmit all forwarding service booking requests at least seventy-two (72) hours prior to the scheduled train departure and no later than 7 days before the vessel cut-off time, whichever is applicable.\\nFor clients requiring first-mile service, submit a first-mile service request notice no less than seventy-two (72) hours in advance.\\nComplete and submit accurate export documents as per the request of the Service Provider; payment must be submitted at least 36 hours before train departure.\\nDeliver all cargo to the designated loading port or freight station at least three (3) hours prior to the scheduled train loading time.\\nFailure to meet the stated deadlines may result in cancellation of the booking and transfer arrangements; any resulting delays, penalties, or additional costs shall be the sole responsibility of the Client.\\nIf the Client fails to deliver the container, fails to provide the requested documents for completing export documents as instructed above, or cancels after wagon reservation, the Client shall pay USD 150.00 per wagon as a penalty, after notification.\\nContainers must have four (4) undamaged corners.\\nOne flat wagon must carry either one 40ft container or two 20ft containers.\\nIf two 20ft containers are loaded on one flat wagon, their weight difference must not exceed 10 tons.\\nThe gross weight of the container must not exceed the standard loading capacity indicated on the container; the Client is responsible for ensuring full compliance with the maximum allowable load.\\nProhibited cargo: cargo covered with tarpaulin is not allowed due to safety risks.\\nIf the cargo to be transported is dangerous and/or valuable goods, notify the Service Provider 48 (forty-eight) hours before the wagon booking for further discussion and decision.\\nRefund requests before wagon booking require an official request, with a 3% administrative fee deducted. If the refund is due to the Service Provider, the Client shall receive a full refund. Refunds not requested and completed within six months shall be considered waived.\\nAny delay caused by missing or incorrect documents shall be the Client''s responsibility.\\n100% of the transportation and customs clearance fee must be paid in advance.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Complete gate pass processing and submit to Nagad Station for each shipment within eighteen (18) hours after train departure.\\nThe Service Provider reserves the right to refuse the transportation of any cargo classified as dangerous goods.\\nMaintain cargo liability insurance for railway transport; additional insurance for port handling or last-mile transport shall be the Client''s responsibility.\\nThe Service Provider is not liable for customs penalties or demurrage due to delays beyond its control.\\nNotify the Client immediately, in writing, of any delays, port issues, or customs holds.\\nThe Service Provider shall not be liable for:\\n- Inherent defects of the cargo.\\n- Improper packing or loading conducted by the Client.\\n- Customs-related delays.\\n- Delays caused by force majeure events.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The railway transportation charges and the freight forwarding and customs clearance charges for each corridor (per 40ft container and per two 20ft containers) are set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per container.\\nWhere the total cargo weight exceeds fifty (50) metric tons per two (2) 20ft containers, an additional charge shall apply for each excess metric ton at the overweight rate set out in the Rate Schedule.\\nFor consolidated containers containing more than one (1) shipping document, the first document shall be included under the agreed contract rate; any additional document within the same container shall be subject to the extra-document charge set out in the Rate Schedule.\\nPayment must be supported by an official receipt before cargo departs from Galaan Multipurpose Port/Modjo.\\nIf the Client uses PIL Shipping Line, any local charge incurred will be covered by the Client as per the invoice issued by the shipping line.\\nIf storage or demurrage occurs due to Client-related issues (delay in document submission, payment delay, or any other Client-related reason), the Client shall pay the corresponding charges; charges apply per day after the free storage period, based on the invoice and SGTD tariff.\\nDuring export season, EDR may provide seasonal export support through the facilitation of empty containers.\\nAdditional costs (if applicable):\\n- First-mile delivery service by truck within Addis Ababa or Modjo and surrounding areas, originating from warehouses or any other places designated by the Client, shall incur an additional cost fully covered by the Client.\\n- For clients utilizing EDR''s first- or last-mile logistics services, the applicable charges shall vary based on the cargo movement route.\\n- The charge for first-mile delivery to Galaan Multipurpose Port and Modjo dry port shall be communicated to the Client by the Service Provider after receiving the necessary details regarding the cargo origin, type, and weight.\\n- For any vessel outbound charges, IMO charges, or other fees not included in the port handling payment, the Service Provider shall request the Client to settle the required amount based on the official receipt issued by the port or the shipping line.\\nPayment terms:\\n- All charges, including rail transport and customs clearance charges, remain 100% payable in advance.\\n- Payments shall be calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date the wagon or train number is provided.\\n- If the exchange rate changes between the payment and the wagon assignment date, adjustments will be made accordingly.\\n- Any additional costs incurred due to customs issues or port delays shall be borne by the Client and paid based on actual costs, supported by official receipts, within 10 days.\\n- Late payment incurs a penalty of 10%.", "order": 5, "title": "Pricing and Payment Terms"}, {"id": "contract-documents", "body": "The following documents shall constitute the contract between the Client and the Service Provider:\\n- Any amendments made to this contract (if applicable).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if applicable).\\nIn the event of any discrepancy between these documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "Consignment Note (cargo handover document).\\nPayment summary prepared as per the agreed tariff, if required.", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over and handing over of the container cargo on the Freight Carriage Acceptance Sheet of EDR in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the container cargo by the Service Provider and of the kind, number, and weight of the goods.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 8, "title": "Consignment Notes"}, {"id": "amendment", "body": "This contract can be amended by mutual agreement.\\nNotwithstanding the above, the Service Provider may revise transport tariffs due to operational and regulatory changes by providing at least five (5) working days'' prior written notice to the Client.", "order": 9, "title": "Amendment"}, {"id": "termination", "body": "The contract may be terminated:\\n- By mutual agreement.\\n- Upon completion of the contract period or agreed cargo shipments.\\n- If either party breaches fundamental terms.\\nIf terminated for cause, the terminating party must issue a 15-day written notice specifying the breach and allow an opportunity to cure, if applicable.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract is valid once signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "Valid until August 31, {{contractYear}}, with a possible extension upon mutual agreement.", "order": 12, "title": "Contract Period"}, {"id": "disputes", "body": "Disputes shall be settled amicably.\\nIf amicable settlement fails, disputes shall be submitted to the Federal Court located in Addis Ababa.\\nThe signatories confirm that they are fully authorized to sign and execute this Contract Agreement; the power of attorney of the signatories for the parties is enclosed with this contract agreement.", "order": 13, "title": "Settlement of Disputes"}, {"id": "customs-clearing", "body": "The Service Provider shall carry out customs clearing on behalf of the Client for the cargo covered by this Agreement, including declaration, lodgement, and follow-up at the customs stations of Djibouti and Ethiopia as applicable to the agreed corridor.\\nThe Service Provider shall act only within the authority granted by the Client and shall not amend a declaration without the Client''s written instruction.\\nCustoms duties, taxes, and any government charges assessed on the cargo remain payable by the Client and are not included in the freight price; the Service Provider shall settle them on the Client''s behalf only where the Client has placed the corresponding funds in advance.\\nThe Service Provider shall hand over all customs documents obtained in the course of clearing to the Client upon completion of each shipment.", "order": 14, "title": "Customs Clearing Services"}, {"id": "customs-client-duties", "body": "Grant the Service Provider a duly signed and stamped power of attorney authorising it to act as the Client''s customs agent for the duration of this Agreement.\\nSubmit every document required for declaration (commercial invoice, packing list, bill of lading or airway bill, permits, certificates of origin, and any authority-specific licence) within one (1) calendar day of the Service Provider''s request.\\nWarrant that the declared description, quantity, value, and tariff classification of the cargo are complete and accurate.\\nBear any penalty, demurrage, storage, or re-inspection cost arising from incorrect, incomplete, or late Client-supplied information or documentation.\\nSettle assessed duties and taxes within the period notified by the Service Provider, failing which the Service Provider may suspend clearing and the cargo shall remain at the Client''s risk and cost.", "order": 15, "title": "Client Obligations for Customs Clearing"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('79b1c17d-ae24-4945-98c5-ec3f58823ce7', 'EXPORT_CONTAINER_NO_CUSTOMS', 'Container Export Contract (without customs clearing)', 'Export container transport, freight forwarding, and customs clearing from Galaan Multipurpose Port or Modjo dry port to SGTD container freight station (Djibouti). Customs clearing is handled by the Client.', 'Export Container Transport, Freight Forwarding and Customs Clearing Service', '["The parties have agreed on the following services: rail transport, customs clearance, transit work, freight forwarding, and handling of container cargo."]', '[{"id": "objective", "body": "Customs clearance (Ethiopia side):\\n- Processing of export declarations.\\n- Coordination with the Ethiopian Customs Authority for clearance.\\n- Ensuring compliance with all export regulations.\\nRail transport:\\n- Transportation of containers from Galaan Multipurpose Port (GMP) or Modjo dry port to SGTD container freight station.\\nDjibouti transit and handling:\\n- Customs clearance in Djibouti.\\n- Coordination with Djibouti port and transit authorities.\\n- Freight forwarding and last-mile facilitation as required.\\nExcluded costs:\\n- Shore handling.\\n- Shifting of containers from SGTD to DMP or DMP to SGTD port.", "order": 1, "title": "Objective and Scope of the Services"}, {"id": "client-obligations", "body": "Give written/email instructions to the Service Provider for transportation of containers from Galaan Multipurpose Port (GMP) and/or Modjo to Djibouti.\\nSupply a minimum of two (2) 20ft containers (or an equivalent load to fill one flat wagon).\\nSubmit all forwarding service booking requests at least seventy-two (72) hours prior to the scheduled train departure and no later than 7 days before the vessel cut-off time, whichever is applicable.\\nFor clients requiring first-mile service, submit a first-mile service request notice no less than seventy-two (72) hours in advance.\\nComplete and submit accurate export documents as per the request of the Service Provider; payment must be submitted at least 36 hours before train departure.\\nDeliver all cargo to the designated loading port or freight station at least three (3) hours prior to the scheduled train loading time.\\nFailure to meet the stated deadlines may result in cancellation of the booking and transfer arrangements; any resulting delays, penalties, or additional costs shall be the sole responsibility of the Client.\\nIf the Client fails to deliver the container, fails to provide the requested documents for completing export documents as instructed above, or cancels after wagon reservation, the Client shall pay USD 150.00 per wagon as a penalty, after notification.\\nContainers must have four (4) undamaged corners.\\nOne flat wagon must carry either one 40ft container or two 20ft containers.\\nIf two 20ft containers are loaded on one flat wagon, their weight difference must not exceed 10 tons.\\nThe gross weight of the container must not exceed the standard loading capacity indicated on the container; the Client is responsible for ensuring full compliance with the maximum allowable load.\\nProhibited cargo: cargo covered with tarpaulin is not allowed due to safety risks.\\nIf the cargo to be transported is dangerous and/or valuable goods, notify the Service Provider 48 (forty-eight) hours before the wagon booking for further discussion and decision.\\nRefund requests before wagon booking require an official request, with a 3% administrative fee deducted. If the refund is due to the Service Provider, the Client shall receive a full refund. Refunds not requested and completed within six months shall be considered waived.\\nAny delay caused by missing or incorrect documents shall be the Client''s responsibility.\\n100% of the transportation and customs clearance fee must be paid in advance.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Complete gate pass processing and submit to Nagad Station for each shipment within eighteen (18) hours after train departure.\\nThe Service Provider reserves the right to refuse the transportation of any cargo classified as dangerous goods.\\nMaintain cargo liability insurance for railway transport; additional insurance for port handling or last-mile transport shall be the Client''s responsibility.\\nThe Service Provider is not liable for customs penalties or demurrage due to delays beyond its control.\\nNotify the Client immediately, in writing, of any delays, port issues, or customs holds.\\nThe Service Provider shall not be liable for:\\n- Inherent defects of the cargo.\\n- Improper packing or loading conducted by the Client.\\n- Customs-related delays.\\n- Delays caused by force majeure events.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The railway transportation charges and the freight forwarding and customs clearance charges for each corridor (per 40ft container and per two 20ft containers) are set out in the Rate Schedule immediately below, expressed as unit prices per origin → destination lane and per container.\\nWhere the total cargo weight exceeds fifty (50) metric tons per two (2) 20ft containers, an additional charge shall apply for each excess metric ton at the overweight rate set out in the Rate Schedule.\\nFor consolidated containers containing more than one (1) shipping document, the first document shall be included under the agreed contract rate; any additional document within the same container shall be subject to the extra-document charge set out in the Rate Schedule.\\nPayment must be supported by an official receipt before cargo departs from Galaan Multipurpose Port/Modjo.\\nIf the Client uses PIL Shipping Line, any local charge incurred will be covered by the Client as per the invoice issued by the shipping line.\\nIf storage or demurrage occurs due to Client-related issues (delay in document submission, payment delay, or any other Client-related reason), the Client shall pay the corresponding charges; charges apply per day after the free storage period, based on the invoice and SGTD tariff.\\nDuring export season, EDR may provide seasonal export support through the facilitation of empty containers.\\nAdditional costs (if applicable):\\n- First-mile delivery service by truck within Addis Ababa or Modjo and surrounding areas, originating from warehouses or any other places designated by the Client, shall incur an additional cost fully covered by the Client.\\n- For clients utilizing EDR''s first- or last-mile logistics services, the applicable charges shall vary based on the cargo movement route.\\n- The charge for first-mile delivery to Galaan Multipurpose Port and Modjo dry port shall be communicated to the Client by the Service Provider after receiving the necessary details regarding the cargo origin, type, and weight.\\n- For any vessel outbound charges, IMO charges, or other fees not included in the port handling payment, the Service Provider shall request the Client to settle the required amount based on the official receipt issued by the port or the shipping line.\\nPayment terms:\\n- All charges, including rail transport and customs clearance charges, remain 100% payable in advance.\\n- Payments shall be calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date the wagon or train number is provided.\\n- If the exchange rate changes between the payment and the wagon assignment date, adjustments will be made accordingly.\\n- Any additional costs incurred due to customs issues or port delays shall be borne by the Client and paid based on actual costs, supported by official receipts, within 10 days.\\n- Late payment incurs a penalty of 10%.", "order": 5, "title": "Pricing and Payment Terms"}, {"id": "contract-documents", "body": "The following documents shall constitute the contract between the Client and the Service Provider:\\n- Any amendments made to this contract (if applicable).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if applicable).\\nIn the event of any discrepancy between these documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "Consignment Note (cargo handover document).\\nPayment summary prepared as per the agreed tariff, if required.", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over and handing over of the container cargo on the Freight Carriage Acceptance Sheet of EDR in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the container cargo by the Service Provider and of the kind, number, and weight of the goods.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 8, "title": "Consignment Notes"}, {"id": "amendment", "body": "This contract can be amended by mutual agreement.\\nNotwithstanding the above, the Service Provider may revise transport tariffs due to operational and regulatory changes by providing at least five (5) working days'' prior written notice to the Client.", "order": 9, "title": "Amendment"}, {"id": "termination", "body": "The contract may be terminated:\\n- By mutual agreement.\\n- Upon completion of the contract period or agreed cargo shipments.\\n- If either party breaches fundamental terms.\\nIf terminated for cause, the terminating party must issue a 15-day written notice specifying the breach and allow an opportunity to cure, if applicable.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract is valid once signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "Valid until August 31, {{contractYear}}, with a possible extension upon mutual agreement.", "order": 12, "title": "Contract Period"}, {"id": "disputes", "body": "Disputes shall be settled amicably.\\nIf amicable settlement fails, disputes shall be submitted to the Federal Court located in Addis Ababa.\\nThe signatories confirm that they are fully authorized to sign and execute this Contract Agreement; the power of attorney of the signatories for the parties is enclosed with this contract agreement.", "order": 13, "title": "Settlement of Disputes"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +INSERT INTO freight.contract_templates (id, code, name, description, document_title, whereas_clauses, articles, is_active, created_at, updated_at, deleted_at) VALUES ('cfbe197f-0e08-4af1-8622-8442fda8a170', 'INTERCITY_CONTAINER', 'Container Intercity Contract', 'Domestic (intercity) container transport by railway between Ethiopian terminals — Galaan Multipurpose Port, Modjo dry port, and Dire Dawa — including empty repositioning.', 'Intercity Container Transport Service by Railway', '["The Client has requested and agreed to the transportation of container cargo between the agreed Ethiopian railway terminals (Galaan Multipurpose Port (GMP), Modjo dry port, and Dire Dawa), including the repositioning of empty containers between those terminals, using the Addis Ababa–Djibouti railway line within Ethiopia.", "The Service Provider has agreed to transport the container cargo as per the terms of this contract."]', '[{"id": "objective", "body": "To provide domestic railway transportation services for 40ft and/or 20ft full containers between the agreed Ethiopian terminals (Galaan Multipurpose Port (GMP), Modjo dry port, and Dire Dawa), and the repositioning of empty containers between those terminals.\\nThe scope of the services comprises:\\n- Railway transport service between the agreed origin and destination terminals.\\n- Cargo handling at Galaan Multipurpose Port (GMP).", "order": 1, "title": "Objective and Scope of the Services"}, {"id": "client-obligations", "body": "Give written/email/electronic shipment instructions to the Service Provider for transportation of container cargo between the agreed terminals.\\nPrepare all necessary documents and facilities for shipment.\\nEnsure the minimum supply of containers per shipment agreed with the Service Provider for the selected loading terminal and destination.\\nOne flat wagon must carry either one 40ft container or two 20ft containers.\\nIf two 20ft containers are loaded on one flat wagon, their weight difference must not exceed 10 tons.\\nEnsure timely loading and unloading of cargo.\\nAssign representatives at both ends to oversee container handover and ensure the necessary arrangements for cargo reception at the destination upon arrival.\\nMaintain and provide detailed cargo information (type, weight, destination, etc.).\\nBe responsible for cargo handling, loading, and unloading of both empty and full containers at Modjo and Dire Dawa dry port.\\nBook wagons at least five (5) days in advance.\\nEnsure containers are ready one day before the planned loading date.\\nCollect the full container from Galaan Multipurpose Port (GMP) within three (3) calendar days from the day following the arrival notice.\\nIf the Client fails to collect the container within the specified period, the Service Provider shall have the right to reposition the container to any location it deems appropriate; in such case, the Service Provider shall not be held responsible for any damage or loss arising from such repositioning.\\nIf the Client fails to collect the container from Galaan Multipurpose Port within the specified period, the Client shall be liable to pay demurrage charges of 15 USD per day per 20ft container and 27 USD per day per 40ft container, calculated based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date of payment.\\nIn the event the Client fails to collect the container(s) within the specified period, the Client shall be liable to pay double handling charges of 27 USD per 20ft container per handling or 40 USD per 40ft container per handling.\\nCollect the containers within one day at Dire Dawa and Modjo dry port, or make the necessary payment to the dry port as per the standard of the dry port.\\nOnce empty containers are returned from the Client''s premises and stored at a dry port while awaiting train allocation, any demurrage and/or storage charges incurred from the dry port thereafter shall be the sole responsibility of the Client.\\nProvide clean empty containers that meet the receiving terminal''s standards; additional cleaning costs incurred due to non-compliance will be borne by the Client.\\nEnsure containers are structurally intact and meet weight distribution requirements.\\nProhibited cargo: cargo covered with tarpaulin is not allowed due to safety risks.\\nNotify the Service Provider forty-eight (48) hours in advance before wagon booking if transporting hazardous or valuable goods.\\nIf a booked wagon is not loaded due to Client-related issues, including but not limited to a damaged container, missing lock, unpaid demurrage, port system errors, or incomplete documentation and submission, the Client shall be charged 100% of the total price of the reserved wagon.\\nRefund requests before wagon booking require an official request, with a 3% administrative fee deducted. If the refund is due to the Service Provider, the Client shall receive a full refund. Refunds not requested and completed within six months shall be considered waived.\\nPay 100% of the transportation fee in advance for each train set.\\nSettle additional penalties due to non-compliance within ten (10) days of invoice issuance.\\nLate payment incurs a penalty of an additional 10%.", "order": 2, "title": "Obligations of the Client"}, {"id": "provider-obligations", "body": "Assign the necessary voyage based on the operational schedule and cargo demand, and notify the train schedule 48 hours in advance.\\nProvide a list of wagons/voyage or train number 24 hours in advance and update corrections 12 hours before arrival.\\nProvide safe transportation of the containers.\\nDeliver the cargo within two (2) days after train departure, provided that all required documents are submitted on time and no unforeseen circumstances or events occur.\\nIn the event of export cargo operations, the Service Provider may prioritize the loading of export containers during the loading of empty containers and the unloading of containers from the train at Galaan Multipurpose Port.\\nThe Service Provider reserves the right to refuse the transportation of any cargo classified as dangerous goods.\\nIf any operational, technical, or mechanical problem occurs throughout the transit, notify the Client and the relevant authorities and arrange cargo transfer within four (4) days.\\nProvide accident or defect reports if needed.\\nBuy cargo liability insurance for each wagon.", "order": 3, "title": "Obligations of the Service Provider"}, {"id": "force-majeure", "body": "Neither party shall be liable for delays or non-performance caused by force majeure events beyond their reasonable control.\\nForce majeure shall be interpreted in accordance with the Ethiopian Civil Code.", "order": 4, "title": "Force Majeure"}, {"id": "pricing", "body": "The applicable rate per 40ft container or per two (2) 20ft containers for the agreed route is set out in the Rate Schedule immediately below, expressed as a unit price per origin → destination lane and per container.\\nIf cargo exceeds 40 tons per two 20ft containers of gross weight, additional charges apply proportionally.\\nGross weight shall be the total sum of cargo, packing, and container tare weight.\\nPayment for any additional tonnage shall be made in advance before the container is loaded onto the wagon.\\nThe price of loading and unloading and container handling at Modjo and Dire Dawa dry port is not part of this contract; it is the Client''s responsibility.\\nAdditional costs (if applicable):\\n- Last-mile delivery service by truck from the destination terminal to the Client''s premises shall incur an additional cost, fully covered by the Client.\\n- For clients utilizing EDR''s last-mile logistics services, the applicable charges shall vary based on the cargo movement route and shall be communicated to the Client by the Service Provider after receiving the necessary details regarding the cargo destination, type, and weight.\\nAll payments shall be made one hundred percent (100%) in advance.\\nPayment may be made in Ethiopian Birr based on the Commercial Bank of Ethiopia''s daily selling exchange rate on the date the wagon or train number is provided; if the exchange rate changes between the payment and the wagon assignment date, adjustments will be made accordingly.", "order": 5, "title": "Contract Price and Terms of Payment"}, {"id": "contract-documents", "body": "The following documents constitute this contract:\\n- Amendments (if any).\\n- This Contract Agreement.\\n- Final minutes of negotiation (if any).\\nIf there is any discrepancy between the documents, they shall be interpreted with priority in the order listed above.", "order": 6, "title": "Contract Documents"}, {"id": "documentation", "body": "Equipment Interchange Receipt, Railway Waybill, Container Carriage Acceptance Sheet, and incidental charges (if any).\\nPayment summary as per the agreed contract price (if required).", "order": 7, "title": "Documentation Requirements"}, {"id": "consignment-notes", "body": "The Service Provider must certify the taking over and handing over of the container cargo on the Freight Carriage Acceptance Sheet of EDR in an appropriate manner and provide it to the Client.\\nThe Freight Carriage Acceptance Sheet shall be prima facie evidence of the receipt of the container cargo by the Service Provider and of the kind, number, and weight of the goods.\\nUpon delivery of the cargo to the Client, the Cargo Handover Out Voucher signed by both parties shall serve as evidence of cargo receipt.", "order": 8, "title": "Consignment Notes"}, {"id": "amendment", "body": "This contract can be amended by mutual agreement.\\nNotwithstanding the above, the Service Provider may revise transport tariffs due to operational and regulatory changes by providing at least five (5) working days'' prior written notice to the Client.", "order": 9, "title": "Amendment"}, {"id": "termination", "body": "The contract may be terminated:\\n- By mutual agreement.\\n- Upon completion of the contract period or agreed cargo shipments.\\n- If either party breaches fundamental terms.", "order": 10, "title": "Termination of Contract"}, {"id": "effectiveness", "body": "The contract is valid once signed by both parties.", "order": 11, "title": "Contract Effectiveness"}, {"id": "duration", "body": "Valid until August 31, {{contractYear}}, with a possible extension upon mutual agreement.", "order": 12, "title": "Contract Period"}, {"id": "disputes", "body": "Disputes shall be settled amicably.\\nIf unresolved, disputes shall be taken to the Federal Court in Addis Ababa.", "order": 13, "title": "Settlement of Disputes"}]', true, '2026-08-05 07:31:08.510384+00', '2026-08-05 07:31:08.510384+00', NULL); +`, + dropdown_settings: ` +INSERT INTO freight.dropdown_settings (id, code, label, description, multiple, meta, created_at, updated_at, deleted_at) VALUES ('7d01044c-0f2b-497d-ad1a-781c1b82f2b1', 'general_contract_period', 'General Contract Period (months)', 'How many months a general contract stays open for ordering after activation.', false, NULL, '2026-08-05 07:31:06.89436+00', '2026-08-05 07:31:06.89436+00', NULL); +INSERT INTO freight.dropdown_settings (id, code, label, description, multiple, meta, created_at, updated_at, deleted_at) VALUES ('a24f1cf9-4c8b-4347-9454-417dd425925c', 'contract_validity_periods', 'Contract Validity Periods (days)', 'Validity durations (in days) a staff can choose when accepting a submitted contract.', false, NULL, '2026-08-05 07:31:06.898804+00', '2026-08-05 07:31:06.898804+00', NULL); +INSERT INTO freight.dropdown_settings (id, code, label, description, multiple, meta, created_at, updated_at, deleted_at) VALUES ('52a2969a-d720-4c4b-87f5-e710ca5008f2', 'ro_vessel_min_days', 'RO vessel minimum lead time (days)', 'Minimum days between today and the vessel departure date on an export Release Order.', false, NULL, '2026-08-05 07:31:07.906349+00', '2026-08-05 07:31:07.906349+00', NULL); +INSERT INTO freight.dropdown_settings (id, code, label, description, multiple, meta, created_at, updated_at, deleted_at) VALUES ('e1fb2dfd-f166-4dd7-8b93-339b296c487b', 'import_train_numbers', 'Import train numbers', 'Even IMPORT run numbers (Djibouti → Ethiopia) selectable when building a train. The paired export number is derived automatically (import − 1).', false, '{"clearable": true, "searchable": true}', '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +`, + dropdown_options: ` +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('ec8b7dce-6c1a-4a55-80e6-e455d743747f', '7d01044c-0f2b-497d-ad1a-781c1b82f2b1', '3', '3 months', NULL, false, 0, NULL, '2026-08-05 07:31:06.89436+00', '2026-08-05 07:31:06.89436+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('aedbb6db-51bc-4b0e-98e9-a366afb97fa2', 'a24f1cf9-4c8b-4347-9454-417dd425925c', '180', '6 months', NULL, false, 0, NULL, '2026-08-05 07:31:06.898804+00', '2026-08-05 07:31:06.898804+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('0abee7ce-91c7-4f09-afa9-e33aa8e3de58', 'a24f1cf9-4c8b-4347-9454-417dd425925c', '365', '1 year', NULL, false, 1, NULL, '2026-08-05 07:31:06.898804+00', '2026-08-05 07:31:06.898804+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('2191ce22-9746-47bf-b799-6355bf4e24d6', 'a24f1cf9-4c8b-4347-9454-417dd425925c', '730', '2 years', NULL, false, 2, NULL, '2026-08-05 07:31:06.898804+00', '2026-08-05 07:31:06.898804+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('bff86860-2ce7-43bb-a27a-b1ce1bbf41c8', '52a2969a-d720-4c4b-87f5-e710ca5008f2', '2', '2 days', NULL, false, 0, NULL, '2026-08-05 07:31:07.906349+00', '2026-08-05 07:31:07.906349+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('4e9c93ae-b530-4165-abec-6396b859b07a', '52a2969a-d720-4c4b-87f5-e710ca5008f2', '3', '3 days', NULL, false, 1, NULL, '2026-08-05 07:31:07.906349+00', '2026-08-05 07:31:07.906349+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('c5235b46-77c0-4525-8ff6-3e601575da3e', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8002', '8002', NULL, false, 0, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('7801c5fb-d32b-45ca-bf5b-2d5cf6151d85', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8102', '8102', NULL, false, 1, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('efc5f757-fe78-48a6-885f-e15240b204af', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8202', '8202', NULL, false, 2, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('a20cfe92-ebe3-4a61-9cdc-0da9026a54a2', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8302', '8302', NULL, false, 3, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('cb9e619e-8170-423e-80b4-b9a93812f197', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8402', '8402', NULL, false, 4, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('041fba86-4b7a-4d92-b2ad-fe1a36d74a5e', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8502', '8502', NULL, false, 5, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('a2c8bbd2-d538-4cb1-a68f-fa8e6a65fdda', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8602', '8602', NULL, false, 6, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('aac4f7ce-2cd1-4ae3-9f3f-3d88c29101c1', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8702', '8702', NULL, false, 7, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('832e6846-52ab-4945-83cf-9b085007f267', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8802', '8802', NULL, false, 8, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('fe334532-c484-4ba3-be02-bea841824b3e', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '8902', '8902', NULL, false, 9, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +INSERT INTO freight.dropdown_options (id, setting_id, value, label, note, is_disabled, display_order, meta, created_at, updated_at, deleted_at) VALUES ('252f6260-2940-4cc6-a758-348a27f75ac0', 'e1fb2dfd-f166-4dd7-8b93-339b296c487b', '9002', '9002', NULL, false, 10, NULL, '2026-08-05 07:31:09.035777+00', '2026-08-05 07:31:09.035777+00', NULL); +`, + exchange_settings: ` +INSERT INTO freight.exchange_settings (id, fallback_rate, fallback_source, last_synced_at, updated_by_id, created_at, updated_at, deleted_at) VALUES ('d095c92e-01c4-4ad7-bfe0-782124a9c4b6', 162.416500, 'AUTO', NULL, NULL, '2026-08-05 07:31:09.389185+00', '2026-08-05 07:31:09.389185+00', NULL); +`, + priority_configs: ` +INSERT INTO freight.priority_configs (id, type, label, currency, min_wagon_count, max_wagon_count, score_points, is_active, display_order, created_at, updated_at, deleted_at) VALUES ('56b3b5b4-e6f0-435c-b275-fe03cc6e100a', 'CUSTOMS', 'With customs 1–10 wagons', NULL, 1, 10, 7, true, 1, '2026-08-05 07:31:08.406818+00', '2026-08-05 07:31:08.406818+00', NULL); +INSERT INTO freight.priority_configs (id, type, label, currency, min_wagon_count, max_wagon_count, score_points, is_active, display_order, created_at, updated_at, deleted_at) VALUES ('79c1a2b1-e98f-4142-9093-56003d354f25', 'CUSTOMS', 'With customs 11–53 wagons', NULL, 11, 53, 15, true, 2, '2026-08-05 07:31:08.406818+00', '2026-08-05 07:31:08.406818+00', NULL); +`, + service_types: ` +INSERT INTO freight.service_types (id, service_name, description, can_be_booked_alone, includes_first_mile, includes_last_mile, includes_customs, is_active, display_order, created_at, updated_at, deleted_at, code) VALUES ('c5913b29-579c-4d09-a701-c9e9f20c9770', 'Rail Transport Only', NULL, true, false, false, false, true, 1, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, 'RAIL'); +`, + train_scheduling_global_rules: ` +INSERT INTO freight.train_scheduling_global_rules (id, max_train_length_meters, max_train_weight_tons, max_wagons_per_train, max_20ft_container_weight_tons, max_20ft_pair_weight_diff_tons, created_at, updated_at, deleted_at, import_window_lead_days, export_booking_lead_hours, window_open_hour, window_duration_hours, doc_review_minutes, payment_window_minutes, window_close_hour, import_close_offset_minutes, export_close_offset_minutes, export_payment_window_minutes) VALUES ('bf410357-b2ce-4c29-bb8e-1e1d7d8806a7', 760.00, 3500.000, 53, 30.000, 10.000, '2026-08-05 07:31:05.884714+00', '2026-08-05 07:31:05.884714+00', NULL, 3, 24, 8, 3.0000, 30, 60, 17, NULL, NULL, 60); +`, + truck_types: ` +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('f38f5b28-96a3-4e23-b238-2770a33da95a', 'TRUCK', 'Truck', NULL, true, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('5fad6cd6-3b75-4ec8-b6cf-475d7943662d', 'TRAILER', 'Trailer', NULL, true, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('4e78fe5f-3c17-403d-9872-5c210f314d13', 'TANKER', 'Tanker', NULL, true, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('c45f7bd3-0807-4243-a215-59d79d81bc31', 'FLATBED', 'Flatbed', NULL, true, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('00ca6ed9-068c-4ef5-88e3-ad50796ae2a2', 'VAN', 'Van', NULL, false, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('2a9b9d14-490b-4575-b6d6-c2a3bd5f03c7', 'CAR', 'Car', NULL, false, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('27d7481e-6545-4bb5-b72e-b39839e56ac3', 'BUS', 'Bus', NULL, false, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +INSERT INTO freight.truck_types (id, code, name, capacity_tons, has_trailer, description, is_active, created_at, updated_at, deleted_at) VALUES ('773c5365-1288-4999-b8b1-67d88f380e08', 'CASONI', 'Casoni (rigid, no trailer)', NULL, false, NULL, true, '2026-08-05 07:31:09.136545+00', '2026-08-05 07:31:09.136545+00', NULL); +`, + wagon_types: ` +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('2bd636b7-3951-4164-a2c6-fe364a8110c0', 'NW7', 'Double deck sedan wagon', 22.000, 26.066, '{vehicles,sedan}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, NULL, 37.100, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('f7886975-ba6f-422d-8de4-e672c8482699', 'NW5', 'Flat wagon', 70.000, 13.966, '{container,steel,machinery}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, 1.300, 22.400, true, 30.480); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('ba981b9b-972e-4301-a857-aafbb35612e0', 'PW2', 'Box wagon', 70.000, 17.066, '{"general cargo","break bulk"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, 1.600, 25.200, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('9fe9a541-6245-4d25-b17d-68aa5f74dcf5', 'GW2', 'Tank wagon', 70.000, 12.228, '{liquid,fuel}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, NULL, 23.000, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('7b5d91ee-d36c-4383-a27b-3b65179d568d', 'CW4', 'Gondola covered wagon', 70.000, 13.976, '{"covered bulk cargo"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, 1.300, 24.800, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', 'CW3', 'Gondola open wagon', 70.000, 13.976, '{"open bulk cargo"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, 1.300, 23.400, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('20cd13b8-6992-4f9d-86ba-da6cfbbf2527', 'KW2', 'Hopper covered wagon', 69.000, 16.466, '{"bulk grains"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, 1.500, 25.200, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('02f1d786-e4c5-49a8-9e88-8d09f3e1a903', 'KW3', 'Hopper wagon open', 70.000, 14.400, '{coal,"bulk cargo"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, NULL, 24.000, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', 'NW6', 'Flat wagon (long)', 70.000, 18.560, '{"long cargo"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, NULL, 25.300, false, NULL); +INSERT INTO freight.wagon_types (id, code, name, capacity_tons, length_meters, supported_load_types, is_active, created_at, updated_at, deleted_at, equated_length_m, tare_weight_tons, supports_container, max_container_gross_t) VALUES ('efcee536-852b-4532-a6c6-bd2dd4f5e10e', 'BW1', 'Refrigerated wagon', 38.000, 21.996, '{"refrigerated cargo"}', true, '2026-08-05 07:31:05.293615+00', '2026-08-05 07:31:06.108196+00', NULL, NULL, 32.100, false, NULL); +`, + yards: ` +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('ef184178-12ee-4657-a13b-aabce861912f', 'KALITY', 'Kality Rail Terminal', 'Ethiopia', true, 1, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('4aa63253-57a2-4ab1-a783-09eb501a08a9', 'MOJO', 'Mojo Dry Port', 'Ethiopia', true, 2, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('b2c4fc10-2a24-4898-82f9-0a81f2783c7a', 'DIRE_DAWA', 'Dire Dawa Yard', 'Ethiopia', true, 3, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('d99d1607-e0c1-4af2-9f21-a76b2ad493ac', 'DJIB_PORT', 'Djibouti Port Terminal', 'Djibouti', true, 4, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('d8aa7ef7-7ec6-44bf-8342-88aec811ac6a', 'NAGAD', 'Nagad Terminal, Djibouti', 'Djibouti', true, 5, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('f07a71e1-0631-4779-b160-42f01060ca29', 'LEGACY_ORIGIN', 'Legacy Origin', 'Ethiopia', true, 99, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('f6962f85-305e-4e90-9226-f6cc191cb8f7', 'LEGACY_DEST', 'Legacy Destination', 'Ethiopia', true, 100, '2026-08-05 07:31:04.600266+00', '2026-08-05 07:31:04.600266+00', NULL, false); +INSERT INTO freight.yards (id, code, label, country, is_active, display_order, created_at, updated_at, deleted_at, has_facility) VALUES ('bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', 'DORALEH', 'Doraleh', 'Djibouti', true, 12, '2026-08-05 07:31:08.870506+00', '2026-08-05 07:31:08.870506+00', NULL, false); +`, + wagons: ` +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('efceade8-da1c-4990-b3a4-af59e74a4de5', 'ER0001', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f087a26c-ac84-453c-8bb9-e54a8928bcc4', 'ER0002', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('04ec17f9-b396-433b-bee3-a82de0c16bed', 'ER0003', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c7c605fd-d6d3-437f-b93c-a646751b5f0f', 'ER0004', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('feda7bce-0c97-4af4-bebc-19e4273c4828', 'ER0005', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5b9065d8-566f-4f0e-a584-4ff1115f64aa', 'ER0220', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('843b1eb5-5eb9-493f-a3e3-5b88cedb6128', 'ER0222', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d21f91c9-ebe2-4dcb-95d8-0bcaed76ab34', 'ER0223', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('092a99b6-1b56-426e-82a1-e446d64a0408', 'ER0226', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a462dbdd-59bc-46bb-bb64-094aab773a62', 'ER0228', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('65b77a30-cb40-489c-b7fe-158c4b0aab94', 'ER0230', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('db500cb6-f7dd-46cb-a732-2cc0b9fa4501', 'ER0235', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1353b30e-117f-4449-b00a-8d45adcf0ab4', 'ER0237', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a67a8541-9258-4049-97a5-5708790c6dba', 'ER0238', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('46d60f75-eafe-45ca-a0a7-3fb819272d9d', 'ER0239', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a4231843-d2ed-45c3-a0e5-f9adb226302f', 'ER0240', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5a54156e-3c4c-4f63-86a1-fc26f0cf71b0', 'ER0241', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c17def2a-9c74-4800-a9c7-ef6170bc0e8d', 'ER0242', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('75dfb8ba-ebc3-41bc-a937-97868d2d6c3f', 'ER0244', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6117b8b2-f7b3-416b-8ec6-a832b610ee5c', 'ER0245', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7231acc8-c44a-4578-973a-793902f23f8f', 'ER0246', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6665c422-1ca2-4c69-9893-cb46fe86cb3b', 'ER0247', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('95fa646f-cebb-4160-adec-86c21675d765', 'ER0248', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d4581d3f-18e8-4bf0-9a76-799a309db932', 'ER0249', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6597927a-f846-437c-9652-18893dc269c0', 'ER0252', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ae81a93e-10f1-40c6-b3b9-965155532157', 'ER0253', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4af8534c-f937-478a-9618-512271dc3f3b', 'ER0255', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2ea47018-c73f-48e6-b2fa-967ef5fd58b2', 'ER0256', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('93d6f746-8843-4907-bc2e-d9afbfc60517', 'ER0258', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('09d84453-9408-423e-b4c3-94687b7e13cb', 'ER0260', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('200e08b2-fa95-4e42-b25e-dff0b00fd73a', 'ER0261', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d2da6f6d-c094-4a50-b168-fa2bc7dc6497', 'ER0265', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe9b0f33-d994-4872-9109-355a04b046d4', 'ER0267', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('898578dd-67b6-4fd6-8fbf-fd1c00dce2d4', 'ER0269', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5e680d5b-73cf-4b53-9ba5-c8115d6597c8', 'ER0295', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b6195ff9-a4ff-4908-a76f-7b37ebd58e27', 'ER0296', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('25ab7769-d72c-4ab0-b131-5d32b76a7652', 'ER0297', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4f3aa099-255f-4826-ac67-842c13db0c5a', 'ER0299', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9370378b-4610-4b81-8279-6c28bc4eb2fd', 'ER0301', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('81a7e9fd-82d6-4ff3-b57c-f8227d2e042b', 'ER0302', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('938cab4e-f51c-42c9-94e0-9ebd7ae71500', 'ER0303', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('108b055b-5308-4363-8709-c4d1baa1cf50', 'ER0304', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('01f0e001-4b3b-4b79-96b8-dc7d2d3cc974', 'ER0305', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('47f81b2c-be78-41e8-872d-9b2560e43a1a', 'ER0308', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('191f88c9-64d7-4ff3-9bb1-159b6cd3993c', 'ER0309', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('971ab325-5bc5-4dc9-b1e3-f244b40f3772', 'ER0311', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('197ca87b-1234-4422-a8a3-1b8d3e25f768', 'ER0312', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('16882d5a-4a81-4d37-93b0-e8b092b5efbc', 'ER0370', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('687aca49-626b-4221-a85f-fb4ef261c60f', 'ER0371', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cb807103-d185-4b18-9dd6-e3c4652220f1', 'ER0372', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3ba691b3-59d5-41dc-8372-77bfa58df017', 'ER0373', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e0fee328-7f50-41f0-aed2-2983fae71a0f', 'ER0374', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6efc8d31-f013-4c8e-9d80-8ecb118feb67', 'ER0375', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ead00684-c1ff-4436-9ff4-5a1c6c226b9d', 'ER0376', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe38f46c-5435-4264-8645-91c3787be639', 'ER0377', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d4274ca2-a77f-42b9-b46b-2600d434b1da', 'ER0378', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ab0f4ce0-ff11-48db-a460-453b367dd0da', 'ER0379', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('daa1e05c-5160-4a4c-87f5-386b1ae8f6e5', 'ER0380', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2a9e2cd-5f50-4b43-8838-40dfd44e8577', 'ER0381', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4798ff1b-0b5b-4e85-a1b7-ded6467e7678', 'ER0382', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('47d7370e-1f52-4096-bcba-78e83331fc9b', 'ER0383', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('778a0b73-e81d-4c7a-a3ec-f2f1e720deed', 'ER0384', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a47a9170-810b-41c7-a62d-5033df3af1fb', 'ER0385', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d0a2a138-be52-4546-ac1c-76b85e7b8af8', 'ER0386', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9917a998-e75f-4a2c-85ca-4221c286bbc7', 'ER0387', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('731e07f9-ab01-4b06-9f8f-28db7815e1a8', 'ER0388', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d5333661-a46d-4568-a183-2535fcf28c5f', 'ER0389', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6cd0288f-08d1-433f-85e4-6014b9927586', 'ER0390', '02f1d786-e4c5-49a8-9e88-8d09f3e1a903', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe9002ef-4073-4624-ab2a-1638b117caf0', 'ER0401', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('35925577-66ab-4cb3-86e9-66a6cfaeab5b', 'ER0426', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d67a08fb-e3f3-4d0c-aafd-bae17640133b', 'ER0427', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1a15874a-4776-4729-87ab-927ccbaede70', 'ER0438', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8ec6681f-6d82-4f95-84ac-f8c4cc85e440', 'ER0439', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1828d437-9d34-4141-8d8b-9b381bbac55a', 'ER0457', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8dbea1a0-8c04-4387-9431-f031c00411b3', 'ER0472', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('65089613-a418-44b6-835c-15cd66e0c299', 'ER0482', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('77286c81-bd2a-4a45-abef-0134249269c0', 'ER0493', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3f34e798-2a95-438d-ab82-e31d460cd885', 'ER0495', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a8791b74-a567-4003-9858-319dc53adc19', 'ER0509', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('386d99ff-459b-492f-8b78-59cda4227b4a', 'ER0510', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('99a6eb73-d7b2-4aae-891e-30738143d99f', 'ER0523', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('eca6f4fb-3096-4e11-b444-ccd3df4b8b89', 'ER0532', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8566f603-592c-457c-83a0-2370074d1a40', 'ER0534', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c6b5e39b-106f-4241-ab38-29d7a62a6db8', 'ER0535', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0ff382b7-952d-46f6-a630-040daec1af24', 'ER0543', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c767da8a-638f-43db-9065-e33d558b4504', 'ER0549', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c210de55-b995-4ce1-bb55-fbb8d71f82d7', 'ER0579', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7ed8b8b8-74fe-4ac1-a7c3-41cf0fe75282', 'ER0581', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9f896f23-0527-4a86-8400-d2881409c721', 'ER0586', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('96d0767c-050e-40ae-8aff-7b66a0b717c8', 'ER0595', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('118a28cd-3309-45b7-b5fc-78dc8b6018e3', 'ER0604', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f7120939-932d-4de5-9212-b4590d163eb6', 'ER0609', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2fe4bf7f-4d09-4997-a894-5e2404f90207', 'ER0611', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('58622396-b1e0-420a-a369-72e1e21465fe', 'ER0632', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4c6746fc-2a3e-45af-b5f4-25ba4026757d', 'ER0639', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('68842cde-2cc7-408b-94ee-2723c0e3ba51', 'ER0657', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('65c7159d-d0c4-4134-9d8f-65164f91aaf6', 'ER0687', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5e8d0e19-08b9-4149-afed-87989cc63587', 'ER0688', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fdfdcdc5-524b-49a1-af38-2eaf3aac0bd1', 'ER0690', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66c38cf9-26f9-4d53-96df-e7368ca3b29a', 'ER0696', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8c62e85c-dec3-4966-8815-b941822766c9', 'ER0701', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bd6a8ed1-a7ac-4bcd-8189-4866d6e41812', 'ER0708', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bb66f97c-eb52-441b-ac54-b86f4107da0e', 'ER0709', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('46ed9baf-1a6b-49ee-a318-37662e5a46ab', 'ER0710', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9319c6b6-df6b-4731-9bc5-17a0d15e29aa', 'ER0719', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('24e52947-9665-4ab1-99ed-2e6a2c21285e', 'ER0721', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b0f4aee1-3b2a-4bc2-8d00-a8a7f3e1c104', 'ER0722', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ca7aca7-bad6-40fd-b935-2b22d6953f56', 'ER0727', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8349164a-3138-4791-a7bd-6608115072fa', 'ER0731', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a84261d8-3a7c-4ea8-b4e7-5644f00a1485', 'ER0742', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('603c83b4-f8fa-4886-8ae2-b451a974146f', 'ER0745', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0946cfd4-6b82-4f74-8af7-eaf94f60ff93', 'ER0750', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('07ed91db-0975-40c8-92b5-fdcf0dcdc187', 'ER0757', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0ff14a93-438f-4fc9-a30a-cdfbc418240d', 'ER0773', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c3424af3-0228-4933-9824-a4dd334c7b6e', 'ER0779', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b6d617bf-13b9-47ea-9651-a0194cd33ade', 'ER0783', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ffe576b-1548-48cb-b95b-95fdfd8e3fca', 'ER0792', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('80e0df88-e536-4212-bbad-59422a3a7baf', 'ER0793', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3d25dd34-92a9-41c2-9bec-6e57ade1f91c', 'ER0813', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('209cede5-60c9-4518-bd34-a7a14c73fe92', 'ER0817', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('115be47f-b66d-4754-9cea-f548ae13669d', 'ER0828', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dc7f0316-22e8-42ae-a973-0fafb2963947', 'ER0829', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5cd52b73-f604-47aa-bc0b-7f1c0b346de6', 'ER0834', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7191777c-7e93-43ee-801d-0f03ee8d93d6', 'ER0848', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8de34884-3cbe-44e3-87e2-82920e9eda66', 'ER0856', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fd677c07-3cfb-4725-bef4-5a6bb51aa965', 'ER0860', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1552469c-786a-441a-a9a5-2b6c8835526e', 'ER0862', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('421cedae-de56-455a-b657-cb372a02a716', 'ER0867', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f8dd2362-8cc2-4801-aa3c-9a74fcb60785', 'ER0869', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4b99149a-1d00-4c78-827f-1f8cb1da56c2', 'ER0871', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bb326a6f-8fac-4d0f-9018-ee2b70d1b6ba', 'ER0875', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c3038cee-05b2-4749-b643-4bf1fd1468d2', 'ER0892', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a67f0c02-e4a7-40ac-8391-f591d8ad4c14', 'ER0931', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ab052975-5b46-41ca-b0a9-7129e5547e14', 'ER0932', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e69db4d2-72f5-40d1-88e6-ff49f980b11f', 'ER0938', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('16899bf0-1de4-4e2d-8f3f-698ba0c8c166', 'ER0941', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('09426b78-7102-4e62-b9cd-87c856e91c76', 'ER0942', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('73949863-70ec-413f-8d7c-d36f823b893e', 'ER0943', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b3125715-ac8a-4991-9008-22b138ea9347', 'ER0944', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('13801ab0-008c-4703-b0f6-352549395ec8', 'ER0945', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3b684e22-05bc-47ae-9de7-a215d9665928', 'ER0946', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('481de8fb-4a6d-4342-adff-41a80ff40486', 'ER0947', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f70ef069-e6ab-4228-9de0-28ed2cfe347c', 'ER0948', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d0db2798-fcfa-455d-90ba-9127eacd4948', 'ER0949', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2af890c0-5d36-47f1-a8db-f7daaec14d16', 'ER0950', 'efcee536-852b-4532-a6c6-bd2dd4f5e10e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('600984af-0ca5-4698-9bfc-1f79429ec45d', 'ER0951', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f17ae313-86d7-4144-abd3-9c9aa598d095', 'ER0952', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5ec4629f-958f-4f8b-9c3c-6ca4f855f237', 'ER0953', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2e8d4acc-2da4-4b51-ad26-4037d36e01be', 'ER0954', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bf29c94a-1d74-48a4-a018-2c8874ba2b0c', 'ER0955', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c0bed9de-b81b-428f-9ae2-f3b8b78c7423', 'ER0956', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('40e20038-34e3-47b9-b848-22c43cf33f05', 'ER0957', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8d6157d2-5e15-4798-a349-3c74317e86b1', 'ER0958', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e80818c0-cf2d-4bd5-9f9a-79c048ac6934', 'ER0959', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d4cbefd6-7b32-4784-aa57-7194baaacd9a', 'ER0960', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('255bc431-8eef-4480-afaf-19f0f85a5250', 'ER0961', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3db764c7-ec43-4e3b-adc4-800d1bc6fd8c', 'ER0962', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('85f4d239-7dba-42aa-8059-4d40f48ac325', 'ER0963', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('19abb8bf-30dd-4004-abde-d9029246a623', 'ER0964', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0e334a57-668f-42e6-a6ed-25a0dd10f55b', 'ER0965', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ba362c78-2a8c-47ae-85bf-83daa770d357', 'ER0966', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2d235929-bb5b-4204-aba3-aa4413115043', 'ER0967', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d24e0168-688a-4f8c-9e24-6068c23664be', 'ER0968', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3cc124d3-1aff-4ca3-bf24-ad0d62cb881d', 'ER0969', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4a1db9e4-0fd0-458a-bfe7-8b450b85d654', 'ER0006', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('29533a21-fb3a-4399-8e90-7261b625a802', 'ER0007', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('13030dac-eb8d-41e6-a4a6-dbd5ca6f2575', 'ER0008', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9387846e-7952-435f-977e-a4d19760788f', 'ER0009', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f09fc4a0-9110-49e5-be90-f5f12d2cd1f7', 'ER0010', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('93941159-85af-439f-a8ca-03c616b5ae82', 'ER0011', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3e7574c3-2010-4b2e-b7dc-7e5e46be672f', 'ER0012', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b3893de5-096d-45d5-90b3-4d21b2eaff52', 'ER0013', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('82ebe4f6-1dd9-4b1e-bce2-53737bd39046', 'ER0014', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e23ddf96-690a-4d9a-b5cb-e677f1258c0f', 'ER0015', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cf4bea71-b8f3-49ae-8aa6-99759f83c96b', 'ER0016', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3b773879-0019-46cd-9d88-a86c0e783920', 'ER0017', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f32caed5-22e4-4ad7-b7bf-e4d2c7b58452', 'ER0018', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('03d4dd21-30c1-43ad-8ee6-9e80f76cbe5f', 'ER0019', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bcb6661a-7e2d-4619-9d35-60b1f87390b5', 'ER0020', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('36699e6f-c80d-42c6-a8e2-34416bafac4b', 'ER0021', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('45cb0daf-5635-4e8e-81bc-eb57a8ee31f9', 'ER0022', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9908a1e4-4ac9-4339-bf15-d718c0e4c1bf', 'ER0023', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c6ea8c9a-f7d9-4b3b-9c19-3efe66a99c5b', 'ER0024', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('082b3472-b360-4b6e-9eba-70bef8272791', 'ER0025', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('61cad62b-368d-4937-828b-09ba9d8875fa', 'ER0026', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0583627c-94f5-440b-b7d4-2e24ca9762ed', 'ER0027', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a4d31ece-005e-4ec5-87c0-0e0de97ca7ad', 'ER0028', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('11144213-f8a5-45d2-8d9c-2c1bc978a82e', 'ER0029', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('31b55af2-5b11-4952-9d07-078104ebeaac', 'ER0030', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dc8fb0cf-1270-4784-8784-c85e4736e2b1', 'ER0031', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('25a9a57f-2338-4618-96fa-a1e56e442de7', 'ER0032', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0942973-f0e8-4302-bffa-a821f23b4d54', 'ER0033', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('92f2c3e3-6a28-4933-9dca-a43e60116fe7', 'ER0034', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5a515a3c-73ca-4745-9e30-c5d962e373a1', 'ER0035', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4666e2db-f7c1-426a-a904-43052a876596', 'ER0036', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fd040b14-77ac-4772-88df-0a27dcfa6576', 'ER0037', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e7af13a2-2035-413b-8fe4-eab77193bdba', 'ER0038', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c144db12-9310-40f1-a876-3137fa1a8fa4', 'ER0039', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5523adee-261e-4a23-8e12-ebceb1009861', 'ER0040', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bd4d177c-99a3-4a4e-ab0d-bb4e64fe7aa2', 'ER0041', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9789b41a-4fec-45a6-a921-253fbc0f5e00', 'ER0042', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1d2f7268-2806-4ed3-8c9b-88b86a08e3bb', 'ER0043', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fbce9f69-8122-458e-915f-92a7196a74f4', 'ER0044', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca40e343-c2b0-4d42-b1b2-d878dacee532', 'ER0045', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7838d70c-6780-449f-890d-43e016e86330', 'ER0046', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5eaae9e6-4038-4c7c-a54f-ea71290b45ae', 'ER0047', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8096a852-e1e5-49cd-8780-ef290fbff727', 'ER0048', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bd0c82dd-59a9-4d7b-8b39-c1a832cc9a53', 'ER0049', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('91644b7d-11fd-477e-b6cc-e558b29efacd', 'ER0050', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4f65b024-d98c-4c31-bcca-eadcf9c7a253', 'ER0051', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e28a8739-35b5-42b0-89e6-f52feef60f58', 'ER0052', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e9bdc4b9-8cc3-42bc-b9ac-41b1b14fe713', 'ER0053', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f9dd65c4-1b9c-4ee1-beff-328a8ba75b43', 'ER0054', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7ee755a2-297d-4a52-84fb-88bc55dd79f1', 'ER0055', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f79bd22d-3a3d-4bb7-932b-8c650fd0b7e5', 'ER0056', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('34ddabc2-a98d-4798-94e2-8c5cefb44ad8', 'ER0057', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cf0bbe40-b70b-4e41-8c70-2cba03059661', 'ER0058', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('25335eba-c84a-4f33-b42f-8b8edf5cad1a', 'ER0059', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca1821bd-03fc-40b9-a25b-cdbfd065746b', 'ER0060', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9edffff5-691f-4d4b-b2ab-ced742d944a8', 'ER0061', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8918bfdd-4a54-4ea0-b62b-adf786c0012a', 'ER0062', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('de5d64ac-980e-4ec4-9535-d6f3e308b97f', 'ER0063', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('609e75f9-82ce-447d-a729-087117659383', 'ER0064', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66bd4bf8-4d80-45ce-9d28-bd822e1e4c20', 'ER0065', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('01ab0fb9-f2da-4a65-b74e-2ffb70df7b22', 'ER0066', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c687f152-0680-4ed1-b650-e3591ceafa37', 'ER0067', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a3ca1605-05ab-43eb-b4c5-8b45b0ba5ed1', 'ER0068', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2f1f255-8406-423a-a127-6172ed515759', 'ER0069', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('01018755-ee54-4937-8093-e8c9f08a0531', 'ER0070', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('031c8d2c-f82f-49fd-b253-30938749038b', 'ER0071', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6ff0dbdc-950e-4e8f-9c27-79c959212cff', 'ER0072', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c278e04-c0e2-4ea5-817a-7bf51f28575d', 'ER0073', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c70b4928-7639-4498-9930-9ec2df6e8239', 'ER0074', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cd3c9e82-d861-4ba2-947b-32f7ad6ea84a', 'ER0075', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cc2ed6a7-6af2-4398-ab2a-4469bcfc8d09', 'ER0076', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cfeeb680-1fd7-4395-aab8-ee09ab40ef55', 'ER0077', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ea042b6f-a767-4dbf-be81-bbd3f5b504cb', 'ER0078', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('15c2cb66-21b3-4ad3-8984-5dc601cea9f8', 'ER0079', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1b9e5ec1-07a9-4e45-8bb6-9802dcb5f838', 'ER0080', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('094ea7d1-13dd-4447-a439-4013fc190d08', 'ER0081', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0dadba3-50f5-4e84-ad0b-9da188f473c7', 'ER0082', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2e22c46d-b770-4670-9ee5-52a6bf0f6ec9', 'ER0083', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('813acf62-dbae-4c3e-b455-e5013a672412', 'ER0084', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e3adfe38-d991-4e99-a57d-61008b0a128d', 'ER0085', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7cf5cc8d-c448-4470-8c3f-8ba058305786', 'ER0086', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('89e28e6a-dd14-4c54-ae1d-ae14b5ab4909', 'ER0087', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('21defb90-af54-4f15-8162-5917edb28d0b', 'ER0088', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c6a31dc6-461e-4f56-b297-410898a9d868', 'ER0089', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('312a751d-13cc-4af9-abf8-ca23fa48ce12', 'ER0090', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('30fcd00a-1791-4099-842c-e78080cd115f', 'ER0091', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('33f3802c-157f-41b2-988b-54f059921d85', 'ER0092', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a8d7cfaf-245f-417e-b3d7-dee3083d6fdf', 'ER0093', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0f95499c-3880-4446-8f76-8a58ab906138', 'ER0094', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b4e883d4-0c74-4d0b-8ad3-2f5cf8f52ee0', 'ER0095', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('11975e34-284a-46c5-802d-9d35ce5e2712', 'ER0096', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('28d7a0f5-d2f1-443e-9f07-916923b28cd3', 'ER0097', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b2177901-e5fa-4b20-9d02-a0a2d42c4b44', 'ER0098', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3948f1ba-c5c3-40a8-94b1-41c7dd5330d7', 'ER0099', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('05e32a38-e115-4cd5-83b4-737e98d80116', 'ER0100', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7c85b7a1-1478-4820-bfa5-2846d05d45c7', 'ER0101', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1f62d884-427b-4e35-8637-4dc9e88aed50', 'ER0102', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63e51c94-6188-4475-bfba-7e093b6d832d', 'ER0103', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c6e3254e-10aa-4546-8172-0570353819ad', 'ER0104', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d10a5010-ae63-4b06-bc1c-36b52a4270cd', 'ER0105', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d0fed052-881a-4bcd-91c6-306816c9a4b4', 'ER0106', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('de4d4d24-9f34-435a-bbf5-cf66cfb74443', 'ER0107', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('804f33fe-39ae-4475-be4f-b154252df8bc', 'ER0108', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b652f660-b5a7-457b-9a34-c029e07f672b', 'ER0109', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('58db2ca5-4dab-4adf-94ed-ca9ffc9bf117', 'ER0110', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ef921e85-659e-4c07-b1fc-f8f9ef2f414f', 'ER0111', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('542ff206-1f14-4ee2-ac6b-59217ac5e951', 'ER0112', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8b9e06a6-6f4f-4a89-babf-d8e7d3e603e5', 'ER0113', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c5e6278d-ab0c-4fa9-a1a9-97ab895d200b', 'ER0114', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('46f0bf81-8df9-47a3-ab8a-b2992418453c', 'ER0115', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c9f80b53-60de-4627-8772-11735499baee', 'ER0116', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('800e7511-9ca4-4505-aad1-8a60179aa459', 'ER0117', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('88e0ebac-f05a-476a-bf06-2898256fa000', 'ER0118', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ccd4ef12-70d4-4681-8bc9-6063f27e7698', 'ER0119', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bbeb1539-e049-4032-b2ff-6351157021a4', 'ER0120', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('30ab10e8-ff91-4bac-a399-abeaa0ba9b49', 'ER0121', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9a618481-ad8a-4a8c-9c8f-e5e9493ce5e1', 'ER0122', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('086774b9-56fe-4b49-ab45-adc881ce417d', 'ER0123', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d967cb96-3b8c-4b57-b83f-b6cc7b31d46d', 'ER0124', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ee872a5e-a6d7-40dc-a572-7f96deeea321', 'ER0125', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2a2e0ef-5434-455c-8322-1ee061187cd6', 'ER0126', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('38d9618e-e138-4fe0-9d6d-1963939a16d0', 'ER0127', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cc18fa46-8ce3-4472-b20f-7fbe61f72a3e', 'ER0128', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b4d756f8-4d7c-4249-8320-abd23e353cb6', 'ER0129', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8a308a64-aea5-4d57-827f-dfa576140bf3', 'ER0130', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a461b3c1-177f-4cfd-b8cc-8703221c2259', 'ER0131', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8c1aecbb-aced-49da-a3f1-91fe5117c6de', 'ER0132', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('88dd1f41-c224-4e7f-9b65-d5acc4262dab', 'ER0133', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b17533fc-80df-4008-8d8e-6bcda46c02e1', 'ER0134', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b5a832e3-e6ab-4c6b-8e91-72be3bab307e', 'ER0135', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c151db62-50af-425e-9ab7-0b8972c24bb3', 'ER0136', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('910c3b2e-d66c-4533-98fd-814af79bd36b', 'ER0137', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a337a147-9520-4b4c-8bb1-01de893e0a05', 'ER0138', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7f5245dd-026d-451a-9102-ab7ecd30aa2c', 'ER0139', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2314b085-8e6f-4d5a-a59e-84a9c92c603b', 'ER0140', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fd96d263-86b2-43bc-97c6-de54a595ab87', 'ER0141', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('248ba5bf-6a62-4958-8877-3c44932510aa', 'ER0142', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a65d0ec3-a660-4eb5-8109-cb5940fca939', 'ER0143', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('def6c5b3-1d71-4519-bd43-b5ce477e9b31', 'ER0144', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('309cc736-1e8d-4d43-a241-c77a772acbc8', 'ER0145', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e32c1c41-3f8b-48e4-9b66-bb912af456c4', 'ER0146', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('51a39d5d-e07c-4b5b-95aa-07c61707973a', 'ER0147', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9d024616-3e25-46cf-ad39-b6d2ca5e7667', 'ER0148', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f95a9219-de6e-4186-9d53-6d7013581049', 'ER0149', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('340f1b07-d7d9-47c6-897c-aa32f7509ee2', 'ER0150', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('475e774c-1c1b-464e-acc5-ad08936eed59', 'ER0151', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3a0298cc-5299-4028-ae21-8fc0d9ba0def', 'ER0152', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8be287d9-3a80-4c83-9e07-984ea146238c', 'ER0153', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('07ec6bb9-a41f-43ac-9ca5-9d436e042138', 'ER0154', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5970e954-dade-4c7f-8437-29848382465b', 'ER0155', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca009387-08b8-4a97-8654-32faf0475ef5', 'ER0156', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6690e811-c449-4857-b1ca-4bce7a3548e2', 'ER0157', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('80bbb133-9997-4edc-a4cd-9f2b0b0a07ee', 'ER0158', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('985844aa-9c51-4aad-a47b-a09234c12ef2', 'ER0159', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('23659776-def6-400f-a8e2-77a29bf73239', 'ER0160', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('40c2e6cd-5f26-4589-8aea-4202c40b15c1', 'ER0161', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9afd795d-b0a1-4645-9759-65a5e90e05d8', 'ER0162', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('93fe5fdb-266d-4679-9c40-92667b385a2d', 'ER0163', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('278b60d1-6561-4459-a403-34b431673cf0', 'ER0164', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('923e947a-1a17-4c3a-8014-53d139706913', 'ER0165', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('33de1811-8dfd-4dcb-ac94-b1c64529d7ea', 'ER0166', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8195958b-6a19-4560-ac06-e2abe1282f4d', 'ER0167', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e8481e2f-ff52-41db-af7d-b1cde9aad4e0', 'ER0168', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('610eef4d-d58f-4f69-abfb-5cad2c9e6d04', 'ER0169', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('95724265-7a53-4ecd-84bc-e2ae8055c495', 'ER0170', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ada828a9-83eb-46f0-99a2-0983db19ca90', 'ER0171', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6f2defbd-468d-4308-9bf0-25c1a6da0b48', 'ER0172', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e43ab168-18f0-4b19-8210-806a4230ce4c', 'ER0173', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0fce64c5-84d4-4ea3-a26d-62051c741c27', 'ER0174', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f1b83abb-1037-4a4f-a041-69e199c7900d', 'ER0175', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('abb65568-fe17-4c6f-b6f5-d144a7d45f9a', 'ER0176', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f0f3c747-3abe-48b3-8669-1ed643eb47d7', 'ER0177', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e18d852a-ced4-45d9-82f6-9d252fdffe1d', 'ER0178', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1e3d9c1a-b18e-4862-a7ed-8b673dcafa88', 'ER0179', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('54454191-ecba-454f-aa15-8534f6ea51c4', 'ER0180', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('52193246-3094-499a-baca-34b459c6867a', 'ER0181', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ff2cfd0d-bbdc-42ce-a794-988cd053f8f6', 'ER0182', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5cfc39cb-a35c-4b42-9e90-2b8739bf690e', 'ER0183', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1d27e565-7595-4701-9b7d-4acd51c243a4', 'ER0184', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8aa4b74a-9383-4c5e-adb3-6fe1db136314', 'ER0185', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d41987d0-66a0-4334-8101-761a7edbd9ab', 'ER0186', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1b8e0441-ebaa-4dd6-9701-4bd136114176', 'ER0187', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6371df15-04cd-4817-b57a-bb113704c475', 'ER0188', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cad85ec2-2316-468b-83ef-898d5a9aa403', 'ER0189', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6aaf21f4-18ac-48dd-ade8-dbd2f2f2325b', 'ER0190', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('55a50468-d591-4ddb-ab9d-9d502f1c5a19', 'ER0191', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('82628805-484c-43fd-b8a2-2efe1ad00cf4', 'ER0192', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('744f36d7-3507-414d-8374-f5c6a12cc609', 'ER0193', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b81d459c-8ab4-4b83-b47b-4c6a4337ab0b', 'ER0194', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1513a30f-cc55-46b2-be05-a7d87f3e2c44', 'ER0195', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3c503d76-15ae-4ae2-9e71-6b69f38ab082', 'ER0196', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('32d0830b-041f-4611-98ec-4180b039fe4e', 'ER0197', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('746f5f66-8ffb-4006-83eb-c5603375eb2d', 'ER0198', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('723a5f58-874b-401f-b1a5-9fb9575795d8', 'ER0199', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9d16b293-e86c-4a30-8228-647b5052cf72', 'ER0200', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8755cdd1-4ea2-4814-b468-6d1c8a1d8a8e', 'ER0201', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5438749e-2554-4931-b97f-90ae2c12d148', 'ER0202', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6fd9cf36-62e7-4581-86e6-b90227a1becd', 'ER0203', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('87e86711-64e1-4f85-bb75-a83e399d5c81', 'ER0204', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a97ac69f-41cf-48b8-9f8b-8198bb446bb1', 'ER0205', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f0a515b9-1fa4-4bd7-9bbe-b8684c93f095', 'ER0206', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c09c3a9-c313-4bb5-86e4-856bd4634ee0', 'ER0207', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1cf55023-a30a-4406-ae6b-cd7a332ca2aa', 'ER0208', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a6a42d43-187d-45cb-8101-0e3feb1f7152', 'ER0209', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63345e78-5040-44f0-87a8-800b5bff5bb9', 'ER0210', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0a571466-4138-4461-a2be-cb4924d6c8ac', 'ER0211', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9a8a587e-265d-4a48-a0d4-347ac08334a2', 'ER0212', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4cc2aef5-d99d-4066-ab44-e0c856731acd', 'ER0213', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e999cd2b-ebe5-45b9-b65f-fca6b084161a', 'ER0214', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c835a849-95cb-42dd-93bd-cc7a4d37cb7f', 'ER0215', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c0a794be-9afd-44de-a79c-935531514283', 'ER0216', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4f547c30-5333-44d1-8f12-cbc1242714d6', 'ER0217', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('31a051ff-024f-425d-a09a-d2c971f8f9d9', 'ER0218', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ac332250-3ecc-4bf9-aedf-27f7e9757618', 'ER0219', 'ba981b9b-972e-4301-a857-aafbb35612e0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e8bc8fec-d681-464e-98c8-1b942a1824e9', 'ER0272', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('86b8e939-55cc-4fdf-8ef6-4ef2d8ba6eb7', 'ER0273', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0ab894e4-92aa-4e4d-aec6-0fc7af24dda1', 'ER0277', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d2c57e15-2a37-43ef-afc9-6cfb28525042', 'ER0278', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c706702f-8701-4074-a199-95700962c124', 'ER0279', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8ff793a3-276c-4c2e-9117-57fc69f31c6f', 'ER0280', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b9444e2a-8f50-4981-8d46-e3a35d8c631b', 'ER0281', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4b051af8-9ef5-412d-874d-35923c9015c4', 'ER0283', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6dafaff2-f848-42d4-bded-2c2c9111e705', 'ER0284', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('39070353-0374-4147-8ed2-4ee2533e67d8', 'ER0286', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b59ce268-2eb9-465f-87e3-bc152c926838', 'ER0288', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66aabe5b-f187-42de-ba5e-1bb4b74f9961', 'ER0290', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('65da8564-6072-4fc3-8bd1-9b931c67ff3b', 'ER0317', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a4389a81-89ff-4134-83e7-34b57acbac70', 'ER0318', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('38d1fb88-cc3c-4492-a947-019687516be2', 'ER0319', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d391172c-8b85-4e6c-87f3-0332b6fdeba1', 'ER0320', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cbeb9882-0b1d-4593-ad44-6816ceedc2a8', 'ER0321', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8123eeb6-418b-429f-9012-7e7c39714b7c', 'ER0323', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('16221585-3a0b-4ef9-9b89-d4e71a330b80', 'ER0324', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('665691e8-8462-49f3-b6e8-1504f2791ac9', 'ER0325', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c0662921-fd6b-4491-8846-2113190425f2', 'ER0326', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e29a542a-bd26-4731-8685-3c5d817e913c', 'ER0328', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d34d8447-67a1-4987-a9f2-4cc491d4ed0f', 'ER0329', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b0d4bb17-074a-4652-99ba-9db75ad837cf', 'ER0330', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('837acb7a-d6ac-49ba-8459-9ffef83156c5', 'ER0331', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('94c5abb8-8eb8-4bfd-9f4f-74fe432f4647', 'ER0332', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e9c37ca6-d031-451e-a0e5-fa1356836cd1', 'ER0334', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d81d8984-3817-4460-b4f9-1ab485e16fe7', 'ER0335', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('487de4ad-002b-4035-866d-2dee3f02aadb', 'ER0336', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('712714fd-8575-40ff-aaff-39dd576c945c', 'ER0338', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aa534cb5-f9bd-45a2-8d06-2f428d191a73', 'ER0339', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('78da6b5d-ae44-4860-9bad-1f5cfe7eca05', 'ER0340', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53a9df1a-959f-462d-88bd-6c9848f8cd02', 'ER0341', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0e0faa9d-2005-484c-95d6-ccaa3eb7d403', 'ER0342', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7752733b-c6f7-4924-a056-94135dc92f95', 'ER0343', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b396bf14-5faa-4eaa-94f5-fa5b2b2342da', 'ER0345', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('51f55228-bb29-4e8a-8537-f3528870b5a0', 'ER0346', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('34a26c46-11ef-41ee-af28-4dbf26161258', 'ER0347', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ac0e6790-937d-42b1-92ac-eae81b5431a1', 'ER0350', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b1f665f5-091f-4c73-b23a-de9e447abd8e', 'ER0351', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8b25754a-5e1c-421b-aa44-ca0e9746a371', 'ER0352', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a9d81346-6a5c-4977-a13b-775869af5c7f', 'ER0353', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bc2a9f22-8803-42eb-a5ff-2ed0c5582b67', 'ER0354', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('060253d2-961d-40a5-8e83-46051f533f90', 'ER0355', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3366ae38-a3f9-4b0f-a676-9122f4803ab5', 'ER0356', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9497b230-5583-4e12-893b-b37011da18fb', 'ER0357', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3e8d7ce1-235a-4258-bf53-7944c249fe28', 'ER0358', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4b014804-373f-44ee-b06a-29de5f885ecc', 'ER0359', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1c830dcf-b53f-411a-9cfd-64f1baf54c84', 'ER0360', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cde6b81a-b795-4c0f-aa54-2ad591ec1208', 'ER0361', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0360b8e-a650-4ae7-ae1b-9621f838c2d8', 'ER0362', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2517d347-3a1c-4e12-9093-0b77143800af', 'ER0363', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5c306923-7bcf-4f6c-be5a-fdbc9078da68', 'ER0364', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b7eb0612-f02e-4fc6-ac72-c6ae3333f6ec', 'ER0365', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9578e319-9794-412f-8ece-ccf6b445de61', 'ER0366', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe13dbbc-15b3-4c20-914f-f1df1bd72ad4', 'ER0367', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f6af7816-e6b1-42c8-a2e8-c418d70fd2fc', 'ER0368', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('87a785d0-0713-4796-8f1a-ae5c8f7c2a35', 'ER0369', '20cd13b8-6992-4f9d-86ba-da6cfbbf2527', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0feed691-4a62-40fc-b091-161ba3e668e3', 'ER0970', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e8d6879e-2cae-4444-bd3b-db95d20414db', 'ER0971', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('159e1d22-4d07-4fcd-ac92-d24a3ffd709a', 'ER0972', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('295698c1-f249-4499-bb12-ac103e689e50', 'ER0973', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d9a00691-0f4f-4fff-86f2-afa9c13c98c2', 'ER0974', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3f519548-1779-4bde-8af6-d62286db616d', 'ER0975', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a1c7f44e-d6bc-403f-b75d-b46177e13a4e', 'ER0976', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1f8f3a2b-76ed-4d72-a6cc-2742ea2b2498', 'ER0977', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8a989154-3b29-454a-b08f-62d7ab0d1e97', 'ER0978', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ec340e3-57f8-463c-92f1-6de40944fc6f', 'ER0979', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('68328ea0-4164-45ea-8dce-fd3c3b2213ae', 'ER0980', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5720c652-431b-4399-9fdd-6fb55dfe1658', 'ER0981', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6e88adfc-75b5-45fc-b6dc-d3cee0122233', 'ER0982', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('30642847-f45b-4648-b7c6-4e43236e5af7', 'ER0983', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('45585c0e-9de1-4ba1-8e3d-6997bff8c715', 'ER0984', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('90da9164-d2cf-4622-8b09-343d8428d8d7', 'ER0985', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8a248a3a-c44d-4c1a-9b0b-e35b077a68b8', 'ER0986', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('95c37ce3-030b-4c08-b6ee-cc3dbde3c728', 'ER0987', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('590f361c-7538-44fa-85ba-0541920de462', 'ER0988', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7ced7ebb-3a38-48f1-bc99-444179b860d1', 'ER0989', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0a963d36-88e3-47c9-8da7-b9bc05d55d1c', 'ER0990', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e2f146b6-53c1-4437-a540-dd5cf4ee21d5', 'ER0991', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0f61e5a-d883-422e-8a59-3558e1288e22', 'ER0992', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('19ee51d4-213b-45b0-bfd2-ec48e5e00f64', 'ER0993', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3b4fe7b8-5f30-4942-add4-5e58d852ce42', 'ER0994', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cf955d1b-ba00-4b54-a6ff-cacb9c9e3998', 'ER0995', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('383c798b-ef3f-491c-9be8-e06e7cf02ced', 'ER0996', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f90db5da-8236-488d-9f84-d3ad2d70d13c', 'ER0997', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2342fc04-768b-42c1-85d0-1d7a11179eae', 'ER0998', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('083b1a08-4724-4bc1-8f42-56d2d903d9b7', 'ER0999', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8c812b23-a593-4e5b-90f0-29ec9d3f1e19', 'ER1000', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6474629e-c5e3-41ac-83ec-0973f1878584', 'ER1001', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d7bad221-aec2-4110-9efe-565978e9f78b', 'ER1002', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fc6a80cf-6513-4b5c-8a32-43fefe3a6a5a', 'ER1003', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3c1cc41e-2302-4640-9e9e-b79b724d6ee5', 'ER1004', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b8329eca-41b7-4662-a6ef-41e5169ec6c4', 'ER1005', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4a0c027a-1072-4b2a-83da-ecb60ed48567', 'ER1006', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('be475678-d27c-480b-b889-e7c553ef0442', 'ER1007', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('95ba8ebd-731d-417b-982d-5dd783d7133b', 'ER1008', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9cbe79e6-a9a5-4039-a2e4-c5ef9473a1d4', 'ER1009', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('479dbd14-a02d-4ff4-8668-a09b3af575cf', 'ER1010', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('086e4cbf-622b-41da-bae7-8edd920a2881', 'ER1011', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4c43ecbe-b196-43ff-9ecb-0b978bcbdbe6', 'ER1012', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d178148e-d5ec-479f-aa53-03886d48ad50', 'ER1013', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('40d8a4a0-e00f-4cc3-b588-6161d2b1d539', 'ER1014', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('03be9a2c-89eb-40af-a74c-f8bb177c5f5c', 'ER1015', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ec0e58c-bdeb-4d08-8fcc-2eed5816ee29', 'ER1016', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d408d9bc-2bcc-4190-8c37-1a3e83dd5dd2', 'ER1017', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a2fb2e41-0fad-4e49-9108-9ac0f288e24e', 'ER1018', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e37b5c10-ad2c-4b2d-aec7-6c856bb1f747', 'ER1019', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9ef7a85b-a56f-4907-b0c3-cf4309aca558', 'ER1020', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a7c46698-ce09-45b5-b5ec-f259cf2dca6e', 'ER1021', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('48b2b8cb-b569-4ca5-8ad5-eb83a3864144', 'ER1022', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bba757fb-5728-4708-95cb-adeeafaec710', 'ER1023', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('72ec5405-e0e7-4aed-a83a-c8e015db6c05', 'ER1024', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('814e959b-bc9a-44b7-8483-2a721fbcf944', 'ER1025', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f56cf74f-fb88-46d1-a59e-1a314fb78d33', 'ER1026', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2cdfa8f-0af2-4552-b3cb-5a7bbb78ffe3', 'ER1027', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('08d97108-17cd-4247-8e9b-17060d8ba4a3', 'ER1028', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('32ae0beb-28ee-4d92-bff0-1f24a99c62f1', 'ER1029', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9ea08a04-cc2a-44ea-af9a-51331362af18', 'ER1030', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('85c4e40f-8071-4cfd-aaac-c679d8ee814b', 'ER1031', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4ebe9f3e-0cf7-4f14-89eb-85f1e9f470f8', 'ER1032', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4c5caf92-0311-49bd-a060-fb349576c23b', 'ER1033', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4e51d3e0-105d-47c9-b2e5-4a3aa84650ef', 'ER1034', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0ec15e58-10f9-4572-83d3-c788df83547e', 'ER1035', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9806782f-f1fa-4647-a790-1d9ce0cf8a63', 'ER1036', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('39371efc-0626-44df-b454-756c419e9f5d', 'ER1037', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9e882be3-d28a-4b12-81e7-5c1146b70ec3', 'ER1038', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('130f09e7-7920-4967-ac97-d0df1be9a1eb', 'ER1039', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2f7bc2b-2c64-4593-91f1-077172020795', 'ER1040', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66c749b2-7b09-4137-95a7-d41474a14de0', 'ER1041', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4865fd4c-a040-4b3b-b645-5d7ae487d5a8', 'ER1042', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cbffde1f-e1fb-42a3-a32f-fe79e70a1641', 'ER1043', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('366d14a9-8597-4d41-b40f-0e82dccda6a8', 'ER1044', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4d24cbf6-269e-4755-89b8-29a94755c10d', 'ER1045', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3b544a10-39a6-4ea6-a06a-e109b24d3bb1', 'ER1046', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('65ab09ec-94b4-4402-95a2-2f1d94ff7dd4', 'ER1047', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4847746f-1a7e-445f-8e8f-2445a856b578', 'ER1048', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1912a39f-ebac-4fb4-85c9-1e77058e85d6', 'ER1049', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f7bd3e9b-ae78-4597-81d6-0701364bc009', 'ER1050', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5101c290-de1d-4c7e-bd44-19e333aa986f', 'ER1051', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76054978-14c8-4285-abf1-eabdc245f5de', 'ER1052', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d29369e1-c755-4fbc-8e01-c50292d0fd5e', 'ER1053', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aedce45f-d0ae-4804-ae9c-765cb31b3729', 'ER1054', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('72a392a4-5565-43f7-9f31-2044a363cf8c', 'ER1055', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7237eb49-874b-406a-84e5-004a3c32cd1e', 'ER1056', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a08c9c0a-471f-4693-a87e-2d2c91655dbe', 'ER1057', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('150cd759-d37f-448b-8309-f6721b0f9e40', 'ER1058', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8dffaaa5-eb56-4ca0-8daa-debcd900c322', 'ER1059', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('386d05cf-47e0-4929-8fb8-8a02ee952d06', 'ER1060', '9fe9a541-6245-4d25-b17d-68aa5f74dcf5', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c587df1-b353-4789-bacd-b2cdc4078246', 'ER1061', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('106f99a2-e09b-4b3f-98c6-526225df61ad', 'ER1062', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f36bf423-ddf5-4959-8ade-d1e842dd875c', 'ER1063', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d145bfa6-0064-4289-bca0-98e40ee7d740', 'ER1064', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('de928155-d804-4eb7-b49a-dc94fc54c0db', 'ER1065', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7b8cb7ac-d503-4c81-923a-f3a4ac662227', 'ER1066', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f859677d-ab86-4bf1-9245-07c88f53cd4b', 'ER1067', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4375456b-8894-47e6-b136-02f163831257', 'ER1068', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3eaff31a-37e5-4efc-a21b-2a3cc288b46e', 'ER1069', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cc105d80-3d71-401e-bbb3-de9983e74818', 'ER1070', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('30dadc09-5617-499a-848c-7ad2d6cfb1a4', 'ER1071', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2457be1f-81b9-45f7-9f45-23ca36af7c78', 'ER1072', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('83afc832-d20b-47ec-b51b-8999f1a92c5f', 'ER1073', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d4e1b1b6-e8a5-46ce-b447-04419bf6ba79', 'ER1074', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ef070b5c-ce80-4a10-aeda-4d680ad9fab0', 'ER1075', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7e1aa936-93be-43db-a059-99145ba96c69', 'ER1076', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('51b724f3-f0ea-4efc-8e53-106e8f67d5ac', 'ER1077', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f33b909a-c281-4f3e-a19c-e6f84fae1139', 'ER1078', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9be259e4-cf2f-4a50-bb5f-f505f72ad946', 'ER1079', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('820e9387-f3c9-4f87-b167-d8fd64e7979f', 'ER1080', '8ba35b55-6d19-46cb-bbbd-2fcfe852d84e', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2c972cf2-7b8a-4216-acbe-709b62f368f6', 'ER1081', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('99a89b8d-95c6-4725-96ea-f47fc4e8b40c', 'ER1082', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('201f6b9d-ef86-4b87-ac0d-3798b15390b1', 'ER1083', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7036a580-0138-47de-a000-fe80784c3a35', 'ER1084', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d379d2f1-3d65-4409-9b47-0a68e576ad97', 'ER1085', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7a663d25-db3e-4f69-ab94-6eb1122feb7d', 'ER1086', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('692ae9b0-fbab-4ccc-aeb8-902a18e32423', 'ER1087', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('88ecc5ec-b4bd-4220-b40e-5c25e7dbd50e', 'ER1088', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b760a536-efd5-4176-80a5-e2a6f92126d7', 'ER1089', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('81bb821a-e92e-4ee4-b0e5-adba3f58f614', 'ER1090', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7732c5b6-9321-4937-99b7-35431b5c1c34', 'ER1091', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('07bd556a-1c27-41aa-9722-c0be3ce9c3d4', 'ER1092', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7e863102-685a-4547-a7a4-016ff4a98062', 'ER1093', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('32b11f91-b747-4a28-ad30-a5ce0369756f', 'ER1094', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('140a3608-29b9-4d7b-89b2-9d08f28539a0', 'ER1095', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7fbabf73-f280-4c5c-89de-297a0c71f3b5', 'ER1096', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('60ebf823-cf72-4575-ab4d-e219b8cc80a6', 'ER1097', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6978580d-f063-4d62-a4a2-238932bd8b4c', 'ER1098', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('931e2ae4-da9c-49ae-ad94-86c28e805849', 'ER1099', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b272cf07-aedf-4e42-b1f0-84b33fdcd9cc', 'ER1100', '2bd636b7-3951-4164-a2c6-fe364a8110c0', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', NULL, NULL); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a00b16a1-0add-4e38-8770-67ffd0d5b314', 'ER0410', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('288c8d53-b005-4186-9f87-d75f19139a45', 'ER0419', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('58ac3cdf-ca51-484a-8aeb-a179409a0d93', 'ER0424', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4a49aed9-b583-414d-8209-ccdc691b1f12', 'ER0432', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b18a5ec1-f656-4a4a-a832-7f57899d9f3d', 'ER0440', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c5399d04-cce5-4353-a6e5-f4e7d26caf93', 'ER0447', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('418d9cc2-e3d3-404f-983d-712c98ddf8fa', 'ER0462', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1f73c17d-adf5-4b1d-ac1e-6ae952cad378', 'ER0474', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6569eff1-2138-45e1-abb4-81d898a3dc9e', 'ER0479', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e03ea1a1-44d6-4747-81ed-fab4cf79d92e', 'ER0519', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ad97b2f9-58dc-481e-a460-ffb30a0c2459', 'ER0539', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b7ee6958-3d5a-4d36-a467-7897bd0191dc', 'ER0541', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9ae9a44e-46b6-42e0-8d11-71a828aa3967', 'ER0544', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2d3c9b7e-f45f-40a0-8042-bcffea8a7e1d', 'ER0547', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('869082ba-0e67-4c45-a640-ef37710e51c1', 'ER0557', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c112a83b-4587-43ca-bcc9-5d5c15e32fb9', 'ER0635', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a05b4402-a684-4f33-bbf3-c355af91eaa0', 'ER0650', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4fe86268-f921-41f0-91c9-77b0fc775b72', 'ER0656', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('15592854-9bd6-4c4b-a7cb-5fecea482582', 'ER0660', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('432bc697-a5b9-4ea7-a56d-d1b5a72a81e6', 'ER0663', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bf7d3345-ec27-4817-8471-1cb277a591bf', 'ER0666', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cc19bbd2-276b-4a03-82ba-2861bad8b900', 'ER0674', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0d460fa1-6e3d-41a0-980e-e5aca2d49f72', 'ER0692', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c7762095-f936-4868-9abb-c7a22d1875e5', 'ER0694', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3ffc9641-ba02-4a3b-a1b0-0261c9c02dab', 'ER0695', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fda4805b-e7ea-4c55-8bf0-1b497522fe66', 'ER0712', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e806d025-8200-445c-a04c-ebadd110fb68', 'ER0724', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3dd1c767-0888-4e33-8de5-4fde93eaf215', 'ER0734', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0f98dff8-4da9-4e7e-917e-96bc513349bd', 'ER0744', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1969803e-c560-42a4-8a79-9630e606b486', 'ER0764', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63d90c62-9c77-488a-8b38-0aba525dc597', 'ER0782', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('da04f0af-eae6-4c1f-86c3-54f1420abd73', 'ER0784', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('668b23c5-4ff2-4121-85a0-9cb9c96947f6', 'ER0786', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('783d0c68-9578-4ec3-a641-3363032981c6', 'ER0790', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('760586d2-591b-4c53-82cb-3e66372aeed8', 'ER0791', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f8eabf31-bee1-43fc-894a-526cff563abc', 'ER0816', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5c9f8c1f-4860-4fdc-8af0-1386503cc305', 'ER0820', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dbf7b1ad-92ed-4998-9e45-8ad2fcc804db', 'ER0825', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('afdcd17b-d99a-4b9c-a60d-c1c00451056a', 'ER0826', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76d50921-6e07-4f20-b7df-de29e63ef213', 'ER0835', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4eb2c46f-8a94-4a42-9ec3-a9ea329f97e1', 'ER0840', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b35794d7-5209-4380-a531-30b693427b4e', 'ER0850', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7b0b9582-8118-410c-81fb-b149e0e2989e', 'ER0858', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('faf7e51c-9875-4485-b674-5c97957c6bc4', 'ER0868', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fab8463a-db8f-4f18-8ecf-545aa87d9a82', 'ER0879', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5d6785d0-171b-4b37-a81e-37b72e5dada1', 'ER0885', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5a008a04-244c-4f9e-9a11-65a662ccc3ab', 'ER0901', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('eb9919f6-f02e-44cd-bd1f-297bec13006b', 'ER0905', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('447d46e7-9dfc-4e6c-b210-1de9a36c2e2e', 'ER0915', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e94da3bc-fe8a-4c04-bbcc-20501dad02dd', 'ER0926', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8001', '8002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f5d2e0d3-e3c5-4300-811d-e6f96305d60a', 'ER0254', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4dc4194f-7d05-4e07-bcef-307af0fc7ff0', 'ER0316', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('765b0b88-febb-4756-b155-4c7fd425fd53', 'ER0407', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2c214896-bafd-41dd-b6a5-5fc84d99aecf', 'ER0412', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8b3bea30-2cc3-46bf-b53d-e02d0c6ae65f', 'ER0422', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1a8b5c01-9501-4edc-940a-bcd3706fd149', 'ER0431', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d23b1444-c833-4ebe-acb1-823e04578407', 'ER0435', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('97622066-43bd-4106-8d05-03bfd9997fe5', 'ER0458', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2969bc56-7c35-4dcd-9044-1894b57976a4', 'ER0459', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5644fbf8-f2d2-4336-8981-6f94b82c3ea8', 'ER0470', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('994c7d5d-f499-4b44-9ccc-19b67b9027e9', 'ER0480', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d47a8d1d-a79d-48ea-8c17-3a5ff5316e13', 'ER0515', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c08deeeb-114c-43d4-bc3a-c3be61b16ffa', 'ER0520', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d9e1d1b0-2f9e-4736-b810-a4796254837a', 'ER0521', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b7b993f9-612b-4fec-a8b3-3bcbe1eb5837', 'ER0527', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1f1703fd-665f-429c-a19a-6bde1e5b38db', 'ER0555', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('816707ad-7609-406c-9d7f-39653b101c11', 'ER0559', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f40d7ea6-845e-4c26-8608-fa36f9416ab4', 'ER0567', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e57bbc23-ada2-486a-9efb-b8f88ca48dc3', 'ER0590', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('02f4e7ca-b092-47b4-a8db-8d826586a63f', 'ER0600', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a1367c49-5e53-4ff7-ae02-4f8ac2b9c1ce', 'ER0633', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cb7185f2-4986-46ce-ba36-8145ae13ea2e', 'ER0646', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f3d5451d-0d12-4a1b-8d15-c7f6e7c138d4', 'ER0648', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('74f0950a-cd54-4acc-8cab-8ba87850a1da', 'ER0654', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a35503ca-c3c6-4409-8777-39ac5cdb6b43', 'ER0676', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('94d4bf5d-f1c5-4fe1-8117-8cb43cc73d16', 'ER0697', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('806b59a1-6a6d-456b-8772-430a013827d6', 'ER0703', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('36bc1a03-5e33-4458-9099-30ba59c1d4cc', 'ER0723', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8aba3f55-01e8-4ed1-b014-e8caf469b069', 'ER0725', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d28263db-28ea-4213-bd33-92f5175dd3fa', 'ER0746', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2adf25c3-1201-402c-8abb-c41940ba7514', 'ER0747', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('37c13aab-bcd1-4157-a988-a1a7077be3b3', 'ER0752', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e2952143-9393-4ced-bf98-41e978cc0440', 'ER0760', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('12db1bd2-e648-40e2-a46c-7c1914322387', 'ER0768', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7cc630aa-f6b4-4920-b5a0-ca7c37921f2b', 'ER0800', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e2c34803-fd89-4e86-acc3-5eb91411453d', 'ER0821', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('407b4791-6324-4dee-a78a-b9f8a4e94770', 'ER0838', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('57fabbc9-2b37-4a50-9cca-53852bbbe968', 'ER0843', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bc88fbdc-091c-491f-8e34-7c84fd63edaa', 'ER0844', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2b19b391-86a4-4bee-a716-005f4024305f', 'ER0846', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cf7ce05e-b961-45e9-98b9-10455a2a2c6b', 'ER0852', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7ee1f666-e0b2-453e-acab-c1ebe3a40c8e', 'ER0863', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('90f42343-6adc-49d9-b4e1-37435fecb868', 'ER0880', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('79c1321a-be7c-4172-9e5e-7940f21074ba', 'ER0914', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('07b4eb3a-2689-4f2d-82d7-1bc70bd78fd5', 'ER0920', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ce293480-3b75-4108-af37-b7858edf5444', 'ER0923', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('72ffb226-f3d3-441e-b641-d1fc3f80aec8', 'ER0925', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b4c1d0e9-9efb-4a23-8f52-f25668882b59', 'ER0937', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f19ff037-0b1e-4251-9cf7-603bd9a2371a', 'ER0939', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8101', '8102'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6cae069f-d7df-41bb-bf6f-978be2c808bd', 'ER0231', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c752e889-1cf4-46ae-a26c-7ffbe9e5332f', 'ER0236', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d8e6a374-2048-487d-a486-3cb18a6ae3ba', 'ER0274', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0b9512ff-b624-4f00-a1f4-e122e02284b9', 'ER0314', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e2118b86-7075-4a02-baa2-6a8cad268128', 'ER0322', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('401cc1ed-5efe-478a-a08c-feae6daae963', 'ER0348', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3c5300fc-cbfa-4f63-ab29-9fd1eb62a7b4', 'ER0411', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('33145d41-d959-498a-b0c2-65bd52104b1f', 'ER0430', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('78dcd996-d03a-4490-a4b0-e2fca285acaf', 'ER0443', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('55420e4c-17b2-4eb4-af1d-f4cb10d95ab5', 'ER0445', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5663f527-a6b8-4056-a6dc-738188bfa5bb', 'ER0452', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a83ac6fa-dfa9-455c-9a17-9c448a8fc5e2', 'ER0456', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2da33db0-c125-4c7e-930b-071a34dca4d7', 'ER0464', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('def2913a-15f3-4e30-82ec-b32d96334025', 'ER0491', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2a2189df-a64d-4684-92de-c4d080c23493', 'ER0505', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b6ac56dc-60c8-4091-bc6a-40a218d7e89a', 'ER0514', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('77cad373-50a1-4df1-acc1-a74185853608', 'ER0524', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8c0e7c53-75eb-42fa-a1f4-0928b5b9ce25', 'ER0538', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('37529518-e9f5-4f76-8600-661e0d58ad0f', 'ER0542', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f6e0b649-7408-4592-a331-5cafc9a607c1', 'ER0564', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cfa63df3-ce43-4260-89bc-c96919d332eb', 'ER0568', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6149ff5d-3c69-43b5-adbf-052f0fa0cd2e', 'ER0571', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f0cd30ad-3d33-49fc-bb0d-413033bcedb3', 'ER0585', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f8f2336b-78fc-4131-87da-ccf88c1589a8', 'ER0588', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3bb5610b-caf0-4a45-817c-816adbaaa9c4', 'ER0596', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bd16e101-f663-4de2-9032-c93b5e7c6d4c', 'ER0606', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2fdf729b-1315-4f31-88b1-424184966b2c', 'ER0618', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76489cef-51d6-4b07-ab3d-b551258e6a03', 'ER0624', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3201d1bf-f605-42e7-8cdf-650b8c7a929b', 'ER0625', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a242f221-ea4f-4766-b5cc-c341d3aea4c1', 'ER0642', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ffcd901-40f0-485b-94d2-975eeb203c09', 'ER0662', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76919693-d257-4379-bace-4d2df2f0df95', 'ER0684', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('af411f62-7475-483c-a313-4ef65e6cd343', 'ER0698', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('569ec48f-ca93-43e7-923f-55807a79a6a4', 'ER0733', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f506ca35-e4cf-4537-9a30-f42972cbd82a', 'ER0771', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('46195d01-7a88-42ac-a168-3b311c579ea7', 'ER0776', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9e7640a3-51ec-4e01-8fa1-d9956db413cb', 'ER0794', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9e5bce95-8c4b-4c6d-809d-692ec047dc22', 'ER0799', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('817d9853-e8eb-4fb7-a09b-7559e4a967a7', 'ER0812', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bfcb0fed-bfe1-4581-bc0d-b40a613165d1', 'ER0822', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('266be7aa-78b9-4cb5-89d8-ee0e74aae0e5', 'ER0833', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dd436170-9321-4301-9454-6274c19bbf74', 'ER0839', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0961b8e3-6ab4-4f60-8e8f-4658f54f32a4', 'ER0845', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ecc660f8-7bac-4c61-b447-16ecc48368b2', 'ER0855', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f529a1a9-93be-4b81-8901-05a43c9e8dff', 'ER0888', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76dbb4b1-c7b3-4493-a3a5-33a3cb7316bc', 'ER0906', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('219e1e02-fbb7-46a4-8304-30db4ecae9f5', 'ER0907', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a65b8d3c-aa5b-4a6f-8ea2-0610ffc1b092', 'ER0918', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9ead7076-f393-4435-a667-5361e742ac5b', 'ER0928', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5781291b-9511-4328-a6ed-c52565962dc5', 'ER0933', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8201', '8202'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4ff4bf36-0ee8-47f1-944a-5db4eb102583', 'ER0232', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('39723017-9af6-4b50-83e2-770939d81a96', 'ER0250', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ef55a00b-f682-4559-b18e-adadc1b8f6f5', 'ER0264', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca139145-2f6b-44f8-85c5-760414bbac11', 'ER0292', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('103569e9-bebc-4e5b-b628-a068340fec68', 'ER0396', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d70044ff-0fba-4375-a416-57f424dc6633', 'ER0400', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('febc9b80-1358-4d44-8faa-da9ef45355c4', 'ER0420', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('025a3a3f-b7c9-4700-bd9c-e4a4b667baed', 'ER0421', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca3a197a-c0d1-4790-bd8c-5745396f4f04', 'ER0425', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('deaab6d4-3ef5-4a58-9c89-a1c8b9f196da', 'ER0475', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8c73e07c-8bde-4313-97cd-e1579058e103', 'ER0484', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c29ef016-5cde-4d6d-9f6d-af6c69832d38', 'ER0485', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aa4cc206-c6f7-40da-8093-aea833cd30b1', 'ER0513', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b31400f1-36cb-43f8-84d4-ceb4d210e6cf', 'ER0528', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('16103891-1897-4461-b952-be9a26606d99', 'ER0537', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e342e3df-c84f-45cd-9ff0-a49a5c951c68', 'ER0558', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('34435d82-1ae0-41f8-aad9-6c4c7fccd46c', 'ER0562', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7baf756e-e67c-42af-851e-0f281de7dec5', 'ER0566', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('be7f7bb0-dec3-4315-992f-14b7525f38dc', 'ER0575', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('20cb44ac-bb51-4beb-be6c-1ae23ea2de44', 'ER0577', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8680bb9e-56f0-465e-afb4-855ec32251ae', 'ER0578', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e904565c-9dd0-422f-84a8-af1b256f6ba9', 'ER0594', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('174c2146-818e-4347-90f5-4870f63c553e', 'ER0599', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4f4b1a91-33eb-4dc5-a761-20989979d5cd', 'ER0612', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5b099e8b-2c34-4571-a096-c7fd3421e313', 'ER0622', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('58b34085-3d72-4db0-9e30-6081aae3256d', 'ER0630', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ae0f395c-5ef0-417d-b1be-da53038f7d8a', 'ER0673', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('345a7bcb-89cc-430a-963a-c4fc4c90c6a4', 'ER0686', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3850dd5d-1766-4c31-a6f4-03e986979f53', 'ER0691', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0ac94618-a95d-4438-abce-b2132d3bc511', 'ER0728', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bda0d920-5ddd-4c5c-a6c7-4749911640e4', 'ER0761', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2afa9ea1-b3d5-4c07-972c-e10b9c4fa68d', 'ER0762', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('20ec4789-e5b6-42ac-9774-f4c2984ca87c', 'ER0766', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ac110c50-160c-44c1-8e5a-ed939c5548b6', 'ER0780', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('14f26cf7-7939-4e5c-9632-d84169a4a7cf', 'ER0801', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('87605dc1-afbb-45cf-99f5-84fcc2821bd1', 'ER0804', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d45222de-aaab-4c3f-b85a-7b35cc7e51cb', 'ER0806', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b4020db7-f7bd-4e1a-b84b-43b2f75f43ea', 'ER0818', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e7fe0225-fef2-463d-ad29-7b692b13ccaa', 'ER0830', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0e99fe8-d873-4f4d-9d41-8c7f41a465e7', 'ER0831', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('afbcc0f6-a537-4d49-9f0f-1a484216fa60', 'ER0849', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('52f3109a-0d73-4d7a-915c-fa709056b4cc', 'ER0870', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a98f1d3d-e345-4007-b5e2-35eb18c9fb8a', 'ER0876', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('44c97804-82ab-4cc2-b987-eee8aa8ccb75', 'ER0881', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c857bc75-6371-49fe-8c89-5fbbb95299d4', 'ER0898', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0f06df36-d78b-46ea-9131-80390cca4a2a', 'ER0917', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('455e8879-89de-4cc4-b30c-28d479f04354', 'ER0935', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8301', '8302'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('32be1ba8-11bb-4654-ae8e-d955e226c2de', 'ER0391', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f4738619-8a39-49b8-9baa-7cf04572d5ef', 'ER0392', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fae50b70-4e84-41ee-942c-0b602ef48ffc', 'ER0393', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bebe88f8-b7a3-4448-962d-17909e68d351', 'ER0397', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5125de0d-c6f3-4b4f-b74b-12fe3fdbbe1a', 'ER0402', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7fa7961a-d377-489c-b468-27024efc2927', 'ER0415', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('26d39900-f91b-4995-a829-20331c896c90', 'ER0434', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e3360e6a-1f97-42b5-97cb-dea0ef28f3d2', 'ER0437', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8f5997d5-1408-4dc6-88b8-9e94bb05e123', 'ER0442', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e5c241a6-4310-40a1-aa17-9601b7272813', 'ER0451', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7675ae12-064a-4e16-9361-4176971630d7', 'ER0454', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ae4ac01-9a83-43b3-944e-5a4ea9820975', 'ER0500', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53b2037d-9007-4e90-b96f-0c35ba773fab', 'ER0502', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('84ca94e7-4fd9-4566-88ae-d6fef2bc458f', 'ER0522', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('64406b13-3ef4-4e09-b5dc-cf59fdc2b527', 'ER0530', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cfc4b28b-fb5b-43e8-bf72-c196c8439841', 'ER0540', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e550e034-7d42-46df-9823-e54337617934', 'ER0550', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4ea5bbaf-b624-47cc-b6be-9711b24536e2', 'ER0561', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b46c8fd6-69b3-4dc7-b986-fe7e9ae16fb5', 'ER0563', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('917218e4-64a0-4761-9850-49542dafd987', 'ER0565', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b1038243-4f97-48b1-8631-d1485d1cf967', 'ER0573', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('18ff2a9f-a51a-4b42-bee5-b69d3ba031a0', 'ER0602', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('11b229ea-7956-4cc1-b541-ddb4518d3029', 'ER0614', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f4ce0746-2f79-454c-9ac9-b5886a091cc9', 'ER0615', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2d98a48b-99df-41a1-9924-de67af42cc9d', 'ER0616', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3fa339e1-3685-4aef-8c13-e2922574d9a8', 'ER0636', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9886782c-fb85-4190-8977-359d60ccd2f5', 'ER0641', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('450ea166-fb63-44fb-b298-e9ebbdd278ba', 'ER0649', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5d885aa9-c3f9-405e-842e-5493327ebe14', 'ER0653', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('79b6e298-b56b-48ab-a721-14d6ba29681a', 'ER0658', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2c814c13-e4a6-4524-af6c-8e5dddfd5bcd', 'ER0664', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ba0ebee3-a626-4863-93f0-83a41b7c1b89', 'ER0678', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6fa3c5e1-631a-4b3d-9be1-d213cc3888a3', 'ER0682', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aebce28f-37d2-4f62-a7f5-f360c65fe8cc', 'ER0704', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('db80dceb-cbdf-49bc-8e40-774604d4feb6', 'ER0715', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('57e8292a-c848-446e-88d2-320377bbd864', 'ER0720', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9023ce31-8705-4ddc-b6a2-b0be94904a07', 'ER0729', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ed6b5dd-2cd6-4db9-a5fe-1240f1b11d7c', 'ER0730', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c1d9d47f-4044-463c-8749-16af7e838dae', 'ER0739', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4a45f635-9439-4d59-bfcb-9e467f23674c', 'ER0740', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b471677b-1010-4331-a7e0-652ae05ab00c', 'ER0755', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('64d28f20-d512-4dfe-9e25-01118372a84e', 'ER0758', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7ed0ddb7-2e46-4145-9b05-6cd56c6037f7', 'ER0772', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0fa34c0d-0070-4a0f-b624-2c0506201f9e', 'ER0787', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('386c4cb4-dc67-4a51-ba00-e933f6d9ad99', 'ER0789', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c19cfdc-4ff0-4ab4-a68c-9d55bf98e1e4', 'ER0798', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('91475f3f-93dd-40bc-b0e5-8d85df7af33e', 'ER0819', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4e8e5886-6f4d-47cb-8214-aa4cd3a9c554', 'ER0884', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b50006bd-23f2-499c-8670-f73831a99907', 'ER0940', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8401', '8402'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3b45216f-b3d3-428b-9e2e-226805feb575', 'ER0243', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66f1884b-8e62-4bf2-8bb5-6db5630b06ec', 'ER0276', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6021dde4-d44b-44e2-9426-ff02d19a7349', 'ER0289', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('75e88208-ea76-41a8-93be-e9fb21c2d824', 'ER0307', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dd1ee306-97f8-45b6-8d7d-31e4015205c3', 'ER0395', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c3a74f62-ca5d-4e9e-86a3-6c4f2936647f', 'ER0398', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1f00300c-f30f-48b9-8d58-2c06e01f1eca', 'ER0405', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8f3a0f3f-e94a-48fd-817e-c6703209d55b', 'ER0408', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('592a9a4d-e01d-4982-a892-a2563e368200', 'ER0417', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4b310da2-5a96-411c-8139-16d9af29d1b3', 'ER0418', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5eb79092-a49a-4e2c-a8da-db29ca5c5b76', 'ER0433', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8d2030e0-cbab-4145-8997-eb8f69fe7028', 'ER0461', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8531d883-91ba-42d1-930e-417f1b7817be', 'ER0483', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('655bf75d-8bd0-400e-8ccb-9da35c9563b2', 'ER0486', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ada0c954-818d-464b-b645-14c10bed38b1', 'ER0492', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7fbcf57b-60a2-416d-882c-55b8f64b038b', 'ER0498', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6ce448ad-fe7e-4747-bae2-fa2fc8716aea', 'ER0503', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('54a54e8e-af22-4e23-8c00-b9b9cc1c3522', 'ER0508', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0857e35e-736f-4482-9eab-cd1193ed7a3c', 'ER0516', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bef3c26c-1b21-40c3-a93b-70604f8f2e7f', 'ER0517', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('37aa644d-13a6-47c1-8e10-a11375e855c6', 'ER0536', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('929bacb9-1971-4da7-a46e-95e25e2ee18b', 'ER0572', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b41d60fa-50d4-42af-b2d0-2eb7b438e6c0', 'ER0583', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f1a5a1e6-40a7-4344-b263-533382f0335e', 'ER0587', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cb3e714d-3c75-45d7-9c27-a654beadaf1e', 'ER0603', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('90dfda6f-a07e-43d7-b53c-6403c10e70c9', 'ER0637', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ef765ad9-9d68-48a6-a88d-aa0c512642d5', 'ER0640', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('42e14dc4-2c2f-40ff-9174-c6c08d89d7e5', 'ER0702', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3a7ce3bf-999a-4159-8129-c8f9a9c85a8a', 'ER0707', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7390fbfd-1b5e-4c86-b484-4886fdfaef98', 'ER0713', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('222a866e-b908-4911-96a8-1fd6a747e9ab', 'ER0714', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8d04f3e5-674f-497c-ae28-30b2760555c7', 'ER0735', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca46a5d5-24ce-4cbe-b82d-20332898a151', 'ER0736', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('28d94088-1611-4f2b-904e-72e69c045966', 'ER0748', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe7eebbd-0f0e-4ca7-b9b9-ae23dc561c1f', 'ER0756', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('57af0deb-6fc7-44e7-82d9-ce4f58ead398', 'ER0759', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f4208f89-2baa-4744-9b29-a8d3737e29f4', 'ER0781', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4cd06a7c-eefb-4abd-a89d-56d8969e8b56', 'ER0796', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fadb0c34-dc98-4f8e-a8bf-37eedf00e87b', 'ER0807', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a326bc9c-872c-46c3-b958-8607936d4f1c', 'ER0814', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aafe2760-86d7-43c3-80c7-f2e878fd9060', 'ER0824', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('17d6c9b0-5a61-4b51-9c5b-92b595f8a1c3', 'ER0837', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('067d7c61-9700-4a29-adfc-122c2235e1e8', 'ER0847', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e8745d10-a448-4b94-9880-5078b6e19ea7', 'ER0853', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5bfc6567-b392-4ac2-9b09-34736efbc445', 'ER0857', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a2301a1a-15ad-4ac6-bcc5-7866fe7e7ae7', 'ER0859', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1629b705-12f9-4595-abf7-411e9419b545', 'ER0877', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4ce69add-afc2-4739-bff2-cdcf05c4f931', 'ER0902', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c53d8613-5eb9-4b2f-90ee-3604cd67c28c', 'ER0919', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('66a0ec93-0a11-4c50-b1d9-350d92483300', 'ER0924', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('276a4503-4922-4b2b-a539-204dd7d01872', 'ER0929', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8501', '8502'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5b5f4e09-639a-40f6-814f-e88832a8ba22', 'ER0234', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c2d25c3e-c9b3-4d44-bc7e-67f929765a01', 'ER0257', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e1e3766a-07fc-4cd9-84e8-44686a848c64', 'ER0262', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('df89693c-b27b-4846-9d27-490b87c343e6', 'ER0266', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7b606510-c3e5-4adc-9642-dc7cb90311b9', 'ER0268', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5218c202-9fa5-4f27-aabb-05b99c03e129', 'ER0293', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b21d8b50-a2bd-4385-b61c-c96700445a10', 'ER0294', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('45fbe1ad-c3b8-439e-9a2a-26bc3bdfd465', 'ER0300', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('24c48db9-ef4c-4f6d-8637-5fd9d772b019', 'ER0306', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5afa5ad2-d2e9-43b5-abe2-4de4c037bfd5', 'ER0455', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9bc9836b-20bb-4030-8f6f-71042710a5cc', 'ER0487', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5d1f7f47-9df2-4c85-a3a8-b05eaa5ff581', 'ER0488', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('916a503c-ed46-4a05-8da0-70b9966fe939', 'ER0494', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('44107f3b-34cd-42b3-9871-20ed9172cc34', 'ER0496', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('90da126b-3b7a-4856-b488-e80cde70e426', 'ER0526', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('485b767d-adf2-4693-a40a-88a0cba082af', 'ER0545', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b36ae160-3d96-471a-a00d-d519d48aa124', 'ER0551', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca166db1-61af-4c80-ba81-93dd4da40e0b', 'ER0556', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('75ab7abc-2b77-4cc6-91a9-c72dbde3e0c4', 'ER0605', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4426c5ed-32b3-4315-93a6-c38f63052ed9', 'ER0621', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('144110f5-29e0-45b2-b16f-dec5efe60dca', 'ER0628', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('01e0afe2-27e9-4b72-94f2-c26075cb2468', 'ER0629', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76695a22-10ca-4c5a-959d-dfc40d3c37f4', 'ER0644', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4add0597-ab48-44bf-9249-82bad9683547', 'ER0667', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d0a73e2a-09fa-43c8-84b3-35ae40093fc2', 'ER0670', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dd6c11d2-4269-45d2-8925-6fa05fc5e0b6', 'ER0677', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1b6c3642-437d-425f-9c9b-ba174d230f2a', 'ER0679', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7f128c18-eebc-4bdb-b0d6-edec7369345b', 'ER0711', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a56d58a3-acd7-45d0-a792-e713c1b8c84b', 'ER0769', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('45aa8a5a-22f7-44a0-8d80-a1c6df6d1126', 'ER0774', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ac16bc34-0986-4782-90e7-c5331e552b08', 'ER0778', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9eee6868-a339-4180-a8e3-dc1939c4b979', 'ER0785', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ce1467d9-6310-4d1e-bb25-d20d74d83c3d', 'ER0795', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('00f786b4-9362-41fa-898e-7cc97856bf1f', 'ER0808', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a9dff12d-3851-4fca-86c0-5b3ccbd88410', 'ER0841', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fb4bf42b-a7b2-405b-8cf2-5acb9fca77f9', 'ER0864', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6a3a1c87-e237-43f2-9871-d8e06b81551c', 'ER0874', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('aba45f65-f9fc-4d59-802f-52918d6a2cbb', 'ER0897', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('22f05112-fd59-4bc5-b20d-f834365b7725', 'ER0910', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f64753b7-8329-49ab-8c83-72354382ad9e', 'ER0921', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('26d1a520-81e5-46c2-aa7b-106b3cb0a5ca', 'ER0922', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('34d5896e-036d-43db-aeb0-21f40ff1893a', 'ER0930', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8601', '8602'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('48b4ea2f-9344-4ac2-9e05-3d01020dbbd1', 'ER0224', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('db4768fc-a3c9-445e-b5f5-c4a3918aa251', 'ER0233', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d85d7d8b-ac82-4701-b803-d5c011c8cf81', 'ER0263', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a8558ac6-1ada-4e6c-86bc-06af088baafa', 'ER0282', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d2557abb-aaf8-461d-af63-0abadceebf69', 'ER0291', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('df532af7-c667-4fc9-8c29-82519e4dda33', 'ER0313', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f91ee436-06ab-4fce-901f-f21630a6548b', 'ER0315', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63b506c4-29cb-4d01-b8d0-4f9c064c1fb2', 'ER0394', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('490bab67-e0f6-46cd-9c1c-84513602c107', 'ER0409', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c2d7f8cc-199d-4898-80f7-5d611d5743d1', 'ER0423', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('92ba1e7e-d73e-4661-9259-6172db65ae76', 'ER0429', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4c75e5e4-fc76-41f9-ba10-1c5842cc066d', 'ER0444', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bbf05411-4a8f-4899-a7b9-7ae5be878503', 'ER0449', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('84835798-8688-44c2-9087-098b580f2530', 'ER0466', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ef2708f0-aac6-42ac-bda3-1b0a5ef7853f', 'ER0467', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f2fb74db-8cf0-4524-9aeb-92069cef0fdc', 'ER0471', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1e3b292e-5ad8-47d6-998b-2ffc905319ec', 'ER0481', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('121c3724-289b-497c-9fda-153bb3a7a795', 'ER0499', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('db166fca-953d-496b-a77d-3713a10ec081', 'ER0518', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4fcaf494-3725-468c-85ec-6cdbaa4f643b', 'ER0525', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6fcf243b-2230-42b8-942c-546be0b6b114', 'ER0531', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7339304c-8400-4939-addc-c2c4aefa9c7d', 'ER0533', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bbed71c2-a657-486d-8f41-fb39d4eb5701', 'ER0548', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fbc0f04c-b8ed-4a76-b3cd-e548fc80f36a', 'ER0553', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c934ebf7-b05e-4e24-845f-af8d6631b02e', 'ER0554', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('864543b5-4b94-4e97-a939-15579f86b60a', 'ER0560', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1cca5ef8-2ded-4432-aef9-482cfe4bdfa6', 'ER0580', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('393f2e14-0b81-4451-9344-d5c52c49860b', 'ER0582', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ebaa136-fa67-47eb-ae1f-c9e721f41f31', 'ER0593', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('eb8b77f6-d06b-478b-b3fb-5d90f9b13deb', 'ER0598', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8f9f6a2c-f941-449d-8196-14c9b6481195', 'ER0607', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e6cc959c-c08c-45a6-9faf-d0686606312b', 'ER0608', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('92c08123-66e6-4200-9fe2-790c1c9fb508', 'ER0613', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e9bba76e-2c70-4e4e-9c5a-a8d4570815fe', 'ER0619', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8840de27-7db1-4c0e-a6b7-7db26f1589e6', 'ER0634', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a777c006-4d1c-4ae2-ac9b-d99b4c4e4bb3', 'ER0645', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('548d55f1-e19c-4e76-a0c4-245c22d64e1c', 'ER0647', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7f81e1a1-7417-46b1-8e00-62710a63f1d6', 'ER0655', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0d5b35a8-2356-4601-b653-bf53c08bf4a6', 'ER0661', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b4ce9b6b-60ca-40eb-980c-00f895005ad7', 'ER0665', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('39e50601-6a88-4f2b-8f05-18e72b09720f', 'ER0671', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d6dee81d-b8a8-4725-bf42-a6b4363b6b78', 'ER0675', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6ff857ae-c692-42a9-9b2c-7e6224bd6151', 'ER0680', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5bc99e38-d1c4-4b2c-b96e-4af70617ebfd', 'ER0683', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('957094af-17b1-4640-a8be-27a8c5095df0', 'ER0689', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('99a6ab1d-e48b-4ced-8667-53027856678d', 'ER0693', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c0f394d8-bca7-440e-a9b3-e685c4fcf22f', 'ER0700', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('74e95deb-8659-4fb9-b2a7-53b0a1b552b3', 'ER0705', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a1f03597-33cc-43ef-bfc0-b78ae6f91827', 'ER0706', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fadeeb80-fb4b-4885-9cd1-f2b7f33bab6e', 'ER0718', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3ae69d77-428a-49de-bcc2-99ffbc981948', 'ER0726', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9c30f391-d476-455f-84e6-c12b699acc7c', 'ER0775', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2d9f04a2-3be9-4d3b-b5b6-1868789bb8ea', 'ER0788', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53d44bfe-09c9-4eb7-86b3-6626813bd203', 'ER0797', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('eda8a7d9-4de9-4720-9620-9c0a065ecc83', 'ER0823', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2bfd5224-4f3f-46ae-b851-498b972c0612', 'ER0854', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8b59cc57-8097-4052-be27-6463663235eb', 'ER0861', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a4bb37cc-a039-48b6-b53a-7380311822a9', 'ER0878', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('666e10a9-1042-4a00-b50b-5ffd59c88b9f', 'ER0887', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c098a51-3be1-41a9-854a-eca567836036', 'ER0890', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9dfd5f00-ce8f-46c8-a235-447943a0452b', 'ER0891', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('113fdac4-2b71-4467-bd9e-4d613d4bfd2b', 'ER0900', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bce95038-cbf3-478b-b797-180cbcedd3c7', 'ER0904', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('886242d5-d42b-4b85-aa34-b92857c9f0dc', 'ER0909', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('d6475596-dc89-48f6-b7e2-f4502af2c6f8', 'ER0911', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('33faf2b3-ccbf-487e-9837-1b5dcc99b6d2', 'ER0934', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8701', '8702'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('15b7ca8c-9922-4a9c-b9b1-6e637e7a1c39', 'ER0275', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('7545a1c0-7027-4c40-ba8c-748e96da1d5c', 'ER0333', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('deb2d3b4-d0ad-4070-b9e0-bfc5c0578e2f', 'ER0344', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9d4f86e5-e1f4-491f-877f-ccffcd14ab6a', 'ER0404', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3c814bed-c470-4b1d-8bb9-69a49df6aeaa', 'ER0436', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('117595c6-8e75-4670-be93-80ecfecd0379', 'ER0460', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5e4a46fe-4a31-48b1-8daa-f8eb5689148e', 'ER0463', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8b9d5d43-5e44-48b2-b1bd-5acff34a15f6', 'ER0465', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5f3820c7-ae84-437f-8950-47800517ff27', 'ER0469', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('481a6c4a-3db2-4fb6-978d-21316ce814c3', 'ER0473', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b85e9254-cadb-440c-8e4e-61802902a665', 'ER0476', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9c1bc306-db4d-4d39-8424-110d870e7dd5', 'ER0501', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ad940857-679b-4420-b129-4b04b5a07811', 'ER0504', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cc4b84b8-c4c4-4dad-ab7b-8d4fe0157ffa', 'ER0546', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8dafc20f-2c2d-40ed-aa3e-c98fafe838cd', 'ER0552', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c01e8109-57ba-48bb-8f23-a91774ec55e2', 'ER0569', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('808333ea-eb66-4d29-86d2-249dc371b100', 'ER0591', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3d0311b1-41a5-4645-bf8c-d306b8a799e6', 'ER0601', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('23c9f847-c950-48df-aec3-ee739cb9ad19', 'ER0610', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('68de6630-d048-4e9f-a75f-080675865052', 'ER0626', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('14fee469-347b-4a0d-9ddb-b64687647af9', 'ER0652', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('23c53815-feed-4e70-ac86-a12ef9a06557', 'ER0669', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e1033611-3fbc-4e58-ad80-27a7c1ceb450', 'ER0716', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('21b6c26c-f555-4a64-a171-0e46cdb5b923', 'ER0717', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('76fb0ea3-1b62-4063-9dfb-4be0c160551b', 'ER0749', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('64024720-d7d1-48d2-bf16-7ca3e44d6578', 'ER0751', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0378f377-221e-4b59-a70b-bafcdc69b1be', 'ER0777', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('68d544ea-7b3f-4de4-8e11-64652d81d21d', 'ER0805', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ea24e86a-1241-43ce-8d69-9121755306b9', 'ER0809', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c116df0-435e-4098-9138-ffa821550a4f', 'ER0811', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8505fe09-a6bf-4b86-bbdf-9cafb57cff07', 'ER0827', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2a6e39dc-85b5-47dd-9a10-81f9f4e10531', 'ER0832', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dd982300-c457-4017-8401-080529e12b12', 'ER0883', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53897945-831d-4b05-99d2-02bc94bdf867', 'ER0886', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6989ad64-80d7-4a48-afa2-1b721ca8e63f', 'ER0889', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3da36b57-8719-4f34-ab0c-d90cf1cf244b', 'ER0894', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('44fa08b3-e6c9-4712-a526-8eef60ed0ff2', 'ER0895', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63d64918-d12b-46fa-a1e2-34fb7134e534', 'ER0896', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5ec32d8c-7594-49a7-a19b-09401a9a9ba5', 'ER0903', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e0f372ab-9312-4429-8a4b-176c337e3e49', 'ER0936', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8801', '8802'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5795e9d8-f589-43aa-a50a-537ee9727cc3', 'ER0221', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0a2841db-8121-4263-9eed-2f51ce413057', 'ER0227', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bab539d3-e05a-4d06-b77f-736d1315fb4b', 'ER0271', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4cbffeae-1565-49d4-86f7-94e165843502', 'ER0287', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5839ffd3-b953-4ed6-8f07-3fada891bd6f', 'ER0310', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6c232d17-3e7c-4773-a9cf-efb7e100cfa5', 'ER0349', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5037e250-5f37-414e-95e6-ddecde35dc1e', 'ER0403', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9cfb155b-a81c-406a-a67c-38efeb6c70ce', 'ER0406', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4e8f2fdd-8873-4048-a296-a1bf79b3fdc5', 'ER0413', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('63a2ce55-b94a-41a5-8415-ce69ff933873', 'ER0414', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('597231aa-cd99-4d70-bf89-1e8dac4339d1', 'ER0416', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('71214120-7d0e-4f44-af70-88b2ccbaeede', 'ER0428', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ad5f34bf-9d9f-46ed-98c1-d25d4350a5f7', 'ER0441', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0745e642-aa0d-4a96-927a-9fa8cce6a236', 'ER0448', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a5a15904-b3fd-40c4-a8f1-a3997d4b8a13', 'ER0453', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c8c35711-bd14-415c-9ac0-02c0c4ca316d', 'ER0468', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dee33af4-9055-4056-b290-d0a5aeee3028', 'ER0478', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('daded727-0378-4ff7-ae2b-48a4c2d5fcf3', 'ER0497', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3c4c57d8-7572-4066-ab3a-ec2cc5ae4dcb', 'ER0506', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('41804040-1ffe-46fd-a1dc-e8090ca632b9', 'ER0507', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('39057978-6d6e-4012-a8ac-80a627651319', 'ER0511', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('caf96e80-497c-4eba-9c8d-7b1c1786a768', 'ER0512', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0a025d5f-2a26-4dd6-8104-2f6bcbc4aeeb', 'ER0584', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1ee39efd-69a8-4611-aedf-ae04cfa104f8', 'ER0589', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c2d1438f-7e25-4cd5-9964-24ff0111a5d5', 'ER0597', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('56763b7d-c8e4-4a19-bb1c-4c36b1bb51c1', 'ER0627', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('95f9fe47-e32c-47ff-80da-530c7d8720d5', 'ER0638', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a616ddb2-541e-465c-9686-0da4045b44a5', 'ER0643', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53578253-6f35-424e-b9e6-182584a515d4', 'ER0659', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c9e3c47e-ec6e-4b04-82b7-15b484d5536b', 'ER0743', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b26a6799-4bee-4477-bcc9-dce162f8fe1f', 'ER0763', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c377e023-995c-4740-a57d-32960a3f96ab', 'ER0765', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('db616bff-378a-4515-8409-f39f669d41d2', 'ER0767', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('082d9f7f-e18c-4372-8889-cd5368c286ed', 'ER0866', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c5a8976a-081e-4877-a381-54cc4be30534', 'ER0873', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('f697d11f-c097-428e-99a4-33cd090b1aec', 'ER0893', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('554e1780-3331-4f54-b012-5ed28ad9d067', 'ER0908', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('986a0cd5-29bb-49af-a152-1470dc24c56b', 'ER0913', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fef77879-433f-4fe1-ba57-e0ba42a50d2e', 'ER0916', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '8901', '8902'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('cbd30f71-825e-4d82-9e05-6e8f9e64fa0d', 'ER0225', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c278a611-1e08-45c7-a5b5-c0ca77da0585', 'ER0229', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1fee60de-d0c5-41de-9c14-f5ad210a1701', 'ER0251', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('53c5c988-f8e8-4b53-b883-6dad185fc23c', 'ER0259', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a0165c32-9d76-4c7b-bec0-32f00cab1d03', 'ER0270', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('908085eb-45d6-4131-8fc3-bdcafa585570', 'ER0285', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('119ae9e0-a633-4db2-8f2a-86ac5add3b48', 'ER0298', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('876e240d-ff7b-4bec-bcf7-28bbaa4d748d', 'ER0327', '7b5d91ee-d36c-4383-a27b-3b65179d568d', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c265c938-843c-43e9-b7c9-169ff60a6fab', 'ER0337', 'a3cd0de4-33f1-43e4-bf27-03a94b03e1e7', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('eb6fdc23-6dd2-462f-a940-b5c6aa9fb809', 'ER0399', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('56bf95fb-9b77-46b7-b25e-6ef87e22ba8e', 'ER0446', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e2108bea-12c6-4586-9f5a-cc1476eee9a9', 'ER0450', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('e52b3ba4-3bad-4fdb-b25d-62476ac70051', 'ER0477', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ebf47cb5-ab4b-450b-8f51-371e86bbdfde', 'ER0489', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('269ece03-5f28-4f84-b0e2-2cd1cf9a4be1', 'ER0490', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4499b6f8-c0d2-45cc-a258-d4dbabe987b0', 'ER0529', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('22f14acc-01d8-49b9-9d1f-59b9a80bfdcf', 'ER0570', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a71488ea-4d28-4c72-badd-5d6bc561f852', 'ER0574', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3dd05274-f775-4bcb-b6da-2a0f84e07a35', 'ER0576', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0f5f4b73-23f8-42da-8585-61c4525e57de', 'ER0592', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bf10f3ba-67a2-4fd6-85f4-0f2e5ee2da92', 'ER0617', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fe1692d2-c43b-4962-9ac0-b5fefdef6c1e', 'ER0620', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fa334b93-427a-4219-af90-8eb0438f3ccf', 'ER0623', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fbf24d86-974a-469c-b7bc-90828fb023c5', 'ER0631', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('0f79d8c5-86fd-48df-9c30-926d860ec1f9', 'ER0651', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('fea11fd0-baa6-4f8d-a461-61b9b8da026d', 'ER0668', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('4a38b1c4-21bd-4cfe-81f5-eda01c54d1bf', 'ER0672', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2ab1614b-cef4-4bce-a939-7e0435403aa4', 'ER0681', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('dfda7d1c-8bd8-46e3-87b1-535ff26e09ba', 'ER0685', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('2ad12db5-339a-4a38-bc8c-a942ec85883f', 'ER0699', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('1a3c1a1d-2d02-4bb0-8a2d-8e9c791d4651', 'ER0732', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('c7cb4640-2251-4c71-9a4d-fd124284fbad', 'ER0737', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('21f7c365-73c7-453e-a8e6-e7fbfa0a88a1', 'ER0738', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('bce08b82-4a75-4d43-bbdf-cc5cb2dee90f', 'ER0741', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ea8bfb8f-7a7f-4c69-b90d-d464f440e5db', 'ER0753', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('a256a58e-1044-448f-9b0d-bbb900243b41', 'ER0754', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b1acbd02-b4e4-4ba4-9633-cc5226264e3a', 'ER0770', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('5cd93f30-2d56-4ce5-91c4-b195fc337bd0', 'ER0802', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ea4b1c28-4e88-42af-b7d2-f5dfe645ffbf', 'ER0803', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('8d2b91cf-5f97-42d0-b34b-0927654f1a28', 'ER0810', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('6add4aab-b606-4503-a983-737c44207a13', 'ER0815', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('721bd886-2d45-4b36-9ed9-a9a8c3e4c82f', 'ER0836', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('3da30c23-fac3-4149-abe2-ce49cddba882', 'ER0842', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('256ab1ed-927b-411a-9ec5-afdfcaacfe61', 'ER0851', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('355f676d-0991-4516-baaa-175328a0f1ca', 'ER0865', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('ca1158e7-f886-495e-9700-be56305b4b39', 'ER0872', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('121aedad-1ab9-49e1-920b-526f2db3cf4c', 'ER0882', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('9ffc812d-a667-4894-9ea2-4a39e3c3f73e', 'ER0899', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('85c8140f-1308-4b5d-b9cb-411e5fefb040', 'ER0912', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +INSERT INTO freight.wagons (id, wagon_number, wagon_type_id, train_id, sequence_number, status, notes, created_at, updated_at, deleted_at, current_location_yard_id, train_set_wagon_id, current_train_schedule_id, current_yard_id, export_train_number, import_train_number) VALUES ('b76d84fd-839e-4bf1-b7f5-ddca82dbbd3a', 'ER0927', 'f7886975-ba6f-422d-8de4-e672c8482699', NULL, NULL, 'AVAILABLE', NULL, '2026-08-05 07:31:08.666221+00', '2026-08-05 07:31:08.870506+00', NULL, NULL, NULL, NULL, 'bf73dbd3-79aa-4ff8-a471-aed47e5ca29d', '9001', '9002'); +`, +}; + +const FOREIGN_KEYS_SQL = ` +ALTER TABLE ONLY freight.last_mile_container_allocations + ADD CONSTRAINT "FK_0bc28c4087bb0c6e435677a6fcb" FOREIGN KEY (last_mile_id) REFERENCES freight.last_mile(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.ff_clients + ADD CONSTRAINT "FK_1101fbe8e745d91b6bd0747b582" FOREIGN KEY (forwarder_company_id) REFERENCES freight.companies(id); + +ALTER TABLE ONLY freight.last_mile + ADD CONSTRAINT "FK_173a865c0889b8c5564993c70ff" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.external_profiles + ADD CONSTRAINT "FK_26d2a16e263ab4fe0a4c8e91954" FOREIGN KEY (company_id) REFERENCES freight.companies(id); + +ALTER TABLE ONLY freight.company_profiles + ADD CONSTRAINT "FK_30228dd283a0f14486346e1db96" FOREIGN KEY (company_id) REFERENCES freight.companies(id); + +ALTER TABLE ONLY freight.first_mile_container_allocations + ADD CONSTRAINT "FK_31dfdcea6bf62ec98f2e5428996" FOREIGN KEY (first_mile_id) REFERENCES freight.first_mile(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.company_change_request + ADD CONSTRAINT "FK_366962cebba507dd8b0146f7f47" FOREIGN KEY (company_id) REFERENCES freight.companies(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouses + ADD CONSTRAINT "FK_374ce3a1439d02d5ff97e479921" FOREIGN KEY (facility_id) REFERENCES freight.facilities(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_container_allocations + ADD CONSTRAINT "FK_4fa907f6cc2cfe181385dcd57c5" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_requests + ADD CONSTRAINT "FK_590f6298c3c3ae09d982f96fb9d" FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.import_djibouti_operations + ADD CONSTRAINT "FK_6c3e3046300b152a13505bf8ffd" FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_6fa72e9c8fdfa587cffd9383470" FOREIGN KEY (destination_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.last_mile_container_allocations + ADD CONSTRAINT "FK_825ceccffec68ac49c85bd75de0" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.interchange_document_items + ADD CONSTRAINT "FK_864508e9249279bd3e12dafdd21" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.company_revisions + ADD CONSTRAINT "FK_8a17ca32f9e4624e1c55c51f7c7" FOREIGN KEY (company_id) REFERENCES freight.companies(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.first_mile_container_allocations + ADD CONSTRAINT "FK_8bba293eb2fd548433d28d97103" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_container + ADD CONSTRAINT "FK_91946ca51ff65658f487eae1162" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_container_allocations + ADD CONSTRAINT "FK_99c89fe4e4c3e3670fdc25ea9a9" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_requests + ADD CONSTRAINT "FK_9e49de0ed55d84d3f97627040cd" FOREIGN KEY (created_booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.cargo_types + ADD CONSTRAINT "FK_CARGO_TYPES_PARENT_GROUP" FOREIGN KEY (parent_group_id) REFERENCES freight.cargo_types(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.first_mile + ADD CONSTRAINT "FK_a19b54ac3d426df8cc0e313be06" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.first_mile + ADD CONSTRAINT "FK_a2ae03360a02c61fdc2e8361ea8" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.ff_clients + ADD CONSTRAINT "FK_af4d6bac2844d39095b2056e978" FOREIGN KEY (client_company_id) REFERENCES freight.companies(id); + +ALTER TABLE ONLY freight.booking_cargo_modifier + ADD CONSTRAINT "FK_booking_cargo_modifier_booking_id" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_cargo_modifier + ADD CONSTRAINT "FK_booking_cargo_modifier_rate_id" FOREIGN KEY (rate_id) REFERENCES freight.rates(id); + +ALTER TABLE ONLY freight.booking_cargo_modifier + ADD CONSTRAINT "FK_booking_cargo_modifier_rate_snapshot_id" FOREIGN KEY (rate_snapshot_id) REFERENCES freight.booking_rate_snapshot(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.booking_container + ADD CONSTRAINT "FK_booking_container_container_type_id" FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.booking_container + ADD CONSTRAINT "FK_booking_container_weight_limit_rule_id" FOREIGN KEY (weight_limit_rule_id) REFERENCES freight.weight_limit_rules(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_rate_snapshot + ADD CONSTRAINT "FK_booking_rate_snapshot_booking_id" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_rate_snapshot + ADD CONSTRAINT "FK_booking_rate_snapshot_rate_id" FOREIGN KEY (rate_id) REFERENCES freight.rates(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_cargo_type_id" FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_company_id" FOREIGN KEY (company_id) REFERENCES freight.companies(id); + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_company_profile_id" FOREIGN KEY (company_profile_id) REFERENCES freight.company_profiles(id); + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_consolidation_partner_id" FOREIGN KEY (consolidation_partner_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_customer_id" FOREIGN KEY (customer_id) REFERENCES freight.customers(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_service_type_id" FOREIGN KEY (service_type_id) REFERENCES freight.service_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_shipping_line_id" FOREIGN KEY (shipping_line_id) REFERENCES freight.shipping_lines(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_bookings_train_id" FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.last_mile + ADD CONSTRAINT "FK_c2d9331fda382ae3e92e6bf913a" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_document_review + ADD CONSTRAINT "FK_c669c986810af3b82cf033a8d79" FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.interchange_document_items + ADD CONSTRAINT "FK_c9fba2c4a1631542a37ad5089d7" FOREIGN KEY (interchange_document_id) REFERENCES freight.interchange_documents(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT "FK_cabe80a0c7b9e0144854a4f353d" FOREIGN KEY (origin_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT "FK_cargoes_cargo_type_id" FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id); + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT "FK_cargoes_container_id" FOREIGN KEY (container_id) REFERENCES freight.containers(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.cargo_type_wagon_types + ADD CONSTRAINT "FK_cgwt_cargo_type" FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.cargo_type_wagon_types + ADD CONSTRAINT "FK_cgwt_wagon_type" FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT "FK_containers_container_type_id" FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id); + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT "FK_containers_wagon_id" FOREIGN KEY (wagon_id) REFERENCES freight.wagons(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.container_type_wagon_types + ADD CONSTRAINT "FK_ctwt_container_type" FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.container_type_wagon_types + ADD CONSTRAINT "FK_ctwt_wagon_type" FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.dropdown_options + ADD CONSTRAINT "FK_dropdown_options_setting" FOREIGN KEY (setting_id) REFERENCES freight.dropdown_settings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.file_upload_fields + ADD CONSTRAINT "FK_file_upload_fields_setting" FOREIGN KEY (setting_id) REFERENCES freight.file_upload_settings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.locomotives + ADD CONSTRAINT "FK_locomotive_current_yard" FOREIGN KEY (current_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.rates + ADD CONSTRAINT "FK_rates_cargo_type_id" FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.rates + ADD CONSTRAINT "FK_rates_destination_yard_id" FOREIGN KEY (destination_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.rates + ADD CONSTRAINT "FK_rates_origin_yard_id" FOREIGN KEY (origin_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.train_locomotives + ADD CONSTRAINT "FK_train_locomotives_locomotive" FOREIGN KEY (locomotive_id) REFERENCES freight.locomotives(id); + +ALTER TABLE ONLY freight.train_locomotives + ADD CONSTRAINT "FK_train_locomotives_train" FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.train_set_locomotives + ADD CONSTRAINT "FK_train_set_locomotives_locomotive" FOREIGN KEY (locomotive_id) REFERENCES freight.locomotives(id); + +ALTER TABLE ONLY freight.train_set_locomotives + ADD CONSTRAINT "FK_train_set_locomotives_train_set" FOREIGN KEY (train_set_id) REFERENCES freight.train_sets(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.train_sets + ADD CONSTRAINT "FK_train_sets_train" FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.trains + ADD CONSTRAINT "FK_trains_current_yard" FOREIGN KEY (current_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT "FK_wagon_current_yard" FOREIGN KEY (current_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT "FK_wagons_current_location_yard_id" FOREIGN KEY (current_location_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT "FK_wagons_train_id" FOREIGN KEY (train_id) REFERENCES freight.trains(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT "FK_wagons_wagon_type_id" FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id); + +ALTER TABLE ONLY freight.warranties + ADD CONSTRAINT "FK_warranties_vehicle_id" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.weight_limit_rules + ADD CONSTRAINT "FK_weight_limit_rules_container_type" FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.work_orders + ADD CONSTRAINT "FK_work_orders_vehicle_id" FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_batch_offers + ADD CONSTRAINT booking_batch_offers_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_batch_offers + ADD CONSTRAINT booking_batch_offers_train_schedule_id_fkey FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_container_units + ADD CONSTRAINT booking_container_units_booking_container_id_fkey FOREIGN KEY (booking_container_id) REFERENCES freight.booking_container(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_contract_signatures + ADD CONSTRAINT booking_contract_signatures_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_contract_signatures + ADD CONSTRAINT booking_contract_signatures_signature_file_id_fkey FOREIGN KEY (signature_file_id) REFERENCES freight.files(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_document_review + ADD CONSTRAINT booking_document_review_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id); + +ALTER TABLE ONLY freight.booking_handovers + ADD CONSTRAINT booking_handovers_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.booking_handovers + ADD CONSTRAINT booking_handovers_edr_assignment_id_fkey FOREIGN KEY (edr_assignment_id) REFERENCES freight.last_mile_vehicle_assignments(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_handovers + ADD CONSTRAINT booking_handovers_truck_assignment_id_fkey FOREIGN KEY (truck_assignment_id) REFERENCES freight.customer_truck_assignments(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.booking_review_note + ADD CONSTRAINT booking_review_note_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT bookings_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id); + +ALTER TABLE ONLY freight.bookings + ADD CONSTRAINT bookings_contract_route_id_fkey FOREIGN KEY (contract_route_id) REFERENCES freight.contract_routes(id); + +ALTER TABLE ONLY freight.clearance_incidents + ADD CONSTRAINT clearance_incidents_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.clearance_milestones + ADD CONSTRAINT clearance_milestones_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.clearance_milestones + ADD CONSTRAINT clearance_milestones_clearance_cycle_id_fkey FOREIGN KEY (clearance_cycle_id) REFERENCES freight.contract_clearance_cycles(id); + +ALTER TABLE ONLY freight.clearance_milestones + ADD CONSTRAINT clearance_milestones_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.compliance_records + ADD CONSTRAINT compliance_records_vehicle_id_fkey FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id); + +ALTER TABLE ONLY freight.contract_approval_steps + ADD CONSTRAINT contract_approval_steps_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_cargo_scope + ADD CONSTRAINT contract_cargo_scope_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_clearance_cycles + ADD CONSTRAINT contract_clearance_cycles_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_document_review + ADD CONSTRAINT contract_document_review_clearance_cycle_id_fkey FOREIGN KEY (clearance_cycle_id) REFERENCES freight.contract_clearance_cycles(id); + +ALTER TABLE ONLY freight.contract_document_review + ADD CONSTRAINT contract_document_review_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_document_revisions + ADD CONSTRAINT contract_document_revisions_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_rate_snapshots + ADD CONSTRAINT contract_rate_snapshots_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_review_notes + ADD CONSTRAINT contract_review_notes_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_routes + ADD CONSTRAINT contract_routes_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contract_signatures + ADD CONSTRAINT contract_signatures_contract_id_fkey FOREIGN KEY (contract_id) REFERENCES freight.contracts(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.contracts + ADD CONSTRAINT contracts_renewal_of_id_fkey FOREIGN KEY (renewal_of_id) REFERENCES freight.contracts(id); + +ALTER TABLE ONLY freight.customer_truck_assignments + ADD CONSTRAINT customer_truck_assignments_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.customer_truck_containers + ADD CONSTRAINT customer_truck_containers_assignment_id_fkey FOREIGN KEY (assignment_id) REFERENCES freight.customer_truck_assignments(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.customer_truck_containers + ADD CONSTRAINT customer_truck_containers_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.facility_handling_events + ADD CONSTRAINT facility_handling_events_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id); + +ALTER TABLE ONLY freight.facility_handling_events + ADD CONSTRAINT facility_handling_events_inventory_id_fkey FOREIGN KEY (inventory_id) REFERENCES freight.warehouse_inventory(id); + +ALTER TABLE ONLY freight.facility_handling_events + ADD CONSTRAINT facility_handling_events_train_schedule_id_fkey FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id); + +ALTER TABLE ONLY freight.facility_handling_events + ADD CONSTRAINT facility_handling_events_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.first_mile_vehicle_assignments + ADD CONSTRAINT first_mile_vehicle_assignments_first_mile_id_fkey FOREIGN KEY (first_mile_id) REFERENCES freight.first_mile(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.first_mile_vehicle_assignments + ADD CONSTRAINT first_mile_vehicle_assignments_vehicle_id_fkey FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id); + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT fk_cargoes_booking FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.cargoes + ADD CONSTRAINT fk_cargoes_wagon_allocation FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT fk_containers_booking FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT fk_containers_booking_container FOREIGN KEY (booking_container_id) REFERENCES freight.booking_container(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.containers + ADD CONSTRAINT fk_containers_wagon_allocation FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.fuel_consumption + ADD CONSTRAINT fk_fuel_consumption_vehicle FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.fuel_purchases + ADD CONSTRAINT fk_fuel_purchases_vehicle FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.invoice_lines + ADD CONSTRAINT fk_invoice_lines_invoice FOREIGN KEY (invoice_id) REFERENCES freight.invoices(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.invoices + ADD CONSTRAINT fk_invoices_company FOREIGN KEY (company_id) REFERENCES freight.companies(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.invoices + ADD CONSTRAINT fk_invoices_company_profile FOREIGN KEY (company_profile_id) REFERENCES freight.company_profiles(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.invoices + ADD CONSTRAINT fk_invoices_payment FOREIGN KEY (payment_id) REFERENCES freight.payments(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.maintenance_costs + ADD CONSTRAINT fk_maintenance_schedule FOREIGN KEY (maintenance_schedule_id) REFERENCES freight.maintenance_schedules(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.payment_refunds + ADD CONSTRAINT fk_payment_refunds_payment FOREIGN KEY (payment_id) REFERENCES freight.payments(id) ON DELETE RESTRICT; + +ALTER TABLE ONLY freight.train_schedule_bookings + ADD CONSTRAINT fk_train_schedule_bookings_booking FOREIGN KEY (booking_id) REFERENCES freight.bookings(id); + +ALTER TABLE ONLY freight.train_schedule_bookings + ADD CONSTRAINT fk_train_schedule_bookings_schedule FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT fk_train_schedules_destination FOREIGN KEY (destination_station_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT fk_train_schedules_origin FOREIGN KEY (origin_station_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT fk_train_schedules_route FOREIGN KEY (route_id) REFERENCES freight.routes(id); + +ALTER TABLE ONLY freight.train_schedules + ADD CONSTRAINT fk_train_schedules_train_set FOREIGN KEY (train_set_id) REFERENCES freight.train_sets(id); + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT fk_train_set_wagons_physical_wagon FOREIGN KEY (physical_wagon_id) REFERENCES freight.wagons(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT fk_train_set_wagons_train_set FOREIGN KEY (train_set_id) REFERENCES freight.train_sets(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT fk_train_set_wagons_wagon_type FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id); + +ALTER TABLE ONLY freight.train_sets + ADD CONSTRAINT fk_train_sets_locomotive FOREIGN KEY (locomotive_id) REFERENCES freight.locomotives(id); + +ALTER TABLE ONLY freight.vehicles + ADD CONSTRAINT fk_vehicles_truck_type FOREIGN KEY (truck_type_id) REFERENCES freight.truck_types(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_allocation_bulk_loads + ADD CONSTRAINT fk_wabl_allocation FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.wagon_allocation_bulk_loads + ADD CONSTRAINT fk_wabl_booking FOREIGN KEY (booking_id) REFERENCES freight.bookings(id); + +ALTER TABLE ONLY freight.wagon_allocation_bulk_loads + ADD CONSTRAINT fk_wabl_cargo_type FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_allocation_container_items + ADD CONSTRAINT fk_waci_allocation FOREIGN KEY (wagon_booking_allocation_id) REFERENCES freight.wagon_booking_allocations(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.wagon_allocation_container_items + ADD CONSTRAINT fk_waci_booking_container FOREIGN KEY (booking_container_id) REFERENCES freight.booking_container(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_allocation_container_items + ADD CONSTRAINT fk_waci_container FOREIGN KEY (container_id) REFERENCES freight.containers(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_allocation_container_items + ADD CONSTRAINT fk_waci_container_type FOREIGN KEY (container_type_id) REFERENCES freight.container_types(id); + +ALTER TABLE ONLY freight.wagon_booking_allocations + ADD CONSTRAINT fk_wagon_booking_allocations_booking FOREIGN KEY (booking_id) REFERENCES freight.bookings(id); + +ALTER TABLE ONLY freight.wagon_booking_allocations + ADD CONSTRAINT fk_wagon_booking_allocations_wagon FOREIGN KEY (train_set_wagon_id) REFERENCES freight.train_set_wagons(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT fk_wagons_current_train_schedule FOREIGN KEY (current_train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagons + ADD CONSTRAINT fk_wagons_train_set_wagon FOREIGN KEY (train_set_wagon_id) REFERENCES freight.train_set_wagons(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT fk_wm_transfer_request FOREIGN KEY (transfer_request_id) REFERENCES freight.wagon_transfer_requests(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_transfer_requests + ADD CONSTRAINT fk_wtr_from_yard FOREIGN KEY (from_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.wagon_transfer_requests + ADD CONSTRAINT fk_wtr_to_yard FOREIGN KEY (to_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.wagon_transfer_requests + ADD CONSTRAINT fk_wtr_wagon_type FOREIGN KEY (wagon_type_id) REFERENCES freight.wagon_types(id); + +ALTER TABLE ONLY freight.gps_devices + ADD CONSTRAINT gps_devices_vehicle_id_fkey FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id); + +ALTER TABLE ONLY freight.last_mile_vehicle_assignments + ADD CONSTRAINT last_mile_vehicle_assignments_last_mile_id_fkey FOREIGN KEY (last_mile_id) REFERENCES freight.last_mile(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.last_mile_vehicle_assignments + ADD CONSTRAINT last_mile_vehicle_assignments_vehicle_id_fkey FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id); + +ALTER TABLE ONLY freight.last_mile_vehicle_containers + ADD CONSTRAINT last_mile_vehicle_containers_assignment_id_fkey FOREIGN KEY (assignment_id) REFERENCES freight.last_mile_vehicle_assignments(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.maintenance_intervals + ADD CONSTRAINT maintenance_intervals_vehicle_id_fkey FOREIGN KEY (vehicle_id) REFERENCES freight.vehicles(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.priority_rule_change_requests + ADD CONSTRAINT priority_rule_change_requests_priority_config_id_fkey FOREIGN KEY (priority_config_id) REFERENCES freight.priority_configs(id); + +ALTER TABLE ONLY freight.rate_change_requests + ADD CONSTRAINT rate_change_requests_rate_id_fkey FOREIGN KEY (rate_id) REFERENCES freight.rates(id); + +ALTER TABLE ONLY freight.route_milestones + ADD CONSTRAINT route_milestones_route_id_fkey FOREIGN KEY (route_id) REFERENCES freight.routes(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.route_milestones + ADD CONSTRAINT route_milestones_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.routes + ADD CONSTRAINT routes_destination_yard_id_fkey FOREIGN KEY (destination_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.routes + ADD CONSTRAINT routes_origin_yard_id_fkey FOREIGN KEY (origin_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.train_checkpoint_events + ADD CONSTRAINT train_checkpoint_events_train_schedule_id_fkey FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT train_set_wagons_alight_yard_id_fkey FOREIGN KEY (alight_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.train_set_wagons + ADD CONSTRAINT train_set_wagons_board_yard_id_fkey FOREIGN KEY (board_yard_id) REFERENCES freight.yards(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_booking_id_fkey FOREIGN KEY (booking_id) REFERENCES freight.bookings(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_from_yard_id_fkey FOREIGN KEY (from_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_to_yard_id_fkey FOREIGN KEY (to_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_train_schedule_id_fkey FOREIGN KEY (train_schedule_id) REFERENCES freight.train_schedules(id) ON DELETE SET NULL; + +ALTER TABLE ONLY freight.wagon_movements + ADD CONSTRAINT wagon_movements_wagon_id_fkey FOREIGN KEY (wagon_id) REFERENCES freight.wagons(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_inventory_movement + ADD CONSTRAINT warehouse_inventory_movement_inventory_id_fkey FOREIGN KEY (inventory_id) REFERENCES freight.warehouse_inventory(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_inventory + ADD CONSTRAINT warehouse_inventory_warehouse_id_fkey FOREIGN KEY (warehouse_id) REFERENCES freight.warehouses(id); + +ALTER TABLE ONLY freight.warehouse_inventory + ADD CONSTRAINT warehouse_inventory_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.warehouse_yards(id); + +ALTER TABLE ONLY freight.warehouse_inventory + ADD CONSTRAINT warehouse_inventory_zone_id_fkey FOREIGN KEY (zone_id) REFERENCES freight.warehouse_zones(id); + +ALTER TABLE ONLY freight.warehouse_loadings + ADD CONSTRAINT warehouse_loadings_warehouse_inventory_id_fkey FOREIGN KEY (warehouse_inventory_id) REFERENCES freight.warehouse_inventory(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_yard_cargo_types + ADD CONSTRAINT warehouse_yard_cargo_types_cargo_type_id_fkey FOREIGN KEY (cargo_type_id) REFERENCES freight.cargo_types(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_yard_cargo_types + ADD CONSTRAINT warehouse_yard_cargo_types_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.warehouse_yards(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_yards + ADD CONSTRAINT warehouse_yards_warehouse_id_fkey FOREIGN KEY (warehouse_id) REFERENCES freight.warehouses(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.warehouse_zones + ADD CONSTRAINT warehouse_zones_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.warehouse_yards(id) ON DELETE CASCADE; + +ALTER TABLE ONLY freight.yard_distances + ADD CONSTRAINT yard_distances_from_yard_id_fkey FOREIGN KEY (from_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.yard_distances + ADD CONSTRAINT yard_distances_to_yard_id_fkey FOREIGN KEY (to_yard_id) REFERENCES freight.yards(id); + +ALTER TABLE ONLY freight.yard_facilities + ADD CONSTRAINT yard_facilities_yard_id_fkey FOREIGN KEY (yard_id) REFERENCES freight.yards(id) ON DELETE CASCADE; +`; + +export class FreightBaseline3250000000000 implements MigrationInterface { + name = "FreightBaseline3250000000000"; + + public async up(queryRunner: QueryRunner): Promise { + // Databases migrated before the squash already have every object below. + if (await queryRunner.hasTable("freight.bookings")) return; + + await queryRunner.query(STRUCTURE_SQL); + for (const sql of Object.values(FREIGHT_SEED_SQL)) { + await queryRunner.query(sql); + } + await queryRunner.query(FOREIGN_KEYS_SQL); + } + + public async down(): Promise { + // Reverting the baseline means dropping the entire freight schema, which is + // never what a `migration:revert` intends. Drop the database instead. + throw new Error( + "FreightBaseline3250000000000 is a squashed baseline and cannot be reverted", + ); + } +} diff --git a/apps/edr-freight-api/src/scripts/migrate.ts b/apps/edr-freight-api/src/scripts/migrate.ts index 7f331e1d3..ac8a97b28 100644 --- a/apps/edr-freight-api/src/scripts/migrate.ts +++ b/apps/edr-freight-api/src/scripts/migrate.ts @@ -1,24 +1,179 @@ import "dotenv/config"; -import { AppDataSource } from "../data-source"; -import { ensurePostgresSchemas } from "../config/ensure-postgres-schemas"; -import { buildDataSourceOptions } from "../config/database.config"; +import { DataSource, DataSourceOptions } from "typeorm"; +import { + ensurePostgresSchemas, + APPLICATION_SEARCH_PATH, +} from "../config/ensure-postgres-schemas"; +import { + buildDataSourceOptions, + buildIamMigrationDataSourceOptions, + buildFreightMigrationDataSourceOptions, + FREIGHT_MIGRATIONS, + IAM_MIGRATIONS, + LEGACY_MIGRATIONS, +} from "../config/database.config"; -async function main(): Promise { +/** + * Migrations run as two independent histories: + * + * 1. IAM — migrations shipped by `@tria-plc/iamapi-common`, recorded in + * `iam.typeorm_migrations`. + * 2. Freight — this app's `src/migrations/*`, recorded in `freight.migrations`. + * + * They used to share `public.migrations`, which meant a single ordered history + * across two independently versioned sources: dropping in a new IAM package + * release interleaved its migrations with freight's by timestamp, and + * `migration:revert` could not tell the two apart. `adoptLegacyHistory()` below + * moves the existing rows into the two tables on the first run after this change, + * so nothing re-runs. + */ + +/** + * The pooler in front of the remote DB rejects the Postgres `options` startup + * parameter, so search_path is set per physical connection instead. pg queues the + * SET on the client before the pool hands it to a caller, so every query a + * migration issues already sees the full schema search order. + */ +function applySearchPath(dataSource: DataSource): void { + const pool = (dataSource.driver as { master?: unknown }).master as + | { on?: (event: string, cb: (client: unknown) => void) => void } + | undefined; + + pool?.on?.("connect", (client) => { + (client as { query: (sql: string) => Promise }) + .query(`SET search_path TO ${APPLICATION_SEARCH_PATH}`) + .catch(() => { + /* connection will be validated on first real query */ + }); + }); +} + +async function initialize(options: DataSourceOptions): Promise { + const dataSource = new DataSource(options); + await dataSource.initialize(); + applySearchPath(dataSource); + return dataSource; +} + +function qualified({ + schema, + table, +}: { + schema: string; + table: string; +}): string { + return `"${schema}"."${table}"`; +} + +/** Same shape TypeORM's MigrationExecutor creates for a Postgres history table. */ +async function createHistoryTable( + dataSource: DataSource, + target: { schema: string; table: string }, +): Promise { + await dataSource.query( + `CREATE TABLE IF NOT EXISTS ${qualified(target)} ( + "id" SERIAL NOT NULL, + "timestamp" bigint NOT NULL, + "name" character varying NOT NULL, + CONSTRAINT "PK_${target.schema}_${target.table}" PRIMARY KEY ("id") + )`, + ); +} + +async function countRows( + dataSource: DataSource, + target: { schema: string; table: string }, +): Promise { + const [{ count }] = (await dataSource.query( + `SELECT count(*)::int AS count FROM ${qualified(target)}`, + )) as [{ count: number }]; + return count; +} + +/** + * Copy the pre-split `public.migrations` rows into the per-owner tables. + * + * Only fills a table that is still empty — once a history is live it is the + * source of truth, and re-copying would resurrect rows that a deliberate + * `migration:revert` removed. `public.migrations` is intentionally left in place: + * it is the rollback path if an older build of this app is redeployed. + */ +async function adoptLegacyHistory( + dataSource: DataSource, + iamMigrationNames: string[], +): Promise { + const legacyExists = (await dataSource.query( + `SELECT to_regclass($1) IS NOT NULL AS present`, + [`${LEGACY_MIGRATIONS.schema}.${LEGACY_MIGRATIONS.table}`], + )) as [{ present: boolean }]; + + if (!legacyExists[0].present) return; + + await createHistoryTable(dataSource, IAM_MIGRATIONS); + await createHistoryTable(dataSource, FREIGHT_MIGRATIONS); + + const adopt = async ( + target: { schema: string; table: string }, + /** true → rows whose name is an IAM migration; false → everything else. */ + isIam: boolean, + ): Promise => { + if ((await countRows(dataSource, target)) > 0) return; + + const inserted = (await dataSource.query( + `INSERT INTO ${qualified(target)} ("timestamp", "name") + SELECT legacy."timestamp", legacy."name" + FROM ${qualified(LEGACY_MIGRATIONS)} legacy + WHERE legacy."name" ${isIam ? "= ANY" : "<> ALL"}($1::text[]) + ORDER BY legacy."timestamp" + RETURNING "name"`, + [iamMigrationNames], + )) as unknown[]; + + console.log( + `adopted ${inserted.length} row(s) from ${qualified(LEGACY_MIGRATIONS)} into ${qualified(target)}`, + ); + }; + + await adopt(IAM_MIGRATIONS, true); + await adopt(FREIGHT_MIGRATIONS, false); +} + +async function runMigrations( + label: string, + dataSource: DataSource, +): Promise { + const applied = await dataSource.runMigrations(); + for (const migration of applied) { + console.log(`applied [${label}]: ${migration.name}`); + } + if (applied.length === 0) console.log(`no pending ${label} migrations`); +} + +export async function runAllMigrations(): Promise { await ensurePostgresSchemas(buildDataSourceOptions()); - await AppDataSource.initialize(); + const iam = await initialize(buildIamMigrationDataSourceOptions()); try { - const applied = await AppDataSource.runMigrations(); - for (const migration of applied) { - console.log(`applied: ${migration.name}`); - } - if (applied.length === 0) console.log("no pending migrations"); + const iamMigrationNames = iam.migrations.map( + (migration) => migration.name ?? migration.constructor.name, + ); + await adoptLegacyHistory(iam, iamMigrationNames); + await runMigrations("iam", iam); } finally { - await AppDataSource.destroy(); + await iam.destroy(); + } + + const freight = await initialize(buildFreightMigrationDataSourceOptions()); + try { + await runMigrations("freight", freight); + } finally { + await freight.destroy(); } } -main().catch((err) => { - console.error(err); - process.exit(1); -}); +if (require.main === module) { + runAllMigrations().catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/apps/edr-freight-api/src/scripts/run-migrations.ts b/apps/edr-freight-api/src/scripts/run-migrations.ts index b5cb23078..33934f5d5 100644 --- a/apps/edr-freight-api/src/scripts/run-migrations.ts +++ b/apps/edr-freight-api/src/scripts/run-migrations.ts @@ -1,21 +1,11 @@ -import { AppDataSource } from '../data-source'; +import { runAllMigrations } from './migrate'; -async function runMigrations() { - try { - console.log('Initializing datasource...'); - await AppDataSource.initialize(); - console.log('Datasource initialized. Running migrations...'); - const migrations = await AppDataSource.runMigrations(); - console.log(`Applied ${migrations.length} migrations.`); - await AppDataSource.destroy(); - process.exit(0); - } catch (err) { +// Alias for `migrate.ts` — the real logic lives there. IAM and freight now run as +// two separate migration histories, so this must not go back to +// `AppDataSource.runMigrations()`: the runtime DataSource carries no migrations. +runAllMigrations() + .then(() => process.exit(0)) + .catch((err) => { console.error('Migration run failed:', err); - try { - await AppDataSource.destroy(); - } catch {} process.exit(1); - } -} - -runMigrations(); + }); diff --git a/apps/edr-freight-api/src/scripts/seed-edr-wagons.ts b/apps/edr-freight-api/src/scripts/seed-edr-wagons.ts index c333abf40..2c52a9744 100644 --- a/apps/edr-freight-api/src/scripts/seed-edr-wagons.ts +++ b/apps/edr-freight-api/src/scripts/seed-edr-wagons.ts @@ -1,9 +1,5 @@ -import { AppDataSource } from '../data-source'; -import { SeedEdrWagonFleetErNumbering2260000000000 } from '../migrations/2260000000000-SeedEdrWagonFleetErNumbering'; -import { AddWagonTrainNumbers2270000000000 } from '../migrations/2270000000000-AddWagonTrainNumbers'; -import { SeedWagonRunNumbers2280000000000 } from '../migrations/2280000000000-SeedWagonRunNumbers'; -import { WagonNumberPartialUnique2280000000000 } from '../migrations/2280000000000-WagonNumberPartialUnique'; -import { SeedWagonYardDoraleh2290000000000 } from '../migrations/2290000000000-SeedWagonYardDoraleh'; +import { AppDataSource } from "../data-source"; +import { FREIGHT_SEED_SQL } from "../migrations/3250000000000-FreightBaseline"; async function seedEdRWagons() { await AppDataSource.initialize(); @@ -14,18 +10,13 @@ async function seedEdRWagons() { await queryRunner.connect(); await queryRunner.startTransaction(); - // Fleet first (recreates every wagon with NULL yard + NULL runs), then the - // columns are ensured to exist, then the run roster and the yard are applied - // on top. Same order the migrations run in, so the script and a fresh - // migrate agree. - await new SeedEdrWagonFleetErNumbering2260000000000().up(queryRunner); - await new AddWagonTrainNumbers2270000000000().up(queryRunner); - // Not a wagon seed, but it owns wagon_number uniqueness — included so this - // script leaves the same schema a real `migration:run` would, rather than a - // database missing the partial unique index. - await new WagonNumberPartialUnique2280000000000().up(queryRunner); - await new SeedWagonRunNumbers2280000000000().up(queryRunner); - await new SeedWagonYardDoraleh2290000000000().up(queryRunner); + // Replays the fleet exactly as the baseline migration seeds it on a fresh + // database — wagon numbers, types, run roster and yard already in their final + // state. Wipes first, so this is a reset rather than a top-up. The wagon-seed + // migrations this used to call one by one are now folded into + // `3250000000000-FreightBaseline`. + await queryRunner.query(`DELETE FROM freight.wagons`); + await queryRunner.query(FREIGHT_SEED_SQL.wagons); const summary = await queryRunner.query(` SELECT @@ -74,11 +65,11 @@ async function seedEdRWagons() { await queryRunner.commitTransaction(); - console.log('\nFleet by wagon type:'); + console.log("\nFleet by wagon type:"); console.table(summary); - console.log('Run roster (export/import pairs):'); + console.log("Run roster (export/import pairs):"); console.table(runs); - console.log('Fleet by yard:'); + console.log("Fleet by yard:"); console.table(yards); console.log( `Seeded EDR wagon fleet — ${totals.total} wagons total (expected 1100), ` + @@ -94,6 +85,6 @@ async function seedEdRWagons() { } seedEdRWagons().catch((error) => { - console.error('Failed to seed EDR wagon fleet:', error); + console.error("Failed to seed EDR wagon fleet:", error); process.exit(1); });