mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 01:48:12 +00:00
feat: Implement consolidated booking functionality
- Added support for viewing and managing consolidated bookings in BookingRequestDetailPage. - Enhanced BookingRequestsPage to display paired bookings in a single row. - Introduced pairedDecision method in bookings service to handle decisions for both halves of a consolidated pair. - Updated contracts service to include methods for manual consolidation of odd-20ft bookings. - Created new components for selecting and editing consolidation partners. - Added tests for paired decision logic and manual consolidation scenarios. - Updated UI to reflect changes in booking handling and provide user feedback for odd container counts.
This commit is contained in:
@@ -163,11 +163,17 @@ export function Step8Review({
|
||||
.join(", ")
|
||||
: "";
|
||||
|
||||
// 20ft containers must pair up (two per wagon) — an odd total blocks submit.
|
||||
// 20ft containers must pair up (two per wagon). Without customs an odd total
|
||||
// still blocks submit — nothing downstream can place the unpaired container.
|
||||
// With customs it is allowed: Global Logistics completes the booking and links
|
||||
// it to another customer's odd booking so the two share the wagon, so an odd
|
||||
// count here is only a notice.
|
||||
const { hasOddUnit: hasOdd20ft, ft20Wagons: twentyFtCount } =
|
||||
values.cargoType === "container"
|
||||
? calcWagons(values.containers ?? [])
|
||||
: { hasOddUnit: false, ft20Wagons: 0 };
|
||||
const oddPairsViaCustoms = hasOdd20ft && Boolean(values.customsClearingEnabled);
|
||||
const oddBlocksSubmit = hasOdd20ft && !oddPairsViaCustoms;
|
||||
|
||||
const isGeneralContract = values.bookingType === "general_contract";
|
||||
// Both one-time and general contracts take the bulk amount from the cargo step
|
||||
@@ -543,7 +549,7 @@ export function Step8Review({
|
||||
</Paper>
|
||||
|
||||
<Paper radius={20} p="lg" withBorder bg="white">
|
||||
{hasOdd20ft ? (
|
||||
{oddBlocksSubmit ? (
|
||||
<Box mb="md">
|
||||
<AlertBox tone="error">
|
||||
<p className="font-semibold">
|
||||
@@ -558,6 +564,20 @@ export function Step8Review({
|
||||
</p>
|
||||
</AlertBox>
|
||||
</Box>
|
||||
) : oddPairsViaCustoms ? (
|
||||
<Box mb="md">
|
||||
<AlertBox tone="info">
|
||||
<p className="font-semibold">
|
||||
Odd number of 20ft containers ({twentyFtCount})
|
||||
</p>
|
||||
<p className="mt-1 text-xs">
|
||||
20ft containers travel two per wagon, so one of yours will
|
||||
share a wagon with another shipment. Global Logistics
|
||||
arranges the pairing when completing your booking — you are
|
||||
billed only for your own containers.
|
||||
</p>
|
||||
</AlertBox>
|
||||
</Box>
|
||||
) : noWagonForSelectedDay ? (
|
||||
<Box mb="md">
|
||||
<AlertBox tone="error">
|
||||
@@ -587,7 +607,7 @@ export function Step8Review({
|
||||
leftSection={<Send size={16} />}
|
||||
onClick={onSubmit}
|
||||
loading={submitPending}
|
||||
disabled={submitPending || hasOdd20ft || noWagonForSelectedDay}
|
||||
disabled={submitPending || oddBlocksSubmit || noWagonForSelectedDay}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
|
||||
@@ -106,14 +106,14 @@ export default function NewShipmentRequestPage() {
|
||||
contract.cargoScope?.[0];
|
||||
const isPerItem = bulkScope?.cargoType?.unitOfMeasure === "PER_ITEM";
|
||||
|
||||
// 20ft containers ride two per wagon, so an odd total can never be planned —
|
||||
// and GL's create-booking form blocks it too, so an odd request would only
|
||||
// dead-end there. Same even-number rule the booking forms apply.
|
||||
// 20ft containers ride two per wagon. An odd total leaves one unpaired, which
|
||||
// is allowed here: on a customs contract GL completes the booking and links it
|
||||
// to another customer's odd booking so the two share the wagon. The request is
|
||||
// therefore informational only, not a block.
|
||||
const ft20Requested = isContainer ? Number(qtyBySize["20ft"]) || 0 : 0;
|
||||
const hasOdd20ft = ft20Requested % 2 === 1;
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (hasOdd20ft) return;
|
||||
const dto: Freight.CreateBookingRequestDto = {
|
||||
contractRouteId: route?.id,
|
||||
scheduledDate: hasCustoms ? undefined : scheduledDate || undefined,
|
||||
@@ -220,17 +220,17 @@ export default function NewShipmentRequestPage() {
|
||||
|
||||
{hasOdd20ft ? (
|
||||
<Alert
|
||||
color="red"
|
||||
color="blue"
|
||||
variant="light"
|
||||
radius="md"
|
||||
icon={<AlertCircle size={16} />}
|
||||
title={`Odd number of 20ft containers (${ft20Requested})`}
|
||||
>
|
||||
<Text fz={13}>
|
||||
20ft containers travel two per wagon, so they must be requested
|
||||
in even numbers. Please add one more 20ft container or remove
|
||||
one (e.g. request {ft20Requested + 1} or {ft20Requested - 1}{" "}
|
||||
instead of {ft20Requested}).
|
||||
20ft containers travel two per wagon, so one of yours will
|
||||
share a wagon with another shipment. Global Logistics arranges
|
||||
the pairing when completing your booking — you are billed only
|
||||
for your own containers.
|
||||
</Text>
|
||||
</Alert>
|
||||
) : null}
|
||||
@@ -281,7 +281,6 @@ export default function NewShipmentRequestPage() {
|
||||
leftSection={<Send size={16} />}
|
||||
loading={submit.isPending}
|
||||
onClick={handleSubmit}
|
||||
disabled={hasOdd20ft}
|
||||
>
|
||||
Submit shipment request
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user