diff --git a/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts b/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts new file mode 100644 index 000000000..333a0f541 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/2020000000000-WarehouseCapacityKgToTons.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +/** + * Weights are tonnes everywhere. Warehouse / yard / zone capacity was stored in + * kg (e.g. 25000, 5000, 2500) — convert existing rows to tonnes (÷1000). Cargo + * weight (warehouse_inventory.weight ← cargo_total_weight_vgm) is already tonnes + * and is NOT touched; truck gross weight has no data yet. Runs exactly once + * (tracked by TypeORM) — re-running would divide again. + */ +export class WarehouseCapacityKgToTons2020000000000 implements MigrationInterface { + name = 'WarehouseCapacityKgToTons2020000000000'; + + private readonly tables = ['warehouses', 'warehouse_yards', 'warehouse_zones']; + private readonly columns = ['capacity_weight', 'current_weight', 'max_weight']; + + public async up(queryRunner: QueryRunner): Promise { + for (const table of this.tables) { + for (const column of this.columns) { + await queryRunner.query( + `UPDATE freight.${table} SET ${column} = ${column} / 1000.0 WHERE ${column} IS NOT NULL`, + ); + } + } + } + + public async down(queryRunner: QueryRunner): Promise { + for (const table of this.tables) { + for (const column of this.columns) { + await queryRunner.query( + `UPDATE freight.${table} SET ${column} = ${column} * 1000.0 WHERE ${column} IS NOT NULL`, + ); + } + } + } +} diff --git a/apps/edr-freight-api/src/modules/bookings/customer-truck.service.ts b/apps/edr-freight-api/src/modules/bookings/customer-truck.service.ts index 6f0ec6f55..43c14c7f6 100644 --- a/apps/edr-freight-api/src/modules/bookings/customer-truck.service.ts +++ b/apps/edr-freight-api/src/modules/bookings/customer-truck.service.ts @@ -42,16 +42,16 @@ export class CustomerTruckService { const booking = await this.loadBookingGuard(bookingId); this.assertSelfHaulPaid(booking); - const isExport = booking.tradeDirection === 'EXPORT'; const requested = (dto.containerNumbers ?? []).map((n) => n.trim().toUpperCase()); - // EXPORT: the truck delivers 1–2 known containers. IMPORT: containers are - // not pre-specified — they are registered + weighed when the truck leaves. - if (isExport) { - if (requested.length < 1 || requested.length > 2) { - throw new BadRequestException('An export truck must carry 1 or 2 of the booking containers'); - } - } else if (requested.length > 2) { + // Both import and export specify the containers each truck carries. Capacity + // is size-based: a 40ft container fills the truck (max 1); two 20ft containers + // fit (max 2), no size mixing. #trucks <= #containers follows naturally since + // each container is assigned to exactly one truck. + if (requested.length < 1) { + throw new BadRequestException('Select at least one container for this truck'); + } + if (requested.length > 2) { throw new BadRequestException('A truck carries at most 2 containers'); } @@ -68,6 +68,13 @@ export class CustomerTruckService { throw new ConflictException(`Container ${n} is already loaded onto another truck`); } } + // Size cap: a 40ft container fills the truck. + const sizes = await this.containerSizes(bookingId, requested); + if (sizes.some((s) => s.includes('40')) && requested.length > 1) { + throw new BadRequestException( + 'A 40ft container fills the truck — assign only 1 container to this truck', + ); + } } await this.dataSource.transaction(async (manager) => { @@ -244,7 +251,7 @@ export class CustomerTruckService { } } - const grossKg = await this.vgmKgForContainers(bookingId, requested); + const grossTons = await this.vgmTonsForContainers(bookingId, requested); await this.dataSource.transaction(async (manager) => { await manager.getRepository(CustomerTruckContainer).softDelete({ assignmentId }); await manager.getRepository(CustomerTruckContainer).save( @@ -256,18 +263,19 @@ export class CustomerTruckService { }), ), ); - // Provisional gross from the loaded containers' VGM — overridden by the - // weighed gross on departure. + // Provisional gross (tonnes) from the loaded containers' VGM — overridden + // by the weighed gross on departure. (Column is *_kg but holds tonnes.) await manager.getRepository(CustomerTruckAssignment).update(assignmentId, { - grossWeightKg: grossKg, + grossWeightKg: grossTons, }); }); return this.listTrucks(bookingId); } - private async vgmKgForContainers(bookingId: string, numbers: string[]): Promise { - const [row]: Array<{ kg: string }> = await this.dataSource.query( - `SELECT COALESCE(SUM(bcu.vgm_tons), 0) * 1000 AS kg + /** Summed VGM (tonnes) of the given containers — provisional truck gross. */ + private async vgmTonsForContainers(bookingId: string, numbers: string[]): Promise { + const [row]: Array<{ tons: string }> = await this.dataSource.query( + `SELECT COALESCE(SUM(bcu.vgm_tons), 0) AS tons FROM freight.booking_container_units bcu JOIN freight.booking_container bc ON bc.id = bcu.booking_container_id AND bc.deleted_at IS NULL @@ -276,7 +284,7 @@ export class CustomerTruckService { AND bcu.deleted_at IS NULL`, [bookingId, numbers], ); - return Number(row?.kg ?? 0); + return Number(row?.tons ?? 0); } /** @@ -399,4 +407,20 @@ export class CustomerTruckService { ); return rows.map((r) => r.containerNumber.trim().toUpperCase()); } + + /** Contract container sizes (e.g. "20ft" / "40ft") for the given container numbers. */ + private async containerSizes(bookingId: string, numbers: string[]): Promise { + if (!numbers.length) return []; + const rows: Array<{ size: string | null }> = await this.dataSource.query( + `SELECT bc.container_size AS "size" + FROM freight.booking_container_units bcu + JOIN freight.booking_container bc + ON bc.id = bcu.booking_container_id AND bc.deleted_at IS NULL + WHERE bc.booking_id = $1 + AND UPPER(bcu.container_number) = ANY($2) + AND bcu.deleted_at IS NULL`, + [bookingId, numbers], + ); + return rows.map((r) => (r.size ?? '').trim()); + } } diff --git a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-yard.dto.ts b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-yard.dto.ts index ccdda90d8..56b9d0810 100644 --- a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-yard.dto.ts +++ b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-yard.dto.ts @@ -35,7 +35,7 @@ export class CreateWarehouseYardDto { @Min(0) capacityContainers?: number; - @ApiPropertyOptional({ description: 'Max weight capacity (kg). Defaults to capacityWeight.' }) + @ApiPropertyOptional({ description: 'Max weight capacity (t). Defaults to capacityWeight.' }) @IsOptional() @IsNumber() @Min(0) diff --git a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-zone.dto.ts b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-zone.dto.ts index fbb057fd5..eb29f751f 100644 --- a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-zone.dto.ts +++ b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse-zone.dto.ts @@ -35,7 +35,7 @@ export class CreateWarehouseZoneDto { @Min(0) capacityContainers?: number; - @ApiPropertyOptional({ description: 'Max weight capacity (kg). Defaults to capacityWeight.' }) + @ApiPropertyOptional({ description: 'Max weight capacity (t). Defaults to capacityWeight.' }) @IsOptional() @IsNumber() @Min(0) diff --git a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse.dto.ts b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse.dto.ts index 5a8025948..900a9d8ac 100644 --- a/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse.dto.ts +++ b/apps/edr-freight-api/src/modules/warehouses/dto/create-warehouse.dto.ts @@ -47,7 +47,7 @@ export class CreateWarehouseDto { @Min(0) capacityContainers?: number; - @ApiPropertyOptional({ description: 'Max weight capacity (kg). Defaults to capacityWeight.' }) + @ApiPropertyOptional({ description: 'Max weight capacity (t). Defaults to capacityWeight.' }) @IsOptional() @IsNumber() @Min(0) diff --git a/apps/edr-freight-api/src/modules/warehouses/dto/load-inventory.dto.ts b/apps/edr-freight-api/src/modules/warehouses/dto/load-inventory.dto.ts index 063bb7d1d..c81550cd0 100644 --- a/apps/edr-freight-api/src/modules/warehouses/dto/load-inventory.dto.ts +++ b/apps/edr-freight-api/src/modules/warehouses/dto/load-inventory.dto.ts @@ -6,7 +6,7 @@ export class LoadInventoryDto { @IsUUID() wagonId!: string; - @ApiPropertyOptional({ description: 'Weight loaded onto the wagon (kg)' }) + @ApiPropertyOptional({ description: 'Weight loaded onto the wagon (t)' }) @IsOptional() @IsNumber() @Min(0) diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.service.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.service.ts index ff25258d3..0a0c56821 100644 --- a/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.service.ts +++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.service.ts @@ -44,7 +44,7 @@ export class WarehouseInspectionService { expectedWeight: expected, actualWeight: actual, weightLoss, - weightLossUnit: weightLoss !== null ? 'kg' : null, + weightLossUnit: weightLoss !== null ? 't' : null, hasMissingItems: dto.hasMissingItems ?? false, missingItemsDescription: dto.missingItemsDescription ?? null, remarks: dto.remarks ?? null, diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts index bf7139d72..48b767a09 100644 --- a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts +++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts @@ -2020,7 +2020,7 @@ export class WarehouseInventoryService { activityType: 'INVENTORY_RECEIVED', inventoryId: saved.id, warehouseId: dto.warehouseId, - description: `GRN ${grnNumber}: received ${weight}kg via truck ${truckEntrance.truckPlateNumber}`, + description: `GRN ${grnNumber}: received ${weight}t via truck ${truckEntrance.truckPlateNumber}`, performedBy: dto.performedBy, }, manager, @@ -2677,7 +2677,7 @@ export class WarehouseInventoryService { ['Pickup Truck Plate', data.plateNumber], ['Driver', data.driverName], ['Truck Type', data.truckType], - ['Gross Weight (Loaded on Truck)', `${data.grossWeightKg.toLocaleString()} kg`], + ['Gross Weight (Loaded on Truck)', `${data.grossWeightKg.toLocaleString()} t`], ['Gate-Out Time', gateOut], ['Clearance Status', 'CLEARED FOR WAREHOUSE EXIT'], ]; @@ -3608,8 +3608,8 @@ export class WarehouseInventoryService { ['Booking Containers', data.bookingContainerSummary], ['Cargo / Goods Description', data.cargoDescription], ['Quantity', data.quantity], - ['Received Weight', `${data.weight.toLocaleString()} kg`], - ['Booking Declared Weight', data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} kg` : null], + ['Received Weight', `${data.weight.toLocaleString()} t`], + ['Booking Declared Weight', data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} t` : null], ['Volume', data.volume == null ? null : data.volume.toLocaleString()], ['Warehouse', data.warehouse], ['Yard', data.yard], @@ -3731,7 +3731,7 @@ export class WarehouseInventoryService { `${(data.truckPlateNumber && data.truckWeightKg ? data.truckWeightKg : data.weight - ).toLocaleString()} kg`, + ).toLocaleString()} t`, ], ['Warehouse', data.warehouse], ['Yard', data.yard], @@ -3894,8 +3894,8 @@ export class WarehouseInventoryService { ['Booking Containers', data.bookingContainerSummary], ['Cargo / Goods Description', data.cargoDescription], ['Quantity', data.quantity], - ['Inventory Weight', `${data.weight.toLocaleString()} kg`], - ['Booking Declared Weight', data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} kg` : null], + ['Inventory Weight', `${data.weight.toLocaleString()} t`], + ['Booking Declared Weight', data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} t` : null], ['Warehouse', data.warehouse], ['Yard', data.yard], ['Zone', data.zone], @@ -3968,8 +3968,8 @@ export class WarehouseInventoryService { 1. Goods${esc(data.cargoDescription || data.containerNumber || data.bookingReference)} Container${esc(data.containerNumber)} Booking Containers${esc(data.bookingContainerSummary)} - Inventory Weight${esc(`${data.weight.toLocaleString()} kg`)} - Booking Declared Weight${esc(data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} kg` : null)} + Inventory Weight${esc(`${data.weight.toLocaleString()} t`)} + Booking Declared Weight${esc(data.bookingDeclaredWeight ? `${data.bookingDeclaredWeight.toLocaleString()} t` : null)}
Handover Clause
@@ -4303,9 +4303,9 @@ export class WarehouseInventoryService { dto.truckType?.trim() ? `Truck Type: ${dto.truckType.trim()}` : null, dto.containerNumber?.trim() ? `Container Number: ${dto.containerNumber.trim()}` : null, dto.gateInTime ? `Gate In Time: ${dto.gateInTime}` : null, - `Tare Weight: ${tareWeight} kg`, - grossWeight == null ? null : `Gross Weight: ${grossWeight} kg`, - computedNetWeight == null ? null : `Net Weight: ${computedNetWeight} kg`, + `Tare Weight: ${tareWeight} t`, + grossWeight == null ? null : `Gross Weight: ${grossWeight} t`, + computedNetWeight == null ? null : `Net Weight: ${computedNetWeight} t`, dto.gateOutTime ? `Gate Out Time: ${dto.gateOutTime}` : null, ]; @@ -4357,7 +4357,7 @@ export class WarehouseInventoryService { } private extractExitInspectionNumber(note: string | null | undefined, label: string): number | undefined { - const value = this.extractExitInspectionLine(note, label)?.replace(/\s*kg$/i, ''); + const value = this.extractExitInspectionLine(note, label)?.replace(/\s*(kg|t)$/i, ''); if (!value) return undefined; const parsed = Number(value); return Number.isFinite(parsed) ? parsed : undefined; @@ -4420,9 +4420,9 @@ export class WarehouseInventoryService { truck?.driverName ? `Driver: ${truck.driverName}` : null, truck?.driverPhone ? `Driver Phone: ${truck.driverPhone}` : null, truck?.driverLicenseNumber ? `Driver License: ${truck.driverLicenseNumber}` : null, - truck?.entranceTareWeightKg !== undefined ? `Entrance Tare Weight: ${Number(truck.entranceTareWeightKg)} kg` : null, + truck?.entranceTareWeightKg !== undefined ? `Entrance Tare Weight: ${Number(truck.entranceTareWeightKg)} t` : null, truck?.weighingRequired !== undefined ? `Weighing Required: ${truck.weighingRequired ? 'Yes' : 'No'}` : null, - truck?.exitTareWeightKg !== undefined ? `Exit Tare Weight: ${Number(truck.exitTareWeightKg)} kg` : null, + truck?.exitTareWeightKg !== undefined ? `Exit Tare Weight: ${Number(truck.exitTareWeightKg)} t` : null, truck?.declarationNumber ? `Declaration / Bill of Entry: ${truck.declarationNumber}` : null, truck?.incoterms ? `Incoterms: ${truck.incoterms}` : null, truck?.hsCodes ? `HS Codes: ${truck.hsCodes}` : null, @@ -4430,8 +4430,8 @@ export class WarehouseInventoryService { truck?.itemDescription ? `Item Description: ${truck.itemDescription}` : null, truck?.packagingType ? `Packaging Type: ${truck.packagingType}` : null, truck?.unitCount !== undefined ? `Unit Count: ${Number(truck.unitCount)}` : null, - truck?.grossWeightKg !== undefined ? `Gross Weight: ${Number(truck.grossWeightKg)} kg` : null, - truck?.netWeightKg !== undefined ? `Net Weight: ${Number(truck.netWeightKg)} kg` : null, + truck?.grossWeightKg !== undefined ? `Gross Weight: ${Number(truck.grossWeightKg)} t` : null, + truck?.netWeightKg !== undefined ? `Net Weight: ${Number(truck.netWeightKg)} t` : null, truck?.volumeDimensions ? `Volume / Dimensions: ${truck.volumeDimensions}` : null, truck?.conditionAtReceipt ? `Condition at Receipt: ${truck.conditionAtReceipt}` : null, truck?.damagedRejectedQuantity !== undefined ? `Damaged / Rejected Quantity: ${Number(truck.damagedRejectedQuantity)}` : null, diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/CreateWarehouseModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/CreateWarehouseModal.tsx index 6494906b4..b1afff27b 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/CreateWarehouseModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/CreateWarehouseModal.tsx @@ -169,7 +169,7 @@ export function CreateWarehouseModal({ opened, onClose, warehouse }: CreateWareh setExpectedWeight(v === '' ? '' : Number(v))} /> setActualWeight(v === '' ? '' : Number(v))} diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryDetailModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryDetailModal.tsx index c888253f1..e76baa6f0 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryDetailModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryDetailModal.tsx @@ -78,7 +78,7 @@ export function InventoryDetailModal({ opened, onClose, item }: InventoryDetailM - + diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryInquiryDetailModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryInquiryDetailModal.tsx index 479249894..906ba4b47 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryInquiryDetailModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/InventoryInquiryDetailModal.tsx @@ -67,7 +67,7 @@ export function InventoryInquiryDetailModal({ opened, onClose, result }: Invento - + diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/LoadInventoryModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/LoadInventoryModal.tsx index 7fc43c0d5..f0166714c 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/LoadInventoryModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/LoadInventoryModal.tsx @@ -67,7 +67,7 @@ export function LoadInventoryModal({ opened, onClose, item }: LoadInventoryModal = { LOADED: 'green', }; -const weight = (w: number | null) => (w == null ? '—' : `${Number(w).toLocaleString()} kg`); +const weight = (w: number | null) => (w == null ? '—' : `${Number(w).toLocaleString()} t`); interface BookingGroup { bookingId: string | null; diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx index 3e3877236..822f350a2 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx @@ -520,14 +520,14 @@ function TruckEntranceFields({ {value.weighingRequired && ( onChange({ ...value, grossWeightKg: v === '' ? '' : Number(v) })} /> onChange({ ...value, netWeightKg: v === '' ? '' : Number(v) })} diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/ReleaseOrderModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/ReleaseOrderModal.tsx index 0471d51c6..1bf371e5d 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/ReleaseOrderModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/ReleaseOrderModal.tsx @@ -78,7 +78,7 @@ const lineValue = (notes: string | null | undefined, label: string) => { }; const lineNumber = (notes: string | null | undefined, label: string): number | '' => { - const value = lineValue(notes, label).replace(/\s*kg$/i, ''); + const value = lineValue(notes, label).replace(/\s*(kg|t)$/i, ''); if (!value) return ''; const parsed = Number(value); return Number.isFinite(parsed) ? parsed : ''; @@ -397,13 +397,13 @@ export function ReleaseOrderModal({ opened, onClose, item, truckPrefill }: Relea setGateInTime(e.currentTarget.value)} readOnly={isEntranceLocked} /> - setTareWeight(v === '' ? '' : Number(v))} readOnly={isEntranceLocked} /> - setGrossWeight(v === '' ? '' : Number(v))} disabled={!isExitStep} /> - + setTareWeight(v === '' ? '' : Number(v))} readOnly={isEntranceLocked} /> + setGrossWeight(v === '' ? '' : Number(v))} disabled={!isExitStep} /> + - Computed net: {computedNetWeight == null ? '-' : `${computedNetWeight.toLocaleString()} kg`} + Computed net: {computedNetWeight == null ? '-' : `${computedNetWeight.toLocaleString()} t`} setGateOutTime(e.currentTarget.value)} disabled={!isExitStep} /> diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx index b5deec80e..7dfc1996c 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx @@ -38,7 +38,7 @@ const columns: ColumnDef[] = [ }, { id: 'weight', - header: 'Loaded Weight (kg)', + header: 'Loaded Weight (t)', cell: ({ row }) => formatNumber(row.original.loadedWeight), }, { diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx index 652a26863..e9bb3a162 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx @@ -203,7 +203,7 @@ function PendingPaymentTable({ items, onNavigate }: PendingPaymentTableProps) { }, { id: 'warehouse', header: 'Warehouse', cell: ({ row }) => row.original.warehouse?.code ?? '—' }, { id: 'zone', header: 'Zone', cell: ({ row }) => row.original.zone?.code ?? '—' }, - { id: 'weight', header: 'Weight (kg)', cell: ({ row }) => formatNumber(row.original.weight) }, + { id: 'weight', header: 'Weight (t)', cell: ({ row }) => formatNumber(row.original.weight) }, { id: 'payment', header: 'Payment', diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/CustomerTruckAssignmentCard.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/CustomerTruckAssignmentCard.tsx index 65af584d3..67840c133 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/CustomerTruckAssignmentCard.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/CustomerTruckAssignmentCard.tsx @@ -73,10 +73,7 @@ export function CustomerTruckAssignmentCard({ (n) => !assignedNumbers.has(n), ); - // EXPORT trucks deliver known containers (pre-selected). IMPORT trucks don't — - // staff register + weigh what was loaded when the truck leaves. - const isExport = booking.tradeDirection === "EXPORT"; - + // Both import and export specify the containers each truck carries. const resetForm = () => { setPlateNumber(""); setDriverName(""); @@ -91,8 +88,7 @@ export function CustomerTruckAssignmentCard({ truckPlateNumber: plateNumber.trim().toUpperCase(), driverName: driverName.trim(), truckType: truckType.trim(), - // Import: containers are registered + weighed on departure, not here. - containerNumbers: isExport ? containers : [], + containerNumbers: containers, }), onSuccess: (list) => { queryClient.setQueryData(trucksKey, list); @@ -123,7 +119,7 @@ export function CustomerTruckAssignmentCard({ setError("Plate number, driver name and truck type are required."); return; } - if (isExport && (containers.length < 1 || containers.length > 2)) { + if (containers.length < 1 || containers.length > 2) { setError("Select 1 or 2 container numbers for this truck."); return; } @@ -207,8 +203,8 @@ export function CustomerTruckAssignmentCard({ )} - {/* Add-truck form. Export needs unassigned containers; import always allows another truck. */} - {(isExport ? availableContainers.length > 0 : true) ? ( + {/* Add-truck form — both directions assign the containers each truck carries. */} + {availableContainers.length > 0 ? ( <> @@ -231,19 +227,18 @@ export function CustomerTruckAssignmentCard({ value={truckType || null} onChange={(value) => setTruckType(value ?? "")} /> - {isExport && ( - - )} +