mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
automation of loading and unloading
This commit is contained in:
@@ -14,8 +14,12 @@ export class NormalizeWeightLimitTradeDirectionBoth1749000000000
|
||||
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 $$;
|
||||
END $$;
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddSchedulingAllocationEnhancements1750400000000
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddSchedulingAllocationEnhancements1750400000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddWagonReadiness1750500000000 implements MigrationInterface {
|
||||
name = 'AddWagonReadiness1750500000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_wagons_readiness`);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.wagons
|
||||
DROP COLUMN IF EXISTS readiness
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddGovernmentBookingFields1750600000000 implements MigrationInterface {
|
||||
name = 'AddGovernmentBookingFields1750600000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class CreateSchedulingEvents1750700000000 implements MigrationInterface {
|
||||
name = 'CreateSchedulingEvents1750700000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_scheduling_events_train_schedule_id`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.scheduling_events`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
const hasContainerTypes = await queryRunner.hasTable('freight.container_types');
|
||||
if (!hasContainerTypes) {
|
||||
return;
|
||||
}
|
||||
|
||||
await queryRunner.query(`
|
||||
UPDATE freight.container_types SET wagons_per_unit = 1.00;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddContainerNumberToBookingContainer1750900000000 implements MigrationInterface {
|
||||
name = "AddContainerNumberToBookingContainer1750900000000";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class CreateTrainSchedulingGlobalRules1751000000000 implements MigrationInterface {
|
||||
name = "CreateTrainSchedulingGlobalRules1751000000000";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.train_scheduling_global_rules;`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddDeletedAtToTrainSchedulingGlobalRules1751000000001
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = "AddDeletedAtToTrainSchedulingGlobalRules1751000000001";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.train_scheduling_global_rules
|
||||
DROP COLUMN IF EXISTS deleted_at;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddLocomotiveReadiness1781000000000 implements MigrationInterface {
|
||||
name = 'AddLocomotiveReadiness1781000000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP INDEX IF EXISTS freight.idx_locomotives_readiness`);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.locomotives
|
||||
DROP COLUMN IF EXISTS readiness
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class CreateTrainCheckpointEvents1781000000001 implements MigrationInterface {
|
||||
name = 'CreateTrainCheckpointEvents1781000000001';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX IF EXISTS freight.idx_train_checkpoint_events_schedule`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.train_checkpoint_events`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddBatchBookingFields1781000000002 implements MigrationInterface {
|
||||
name = 'AddBatchBookingFields1781000000002';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// 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<void> {
|
||||
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
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddSelectedForBatchStatus1781000000003 implements MigrationInterface {
|
||||
name = 'AddSelectedForBatchStatus1781000000003';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
// PostgreSQL does not support removing enum values safely.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm';
|
||||
|
||||
export class CreateTrainCompositionRemovalLog1781000000005 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.dropTable('freight.train_composition_removal_logs', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class WagonLocomotiveYardLink1782000000000 implements MigrationInterface {
|
||||
name = 'WagonLocomotiveYardLink1782000000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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";`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddPaymentWebhookEventAndRefund1782000000001 implements MigrationInterface {
|
||||
name = "AddPaymentWebhookEventAndRefund1782000000001";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// 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<void> {
|
||||
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;`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class ExtendPaymentMethodEnum1782000000002 implements MigrationInterface {
|
||||
name = "ExtendPaymentMethodEnum1782000000002";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
// PostgreSQL does not support removing enum values directly.
|
||||
// To roll back, recreate the type without the added values and update the column.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class ReplacePriorityRulesWithPriorityConfigs1783000000000 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.priority_configs;`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class CreateSavedSignatures1784000000000 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.saved_signatures;`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user