mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 12:18:11 +00:00
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.
120 lines
2.7 KiB
TypeScript
120 lines
2.7 KiB
TypeScript
import { IsString, IsEnum, IsNumber, IsOptional, IsUUID, Matches } from 'class-validator';
|
|
import { Transform } from 'class-transformer';
|
|
import {
|
|
FuelType,
|
|
VehicleAvailability,
|
|
VehicleOwnership,
|
|
VehicleStatus,
|
|
} from '../entities/vehicle.entity';
|
|
|
|
/**
|
|
* A vehicle plate is two or three letters, a hyphen, then two to six digits —
|
|
* e.g. ET-9875 or AA-8642. Kept in one place so plate, power-plate and trailer
|
|
* all match and the message stays consistent.
|
|
*/
|
|
export const VEHICLE_PLATE_REGEX = /^[A-Z]{2,3}-\d{2,6}$/;
|
|
export const VEHICLE_PLATE_MESSAGE =
|
|
'must be letters and numbers like ET-9875 or AA-8642';
|
|
|
|
/**
|
|
* Trim and upper-case a plate before validating, so "et-9875" is accepted. An
|
|
* empty optional plate (trailer/power) becomes undefined so @IsOptional skips it
|
|
* rather than failing the pattern.
|
|
*/
|
|
const normalizePlate = ({ value }: { value: unknown }) => {
|
|
if (typeof value !== 'string') return value;
|
|
const trimmed = value.trim().toUpperCase();
|
|
return trimmed === '' ? undefined : trimmed;
|
|
};
|
|
|
|
export class CreateVehicleDto {
|
|
@Transform(normalizePlate)
|
|
@Matches(VEHICLE_PLATE_REGEX, { message: `Plate number ${VEHICLE_PLATE_MESSAGE}` })
|
|
@IsString()
|
|
plateNumber!: string;
|
|
|
|
/** Truck configuration from `freight.truck_types` — drives capacity and whether a trailer plate applies. */
|
|
@IsUUID()
|
|
truckTypeId!: string;
|
|
|
|
@IsString()
|
|
manufacturer!: string;
|
|
|
|
@IsString()
|
|
model!: string;
|
|
|
|
@IsNumber()
|
|
year!: number;
|
|
|
|
@IsEnum(FuelType)
|
|
fuelType!: FuelType;
|
|
|
|
/** Defaults to the truck type's capacity when omitted. */
|
|
@IsOptional()
|
|
@IsNumber()
|
|
capacity?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
vin?: string;
|
|
|
|
@IsOptional()
|
|
@IsEnum(VehicleOwnership)
|
|
ownership?: VehicleOwnership;
|
|
|
|
@IsEnum(VehicleStatus)
|
|
status!: VehicleStatus;
|
|
|
|
@IsOptional()
|
|
@IsEnum(VehicleAvailability)
|
|
availability?: VehicleAvailability;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
description?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
assignedDriverId?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
assignedDriverName?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
code?: string;
|
|
|
|
@IsOptional()
|
|
@Transform(normalizePlate)
|
|
@Matches(VEHICLE_PLATE_REGEX, { message: `Power plate number ${VEHICLE_PLATE_MESSAGE}` })
|
|
@IsString()
|
|
powerPlateNo?: string;
|
|
|
|
@IsOptional()
|
|
@Transform(normalizePlate)
|
|
@Matches(VEHICLE_PLATE_REGEX, { message: `Trailer plate number ${VEHICLE_PLATE_MESSAGE}` })
|
|
@IsString()
|
|
trailerPlateNo?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
estimatedDistanceKm?: number;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
actualDistanceKm?: number;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
locationId?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
pricePerKm?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
currency?: string;
|
|
}
|