diff --git a/apps/edr-freight-api/package.json b/apps/edr-freight-api/package.json index 20bfa1bad..14c28f469 100644 --- a/apps/edr-freight-api/package.json +++ b/apps/edr-freight-api/package.json @@ -27,6 +27,7 @@ "seed:negad-indode-arrived-train": "ts-node -r tsconfig-paths/register src/scripts/seed-negad-indode-arrived-train.ts", "seed:gate-pass-train-scenarios": "ts-node -r tsconfig-paths/register src/scripts/seed-gate-pass-train-scenarios.ts", "auto-unload:arrived-import-trains": "ts-node -r tsconfig-paths/register src/scripts/auto-unload-arrived-import-trains.ts", + "backfill:missing-unload-inventory": "ts-node -r tsconfig-paths/register src/scripts/backfill-missing-unload-inventory.ts", "seed:file-upload-settings": "ts-node -r tsconfig-paths/register src/scripts/seed-file-upload-settings.ts", "seed:dropdown-settings": "ts-node -r tsconfig-paths/register src/scripts/seed-dropdown-settings.ts", "seed:gov-companies": "ts-node -r tsconfig-paths/register src/scripts/seed-gov-companies.ts", diff --git a/apps/edr-freight-api/src/scripts/backfill-missing-unload-inventory.ts b/apps/edr-freight-api/src/scripts/backfill-missing-unload-inventory.ts new file mode 100644 index 000000000..9d51107fe --- /dev/null +++ b/apps/edr-freight-api/src/scripts/backfill-missing-unload-inventory.ts @@ -0,0 +1,63 @@ +import 'reflect-metadata'; +import { config } from 'dotenv'; +import { resolve } from 'path'; +import { NestFactory } from '@nestjs/core'; +import { DataSource } from 'typeorm'; + +config({ path: resolve(__dirname, '../../.env') }); +process.env.TYPEORM_LOGGING = 'false'; + +import { AppModule } from '../app.module'; +import { WarehouseInventoryService } from '../modules/warehouses/warehouse-inventory.service'; + +/** + * One-off backfill for bookings caught by the autoArriveAtFinalYard bug + * (fixed in booking-journey.service.ts): the bulk final-yard arrival used to + * flip booking status to ARRIVED/COMPLETED without ever emitting + * booking.unloadedAtYard, so WarehouseInventoryService never created their + * warehouse_inventory row. Reuses the same idempotent listener the live + * event now calls, so it's safe to re-run. + */ +async function main() { + const app = await NestFactory.createApplicationContext(AppModule, { + logger: ['error', 'warn'], + }); + + try { + const dataSource = app.get(DataSource); + const inventory = app.get(WarehouseInventoryService); + + const bookings: { id: string; tradeDirection: string }[] = await dataSource.query( + `SELECT b.id, b.trade_direction AS "tradeDirection" + FROM freight.bookings b + WHERE b.deleted_at IS NULL + AND b.trade_direction IN ('IMPORT', 'DOMESTIC') + AND b.status IN ('ARRIVED', 'COMPLETED') + AND NOT EXISTS ( + SELECT 1 FROM freight.warehouse_inventory wi + WHERE wi.booking_id = b.id AND wi.deleted_at IS NULL + )`, + ); + + if (bookings.length === 0) { + console.log('No bookings missing their unload inventory row.'); + return; + } + + console.log(`Backfilling ${bookings.length} booking(s)...`); + for (const booking of bookings) { + await inventory.handleBookingUnloadedAtYard({ + bookingId: booking.id, + tradeDirection: booking.tradeDirection, + }); + console.log(` - ${booking.id} (${booking.tradeDirection})`); + } + } finally { + await app.close(); + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +});