mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 13:05:44 +00:00
update locaomotive and fix wagon transfer issue
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsBoolean, IsIn, IsOptional, IsUUID } from 'class-validator';
|
||||
import { IsBoolean, IsDateString, IsIn, IsOptional, IsUUID } from 'class-validator';
|
||||
|
||||
import { PaginationQueryDto } from '../../../common/dto/pagination-query.dto';
|
||||
import {
|
||||
LOCOMOTIVE_STATUSES,
|
||||
LOCOMOTIVE_TYPES,
|
||||
} from '../entities/locomotive.entity';
|
||||
|
||||
export class FilterLocomotivesDto {
|
||||
// Extends the shared pagination DTO for `page`/`pageSize`/`search`; those are
|
||||
// only read by `GET /locomotives/paged` — the plain list ignores them.
|
||||
export class FilterLocomotivesDto extends PaginationQueryDto {
|
||||
@ApiPropertyOptional({ enum: LOCOMOTIVE_STATUSES })
|
||||
@IsOptional()
|
||||
@IsIn([...LOCOMOTIVE_STATUSES])
|
||||
@@ -47,4 +50,14 @@ export class FilterLocomotivesDto {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
excludeTrainId?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Registered on or after this day (YYYY-MM-DD)' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdFrom?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Registered on or before this day (YYYY-MM-DD)' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdTo?: string;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,14 @@ export class LocomotivesController {
|
||||
return this.locomotivesService.findAll(filter);
|
||||
}
|
||||
|
||||
// Must be declared before @Get(':id') so the path isn't captured as an id.
|
||||
@Get('paged')
|
||||
@StaffReference()
|
||||
@ApiOperation({ summary: 'List locomotives, paginated ({items, meta})' })
|
||||
findAllPaged(@Query() filter: FilterLocomotivesDto) {
|
||||
return this.locomotivesService.findAllPaged(filter);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@StaffReference()
|
||||
@ApiOperation({ summary: 'Get a locomotive by ID' })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseRepository } from '@edr/api-common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
import { Locomotive, type LocomotiveStatus, type LocomotiveType } from './entities/locomotive.entity';
|
||||
import { TrainLocomotive } from '../trains/entities/train-locomotive.entity';
|
||||
@@ -16,18 +16,22 @@ export class LocomotivesRepository extends BaseRepository<Locomotive> {
|
||||
}
|
||||
|
||||
/**
|
||||
* List locomotives for the train-builder coupling picker: the usual
|
||||
* status/type/yard filters, plus optional exclusion of any loco already
|
||||
* coupled to a built train. `keepTrainId` spares that one train's own locos
|
||||
* from the exclusion so they stay selectable while editing its consist.
|
||||
* Filter/sort builder shared by the coupling picker and the paginated list:
|
||||
* the usual status/type/yard filters, free-text over code + name, a
|
||||
* registration-day range, and optional exclusion of any loco already coupled
|
||||
* to a built train. `keepTrainId` spares that one train's own locos from the
|
||||
* exclusion so they stay selectable while editing its consist.
|
||||
*/
|
||||
findForCoupling(opts: {
|
||||
buildListQuery(opts: {
|
||||
status?: LocomotiveStatus;
|
||||
locomotiveType?: LocomotiveType;
|
||||
currentYardId?: string;
|
||||
excludeCoupled?: boolean;
|
||||
keepTrainId?: string;
|
||||
}): Promise<Locomotive[]> {
|
||||
search?: string;
|
||||
createdFrom?: string;
|
||||
createdTo?: string;
|
||||
}): SelectQueryBuilder<Locomotive> {
|
||||
const qb = this.repository
|
||||
.createQueryBuilder('locomotive')
|
||||
.leftJoinAndSelect('locomotive.currentYard', 'currentYard')
|
||||
@@ -39,6 +43,25 @@ export class LocomotivesRepository extends BaseRepository<Locomotive> {
|
||||
if (opts.currentYardId)
|
||||
qb.andWhere('locomotive.currentYardId = :yardId', { yardId: opts.currentYardId });
|
||||
|
||||
const search = opts.search?.trim();
|
||||
if (search) {
|
||||
qb.andWhere('(locomotive.code ILIKE :search OR locomotive.name ILIKE :search)', {
|
||||
search: `%${search}%`,
|
||||
});
|
||||
}
|
||||
|
||||
// Registration-day range, both ends inclusive (the UI picks whole days).
|
||||
if (opts.createdFrom) {
|
||||
qb.andWhere('locomotive.createdAt >= CAST(:createdFrom AS date)', {
|
||||
createdFrom: opts.createdFrom,
|
||||
});
|
||||
}
|
||||
if (opts.createdTo) {
|
||||
qb.andWhere("locomotive.createdAt < CAST(:createdTo AS date) + INTERVAL '1 day'", {
|
||||
createdTo: opts.createdTo,
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.excludeCoupled) {
|
||||
// NOT EXISTS a link to a DIFFERENT train. Own-train links are kept so the
|
||||
// consist being edited still lists its current locomotives.
|
||||
@@ -53,7 +76,11 @@ export class LocomotivesRepository extends BaseRepository<Locomotive> {
|
||||
qb.andWhere(`NOT EXISTS (${sub.getQuery()})`).setParameters(sub.getParameters());
|
||||
}
|
||||
|
||||
return qb.getMany();
|
||||
return qb;
|
||||
}
|
||||
|
||||
findForCoupling(opts: Parameters<LocomotivesRepository['buildListQuery']>[0]): Promise<Locomotive[]> {
|
||||
return this.buildListQuery(opts).getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { PaginatedResponse } from '@edr/types';
|
||||
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { paginateQuery } from '../../common/utils/pagination.util';
|
||||
|
||||
import { CreateLocomotiveDto } from './dto/create-locomotive.dto';
|
||||
import { FilterLocomotivesDto } from './dto/filter-locomotives.dto';
|
||||
import { UpdateLocomotiveDto } from './dto/update-locomotive.dto';
|
||||
@@ -53,6 +56,21 @@ export class LocomotivesService {
|
||||
});
|
||||
}
|
||||
|
||||
/** Same filters as `findAll` plus search/date range, on the shared list envelope. */
|
||||
findAllPaged(filter: FilterLocomotivesDto): Promise<PaginatedResponse<Locomotive>> {
|
||||
const qb = this.locomotivesRepository.buildListQuery({
|
||||
status: filter.status as LocomotiveStatus | undefined,
|
||||
locomotiveType: filter.locomotiveType as LocomotiveType | undefined,
|
||||
currentYardId: filter.currentYardId,
|
||||
excludeCoupled: filter.excludeCoupled,
|
||||
keepTrainId: filter.excludeTrainId,
|
||||
search: filter.search,
|
||||
createdFrom: filter.createdFrom,
|
||||
createdTo: filter.createdTo,
|
||||
});
|
||||
return paginateQuery(qb, filter);
|
||||
}
|
||||
|
||||
/** Default max pull weight (tons) applied when the caller omits it. */
|
||||
private static readonly DEFAULT_MAX_PULL_WEIGHT_TONS = 2500;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user