Files
edr-platform/apps/edr-freight-api/src/modules/locomotives/locomotives.service.ts

133 lines
4.5 KiB
TypeScript

import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
import { CreateLocomotiveDto } from './dto/create-locomotive.dto';
import { FilterLocomotivesDto } from './dto/filter-locomotives.dto';
import { UpdateLocomotiveDto } from './dto/update-locomotive.dto';
import {
Locomotive,
type LocomotiveStatus,
type LocomotiveType,
} from './entities/locomotive.entity';
import { LocomotivesRepository } from './locomotives.repository';
@Injectable()
export class LocomotivesService {
constructor(private readonly locomotivesRepository: LocomotivesRepository) {}
findAll(filter: FilterLocomotivesDto): Promise<Locomotive[]> {
return this.locomotivesRepository.findAll({
where: {
...(filter.status ? { status: filter.status as LocomotiveStatus } : {}),
...(filter.locomotiveType
? { locomotiveType: filter.locomotiveType as LocomotiveType }
: {}),
...(filter.currentYardId ? { currentYardId: filter.currentYardId } : {}),
},
relations: { currentYard: true },
order: { code: 'ASC' },
});
}
/** Default max pull weight (tons) applied when the caller omits it. */
private static readonly DEFAULT_MAX_PULL_WEIGHT_TONS = 2500;
/**
* Generate the next sequential locomotive code (LOCO-001, LOCO-002, …) by
* scanning the highest existing LOCO-NNN number. Used when the caller does not
* supply a code.
*/
private async generateCode(): Promise<string> {
const all = await this.locomotivesRepository.findAll({});
let max = 0;
for (const loco of all) {
const match = /^LOCO-(\d+)$/.exec(loco.code ?? '');
if (match) max = Math.max(max, Number(match[1]));
}
return `LOCO-${String(max + 1).padStart(3, '0')}`;
}
async create(dto: CreateLocomotiveDto): Promise<Locomotive> {
const code = dto.code?.trim() || (await this.generateCode());
const [existing] = await this.locomotivesRepository.findAll({ where: { code } });
if (existing) {
throw new ConflictException(`Locomotive code ${code} already exists`);
}
return this.locomotivesRepository.create({
code,
name: dto.name?.trim() || null,
locomotiveType: dto.locomotiveType as LocomotiveType,
status: dto.status as LocomotiveStatus,
currentYardId: dto.currentYardId ?? null,
maxPullWeightTons:
dto.maxPullWeightTons ?? LocomotivesService.DEFAULT_MAX_PULL_WEIGHT_TONS,
maxTrainLengthMeters: dto.maxTrainLengthMeters,
powerKw: dto.powerKw ?? null,
tractionForceKn: dto.tractionForceKn ?? null,
maxSpeedKmh: dto.maxSpeedKmh ?? null,
});
}
async findById(id: string): Promise<Locomotive> {
const locomotive = await this.locomotivesRepository.findById(id, {
relations: { currentYard: true },
});
if (!locomotive) {
throw new NotFoundException(`Locomotive ${id} not found`);
}
return locomotive;
}
async update(id: string, dto: UpdateLocomotiveDto): Promise<Locomotive> {
const locomotive = await this.findById(id);
if (dto.code && dto.code !== locomotive.code) {
const [existing] = await this.locomotivesRepository.findAll({ where: { code: dto.code } });
if (existing && existing.id !== id) {
throw new ConflictException(`Locomotive code ${dto.code} already exists`);
}
}
const updated = await this.locomotivesRepository.update(id, {
...dto,
locomotiveType:
dto.locomotiveType === undefined ? locomotive.locomotiveType : dto.locomotiveType as LocomotiveType,
status: dto.status === undefined ? locomotive.status : dto.status as LocomotiveStatus,
currentYardId:
dto.currentYardId === undefined
? locomotive.currentYardId
: (dto.currentYardId ?? null),
name: dto.name === undefined ? locomotive.name : dto.name?.trim() || null,
powerKw: dto.powerKw === undefined ? locomotive.powerKw : dto.powerKw ?? null,
tractionForceKn:
dto.tractionForceKn === undefined ? locomotive.tractionForceKn : dto.tractionForceKn ?? null,
maxSpeedKmh:
dto.maxSpeedKmh === undefined ? locomotive.maxSpeedKmh : dto.maxSpeedKmh ?? null,
});
if (!updated) {
throw new NotFoundException(`Locomotive ${id} not found`);
}
return updated;
}
async decommission(id: string): Promise<Locomotive> {
await this.findById(id);
const updated = await this.locomotivesRepository.update(id, {
status: 'OUT_OF_SERVICE',
});
if (!updated) {
throw new NotFoundException(`Locomotive ${id} not found`);
}
return updated;
}
}