exclude self from container clash

This commit is contained in:
Marshal
2026-08-06 22:34:53 +00:00
parent 1b8c7e4296
commit 96a4dd2e7f
7 changed files with 37 additions and 8 deletions

View File

@@ -1882,6 +1882,9 @@ export class ContractBookingService {
async validateShipment( async validateShipment(
contractId: string, contractId: string,
dto: CreateBookingUnderContractDto, dto: CreateBookingUnderContractDto,
// Completion/resubmit preview: the booking being completed must not clash
// with its own persisted containers.
excludeBookingId?: string,
): Promise<{ ): Promise<{
overweightLines: Array<{ overweightLines: Array<{
containerTypeCode: string; containerTypeCode: string;
@@ -2043,6 +2046,7 @@ export class ContractBookingService {
originYardId: route?.originYardId, originYardId: route?.originYardId,
destinationYardId: route?.destinationYardId, destinationYardId: route?.destinationYardId,
}, },
excludeBookingId,
); );
containerClashErrors = clashes.map( containerClashErrors = clashes.map(
(c) => (c) =>

View File

@@ -1124,8 +1124,11 @@ export class ContractsController {
validateShipment( validateShipment(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@Body() dto: CreateBookingUnderContractDto, @Body() dto: CreateBookingUnderContractDto,
// Completion/resubmit preview: exclude this booking's own persisted
// containers from the same-train clash check.
@Query('bookingId') bookingId?: string,
) { ) {
return this.contractBookingService.validateShipment(id, dto); return this.contractBookingService.validateShipment(id, dto, bookingId);
} }
@Get(':id/capacity') @Get(':id/capacity')

View File

@@ -961,7 +961,7 @@ export default function GlCreateBookingForm() {
// modal falls back to the contract unit-rate estimate while it loads. // modal falls back to the contract unit-rate estimate while it loads.
const validateShipmentMutation = useMutation({ const validateShipmentMutation = useMutation({
mutationFn: (dto: Freight.CreateBookingUnderContractDto) => mutationFn: (dto: Freight.CreateBookingUnderContractDto) =>
contractsService.validateShipment(id ?? "", dto), contractsService.validateShipment(id ?? "", dto, completeBookingId),
}); });
const validation = validateShipmentMutation.data ?? null; const validation = validateShipmentMutation.data ?? null;

View File

@@ -673,8 +673,16 @@ export const contractsService = {
validateShipment: ( validateShipment: (
id: string, id: string,
payload: Freight.CreateBookingUnderContractDto, payload: Freight.CreateBookingUnderContractDto,
// Completion/resubmit preview: exclude this booking's own containers from
// the same-train clash check.
excludeBookingId?: string,
) => ) =>
postContract<ShipmentValidation>(C.VALIDATE_SHIPMENT(id), payload), postContract<ShipmentValidation>(
excludeBookingId
? `${C.VALIDATE_SHIPMENT(id)}?bookingId=${excludeBookingId}`
: C.VALIDATE_SHIPMENT(id),
payload,
),
/** Remaining bookable quantity per cargo line (GENERAL draw-down cap). */ /** Remaining bookable quantity per cargo line (GENERAL draw-down cap). */
getCapacity: async (id: string): Promise<Freight.ContractCapacityLine[]> => { getCapacity: async (id: string): Promise<Freight.ContractCapacityLine[]> => {

View File

@@ -483,7 +483,12 @@ function NewShipmentBookingForm({
// price modal opens so re-reviewing after an edit re-checks. // price modal opens so re-reviewing after an edit re-checks.
const validateMutation = useMutation({ const validateMutation = useMutation({
mutationFn: (dto: Freight.CreateBookingUnderContractDto) => mutationFn: (dto: Freight.CreateBookingUnderContractDto) =>
api.contracts.validateShipment.call({ id: contractId, dto }), api.contracts.validateShipment.call({
id: contractId,
dto,
// Resubmit preview must not clash with this booking's own containers.
excludeBookingId: completeBookingId,
}),
}); });
function buildDto( function buildDto(

View File

@@ -610,10 +610,14 @@ export const api = {
), ),
validateShipment: endpoint< validateShipment: endpoint<
{ id: string; dto: Freight.CreateBookingUnderContractDto }, {
id: string;
dto: Freight.CreateBookingUnderContractDto;
excludeBookingId?: string;
},
ShipmentValidation ShipmentValidation
>("contracts", "validateShipment", ({ id, dto }) => >("contracts", "validateShipment", ({ id, dto, excludeBookingId }) =>
contractsService.validateShipment(id, dto), contractsService.validateShipment(id, dto, excludeBookingId),
), ),
getContractMilestones: endpoint< getContractMilestones: endpoint<

View File

@@ -400,8 +400,13 @@ export const contractsService = {
validateShipment: async ( validateShipment: async (
id: string, id: string,
dto: Freight.CreateBookingUnderContractDto, dto: Freight.CreateBookingUnderContractDto,
// Completion/resubmit: exclude this booking's own containers from the
// same-train clash check.
excludeBookingId?: string,
): Promise<ShipmentValidation> => { ): Promise<ShipmentValidation> => {
const { data } = await client.post(C.VALIDATE_SHIPMENT(id), dto); const { data } = await client.post(C.VALIDATE_SHIPMENT(id), dto, {
params: excludeBookingId ? { bookingId: excludeBookingId } : undefined,
});
return data.data ?? data; return data.data ?? data;
}, },