mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 21:15:41 +00:00
fix issue -> consolidation
This commit is contained in:
@@ -26,9 +26,18 @@ import { Booking } from './entities/booking.entity';
|
||||
import { assertBookingStatus } from './booking-status.util';
|
||||
import { ContainerValidationService } from './container-validation.service';
|
||||
|
||||
/**
|
||||
* One physical container over its VGM limit. Weight limits are per container,
|
||||
* so an overloaded box is reported (and billed) on its own tons above the
|
||||
* limit — a lighter box on the same line never absorbs them.
|
||||
*/
|
||||
export interface OverweightLine {
|
||||
containerTypeCode: string;
|
||||
/** Container number when known, else "<code> #2" — identifies the box. */
|
||||
containerLabel: string;
|
||||
/** This container's VGM, not the line total. */
|
||||
totalVgmTons: number;
|
||||
/** The per-container limit. */
|
||||
maxAllowedTons: number;
|
||||
excessTons: number;
|
||||
}
|
||||
@@ -250,9 +259,10 @@ export class BookingPricingService {
|
||||
clearanceBlocked.push(...clearance.blocked);
|
||||
}
|
||||
|
||||
// Overweight detail for the customer: map the engine's per-line results back
|
||||
// to the booking's container lines (same order) for code + weights. maxAllowed
|
||||
// is derived from the line total minus the excess the engine computed.
|
||||
// Overweight detail for the customer: one row per over-limit CONTAINER,
|
||||
// mapped back to the booking's container lines (same order) for the code and
|
||||
// the physical container numbers. maxAllowed is the per-container limit,
|
||||
// recovered from that container's weight minus its own excess.
|
||||
const overweightLines: OverweightLine[] = [];
|
||||
const containerLines = (booking.bookingContainers ?? []).filter(
|
||||
(bc) => bc.containerTypeId != null,
|
||||
@@ -261,8 +271,6 @@ export class BookingPricingService {
|
||||
const wr = ruleResult.containerWeightResults[i];
|
||||
if (!wr?.isOverweight) continue;
|
||||
const line = containerLines[i];
|
||||
const totalVgmTons = Number(line?.totalVgmTons ?? 0);
|
||||
const excessTons = Number(wr.overweightExcessTons ?? 0);
|
||||
let code = line?.containerSize ?? '';
|
||||
if (line?.containerTypeId) {
|
||||
try {
|
||||
@@ -271,12 +279,32 @@ export class BookingPricingService {
|
||||
// fall back to the container size label
|
||||
}
|
||||
}
|
||||
overweightLines.push({
|
||||
containerTypeCode: code,
|
||||
totalVgmTons,
|
||||
maxAllowedTons: Math.max(0, totalVgmTons - excessTons),
|
||||
excessTons,
|
||||
});
|
||||
const numbers = (line?.units ?? [])
|
||||
.slice()
|
||||
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
||||
.map((u) => u.containerNumber);
|
||||
// Legacy weight results carry no per-unit detail (a line total only) —
|
||||
// report the line as a single row, as before.
|
||||
const units = wr.overweightUnits?.length
|
||||
? wr.overweightUnits
|
||||
: [
|
||||
{
|
||||
unitIndex: 0,
|
||||
vgmTons: Number(line?.totalVgmTons ?? 0),
|
||||
excessTons: Number(wr.overweightExcessTons ?? 0),
|
||||
},
|
||||
];
|
||||
for (const u of units) {
|
||||
overweightLines.push({
|
||||
containerTypeCode: code,
|
||||
containerLabel:
|
||||
(u.unitIndex > 0 ? numbers[u.unitIndex - 1] : null) ||
|
||||
(u.unitIndex > 0 ? `${code} #${u.unitIndex}` : code),
|
||||
totalVgmTons: u.vgmTons,
|
||||
maxAllowedTons: Math.max(0, u.vgmTons - u.excessTons),
|
||||
excessTons: u.excessTons,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -346,6 +374,13 @@ export class BookingPricingService {
|
||||
quantity: qty,
|
||||
vgmPerUnitTons: vgm,
|
||||
totalVgmTons: qty * vgm,
|
||||
// Real per-box weights when the booking recorded them: weight
|
||||
// limits are per container, so 22/18/20t is 2t over on the first
|
||||
// box even though the line total fits a 3x20t allowance.
|
||||
unitVgmTons: (bc.units ?? [])
|
||||
.slice()
|
||||
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
||||
.map((u) => Number(u.vgmTons ?? 0)),
|
||||
isReefer: ct.isReefer,
|
||||
// Per-container opt-ins — PER_CONTAINER surcharges bill these.
|
||||
hazardousQuantity: Number(bc.hazardousQuantity ?? 0),
|
||||
|
||||
@@ -383,6 +383,9 @@ export class BookingWagonCancellationService {
|
||||
status: 'CANCELLED',
|
||||
trainScheduleId: null,
|
||||
requestedTrainScheduleId: null,
|
||||
// A dead booking holds no shipment day — leaving it set lets the
|
||||
// stranded-PAID day sweep pick the booking up and resurrect it.
|
||||
scheduledDate: null,
|
||||
});
|
||||
await this.detachFromSchedule(b);
|
||||
}
|
||||
@@ -568,6 +571,9 @@ export class BookingWagonCancellationService {
|
||||
status: 'CANCELLED',
|
||||
trainScheduleId: null,
|
||||
requestedTrainScheduleId: null,
|
||||
// A dead booking holds no shipment day — leaving it set lets the
|
||||
// stranded-PAID day sweep pick the booking up and resurrect it.
|
||||
scheduledDate: null,
|
||||
});
|
||||
await this.detachFromSchedule(booking);
|
||||
this.notifyCustomer(
|
||||
|
||||
@@ -27,11 +27,15 @@ export class PriceLineItemDto {
|
||||
currency!: string;
|
||||
}
|
||||
|
||||
/** One physical container over its per-container VGM limit. */
|
||||
export class OverweightLineDto {
|
||||
@ApiProperty()
|
||||
containerTypeCode!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@ApiProperty({ description: 'Container number, or "<code> #2" when unnumbered' })
|
||||
containerLabel!: string;
|
||||
|
||||
@ApiProperty({ description: "This container's VGM in tons" })
|
||||
totalVgmTons!: number;
|
||||
|
||||
@ApiProperty()
|
||||
|
||||
Reference in New Issue
Block a user