Files
edr-platform/apps/edr-freight-api/src/scripts/seed-export-djibouti-interchange-demo.ts

209 lines
8.2 KiB
TypeScript

import 'reflect-metadata';
import { config } from 'dotenv';
import { resolve } from 'path';
config({ path: resolve(__dirname, '../../.env') });
import { NestFactory } from '@nestjs/core';
import { DataSource } from 'typeorm';
import { AppModule } from '../app.module';
import { Booking } from '../modules/bookings/entities/booking.entity';
import { Locomotive } from '../modules/locomotives/entities/locomotive.entity';
import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity';
import { ServiceType } from '../modules/rule-engine/entities/service-type.entity';
import { Yard } from '../modules/rule-engine/entities/yard.entity';
import { TrainSchedule } from '../modules/train-schedules/entities/train-schedule.entity';
import { TrainScheduleBooking } from '../modules/train-schedules/entities/train-schedule-booking.entity';
import { TrainSet } from '../modules/train-sets/entities/train-set.entity';
import { WarehouseInventory } from '../modules/warehouses/entities/warehouse-inventory.entity';
import { WarehouseYard } from '../modules/warehouses/entities/warehouse-yard.entity';
import { WarehouseZone } from '../modules/warehouses/entities/warehouse-zone.entity';
import { Warehouse } from '../modules/warehouses/entities/warehouse.entity';
const DEMO_TRAINS = [
{
trainNumber: 'ICD-DEMO-EXP-DJ-01',
bookingRefs: ['ICD-DEMO-EXP-001', 'ICD-DEMO-EXP-002', 'ICD-DEMO-EXP-003'],
arrivalOffsetHours: 1,
},
{
trainNumber: 'ICD-DEMO-EXP-DJ-02',
bookingRefs: ['ICD-DEMO-EXP-004', 'ICD-DEMO-EXP-005', 'ICD-DEMO-EXP-006'],
arrivalOffsetHours: 2,
},
];
async function main() {
const app = await NestFactory.createApplicationContext(AppModule, {
logger: ['error', 'warn', 'log'],
});
try {
const dataSource = app.get(DataSource);
const yardRepo = dataSource.getRepository(Yard);
const serviceTypeRepo = dataSource.getRepository(ServiceType);
const cargoTypeRepo = dataSource.getRepository(CargoType);
const warehouseRepo = dataSource.getRepository(Warehouse);
const warehouseYardRepo = dataSource.getRepository(WarehouseYard);
const warehouseZoneRepo = dataSource.getRepository(WarehouseZone);
const bookingRepo = dataSource.getRepository(Booking);
const inventoryRepo = dataSource.getRepository(WarehouseInventory);
const locomotiveRepo = dataSource.getRepository(Locomotive);
const trainSetRepo = dataSource.getRepository(TrainSet);
const scheduleRepo = dataSource.getRepository(TrainSchedule);
const scheduleBookingRepo = dataSource.getRepository(TrainScheduleBooking);
const originYard =
(await yardRepo.findOne({ where: { code: 'MOJO' } })) ??
(await yardRepo.findOne({ where: { country: 'Ethiopia' } }));
const destinationYard =
(await yardRepo.findOne({ where: { code: 'DJIB_PORT' } })) ??
(await yardRepo.findOne({ where: { code: 'DJIBOUTI' } })) ??
(await yardRepo.findOne({ where: { country: 'Djibouti' } }));
const serviceType =
(await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER' } })) ??
(await serviceTypeRepo.findOne({ where: { isActive: true } }));
const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });
const warehouse = await warehouseRepo.findOne({ where: { code: 'INDODE_OPEN' } });
const warehouseYard = warehouse
? await warehouseYardRepo.findOne({ where: { warehouseId: warehouse.id } })
: null;
const warehouseZone = warehouseYard
? await warehouseZoneRepo.findOne({ where: { yardId: warehouseYard.id } })
: null;
const missing = [
!originYard ? 'Ethiopian origin yard' : '',
!destinationYard ? 'Djibouti destination yard' : '',
!serviceType ? 'service type' : '',
!warehouse ? 'INDODE_OPEN warehouse' : '',
!warehouseYard ? 'warehouse yard' : '',
!warehouseZone ? 'warehouse zone' : '',
].filter(Boolean);
if (missing.length) {
throw new Error(`Cannot seed export Djibouti interchange demo, missing: ${missing.join(', ')}`);
}
const locomotive =
(await locomotiveRepo.findOne({ where: { code: 'ICD-DEMO-LOCO' } })) ??
(await locomotiveRepo.save(
locomotiveRepo.create({
code: 'ICD-DEMO-LOCO',
name: 'Interchange Demo Locomotive',
maxPullWeightTons: 4000,
}),
));
const now = Date.now();
const seededSchedules: TrainSchedule[] = [];
for (const [trainIndex, demo] of DEMO_TRAINS.entries()) {
const existingSchedule = await scheduleRepo.findOne({ where: { trainNumber: demo.trainNumber } });
if (existingSchedule) {
console.log(`Export Djibouti interchange demo already seeded: ${demo.trainNumber}`);
console.log(`Schedule ID: ${existingSchedule.id}`);
seededSchedules.push(existingSchedule);
continue;
}
const arrival = new Date(now - demo.arrivalOffsetHours * 60 * 60 * 1000);
const departure = new Date(arrival.getTime() - 5 * 60 * 60 * 1000);
const trainSet = await trainSetRepo.save(
trainSetRepo.create({
locomotiveId: locomotive.id,
totalWeightTons: 700 + trainIndex * 80,
totalLengthMeters: 360 + trainIndex * 20,
wagonCount: 12 + trainIndex,
status: 'COMPLETED',
}),
);
const schedule = await scheduleRepo.save(
scheduleRepo.create({
trainSetId: trainSet.id,
originStationId: originYard!.id,
destinationStationId: destinationYard!.id,
scheduledDepartureDate: departure,
scheduledArrivalDate: arrival,
actualArrivalAt: arrival,
status: 'ARRIVED' as TrainSchedule['status'],
trainNumber: demo.trainNumber,
direction: 'EXPORT',
}),
);
for (const [bookingIndex, reference] of demo.bookingRefs.entries()) {
const weight = 5200 + trainIndex * 600 + bookingIndex * 800;
const booking = await bookingRepo.save(
bookingRepo.create({
reference,
originYardId: originYard!.id,
destinationYardId: destinationYard!.id,
serviceTypeId: serviceType!.id,
status: 'IN_TRANSIT',
paymentStatus: 'PAID',
scheduledDate: new Date(),
contractType: 'SPOT',
equipmentReturn: 'TERMINAL',
paymentCurrency: 'ETB',
totalAmount: 0,
isGovernment: false,
tradeDirection: 'EXPORT',
freightType: bookingIndex % 2 === 0 ? 'CONTAINER' : 'BULK',
cargoTypeId: cargoType?.id ?? null,
cargoFreeText: cargoType
? null
: `Export Djibouti interchange demo cargo ${trainIndex + 1}-${bookingIndex + 1}`,
cargoTotalWeightVgm: weight,
}),
);
await inventoryRepo.save(
inventoryRepo.create({
warehouseId: warehouse!.id,
yardId: warehouseYard!.id,
zoneId: warehouseZone!.id,
bookingId: booking.id,
quantity: 1,
weight,
status: 'DISPATCHED',
inspectionStatus: 'PASSED',
arrivedAt: new Date(departure.getTime() + 2 * 60 * 60 * 1000),
inspectedAt: new Date(departure.getTime() + 3 * 60 * 60 * 1000),
readyForLoadingAt: new Date(departure.getTime() + 4 * 60 * 60 * 1000),
loadedAt: new Date(departure.getTime() + 4.5 * 60 * 60 * 1000),
dispatchedAt: departure,
notes: '[ICD-DEMO] Eligible for Djibouti export unload and interchange generation',
}),
);
await scheduleBookingRepo.save(
scheduleBookingRepo.create({
trainScheduleId: schedule.id,
bookingId: booking.id,
}),
);
}
seededSchedules.push(schedule);
}
console.log('Export Djibouti interchange demo seeded.');
for (const schedule of seededSchedules) {
console.log(`Train number: ${schedule.trainNumber}`);
console.log(`Schedule ID: ${schedule.id}`);
}
console.log('Open Djibouti Unloading, click "Auto Unload Export Items", then check Interchange Documents.');
} finally {
await app.close();
}
}
main().catch((error) => {
console.error('Export Djibouti interchange demo seed failed:', error);
process.exit(1);
});