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 { BookingContainer } from '../modules/bookings/entities/booking-container.entity'; import { WarehouseInventory } from '../modules/warehouses/entities/warehouse-inventory.entity'; import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity'; import { wagonsPerUnitForSize } from '../modules/rule-engine/container-type.util'; import { ContainerType } from '../modules/rule-engine/entities/container-type.entity'; import { ServiceType } from '../modules/rule-engine/entities/service-type.entity'; import { Yard } from '../modules/rule-engine/entities/yard.entity'; const BOOKING_REFS = [ 'WH-EXP-RCV-001', 'WH-EXP-RCV-002', 'WH-EXP-RCV-003', 'WH-EXP-RCV-004', 'WH-EXP-RCV-005', ]; 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 containerTypeRepo = dataSource.getRepository(ContainerType); const bookingRepo = dataSource.getRepository(Booking); const bookingContainerRepo = dataSource.getRepository(BookingContainer); const inventoryRepo = dataSource.getRepository(WarehouseInventory); 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: { country: 'Djibouti' } })); const serviceType = (await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER', includesFirstMile: false, isActive: true } })) ?? (await serviceTypeRepo.findOne({ where: { includesFirstMile: false, isActive: true } })); const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } }); const containerType = (await containerTypeRepo.findOne({ where: { code: '40FT', isActive: true } })) ?? (await containerTypeRepo.findOne({ where: { code: '40', isActive: true } })) ?? (await containerTypeRepo.findOne({ where: { sizeFt: 40, isActive: true } })) ?? (await containerTypeRepo.findOne({ where: { isActive: true } })); const missing = [ !originYard ? 'MOJO/Ethiopia origin yard' : '', !destinationYard ? 'DJIB_PORT/Djibouti destination yard' : '', !serviceType ? 'active service type without first mile' : '', !containerType ? 'active container type' : '', ].filter(Boolean); if (missing.length) { throw new Error(`Cannot seed warehouse export receive-ready bookings, missing: ${missing.join(', ')}`); } let created = 0; let skipped = 0; const now = Date.now(); for (const [index, reference] of BOOKING_REFS.entries()) { const existing = await bookingRepo.findOne({ where: { reference } }); if (existing) { skipped += 1; continue; } const containerQuantity = index === 4 ? 2 : 1; const weightKg = 18_000 + index * 1_250 + (containerQuantity - 1) * 9_000; const scheduledDate = new Date(now + index * 60 * 60_000); const booking = await bookingRepo.save( bookingRepo.create({ reference, originYardId: originYard!.id, destinationYardId: destinationYard!.id, serviceTypeId: serviceType!.id, status: 'PAID', paymentStatus: 'PAID', scheduledDate, contractType: 'SPOT', equipmentReturn: 'TERMINAL', paymentCurrency: 'ETB', totalAmount: 0, isGovernment: false, tradeDirection: 'EXPORT', freightType: 'CONTAINER', cargoTypeId: cargoType?.id ?? null, cargoFreeText: cargoType ? null : `Warehouse export receive-ready cargo ${index + 1}`, cargoTotalWeightVgm: weightKg, schedulingStatus: 'NOT_SCHEDULED', }), ); await bookingContainerRepo.save( bookingContainerRepo.create({ bookingId: booking.id, containerTypeId: containerType!.id, containerNumber: `EDRU${String(730100 + index).padStart(6, '0')}`, containerSize: containerType!.sizeFt ? `${containerType!.sizeFt}ft` : containerType!.code, quantity: containerQuantity, hazardousQuantity: 0, reeferQuantity: 0, vgmPerUnitTons: Number((weightKg / containerQuantity / 1000).toFixed(3)), totalVgmTons: Number((weightKg / 1000).toFixed(3)), wagonsRequired: Math.max(1, containerQuantity * wagonsPerUnitForSize(containerType!.sizeFt)), isOverweight: false, }), ); const inventory = await inventoryRepo.findOne({ where: { bookingId: booking.id } }); if (inventory) { throw new Error(`Seed invariant failed: booking ${reference} unexpectedly has warehouse inventory`); } created += 1; } console.log(`Warehouse export receive-ready seed complete. Created ${created}, skipped ${skipped}.`); console.log(`Booking refs: ${BOOKING_REFS.join(', ')}`); console.log('Open Backoffice Warehouse > Receive for loading > Export / Receive to Warehouse.'); } finally { await app.close(); } } main().catch((error) => { console.error('Warehouse export receive-ready seed failed:', error); process.exit(1); });