120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import { IsString, IsUUID, IsOptional, ValidateNested, IsArray, IsEmail, Matches, MinLength } from 'class-validator';
|
|
import { Type } from 'class-transformer';
|
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
|
|
export class AddressDto {
|
|
@ApiProperty({ example: '123 Main Street' })
|
|
@IsString()
|
|
@MinLength(5, { message: 'Street must be at least 5 characters' })
|
|
street: string;
|
|
|
|
@ApiProperty({ example: 'Rotterdam' })
|
|
@IsString()
|
|
@MinLength(2, { message: 'City must be at least 2 characters' })
|
|
city: string;
|
|
|
|
@ApiProperty({ example: '3000 AB' })
|
|
@IsString()
|
|
postalCode: string;
|
|
|
|
@ApiProperty({ example: 'NL', description: 'ISO 3166-1 alpha-2 country code' })
|
|
@IsString()
|
|
@Matches(/^[A-Z]{2}$/, { message: 'Country must be a valid 2-letter ISO country code' })
|
|
country: string;
|
|
}
|
|
|
|
export class PartyDto {
|
|
@ApiProperty({ example: 'Acme Corporation' })
|
|
@IsString()
|
|
@MinLength(2, { message: 'Name must be at least 2 characters' })
|
|
name: string;
|
|
|
|
@ApiProperty({ type: AddressDto })
|
|
@ValidateNested()
|
|
@Type(() => AddressDto)
|
|
address: AddressDto;
|
|
|
|
@ApiProperty({ example: 'John Doe' })
|
|
@IsString()
|
|
@MinLength(2, { message: 'Contact name must be at least 2 characters' })
|
|
contactName: string;
|
|
|
|
@ApiProperty({ example: 'john.doe@acme.com' })
|
|
@IsEmail({}, { message: 'Contact email must be a valid email address' })
|
|
contactEmail: string;
|
|
|
|
@ApiProperty({ example: '+31612345678' })
|
|
@IsString()
|
|
@Matches(/^\+?[1-9]\d{1,14}$/, { message: 'Contact phone must be a valid international phone number' })
|
|
contactPhone: string;
|
|
}
|
|
|
|
export class ContainerDto {
|
|
@ApiProperty({ example: '40HC', description: 'Container type' })
|
|
@IsString()
|
|
type: string;
|
|
|
|
@ApiPropertyOptional({ example: 'ABCU1234567', description: 'Container number (11 characters)' })
|
|
@IsOptional()
|
|
@IsString()
|
|
@Matches(/^[A-Z]{4}\d{7}$/, { message: 'Container number must be 4 letters followed by 7 digits' })
|
|
containerNumber?: string;
|
|
|
|
@ApiPropertyOptional({ example: 22000, description: 'Verified Gross Mass in kg' })
|
|
@IsOptional()
|
|
vgm?: number;
|
|
|
|
@ApiPropertyOptional({ example: -18, description: 'Temperature in Celsius (for reefer containers)' })
|
|
@IsOptional()
|
|
temperature?: number;
|
|
|
|
@ApiPropertyOptional({ example: 'SEAL123456', description: 'Seal number' })
|
|
@IsOptional()
|
|
@IsString()
|
|
sealNumber?: string;
|
|
}
|
|
|
|
export class CreateBookingRequestDto {
|
|
@ApiProperty({
|
|
example: '550e8400-e29b-41d4-a716-446655440000',
|
|
description: 'Rate quote ID from previous search'
|
|
})
|
|
@IsUUID(4, { message: 'Rate quote ID must be a valid UUID' })
|
|
rateQuoteId: string;
|
|
|
|
@ApiProperty({ type: PartyDto, description: 'Shipper details' })
|
|
@ValidateNested()
|
|
@Type(() => PartyDto)
|
|
shipper: PartyDto;
|
|
|
|
@ApiProperty({ type: PartyDto, description: 'Consignee details' })
|
|
@ValidateNested()
|
|
@Type(() => PartyDto)
|
|
consignee: PartyDto;
|
|
|
|
@ApiProperty({
|
|
example: 'Electronics and consumer goods',
|
|
description: 'Cargo description'
|
|
})
|
|
@IsString()
|
|
@MinLength(10, { message: 'Cargo description must be at least 10 characters' })
|
|
cargoDescription: string;
|
|
|
|
@ApiProperty({
|
|
type: [ContainerDto],
|
|
description: 'Container details (can be empty for initial booking)'
|
|
})
|
|
@IsArray()
|
|
@ValidateNested({ each: true })
|
|
@Type(() => ContainerDto)
|
|
containers: ContainerDto[];
|
|
|
|
@ApiPropertyOptional({
|
|
example: 'Please handle with care. Delivery before 5 PM.',
|
|
description: 'Special instructions for the carrier'
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
specialInstructions?: string;
|
|
}
|