intercity fix

This commit is contained in:
Marshal
2026-07-31 10:26:17 +00:00
parent d07a2e239e
commit 74b7ee81fc
11 changed files with 679 additions and 49 deletions

View File

@@ -135,11 +135,20 @@ export class BookingContractService {
async generateContractForGovernment(bookingId: string): Promise<void> {
const booking = await this.requireBooking(bookingId);
if (!booking.isGovernment || booking.contractGeneratedAt) return;
const templateKey = this.templateResolver.resolve(booking);
await this.bookingsRepository.update(bookingId, {
contractSummary: this.buildContractSummary(booking),
contractTemplateKey: this.templateResolver.resolve(booking),
contractTemplateKey: templateKey,
contractGeneratedAt: new Date(),
} as never);
// Render the PDF eagerly but NEVER block creation on it — Chromium can take
// seconds (or hang on assets); the document re-renders on view/download.
void this.upsertContractPdf(bookingId, booking.reference, templateKey).catch(
(err) =>
this.logger.warn(
`Government contract PDF deferred for ${booking.reference}: ${err}. It will render on view/download.`,
),
);
}
async streamContract(bookingId: string) {

View File

@@ -23,6 +23,7 @@ import {
DocumentReviewStatus,
} from './entities/booking-document-review.entity';
import { BookingContainer } from './entities/booking-container.entity';
import { BookingContainerUnit } from './entities/booking-container-unit.entity';
import { BookingRateSnapshot } from './entities/booking-rate-snapshot.entity';
import { BookingReviewNote, ReviewNoteType } from './entities/booking-review-note.entity';
import { TrainScheduleBooking } from '../train-schedules/entities/train-schedule-booking.entity';
@@ -201,10 +202,12 @@ export class BookingsRepository extends BaseRepository<Booking> {
vgmPerUnitTons: number;
hazardousQuantity?: number;
reeferQuantity?: number;
containerNumbers?: string[];
weightResult: ContainerWeightResult;
}>,
): Promise<BookingContainer[]> {
const containerRepo = this.dataSource.getRepository(BookingContainer);
const unitRepo = this.dataSource.getRepository(BookingContainerUnit);
const typeRepo = this.dataSource.getRepository(ContainerType);
const saved: BookingContainer[] = [];
@@ -230,7 +233,26 @@ export class BookingsRepository extends BaseRepository<Booking> {
isOverweight: item.weightResult.isOverweight,
overweightExcessTons: item.weightResult.overweightExcessTons,
});
saved.push(await containerRepo.save(row));
const savedRow = await containerRepo.save(row);
saved.push(savedRow);
// Physical container numbers, one unit row each (capped to the line
// quantity; blanks skipped). Optional — units can also be entered later.
const numbers = (item.containerNumbers ?? [])
.map((n) => n.trim())
.filter(Boolean)
.slice(0, item.quantity);
let sortOrder = 0;
for (const containerNumber of numbers) {
await unitRepo.save(
unitRepo.create({
bookingContainerId: savedRow.id,
containerNumber,
vgmTons: item.vgmPerUnitTons,
sortOrder: sortOrder++,
}),
);
}
}
return saved;

View File

@@ -934,6 +934,7 @@ export class BookingsService {
vgmPerUnitTons: c.vgmPerUnitTons,
hazardousQuantity: c.hazardousQuantity,
reeferQuantity: c.reeferQuantity,
containerNumbers: c.containerNumbers,
weightResult: ruleResult.containerWeightResults[i],
})),
);

View File

@@ -74,6 +74,17 @@ export class CreateBookingContainerDto {
@Min(0)
@Transform(({ value }) => Number(value ?? 0))
reeferQuantity?: number;
@ApiPropertyOptional({
description:
'Physical container numbers for this line (each becomes a booking_container_unit; extras beyond `quantity` are ignored)',
type: [String],
})
@IsOptional()
@IsArray()
@IsString({ each: true })
@MaxLength(64, { each: true })
containerNumbers?: string[];
}
/**