feat(container-returns): show booking ref, company and return time

The returns table renders one list holding both booking-linked and standalone
empty returns, but a booking-linked row showed the literal string Associated
in place of its reference, and nothing showed the owning company.

listEmptyReturns becomes a raw projection joining freight.bookings and
freight.companies, so each row carries bookingReference and a companyName that
falls back to the booking's company when none was typed on the return itself.

Return date was collected as a bare date input, storing every return at 00:00.
All three entry points — booking-linked, standalone and the bulk default — now
use datetime-local seeded from local time rather than UTC, and the column
renders date and time.
This commit is contained in:
Hagernesh
2026-08-28 12:24:17 +00:00
parent 2d8b022f6b
commit 3a640de45a
6 changed files with 104 additions and 32 deletions

View File

@@ -84,3 +84,14 @@ export class EmptyContainerReturn extends BaseEntity {
performedBy: string | null;
}>;
}
/**
* A row of the returns list: the entity's own columns plus the booking
* reference and owning company joined in. Standalone returns leave
* `bookingId`/`bookingReference` null.
*/
export interface EmptyContainerReturnListItem
extends Omit<EmptyContainerReturn, 'createdAt' | 'updatedAt' | 'deletedAt'> {
bookingReference: string | null;
createdAt: Date;
}

View File

@@ -27,6 +27,7 @@ import {
import { assertWagonLoad } from './empty-container-wagon.util';
import {
EmptyContainerReturn,
type EmptyContainerReturnListItem,
type EmptyContainerReturnStatus,
} from './entities/empty-container-return.entity';
import {
@@ -163,8 +164,43 @@ export class ImportOperationsService {
return this.getCustoms(bookingId);
}
listEmptyReturns() {
return this.emptyReturns.find({ order: { createdAt: 'DESC' } as never });
/**
* Every empty return, booking-linked and standalone alike, in one list. The
* booking reference and the owning company are joined in so the table can
* show which booking a box came back on without a second round trip — a
* standalone row simply has neither, and falls back to the typed
* `company_name`.
*/
listEmptyReturns(): Promise<EmptyContainerReturnListItem[]> {
return this.emptyReturns.manager.query(`
SELECT
r.id,
r.container_number AS "containerNumber",
r.booking_id AS "bookingId",
b.reference AS "bookingReference",
r.customer_id AS "customerId",
COALESCE(r.company_name, c.name) AS "companyName",
r.return_date AS "returnDate",
r.facility,
r.yard,
r.zone,
r.condition,
r.handover_note AS "handoverNote",
r.status,
r.wagon_allocation_reference AS "wagonAllocationReference",
r.container_size AS "containerSize",
r.train_schedule_id AS "trainScheduleId",
r.wagon_sequence_no AS "wagonSequenceNo",
r.performed_by AS "performedBy",
r.returned_by AS "returnedBy",
r.status_history AS "statusHistory",
r.created_at AS "createdAt"
FROM freight.empty_container_returns r
LEFT JOIN freight.bookings b ON b.id = r.booking_id
LEFT JOIN freight.companies c ON c.id = b.company_id
WHERE r.deleted_at IS NULL
ORDER BY r.created_at DESC
`);
}
listEmptyReturnsForBooking(bookingId: string) {