mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 08:48:11 +00:00
220 lines
7.8 KiB
TypeScript
220 lines
7.8 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 { ImportDjiboutiOperation } from '../modules/train-scheduling/entities/import-djibouti-operation.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';
|
|
|
|
const DEMO_TRAINS = [
|
|
{
|
|
trainNumber: 'IMP-DJB-NAGAD-01',
|
|
bookingRefs: ['IMP-DJB-NGD-001', 'IMP-DJB-NGD-002', 'IMP-DJB-NGD-003'],
|
|
departureOffsetHours: 4,
|
|
},
|
|
{
|
|
trainNumber: 'IMP-DJB-NAGAD-02',
|
|
bookingRefs: ['IMP-DJB-NGD-004', 'IMP-DJB-NGD-005', 'IMP-DJB-NGD-006'],
|
|
departureOffsetHours: 8,
|
|
},
|
|
];
|
|
|
|
function addHours(date: Date, hours: number): Date {
|
|
return new Date(date.getTime() + hours * 60 * 60 * 1000);
|
|
}
|
|
|
|
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 locomotiveRepo = dataSource.getRepository(Locomotive);
|
|
const trainSetRepo = dataSource.getRepository(TrainSet);
|
|
const scheduleRepo = dataSource.getRepository(TrainSchedule);
|
|
const bookingRepo = dataSource.getRepository(Booking);
|
|
const scheduleBookingRepo = dataSource.getRepository(TrainScheduleBooking);
|
|
const importOperationRepo = dataSource.getRepository(ImportDjiboutiOperation);
|
|
|
|
const originYard =
|
|
(await yardRepo.findOne({ where: { code: 'NAGAD' } })) ??
|
|
(await yardRepo.findOne({ where: { country: 'Djibouti' } }));
|
|
const destinationYard =
|
|
(await yardRepo.findOne({ where: { code: 'INDODE' } })) ??
|
|
(await yardRepo.save(
|
|
yardRepo.create({
|
|
code: 'INDODE',
|
|
label: 'Indode Dry Port',
|
|
country: 'Ethiopia',
|
|
isActive: true,
|
|
displayOrder: 6,
|
|
}),
|
|
));
|
|
const serviceType =
|
|
(await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER' } })) ??
|
|
(await serviceTypeRepo.findOne({ where: { isActive: true } }));
|
|
const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });
|
|
|
|
const missing = [
|
|
!originYard ? 'NAGAD/Djibouti origin yard' : '',
|
|
!destinationYard ? 'INDODE destination yard' : '',
|
|
!serviceType ? 'service type' : '',
|
|
].filter(Boolean);
|
|
|
|
if (missing.length) {
|
|
throw new Error(`Cannot seed Djibouti-side import demo, missing: ${missing.join(', ')}`);
|
|
}
|
|
|
|
const locomotive =
|
|
(await locomotiveRepo.findOne({ where: { code: 'ICD-DEMO-IMP-LOCO' } })) ??
|
|
(await locomotiveRepo.save(
|
|
locomotiveRepo.create({
|
|
code: 'ICD-DEMO-IMP-LOCO',
|
|
name: 'Djibouti Import Demo Locomotive',
|
|
locomotiveType: 'DIESEL',
|
|
maxPullWeightTons: 4200,
|
|
maxTrainLengthMeters: 760,
|
|
status: 'IMPORT_READY',
|
|
currentYardId: originYard!.id,
|
|
}),
|
|
));
|
|
|
|
const now = new Date();
|
|
const seededSchedules: TrainSchedule[] = [];
|
|
|
|
for (const [trainIndex, demo] of DEMO_TRAINS.entries()) {
|
|
const existingSchedule = await scheduleRepo.findOne({
|
|
where: { trainNumber: demo.trainNumber },
|
|
});
|
|
|
|
if (existingSchedule) {
|
|
console.log(`Djibouti-side import demo already seeded: ${demo.trainNumber}`);
|
|
console.log(`Schedule ID: ${existingSchedule.id}`);
|
|
seededSchedules.push(existingSchedule);
|
|
continue;
|
|
}
|
|
|
|
const departure = addHours(now, demo.departureOffsetHours);
|
|
const arrival = addHours(departure, 12);
|
|
|
|
const trainSet = await trainSetRepo.save(
|
|
trainSetRepo.create({
|
|
locomotiveId: locomotive.id,
|
|
totalWeightTons: 900 + trainIndex * 120,
|
|
totalLengthMeters: 430 + trainIndex * 25,
|
|
wagonCount: 18 + trainIndex * 2,
|
|
status: 'ASSIGNED',
|
|
}),
|
|
);
|
|
|
|
const schedule = await scheduleRepo.save(
|
|
scheduleRepo.create({
|
|
trainSetId: trainSet.id,
|
|
originStationId: originYard!.id,
|
|
destinationStationId: destinationYard!.id,
|
|
scheduledDepartureDate: departure,
|
|
scheduledArrivalDate: arrival,
|
|
status: 'SCHEDULED' as TrainSchedule['status'],
|
|
trainNumber: demo.trainNumber,
|
|
direction: 'IMPORT',
|
|
maxWagons: 53,
|
|
bookingWindowStatus: 'CLOSED',
|
|
}),
|
|
);
|
|
|
|
for (const [bookingIndex, reference] of demo.bookingRefs.entries()) {
|
|
const weight = 6800 + trainIndex * 900 + bookingIndex * 750;
|
|
const booking = await bookingRepo.save(
|
|
bookingRepo.create({
|
|
reference,
|
|
originYardId: originYard!.id,
|
|
destinationYardId: destinationYard!.id,
|
|
serviceTypeId: serviceType!.id,
|
|
status: 'PAID',
|
|
paymentStatus: 'PAID',
|
|
scheduledDate: departure,
|
|
contractType: 'SPOT',
|
|
equipmentReturn: 'TERMINAL',
|
|
paymentCurrency: 'ETB',
|
|
totalAmount: 0,
|
|
isGovernment: false,
|
|
tradeDirection: 'IMPORT',
|
|
freightType: bookingIndex % 2 === 0 ? 'CONTAINER' : 'BULK',
|
|
cargoTypeId: cargoType?.id ?? null,
|
|
cargoFreeText: cargoType
|
|
? null
|
|
: `Djibouti import demo cargo ${trainIndex + 1}-${bookingIndex + 1}`,
|
|
cargoTotalWeightVgm: weight,
|
|
priorityScore: 80 - trainIndex * 5 - bookingIndex,
|
|
trainScheduleId: schedule.id,
|
|
schedulingStatus: 'SCHEDULED',
|
|
scheduledAt: now,
|
|
}),
|
|
);
|
|
|
|
await scheduleBookingRepo.save(
|
|
scheduleBookingRepo.create({
|
|
trainScheduleId: schedule.id,
|
|
bookingId: booking.id,
|
|
}),
|
|
);
|
|
}
|
|
|
|
await importOperationRepo.save(
|
|
importOperationRepo.create({
|
|
trainScheduleId: schedule.id,
|
|
documents: {
|
|
DELIVERY_ORDER: {
|
|
reference: `DO-${demo.trainNumber}`,
|
|
uploadedAt: now.toISOString(),
|
|
uploadedBy: 'Demo Seeder',
|
|
notes: 'Demo delivery order for Djibouti-side import flow',
|
|
},
|
|
RAILWAY_BILL: {
|
|
reference: `RB-${demo.trainNumber}`,
|
|
uploadedAt: now.toISOString(),
|
|
uploadedBy: 'Demo Seeder',
|
|
notes: 'Demo railway bill for Djibouti-side import flow',
|
|
},
|
|
},
|
|
performedBy: 'Demo Seeder',
|
|
notes: '[ICD-DEMO] Nagad to Indode import train for Djibouti-side flow',
|
|
}),
|
|
);
|
|
|
|
seededSchedules.push(schedule);
|
|
}
|
|
|
|
console.log('Djibouti-side import demo seeded.');
|
|
console.log(`Corridor: ${originYard!.code} -> ${destinationYard!.code}`);
|
|
for (const schedule of seededSchedules) {
|
|
console.log(`Train number: ${schedule.trainNumber}`);
|
|
console.log(`Schedule ID: ${schedule.id}`);
|
|
console.log(`Backoffice URL: /dashboard/operations/train-scheduling-v2/${schedule.id}`);
|
|
}
|
|
} finally {
|
|
await app.close();
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('Djibouti-side import demo seed failed:', error);
|
|
process.exit(1);
|
|
});
|