mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 11:08:12 +00:00
98 lines
3.9 KiB
TypeScript
98 lines
3.9 KiB
TypeScript
import { WagonStatus } from '@edr/types';
|
|
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { DataSource, FindOptionsOrder, FindOptionsWhere, ILike, Repository } from 'typeorm';
|
|
import { CreateTrainDto } from './dto/create-train.dto';
|
|
import { UpdateTrainDto } from './dto/update-train.dto';
|
|
import { TrainLocomotive } from './entities/train-locomotive.entity';
|
|
import { Train } from './entities/train.entity';
|
|
import { Wagon } from '../wagons/entities/wagon.entity';
|
|
|
|
@Injectable()
|
|
export class TrainsService {
|
|
constructor(
|
|
@InjectRepository(Train)
|
|
private readonly trainRepo: Repository<Train>,
|
|
private readonly dataSource: DataSource,
|
|
) {}
|
|
|
|
create(dto: CreateTrainDto): Promise<Train> {
|
|
const train = this.trainRepo.create(dto);
|
|
return this.trainRepo.save(train);
|
|
}
|
|
|
|
findAll(query: Record<string, string | undefined> = {}): Promise<Train[]> {
|
|
const where: FindOptionsWhere<Train>[] | FindOptionsWhere<Train> = [];
|
|
const search = query.search?.trim();
|
|
const status = query.status?.trim();
|
|
|
|
if (search) {
|
|
where.push({ code: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
|
|
where.push({ trainNumber: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
|
|
where.push({ trainName: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
|
|
}
|
|
|
|
const sortBy = ['code', 'trainNumber', 'trainName', 'capacityTons', 'status'].includes(query.sortBy ?? '')
|
|
? (query.sortBy as keyof Train)
|
|
: 'code';
|
|
const sortOrder = query.sortOrder?.toUpperCase() === 'DESC' ? 'DESC' : 'ASC';
|
|
|
|
return this.trainRepo.find({
|
|
where: search ? where : status ? { status: status as Train['status'] } : {},
|
|
order: { [sortBy]: sortOrder } as FindOptionsOrder<Train>,
|
|
skip: query.page && query.limit ? (Number(query.page) - 1) * Number(query.limit) : undefined,
|
|
take: query.limit ? Number(query.limit) : undefined,
|
|
});
|
|
}
|
|
|
|
async findById(id: string): Promise<Train> {
|
|
const train = await this.trainRepo.findOne({ where: { id } });
|
|
if (!train) throw new NotFoundException(`Train ${id} not found`);
|
|
return train;
|
|
}
|
|
|
|
async update(id: string, dto: UpdateTrainDto): Promise<Train> {
|
|
const train = await this.findById(id);
|
|
Object.assign(train, dto);
|
|
// Convert undefined to null for optional fields if needed
|
|
return this.trainRepo.save(train);
|
|
}
|
|
|
|
/**
|
|
* Delete a built train. Blocked while it still has a live (DRAFT/SCHEDULED/
|
|
* DISPATCHED) schedule; otherwise its wagons are freed (back to AVAILABLE)
|
|
* and its locomotive links dropped so nothing is stranded, then the train is
|
|
* soft-deleted. Mirrors TrainBuilderService.disband but prefers softRemove.
|
|
*/
|
|
async remove(id: string): Promise<void> {
|
|
await this.dataSource.transaction(async (manager) => {
|
|
const train = await manager.getRepository(Train).findOne({ where: { id } });
|
|
if (!train) throw new NotFoundException(`Train ${id} not found`);
|
|
|
|
const active: { count: string }[] = await manager.query(
|
|
`SELECT COUNT(*)::text AS count
|
|
FROM freight.train_schedules ts
|
|
JOIN freight.train_sets tset ON tset.id = ts.train_set_id
|
|
WHERE tset.train_id = $1
|
|
AND ts.deleted_at IS NULL
|
|
AND ts.status IN ('DRAFT', 'SCHEDULED', 'DISPATCHED')`,
|
|
[id],
|
|
);
|
|
if (Number(active[0]?.count ?? 0) > 0) {
|
|
throw new ConflictException(
|
|
'Train has active schedules; cancel them before deleting the train',
|
|
);
|
|
}
|
|
|
|
await manager
|
|
.getRepository(Wagon)
|
|
.update(
|
|
{ trainId: train.id },
|
|
{ trainId: null, sequenceNumber: null, status: WagonStatus.Available },
|
|
);
|
|
await manager.getRepository(TrainLocomotive).delete({ trainId: train.id });
|
|
await manager.getRepository(Train).softRemove(train);
|
|
});
|
|
}
|
|
}
|