mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
198 lines
5.0 KiB
TypeScript
198 lines
5.0 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import { Transform, Type } from 'class-transformer';
|
|
import {
|
|
ArrayMinSize,
|
|
IsArray,
|
|
IsBoolean,
|
|
IsDateString,
|
|
IsIn,
|
|
IsInt,
|
|
IsNumber,
|
|
IsOptional,
|
|
IsString,
|
|
IsUUID,
|
|
Min,
|
|
Validate,
|
|
ValidateIf,
|
|
ValidateNested,
|
|
} from 'class-validator';
|
|
import { BOOKING_STATUSES, FREIGHT_TYPES } from '../entities/booking.entity';
|
|
import { BookingFreightShapeConstraint } from './validators/booking-freight.validator';
|
|
|
|
const CONTRACT_TYPES = ['NEW', 'RENEWAL'] as const;
|
|
const EQUIPMENT_RETURNS = ['WITH_RETURN', 'WITHOUT_RETURN', 'NA'] as const;
|
|
const TRADE_DIRECTIONS = ['IMPORT', 'EXPORT', 'DOMESTIC'] as const;
|
|
const PAYMENT_CURRENCIES = ['ETB', 'USD'] as const;
|
|
|
|
export {
|
|
BOOKING_STATUSES,
|
|
CONTRACT_TYPES,
|
|
EQUIPMENT_RETURNS,
|
|
FREIGHT_TYPES,
|
|
TRADE_DIRECTIONS,
|
|
PAYMENT_CURRENCIES,
|
|
};
|
|
|
|
export class CreateBookingContainerDto {
|
|
@ApiProperty({ format: 'uuid', description: 'FK to container_types.id' })
|
|
@IsUUID()
|
|
containerTypeId!: string;
|
|
|
|
@ApiProperty({ description: 'Quantity of containers', minimum: 1 })
|
|
@IsInt()
|
|
@Min(1)
|
|
@Transform(({ value }) => Number(value))
|
|
quantity!: number;
|
|
|
|
@ApiProperty({ description: 'VGM per container in tons', minimum: 0 })
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Transform(({ value }) => Number(value))
|
|
vgmPerUnitTons!: number;
|
|
}
|
|
|
|
export class CreateBookingDto {
|
|
/** Class-level freight shape check (not a request field). */
|
|
@Validate(BookingFreightShapeConstraint)
|
|
freightShapeValidation?: boolean;
|
|
@ApiPropertyOptional({ description: 'Unique booking reference (auto-generated if omitted)' })
|
|
@IsOptional()
|
|
@IsString()
|
|
@Transform(({ value }) => (typeof value === 'string' ? value.trim() : value))
|
|
reference?: string;
|
|
|
|
// @ApiPropertyOptional({ format: 'uuid', description: 'Admin only: target customer (legacy)' })
|
|
// @IsOptional()
|
|
// @IsUUID()
|
|
// customerId?: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid', description: 'Admin only: target company' })
|
|
@IsOptional()
|
|
@IsUUID()
|
|
companyId?: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid' })
|
|
@IsOptional()
|
|
@IsUUID()
|
|
trainId?: string;
|
|
|
|
@ApiProperty({ example: '2026-06-15T00:00:00.000Z' })
|
|
@IsDateString()
|
|
scheduledDate!: string;
|
|
|
|
@ApiProperty({ enum: CONTRACT_TYPES })
|
|
@IsIn([...CONTRACT_TYPES])
|
|
contractType!: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid' })
|
|
@IsOptional()
|
|
@IsUUID()
|
|
@Transform(({ value }) => (value === '' || value == null ? undefined : value))
|
|
previousContractId?: string;
|
|
|
|
@ApiProperty({ format: 'uuid', description: 'FK to service_types.id' })
|
|
@IsUUID()
|
|
serviceTypeId!: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString()
|
|
firstMilePickupAddress?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString()
|
|
lastMileDeliveryAddress?: string;
|
|
|
|
@ApiProperty({ enum: EQUIPMENT_RETURNS })
|
|
@IsIn([...EQUIPMENT_RETURNS])
|
|
equipmentReturn!: string;
|
|
|
|
@ApiProperty({ format: 'uuid', description: 'FK to yards.id (origin)' })
|
|
@IsUUID()
|
|
originYardId!: string;
|
|
|
|
@ApiProperty({ format: 'uuid', description: 'FK to yards.id (destination)' })
|
|
@IsUUID()
|
|
destinationYardId!: string;
|
|
|
|
@ApiProperty({ enum: TRADE_DIRECTIONS })
|
|
@IsIn([...TRADE_DIRECTIONS])
|
|
tradeDirection!: string;
|
|
|
|
@ApiProperty({ enum: FREIGHT_TYPES, description: 'CONTAINER or BULK (mutually exclusive cargo shape)' })
|
|
@IsIn([...FREIGHT_TYPES])
|
|
freightType!: string;
|
|
|
|
@ApiPropertyOptional({
|
|
format: 'uuid',
|
|
description: 'Required for BULK; must be omitted for CONTAINER',
|
|
})
|
|
@ValidateIf((o) => o.freightType === 'BULK')
|
|
@IsUUID()
|
|
cargoTypeId?: string;
|
|
|
|
@ApiPropertyOptional({ maxLength: 200 })
|
|
@IsOptional()
|
|
@IsString()
|
|
cargoFreeText?: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid', description: 'FK to shipping_lines.id' })
|
|
@IsOptional()
|
|
@IsUUID()
|
|
shippingLineId?: string;
|
|
|
|
@ApiProperty({ description: 'Total cargo weight VGM in tons', minimum: 0 })
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Transform(({ value }) => Number(value))
|
|
cargoTotalWeightVgm!: number;
|
|
|
|
@ApiPropertyOptional({ default: false })
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
@Transform(({ value }) => value === 'true' || value === true)
|
|
isHazardous?: boolean;
|
|
|
|
@ApiProperty({ enum: PAYMENT_CURRENCIES })
|
|
@IsIn([...PAYMENT_CURRENCIES])
|
|
paymentCurrency!: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString()
|
|
pnrCode?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsDateString()
|
|
startDate?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsDateString()
|
|
endDate?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString()
|
|
financialTerms?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
type: [CreateBookingContainerDto],
|
|
description: 'Required for CONTAINER (min 1 line); must be empty for BULK',
|
|
})
|
|
@ValidateIf((o) => o.freightType === 'CONTAINER')
|
|
@IsArray()
|
|
@ArrayMinSize(1)
|
|
@ValidateNested({ each: true })
|
|
@Type(() => CreateBookingContainerDto)
|
|
containers?: CreateBookingContainerDto[];
|
|
|
|
@ApiPropertyOptional({ default: false })
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
@Transform(({ value }) => value === 'true' || value === true)
|
|
allowConsolidation?: boolean;
|
|
}
|