mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
209 lines
8.2 KiB
TypeScript
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);
|
|
});
|