mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
fix(warehouses): detention groups by canonical truck type
Join truck_types via vehicles.truck_type_id (normalized legacy vehicle_type only as fallback) so type renames can't unmatch detention rules and FK-less vehicles keep billing.
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Not, Repository } from 'typeorm';
|
||||
import { CreateVehicleDto } from './dto/create-vehicle.dto';
|
||||
import { UpdateVehicleDto } from './dto/update-vehicle.dto';
|
||||
import { Vehicle, VehicleAvailability, VehicleStatus } from './entities/vehicle.entity';
|
||||
import { TruckType } from '../truck-types/entities/truck-type.entity';
|
||||
import { TruckTypesService } from '../truck-types/truck-types.service';
|
||||
import { FirstMile, FirstMileStatus } from '../first-mile/entities/first-mile.entity';
|
||||
import { FirstMileContainerAllocation } from '../first-mile/entities/first-mile-container-allocation.entity';
|
||||
import { LastMile, LastMileStatus } from '../last-mile/entities/last-mile.entity';
|
||||
@@ -18,8 +25,26 @@ export class VehiclesService {
|
||||
@InjectRepository(Vehicle)
|
||||
private readonly vehicleRepo: Repository<Vehicle>,
|
||||
private readonly history: FleetHistoryService,
|
||||
private readonly truckTypes: TruckTypesService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* A trailer plate only exists on a configuration that pulls a trailer — a
|
||||
* rigid truck (Casoni) has none. Checked against the RESULTING record, not
|
||||
* just the patch, so switching an articulated truck to a rigid type cannot
|
||||
* leave its old trailer plate stranded on the row.
|
||||
*/
|
||||
private assertTrailerPlateAllowed(
|
||||
truckType: TruckType,
|
||||
trailerPlateNo?: string | null,
|
||||
): void {
|
||||
if (!truckType.hasTrailer && trailerPlateNo) {
|
||||
throw new BadRequestException(
|
||||
`${truckType.name} has no trailer — remove the trailer plate number`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A driver holds one truck at a time — reassignment requires detaching them
|
||||
* from their current truck first.
|
||||
@@ -54,10 +79,17 @@ export class VehiclesService {
|
||||
await this.assertDriverUnassigned(dto.assignedDriverId);
|
||||
}
|
||||
|
||||
const registrationNumber = `REG-${dto.vehicleType}-${Date.now()}`;
|
||||
const truckType = await this.truckTypes.findById(dto.truckTypeId);
|
||||
this.assertTrailerPlateAllowed(truckType, dto.trailerPlateNo);
|
||||
|
||||
const registrationNumber = `REG-${truckType.code}-${Date.now()}`;
|
||||
const vehicle = this.vehicleRepo.create({
|
||||
...dto,
|
||||
registrationNumber,
|
||||
// Denormalised for truck-detention billing, which groups on this column.
|
||||
vehicleType: truckType.code,
|
||||
// Capacity belongs to the type; an explicit value still wins for one-offs.
|
||||
capacity: dto.capacity ?? truckType.capacityTons ?? undefined,
|
||||
});
|
||||
|
||||
const saved = await this.vehicleRepo.save(vehicle);
|
||||
@@ -148,6 +180,17 @@ export class VehiclesService {
|
||||
await this.assertDriverUnassigned(dto.assignedDriverId, id);
|
||||
}
|
||||
|
||||
// Re-resolve the truck type whenever the type OR the trailer plate moves —
|
||||
// either edit can produce a rigid truck holding a trailer plate.
|
||||
const nextTruckTypeId = dto.truckTypeId ?? vehicle.truckTypeId;
|
||||
let nextTruckType: TruckType | null = null;
|
||||
if (nextTruckTypeId && (dto.truckTypeId !== undefined || dto.trailerPlateNo !== undefined)) {
|
||||
nextTruckType = await this.truckTypes.findById(nextTruckTypeId);
|
||||
const nextTrailerPlate =
|
||||
dto.trailerPlateNo !== undefined ? dto.trailerPlateNo : vehicle.trailerPlateNo;
|
||||
this.assertTrailerPlateAllowed(nextTruckType, nextTrailerPlate);
|
||||
}
|
||||
|
||||
const prev = {
|
||||
assignedDriverId: vehicle.assignedDriverId,
|
||||
assignedDriverName: vehicle.assignedDriverName,
|
||||
@@ -156,6 +199,11 @@ export class VehiclesService {
|
||||
};
|
||||
|
||||
Object.assign(vehicle, dto);
|
||||
// After the patch is applied, so the denormalised billing code always
|
||||
// reflects the type the vehicle actually ends up on.
|
||||
if (nextTruckType) {
|
||||
vehicle.vehicleType = nextTruckType.code;
|
||||
}
|
||||
const saved = await this.vehicleRepo.save(vehicle);
|
||||
|
||||
// Driver (re)assignment — emit an unassign for the old driver and/or an
|
||||
|
||||
Reference in New Issue
Block a user