Enhance clearance milestone management and introduce new contract actions

- Added new milestones for 'Transit Permit Uploaded' and 'Export Transport Document Issued' in the clearance milestone catalog.
- Implemented methods in ClearanceMilestoneService to skip milestones and complete them with metadata.
- Updated ContractBookingService to check boundary conditions before booking creation.
- Introduced new endpoints in ContractsController for uploading customs declarations, advising duty, and handling various document uploads.
- Enhanced the UI to support new clearance actions and display relevant components based on milestone statuses.
This commit is contained in:
marshal
2026-07-01 10:20:16 +03:00
parent ccd5d6de31
commit 612df8daff
36 changed files with 3018 additions and 57 deletions

View File

@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class PhasedClearanceCycleMeta1829000000000 implements MigrationInterface {
name = 'PhasedClearanceCycleMeta1829000000000';
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
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;`,
);
}
}

View File

@@ -0,0 +1,46 @@
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<void> {
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<void> {
await queryRunner.query(`DELETE FROM freight.dropdown_settings WHERE code = $1;`, [
this.code,
]);
}
}