mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
fix conflict
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
* Fix for fresh deployments: AddWarehouseInspection1750000000003 runs before
|
||||
* the warehouse_inventory table exists, so it cannot add inspection_status.
|
||||
*/
|
||||
export class AddWarehouseInventoryInspectionStatusFix1791000000005 implements MigrationInterface {
|
||||
private readonly table = 'freight.warehouse_inventory';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
if ((await queryRunner.hasTable(this.table)) && !(await queryRunner.hasColumn(this.table, 'inspection_status'))) {
|
||||
await queryRunner.addColumn(
|
||||
this.table,
|
||||
new TableColumn({ name: 'inspection_status', type: 'varchar', length: '20', isNullable: true }),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
if ((await queryRunner.hasTable(this.table)) && (await queryRunner.hasColumn(this.table, 'inspection_status'))) {
|
||||
await queryRunner.dropColumn(this.table, 'inspection_status');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Module, forwardRef } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { BookingsModule } from '../bookings/bookings.module';
|
||||
@@ -13,7 +13,7 @@ import { LastMileService } from './last-mile.service';
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([LastMile]),
|
||||
BookingsModule,
|
||||
forwardRef(() => BookingsModule),
|
||||
VehiclesModule,
|
||||
DriversModule,
|
||||
NotificationsModule,
|
||||
|
||||
@@ -15,6 +15,7 @@ import { TrainSchedulesModule } from '../train-schedules/train-schedules.module'
|
||||
import { WagonType } from '../wagon-types/entities/wagon-type.entity';
|
||||
import { WagonTypesModule } from '../wagon-types/wagon-types.module';
|
||||
import { Wagon } from '../wagons/entities/wagon.entity';
|
||||
import { WarehousesModule } from '../warehouses/warehouses.module';
|
||||
import { TrainCheckpointEvent } from './entities/train-checkpoint-event.entity';
|
||||
import { TrainSchedulingGlobalRules } from './entities/train-scheduling-global-rules.entity';
|
||||
import { TrainCheckpointEventsRepository } from './train-checkpoint-events.repository';
|
||||
@@ -44,6 +45,7 @@ import { NotificationsModule } from '../notifications/notifications.module';
|
||||
WagonTypesModule,
|
||||
TrainSetsModule,
|
||||
TrainSchedulesModule,
|
||||
forwardRef(() => WarehousesModule),
|
||||
RuleEngineModule,
|
||||
],
|
||||
controllers: [TrainSchedulingController],
|
||||
|
||||
@@ -147,6 +147,10 @@ describe('TrainSchedulingService', () => {
|
||||
wagonAllocationBulkLoadsRepository as never,
|
||||
trainCheckpointEventsRepository as never,
|
||||
{} as never, // trainCompositionRemovalLogRepository
|
||||
{
|
||||
autoUnloadArrivedBookings: jest.fn(),
|
||||
autoUnloadExportAtDjibouti: jest.fn(),
|
||||
} as never,
|
||||
);
|
||||
|
||||
const defaultFleetWagons = [
|
||||
|
||||
@@ -95,6 +95,8 @@ import { TrainCheckpointEvent } from './entities/train-checkpoint-event.entity';
|
||||
import { TrainCheckpointEventsRepository } from './train-checkpoint-events.repository';
|
||||
import { RecordCheckpointDto } from './dto/record-checkpoint.dto';
|
||||
import { RouteMilestone } from '../routes/entities/route-milestone.entity';
|
||||
import { deriveTradeDirection } from '../../common/derive-trade-direction.util';
|
||||
import { WarehouseInventoryService } from '../warehouses/warehouse-inventory.service';
|
||||
import {
|
||||
autoFillPlacements,
|
||||
findMissingContainerNumberIssues,
|
||||
@@ -167,6 +169,7 @@ export class TrainSchedulingService {
|
||||
private readonly wagonAllocationBulkLoadsRepository: WagonAllocationBulkLoadsRepository,
|
||||
private readonly trainCheckpointEventsRepository: TrainCheckpointEventsRepository,
|
||||
private readonly trainCompositionRemovalLogRepository: TrainCompositionRemovalLogRepository,
|
||||
private readonly warehouseInventoryService: WarehouseInventoryService,
|
||||
private readonly configService?: ConfigService,
|
||||
) {}
|
||||
|
||||
@@ -602,6 +605,74 @@ export class TrainSchedulingService {
|
||||
return this.getTrainScheduleById(scheduleId);
|
||||
}
|
||||
|
||||
private async runWarehouseArrivalAutomation(scheduleId: string) {
|
||||
const [schedule]: Array<{
|
||||
originCountry: string | null;
|
||||
destinationCountry: string | null;
|
||||
destinationCode: string | null;
|
||||
destinationName: string | null;
|
||||
}> = await this.dataSource.query(
|
||||
`SELECT oy.country AS "originCountry",
|
||||
dy.country AS "destinationCountry",
|
||||
dy.code AS "destinationCode",
|
||||
dy.name AS "destinationName"
|
||||
FROM freight.train_schedules ts
|
||||
LEFT JOIN freight.yards oy ON oy.id = ts.origin_station_id
|
||||
LEFT JOIN freight.yards dy ON dy.id = ts.destination_station_id
|
||||
WHERE ts.id = $1 AND ts.deleted_at IS NULL
|
||||
LIMIT 1`,
|
||||
[scheduleId],
|
||||
);
|
||||
|
||||
if (!schedule) return { status: 'SKIPPED', reason: 'Train schedule not found' };
|
||||
|
||||
const direction = deriveTradeDirection(
|
||||
{ country: schedule.originCountry },
|
||||
{ country: schedule.destinationCountry },
|
||||
);
|
||||
|
||||
try {
|
||||
if (direction === 'IMPORT') {
|
||||
return {
|
||||
direction,
|
||||
action: 'IMPORT_AUTO_UNLOAD',
|
||||
status: 'COMPLETED',
|
||||
result: await this.warehouseInventoryService.autoUnloadArrivedBookings(
|
||||
scheduleId,
|
||||
'SYSTEM_TRAIN_ARRIVAL',
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (direction === 'EXPORT' && this.isDjiboutiPortDestination(`${schedule.destinationCode ?? ''} ${schedule.destinationName ?? ''}`)) {
|
||||
return {
|
||||
direction,
|
||||
action: 'EXPORT_DJIBOUTI_AUTO_UNLOAD',
|
||||
status: 'COMPLETED',
|
||||
result: await this.warehouseInventoryService.autoUnloadExportAtDjibouti(
|
||||
scheduleId,
|
||||
'SYSTEM_TRAIN_ARRIVAL',
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return { direction, status: 'SKIPPED', reason: 'No warehouse arrival automation for this route' };
|
||||
} catch (error) {
|
||||
return {
|
||||
direction,
|
||||
status: 'FAILED',
|
||||
reason: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private isDjiboutiPortDestination(value: string | null | undefined): boolean {
|
||||
const normalized = (value ?? '').toUpperCase();
|
||||
return ['DJIBOUTI', 'DORALEH', 'DMP', 'DCT', 'NAGAD'].some((token) =>
|
||||
normalized.includes(token),
|
||||
);
|
||||
}
|
||||
|
||||
async pinWagons(scheduleId: string, dto: PinWagonsDto) {
|
||||
const schedule = await this.trainSchedulesRepository.findByIdWithFullGraph(scheduleId);
|
||||
if (!schedule) {
|
||||
@@ -653,7 +724,9 @@ export class TrainSchedulingService {
|
||||
}
|
||||
});
|
||||
|
||||
return this.getTrainScheduleById(scheduleId);
|
||||
const detail = await this.getTrainScheduleById(scheduleId);
|
||||
const warehouseAutomation = await this.runWarehouseArrivalAutomation(scheduleId);
|
||||
return Object.assign(detail, { warehouseAutomation });
|
||||
}
|
||||
|
||||
async finalizeSchedule(scheduleId: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Module, forwardRef } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { ExchangeModule, ExchangeOptions } from '@edr/api-common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
@@ -70,7 +70,7 @@ import { WarehousesService } from './warehouses.service';
|
||||
]),
|
||||
FilesModule,
|
||||
InterchangeDocumentsModule,
|
||||
LastMileModule,
|
||||
forwardRef(() => LastMileModule),
|
||||
ExchangeModule.forRootAsync({
|
||||
inject: [ConfigService],
|
||||
useFactory: (config: ConfigService): ExchangeOptions =>
|
||||
|
||||
Reference in New Issue
Block a user