feat(wagons): filter list by last-maintenance date range

Adds maintenanceFrom/maintenanceTo to ListWagonsQueryDto and applies them
in WagonsService.buildListQuery as a correlated subquery against
wagon_status_logs (last flip to MAINTENANCE), mirroring the existing
createdFrom/createdTo range filter. Both ends inclusive, whole days.
This commit is contained in:
ghost2023
2026-08-21 15:54:53 +03:00
parent 91c9c3e513
commit ad5caddf60
2 changed files with 35 additions and 0 deletions

View File

@@ -91,4 +91,18 @@ export class ListWagonsQueryDto {
@IsOptional() @IsOptional()
@IsDateString() @IsDateString()
createdTo?: string; createdTo?: string;
@ApiPropertyOptional({
description: 'Last maintenance flip on or after this day (YYYY-MM-DD)',
})
@IsOptional()
@IsDateString()
maintenanceFrom?: string;
@ApiPropertyOptional({
description: 'Last maintenance flip on or before this day (YYYY-MM-DD)',
})
@IsOptional()
@IsDateString()
maintenanceTo?: string;
} }

View File

@@ -90,6 +90,27 @@ export class WagonsService {
}); });
} }
// Last-maintenance range, both ends inclusive. There's no column to
// compare directly — "last maintenance" is the latest status-log flip to
// MAINTENANCE (see attachStatusDates below), so this mirrors that same
// MAX(...) FILTER(...) as a correlated subquery against the same table.
if (query.maintenanceFrom) {
qb.andWhere(
`(SELECT MAX(l.created_at) FROM freight.wagon_status_logs l
WHERE l.wagon_id = w.id AND l.to_status = '${WagonStatus.Maintenance}')
>= CAST(:maintenanceFrom AS date)`,
{ maintenanceFrom: query.maintenanceFrom },
);
}
if (query.maintenanceTo) {
qb.andWhere(
`(SELECT MAX(l.created_at) FROM freight.wagon_status_logs l
WHERE l.wagon_id = w.id AND l.to_status = '${WagonStatus.Maintenance}')
< CAST(:maintenanceTo AS date) + INTERVAL '1 day'`,
{ maintenanceTo: query.maintenanceTo },
);
}
// Search matches the wagon number or either run number. // Search matches the wagon number or either run number.
if (search) { if (search) {
qb.andWhere( qb.andWhere(