fix(bookings): gate export carriage acceptance sheet on GRN receipt

The sheet attests EDR has taken custody. Export custody happens at
warehouse receipt, so the shared received-with-GRN gate now runs even
when wagons are already allocated. Receipt-row query also accepts the
legacy notes GRN fallback, matching the loading gate.
This commit is contained in:
Hagernesh
2026-08-04 07:59:03 +00:00
parent 19ab3af1cb
commit 87b04973d8
5 changed files with 83 additions and 14 deletions

View File

@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class EmptyContainerReturnStatusHistory3220000000000 implements MigrationInterface {
name = 'EmptyContainerReturnStatusHistory3220000000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.empty_container_returns
ADD COLUMN IF NOT EXISTS status_history jsonb NOT NULL DEFAULT '[]'::jsonb
`);
await queryRunner.query(`
UPDATE freight.empty_container_returns
SET status_history = jsonb_build_array(
jsonb_build_object('status', status, 'changedAt', created_at, 'performedBy', performed_by)
)
WHERE status_history = '[]'::jsonb
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.empty_container_returns
DROP COLUMN IF EXISTS status_history
`);
}
}

View File

@@ -56,4 +56,11 @@ export class EmptyContainerReturn extends BaseEntity {
@Column({ name: 'returned_by', type: 'varchar', length: 20, nullable: true })
returnedBy?: 'EDR' | 'CUSTOMER' | null;
@Column({ name: 'status_history', type: 'jsonb', default: () => "'[]'" })
statusHistory!: Array<{
status: EmptyContainerReturnStatus;
changedAt: string;
performedBy: string | null;
}>;
}

View File

@@ -149,12 +149,13 @@ export class ImportOperationsService {
}
async createEmptyReturn(dto: CreateEmptyContainerReturnDto) {
const returnDate = dto.returnDate ? new Date(dto.returnDate) : new Date();
return this.emptyReturns.save(
this.emptyReturns.create({
containerNumber: dto.containerNumber,
bookingId: dto.bookingId ?? null,
customerId: dto.customerId ?? null,
returnDate: dto.returnDate ? new Date(dto.returnDate) : new Date(),
returnDate,
facility: dto.facility ?? null,
yard: dto.yard ?? null,
zone: dto.zone ?? null,
@@ -162,6 +163,9 @@ export class ImportOperationsService {
handoverNote: dto.handoverNote ?? null,
performedBy: dto.performedBy ?? null,
returnedBy: dto.returnedBy ?? null,
statusHistory: [
{ status: 'RETURNED', changedAt: returnDate.toISOString(), performedBy: dto.performedBy ?? null },
],
}),
);
}
@@ -176,6 +180,10 @@ export class ImportOperationsService {
wagonAllocationReference: dto.wagonAllocationReference ?? row.wagonAllocationReference ?? null,
handoverNote: dto.handoverNote ?? row.handoverNote ?? null,
performedBy: dto.performedBy ?? row.performedBy ?? null,
statusHistory: [
...(row.statusHistory ?? []),
{ status: dto.status, changedAt: new Date().toISOString(), performedBy: dto.performedBy ?? row.performedBy ?? null },
],
});
return this.emptyReturns.findOneOrFail({ where: { id } });
}