feat(last-mile): wire multi-container assignment, bulk drawdown + EDR exit papers

Frontend for the per-truck EDR backend:

- Assign modal takes a container LOAD per truck (MultiSelect, max 2) instead of a
  single container, so a truck can carry one 40ft or two 20ft. Sends
  containerNumbers[]; the API enforces the size rule.
- requiredVehicles is now size-aware: a 40ft fills a truck (1 each), two 20ft
  share one. It previously assumed ceil(containers / 2) regardless of size, so a
  2x40ft booking under-counted the trucks needed.
- Bulk bookings show the drawdown in the assign modal — remaining vs total
  tonnage, what's been hauled, and a "fully hauled" state when it reaches 0.
- New "Truck exit papers" row action opens a per-truck list (plate, containers,
  arrival, exit, net weight) with a per-truck exit-paper download.
- last-mile findAll/findById now load each assignment's containers so the UI can
  hydrate a truck's load.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hagernesh
2026-07-16 09:03:04 +00:00
parent ff49554cc2
commit d5182c5d85
5 changed files with 267 additions and 38 deletions

View File

@@ -182,7 +182,7 @@ export class LastMileService {
relations: {
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true, units: true } },
vehicle: true,
vehicleAssignments: { vehicle: true },
vehicleAssignments: { vehicle: true, containers: true },
},
order: { [sortBy]: sortOrder },
skip: (page - 1) * pageSize,
@@ -207,7 +207,7 @@ export class LastMileService {
relations: {
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true, units: true } },
vehicle: true,
vehicleAssignments: { vehicle: true },
vehicleAssignments: { vehicle: true, containers: true },
},
});
@@ -284,7 +284,7 @@ export class LastMileService {
> {
const [lm] = await this.lastMileRepository.findAll({
where: { bookingId },
relations: { vehicle: true, vehicleAssignments: { vehicle: true } },
relations: { vehicle: true, vehicleAssignments: { vehicle: true, containers: true } },
take: 1,
});
if (!lm) return [];