111 lines
2.6 KiB
TypeScript
111 lines
2.6 KiB
TypeScript
import {
|
|
IsString,
|
|
IsDateString,
|
|
IsEnum,
|
|
IsOptional,
|
|
IsInt,
|
|
Min,
|
|
IsBoolean,
|
|
Matches,
|
|
} from 'class-validator';
|
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
|
|
export class RateSearchRequestDto {
|
|
@ApiProperty({
|
|
description: 'Origin port code (UN/LOCODE)',
|
|
example: 'NLRTM',
|
|
pattern: '^[A-Z]{5}$',
|
|
})
|
|
@IsString()
|
|
@Matches(/^[A-Z]{5}$/, { message: 'Origin must be a valid 5-character UN/LOCODE (e.g., NLRTM)' })
|
|
origin: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Destination port code (UN/LOCODE)',
|
|
example: 'CNSHA',
|
|
pattern: '^[A-Z]{5}$',
|
|
})
|
|
@IsString()
|
|
@Matches(/^[A-Z]{5}$/, {
|
|
message: 'Destination must be a valid 5-character UN/LOCODE (e.g., CNSHA)',
|
|
})
|
|
destination: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Container type',
|
|
example: '40HC',
|
|
enum: ['20DRY', '20HC', '40DRY', '40HC', '40REEFER', '45HC'],
|
|
})
|
|
@IsString()
|
|
@IsEnum(['20DRY', '20HC', '40DRY', '40HC', '40REEFER', '45HC'], {
|
|
message: 'Container type must be one of: 20DRY, 20HC, 40DRY, 40HC, 40REEFER, 45HC',
|
|
})
|
|
containerType: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Shipping mode',
|
|
example: 'FCL',
|
|
enum: ['FCL', 'LCL'],
|
|
})
|
|
@IsEnum(['FCL', 'LCL'], { message: 'Mode must be either FCL or LCL' })
|
|
mode: 'FCL' | 'LCL';
|
|
|
|
@ApiProperty({
|
|
description: 'Desired departure date (ISO 8601 format)',
|
|
example: '2025-02-15',
|
|
})
|
|
@IsDateString({}, { message: 'Departure date must be a valid ISO 8601 date string' })
|
|
departureDate: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Number of containers',
|
|
example: 2,
|
|
minimum: 1,
|
|
default: 1,
|
|
})
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(1, { message: 'Quantity must be at least 1' })
|
|
quantity?: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Total cargo weight in kg',
|
|
example: 20000,
|
|
minimum: 0,
|
|
})
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(0, { message: 'Weight must be non-negative' })
|
|
weight?: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Total cargo volume in cubic meters',
|
|
example: 50.5,
|
|
minimum: 0,
|
|
})
|
|
@IsOptional()
|
|
@Min(0, { message: 'Volume must be non-negative' })
|
|
volume?: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Whether cargo is hazardous material',
|
|
example: false,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
isHazmat?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'IMO hazmat class (required if isHazmat is true)',
|
|
example: '3',
|
|
pattern: '^[1-9](\\.[1-9])?$',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
@Matches(/^[1-9](\.[1-9])?$/, {
|
|
message: 'IMO class must be in format X or X.Y (e.g., 3 or 3.1)',
|
|
})
|
|
imoClass?: string;
|
|
}
|