xpeditis2.0/apps/backend/src/application/dto/create-booking-request.dto.ts
2025-10-20 12:30:08 +02:00

120 lines
3.6 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;
}