mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
294 lines
12 KiB
TypeScript
294 lines
12 KiB
TypeScript
import {
|
|
MigrationInterface,
|
|
QueryRunner,
|
|
Table,
|
|
TableIndex,
|
|
TableForeignKey,
|
|
TableColumn,
|
|
} from 'typeorm';
|
|
|
|
export class AddRuleEngineTablesAndCodes1748514000000 implements MigrationInterface {
|
|
name = 'AddRuleEngineTablesAndCodes1748514000000';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
// ── 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<void> {
|
|
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');
|
|
}
|
|
}
|