Fix customer_truck_containers status

This commit is contained in:
Hagernesh
2026-07-08 13:54:02 +00:00
parent 246663641a
commit 33956d07dc
8 changed files with 109 additions and 17 deletions

View File

@@ -1424,12 +1424,14 @@ export class BookingsService {
schedule?.status ?? null;
}
// A generated-but-unsigned handover means the customer must approve delivery.
// Surfaced so the portal shows "Approve delivery" as soon as the handover
// exists, independent of the truck-arrival flag.
// A generated-but-unsigned SELF_HAUL handover means the customer must approve
// delivery from the portal (booking-based, one per booking). EDR last-mile
// handovers are per delivering truck and signed by the receiver at the door,
// so they never surface the portal "Approve delivery" action.
const [pendingHandover] = await this.dataSource.query(
`SELECT 1 FROM freight.booking_handovers
WHERE booking_id = $1 AND signed_at IS NULL AND deleted_at IS NULL
AND mile_type = 'SELF_HAUL'
LIMIT 1`,
[id],
);

View File

@@ -312,6 +312,13 @@ export class CustomerTruckService {
if (assignment.departedAt) {
throw new ConflictException('This truck has already left — its load is locked');
}
// Containers can only be loaded after the truck has physically arrived at the
// warehouse (arrival weighing recorded). Assignment alone is just planning.
if (!assignment.arrivedAt) {
throw new BadRequestException(
'Record the truck arrival before loading — containers can only be loaded onto an arrived truck',
);
}
const requested = (dto.containerNumbers ?? []).map((n) => n.trim().toUpperCase());
if (!requested.length) {
@@ -333,12 +340,16 @@ export class CustomerTruckService {
const grossTons = await this.vgmTonsForContainers(bookingId, requested);
await this.dataSource.transaction(async (manager) => {
await manager.getRepository(CustomerTruckContainer).softDelete({ assignmentId });
// Operator loading the truck: stamp loaded_at so these containers move to
// the LOADED stage (customer assignment alone leaves loaded_at null).
const loadedAt = new Date();
await manager.getRepository(CustomerTruckContainer).save(
requested.map((containerNumber) =>
manager.getRepository(CustomerTruckContainer).create({
assignmentId,
bookingId,
containerNumber,
loadedAt,
}),
),
);

View File

@@ -23,4 +23,12 @@ export class CustomerTruckContainer extends BaseEntity {
@Column({ name: 'container_number', type: 'varchar', length: 64 })
containerNumber!: string;
/**
* When the container was actually loaded onto the truck by the operator.
* Null = customer-assigned (planned) but not yet loaded. Stage LOADED requires
* this to be set, so customer assignment alone does not mark a container loaded.
*/
@Column({ name: 'loaded_at', type: 'timestamptz', nullable: true })
loadedAt?: Date | null;
}