mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 06:28:12 +00:00
add fan number
This commit is contained in:
@@ -43,10 +43,10 @@ export class MoveCustomersToFreightSchema1748900000000 implements MigrationInter
|
||||
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);
|
||||
`);
|
||||
// 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(`
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class BookingFlowRefactor1749200000000 implements MigrationInterface {
|
||||
name = 'BookingFlowRefactor1749200000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddBookingFreightType1749300000000 implements MigrationInterface {
|
||||
name = 'AddBookingFreightType1749300000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
// import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
// export class AddFanNumberToCompanies1749300000000 implements MigrationInterface {
|
||||
// name = 'AddFanNumberToCompanies1749300000000';
|
||||
export class AddFanNumberToCompanies1749300000000 implements MigrationInterface {
|
||||
name = 'AddFanNumberToCompanies1749300000000';
|
||||
|
||||
// public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// await queryRunner.query(`
|
||||
// ALTER TABLE freight.companies
|
||||
// ADD COLUMN fan_number varchar(16) NULL;
|
||||
// `);
|
||||
// }
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// 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<void> {
|
||||
// await queryRunner.query(`
|
||||
// ALTER TABLE freight.companies
|
||||
// DROP COLUMN fan_number;
|
||||
// `);
|
||||
// }
|
||||
// }
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.companies
|
||||
DROP COLUMN IF EXISTS fan_number;
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddContractSignatures1749400000000 implements MigrationInterface {
|
||||
name = 'AddContractSignatures1749400000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddTrainScheduling1749400000000 implements MigrationInterface {
|
||||
name = 'AddTrainScheduling1749400000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddCompanyIdToBookings1749500000000 implements MigrationInterface {
|
||||
name = 'AddCompanyIdToBookings1749500000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddBlocksRoleToApprovalStep1749600000000 implements MigrationInterface {
|
||||
name = 'AddBlocksRoleToApprovalStep1749600000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.booking_approval_step
|
||||
DROP COLUMN IF EXISTS blocks_role;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
// Keep seeded rules on rollback to avoid breaking in-flight bookings.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
await queryRunner.dropIndex('freight.shipping_lines', 'UQ_shipping_lines_code');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.file_upload_fields CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS freight.file_upload_settings CASCADE`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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<void> {
|
||||
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<void> {
|
||||
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;
|
||||
`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user