Implement intercity document handling and rejection notes for contracts

This commit is contained in:
Marshal
2026-07-21 10:20:36 +00:00
226 changed files with 13854 additions and 2973 deletions

View File

@@ -13,11 +13,13 @@ const INDODE_FACILITY = {
facilityType: 'DRY_PORT' as const,
facilityStatus: 'ACTIVE' as const,
locationName: 'Indode',
country: 'Djibouti',
city: 'Djibouti',
address: 'Indode, Djibouti',
latitude: 11.5447,
longitude: 43.145,
// Indode is the Gelan Multipurpose Port outside Addis — the yard carries it as
// KALITY, country Ethiopia. It was seeded as Djibouti, which is the wrong end
// of the line. Coordinates are left unset rather than guessed; fill them in
// when the real position is to hand.
country: 'Ethiopia',
city: 'Addis Ababa',
address: 'Indode (Gelan), Addis Ababa, Ethiopia',
capacity: 50000,
isActive: true,
notes: 'Primary dry port for container consolidation and distribution',
@@ -72,20 +74,22 @@ export class IndodeFacilitySeeder {
const yardRepo = manager.getRepository(WarehouseYard);
const zoneRepo = manager.getRepository(WarehouseZone);
// Ensure facility exists
const facility = await facilityRepo.findOne({
// Ensure facility exists. An existing facility row is not proof the
// warehouses under it survived, so reuse it and carry on rather than
// returning — otherwise a facility with no warehouses stays that way.
const existing = await facilityRepo.findOne({
where: { code: INDODE_FACILITY.code },
});
if (facility) {
this.logger.log('Indode facility already exists, skipping seed');
return;
let savedFacility: Facility;
if (existing) {
savedFacility = await facilityRepo.save({ ...existing, ...INDODE_FACILITY });
this.logger.log(`Facility ${savedFacility.code} already exists, reusing`);
} else {
savedFacility = await facilityRepo.save(facilityRepo.create(INDODE_FACILITY));
this.logger.log(`Created facility: ${savedFacility.code}`);
}
const newFacility = facilityRepo.create(INDODE_FACILITY);
const savedFacility = await facilityRepo.save(newFacility);
this.logger.log(`Created facility: ${savedFacility.code}`);
// Create warehouses for the facility
for (const warehouseData of WAREHOUSES) {
try {

View File

@@ -16,12 +16,19 @@ import { DataSource } from 'typeorm';
* Djibouti and `NEGAD_FY_BCC` in Ethiopia, currently inactive) and it is not yet
* settled which is the intercity facility.
*/
const FACILITY_YARDS: Array<{ code: string; facility: string; hasWarehouse: boolean }> = [
{ code: 'KALITY', facility: 'Indode', hasWarehouse: true },
{ code: 'LEGACY_DEST', facility: 'Sebeta', hasWarehouse: false },
{ code: 'MOJO', facility: 'Modjo', hasWarehouse: false },
{ code: 'ADAMA', facility: 'Adama', hasWarehouse: false },
{ code: 'DIRE_DAWA', facility: 'Dire Dawa', hasWarehouse: false },
const FACILITY_YARDS: Array<{
code: string;
facility: string;
hasWarehouse: boolean;
handlesContainer: boolean;
}> = [
// Containers need a reach stacker or gantry — only these three are equipped.
// Bulk needs far less, so every facility handles it.
{ code: 'KALITY', facility: 'Indode', hasWarehouse: true, handlesContainer: true },
{ code: 'MOJO', facility: 'Modjo', hasWarehouse: false, handlesContainer: true },
{ code: 'DIRE_DAWA', facility: 'Dire Dawa', hasWarehouse: false, handlesContainer: true },
{ code: 'LEGACY_DEST', facility: 'Sebeta', hasWarehouse: false, handlesContainer: false },
{ code: 'ADAMA', facility: 'Adama', hasWarehouse: false, handlesContainer: false },
];
@Injectable()
@@ -35,7 +42,7 @@ export class YardFacilitiesSeeder {
* yards — a missing code is logged and skipped rather than invented.
*/
async run(): Promise<void> {
for (const { code, facility, hasWarehouse } of FACILITY_YARDS) {
for (const { code, facility, hasWarehouse, handlesContainer } of FACILITY_YARDS) {
const [yard]: Array<{ id: string }> = await this.dataSource.query(
`SELECT id FROM freight.yards WHERE code = $1 AND deleted_at IS NULL`,
[code],
@@ -53,11 +60,15 @@ export class YardFacilitiesSeeder {
);
await this.dataSource.query(
`INSERT INTO freight.yard_facilities (yard_id, has_warehouse, equipment_notes)
VALUES ($1, $2, $3)
`INSERT INTO freight.yard_facilities
(yard_id, has_warehouse, handles_container, handles_bulk, equipment_notes)
VALUES ($1, $2, $3, true, $4)
ON CONFLICT (yard_id) WHERE deleted_at IS NULL
DO UPDATE SET has_warehouse = EXCLUDED.has_warehouse, updated_at = NOW()`,
[yard.id, hasWarehouse, `${facility} load/unload facility`],
DO UPDATE SET has_warehouse = EXCLUDED.has_warehouse,
handles_container = EXCLUDED.handles_container,
handles_bulk = EXCLUDED.handles_bulk,
updated_at = NOW()`,
[yard.id, hasWarehouse, handlesContainer, `${facility} load/unload facility`],
);
}
this.logger.log(