mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 07:38:10 +00:00
feat: container/bulk items datatable on warehouse view details
Adds a per-container/bulk items view for a booking with derived lifecycle stage (PENDING -> RECEIVED -> GRN -> LOADED -> LEFT -> DELIVERED) and reference badges (booking, contract, last-mile). Backend containerItems() aggregates booking_container_units + customer_truck_containers + inventory; exposed at GET warehouse-inventory/bookings/:id/container-items. Frontend ContainerItemsModal (opened from the View Details eye): stage tabs with counts, ref columns, checkbox multiselect of loadable items -> pick truck -> load (Truck_dispatch), and per-row per-truck Exit Paper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -333,6 +333,12 @@ export class WarehouseInventoryController {
|
||||
return this.handoverService.list(bookingId);
|
||||
}
|
||||
|
||||
@Get('bookings/:bookingId/container-items')
|
||||
@ApiOperation({ summary: 'Per-container/bulk items of a booking with lifecycle stage + refs' })
|
||||
containerItems(@Param('bookingId', ParseUUIDPipe) bookingId: string) {
|
||||
return this.inventoryService.containerItems(bookingId);
|
||||
}
|
||||
|
||||
@Post(':id/deliver')
|
||||
@ApiOperation({ summary: 'Deliver import goods to the customer + capture proof of delivery' })
|
||||
deliver(@Param('id', ParseUUIDPipe) id: string, @Body() dto: DeliverInventoryDto) {
|
||||
|
||||
@@ -2308,6 +2308,95 @@ export class WarehouseInventoryService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-container (or bulk) items of a booking with their lifecycle stage and
|
||||
* reference sources — drives the container-level detail datatable (stage tabs,
|
||||
* multiselect load-to-truck, per-item actions).
|
||||
*/
|
||||
async containerItems(bookingId: string): Promise<
|
||||
Array<{
|
||||
containerNumber: string;
|
||||
goods: string | null;
|
||||
stage: 'PENDING' | 'RECEIVED' | 'GRN' | 'LOADED' | 'LEFT' | 'DELIVERED';
|
||||
grnNumber: string | null;
|
||||
truckAssignmentId: string | null;
|
||||
truckPlate: string | null;
|
||||
truckArrived: boolean;
|
||||
truckLeft: boolean;
|
||||
bookingReference: string | null;
|
||||
contractId: string | null;
|
||||
hasLastMile: boolean;
|
||||
}>
|
||||
> {
|
||||
const rows: Array<{
|
||||
containerNumber: string;
|
||||
goods: string | null;
|
||||
received: boolean;
|
||||
grnNumber: string | null;
|
||||
truckAssignmentId: string | null;
|
||||
truckPlate: string | null;
|
||||
truckArrived: boolean;
|
||||
truckLeft: boolean;
|
||||
bookingReference: string | null;
|
||||
contractId: string | null;
|
||||
hasLastMile: boolean;
|
||||
delivered: boolean;
|
||||
}> = await this.dataSource.query(
|
||||
`SELECT bcu.container_number AS "containerNumber",
|
||||
COALESCE(ct.cargo_type_name, b.cargo_free_text) AS goods,
|
||||
bcu.received_to_port AS received,
|
||||
bcu.grn_number AS "grnNumber",
|
||||
ctc.assignment_id AS "truckAssignmentId",
|
||||
a.plate_number AS "truckPlate",
|
||||
(a.arrived_at IS NOT NULL) AS "truckArrived",
|
||||
(a.departed_at IS NOT NULL) AS "truckLeft",
|
||||
b.reference AS "bookingReference",
|
||||
b.contract_id AS "contractId",
|
||||
(b.last_mile_delivery_address IS NOT NULL) AS "hasLastMile",
|
||||
COALESCE(inv.status = 'DELIVERED', false) AS delivered
|
||||
FROM freight.booking_container_units bcu
|
||||
JOIN freight.booking_container bc
|
||||
ON bc.id = bcu.booking_container_id AND bc.deleted_at IS NULL
|
||||
JOIN freight.bookings b ON b.id = bc.booking_id
|
||||
LEFT JOIN freight.cargo_types ct ON ct.id = b.cargo_type_id
|
||||
LEFT JOIN freight.customer_truck_containers ctc
|
||||
ON ctc.container_number = bcu.container_number
|
||||
AND ctc.booking_id = b.id AND ctc.deleted_at IS NULL
|
||||
LEFT JOIN freight.customer_truck_assignments a
|
||||
ON a.id = ctc.assignment_id AND a.deleted_at IS NULL
|
||||
LEFT JOIN freight.containers cont ON cont.container_number = bcu.container_number
|
||||
LEFT JOIN freight.warehouse_inventory inv
|
||||
ON inv.container_id = cont.id AND inv.deleted_at IS NULL
|
||||
WHERE bc.booking_id = $1 AND bcu.deleted_at IS NULL
|
||||
ORDER BY bcu.container_number`,
|
||||
[bookingId],
|
||||
);
|
||||
|
||||
return rows.map((r) => ({
|
||||
containerNumber: r.containerNumber,
|
||||
goods: r.goods,
|
||||
stage: r.delivered
|
||||
? 'DELIVERED'
|
||||
: r.truckLeft
|
||||
? 'LEFT'
|
||||
: r.truckAssignmentId
|
||||
? 'LOADED'
|
||||
: r.grnNumber
|
||||
? 'GRN'
|
||||
: r.received
|
||||
? 'RECEIVED'
|
||||
: 'PENDING',
|
||||
grnNumber: r.grnNumber,
|
||||
truckAssignmentId: r.truckAssignmentId,
|
||||
truckPlate: r.truckPlate,
|
||||
truckArrived: r.truckArrived,
|
||||
truckLeft: r.truckLeft,
|
||||
bookingReference: r.bookingReference,
|
||||
contractId: r.contractId,
|
||||
hasLastMile: r.hasLastMile,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-truck exit paper: one paper covering the containers loaded on a specific
|
||||
* customer truck (used when multiple trucks leave separately). Gated on the
|
||||
|
||||
Reference in New Issue
Block a user