Merge pull request #1312 from Tria-plc/freight_feature/usermanagement

Freight feature/usermanagement
This commit is contained in:
marshal
2026-08-17 10:57:20 +03:00
committed by GitHub
9 changed files with 240 additions and 62 deletions

View File

@@ -110,6 +110,7 @@ function makeService(overrides?: {
.fn()
.mockResolvedValue({ id: 'ta-1', name: 'Ahmed Bourhan' }),
} as never, // transit agents
{ findAll: jest.fn().mockResolvedValue([]) } as never, // contracts repository
);
return {

View File

@@ -1,4 +1,5 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import {
ContractDocPhase,
isDeliveryOrderFileCode,
@@ -29,6 +30,7 @@ import { ClearanceMilestoneService } from './clearance-milestone.service';
import { GlOperationsService } from './gl-operations.service';
import { GlExchangeService } from './gl-exchange.service';
import { TransitAgentsService } from '../transit-agents/transit-agents.service';
import { ContractsRepository } from './contracts.repository';
import { AdviseContractDutyDto } from './dto/phased-clearance.dto';
import { buildWorkflowFiles, belongsOnDjClearanceQueue, belongsOnEtClearanceQueue, DJ_BOOKING_QUEUE_STATUSES, persistDeclarationUploads, persistDeliveryOrderUploads, persistDraftDeclarationUploads, persistReleaseOrderUploads, persistTransitPermitUploads, PHASED_CUSTOMS_BOOKING_QUEUE_STATUSES } from './phased-clearance.util';
@@ -155,6 +157,7 @@ export class BookingClearanceService {
private readonly notifier: BookingLifecycleNotifierService,
private readonly glExchangeService: GlExchangeService,
private readonly transitAgentsService: TransitAgentsService,
private readonly contractsRepository: ContractsRepository,
) {}
private async assertPhasedCustoms(booking: Booking): Promise<void> {
@@ -988,7 +991,39 @@ export class BookingClearanceService {
const milestones = await this.workflowService.listMilestonesForBooking(b.id);
if (belongsOnEtClearanceQueue(milestones)) filtered.push(b);
}
return filtered;
return this.attachContractSummary(filtered);
}
/**
* Queue rows show the parent contract's reference and lane. Booking has no
* contract relation, and a bare initiated instance may not carry yards yet —
* so batch-load the contracts (with routes) and fill in what's missing:
* `contractReference` always, origin/destination yards only when the booking
* lacks them (its own route wins).
*/
private async attachContractSummary(bookings: Booking[]): Promise<Booking[]> {
const ids = [...new Set(bookings.map((b) => b.contractId).filter(Boolean))] as string[];
if (!ids.length) return bookings;
const contracts = await this.contractsRepository.findAll({
where: { id: In(ids) },
relations: { routes: { originYard: true, destinationYard: true } },
});
const byId = new Map(contracts.map((c) => [c.id, c]));
for (const b of bookings) {
const contract = b.contractId ? byId.get(b.contractId) : undefined;
if (!contract) continue;
const row = b as Booking & { contractReference?: string | null };
row.contractReference = contract.reference ?? null;
if (b.originYard && b.destinationYard) continue;
const routes = contract.routes ?? [];
const route =
routes.find((r) => r.id === b.contractRouteId) ??
(routes.length === 1 ? routes[0] : undefined);
if (!route) continue;
b.originYard = b.originYard ?? route.originYard;
b.destinationYard = b.destinationYard ?? route.destinationYard;
}
return bookings;
}
async djQueue(): Promise<Booking[]> {
@@ -1008,6 +1043,6 @@ export class BookingClearanceService {
filtered.push(b);
}
}
return filtered;
return this.attachContractSummary(filtered);
}
}

View File

@@ -1368,7 +1368,7 @@ export class TrainSchedulingService {
* in the future) using the CURRENT global-rules config. Schedules already OPEN or
* past their window are left untouched — customers may have booked against the
* times they were shown, so those stay frozen. Returns the count re-stamped.
*/
*/
async restampPendingWindows(): Promise<number> {
const cfg = await this.getWindowConfig();
const now = new Date();