mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 13:40:57 +00:00
fix(freight): filter container returns by returned-by truck type
Top Returned Containers table ignored the EDR/Customer tab because the backend never persisted which truck type performed the return. Added returned_by column + DTO/entity field, wired create payload to send it, and filtered the table by the active tab.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class EmptyContainerReturnedBy3210000000000 implements MigrationInterface {
|
||||
name = 'EmptyContainerReturnedBy3210000000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.empty_container_returns
|
||||
ADD COLUMN IF NOT EXISTS returned_by varchar(20) NULL
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE freight.empty_container_returns
|
||||
DROP COLUMN IF EXISTS returned_by
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { DataSource, In } from 'typeorm';
|
||||
|
||||
import { deriveTradeDirection } from '../../common/derive-trade-direction.util';
|
||||
import { assertExportReceivedWithGrn } from '../../common/export-received-gate';
|
||||
import { Yard } from '../rule-engine/entities/yard.entity';
|
||||
import { ServiceType } from '../rule-engine/entities/service-type.entity';
|
||||
import { TrainSchedule } from '../train-schedules/entities/train-schedule.entity';
|
||||
@@ -239,6 +240,10 @@ export class BookingsService {
|
||||
*/
|
||||
async carriageAcceptanceSheet(bookingId: string): Promise<{ filename: string; buffer: Buffer }> {
|
||||
const booking = await this.findById(bookingId);
|
||||
// The sheet attests that EDR has taken custody. For export that happens at
|
||||
// cargo receipt (GRN), so the GRN is required even when wagons are already
|
||||
// allocated — an allocation is a plan, not possession.
|
||||
await assertExportReceivedWithGrn(this.dataSource, booking);
|
||||
let wagons: CarriageAcceptanceWagonRow[] = await this.dataSource.query(
|
||||
`SELECT tsw.sequence_no AS "sequenceNo",
|
||||
COALESCE(wt.code, wt.name) AS "wagonType",
|
||||
@@ -291,7 +296,10 @@ export class BookingsService {
|
||||
LEFT JOIN freight.containers c
|
||||
ON c.id = inv.container_id AND c.deleted_at IS NULL
|
||||
WHERE inv.booking_id = $1 AND inv.deleted_at IS NULL
|
||||
AND COALESCE(NULLIF(TRIM(inv.grn_number), ''), '') <> ''
|
||||
AND COALESCE(
|
||||
NULLIF(TRIM(inv.grn_number), ''),
|
||||
substring(inv.notes FROM 'GRN Number: ([^\\n\\r]+)')
|
||||
) IS NOT NULL
|
||||
ORDER BY inv.created_at`,
|
||||
[bookingId],
|
||||
)
|
||||
|
||||
@@ -169,6 +169,11 @@ export class CreateEmptyContainerReturnDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
performedBy?: string;
|
||||
|
||||
@ApiPropertyOptional({ enum: ['EDR', 'CUSTOMER'] })
|
||||
@IsOptional()
|
||||
@IsIn(['EDR', 'CUSTOMER'])
|
||||
returnedBy?: 'EDR' | 'CUSTOMER';
|
||||
}
|
||||
|
||||
export class UpdateEmptyContainerReturnStatusDto extends ImportOperationActionDto {
|
||||
|
||||
@@ -53,4 +53,7 @@ export class EmptyContainerReturn extends BaseEntity {
|
||||
|
||||
@Column({ name: 'performed_by', type: 'varchar', length: 120, nullable: true })
|
||||
performedBy?: string | null;
|
||||
|
||||
@Column({ name: 'returned_by', type: 'varchar', length: 20, nullable: true })
|
||||
returnedBy?: 'EDR' | 'CUSTOMER' | null;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ export class ImportOperationsService {
|
||||
condition: dto.condition ?? null,
|
||||
handoverNote: dto.handoverNote ?? null,
|
||||
performedBy: dto.performedBy ?? null,
|
||||
returnedBy: dto.returnedBy ?? null,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user