Files
edr-platform/apps/edr-freight-api/src/modules/vehicles/dto/create-vehicle.dto.ts
Hagernesh cf8a2e928d 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.
2026-07-24 11:55:05 +00:00

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;
}