Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Failing after 5m31s
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m42s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Has been skipped
446 lines
8.4 KiB
TypeScript
446 lines
8.4 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import {
|
|
IsString,
|
|
IsEmail,
|
|
IsNumber,
|
|
Min,
|
|
IsOptional,
|
|
IsEnum,
|
|
IsArray,
|
|
ValidateNested,
|
|
IsUUID,
|
|
IsDateString,
|
|
MinLength,
|
|
MaxLength,
|
|
} from 'class-validator';
|
|
import { Type } from 'class-transformer';
|
|
|
|
/**
|
|
* Create CSV Booking DTO
|
|
*
|
|
* Request body for creating a new CSV-based booking request
|
|
* This is sent by the user after selecting a rate from CSV search results
|
|
*/
|
|
export class CreateCsvBookingDto {
|
|
@ApiProperty({
|
|
description: 'Carrier/Company name',
|
|
example: 'SSC Consolidation',
|
|
})
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(200)
|
|
carrierName: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Carrier email address for booking request',
|
|
example: 'bookings@sscconsolidation.com',
|
|
})
|
|
@IsEmail()
|
|
carrierEmail: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Origin port code (UN/LOCODE)',
|
|
example: 'NLRTM',
|
|
})
|
|
@IsString()
|
|
@MinLength(5)
|
|
@MaxLength(5)
|
|
origin: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Destination port code (UN/LOCODE)',
|
|
example: 'USNYC',
|
|
})
|
|
@IsString()
|
|
@MinLength(5)
|
|
@MaxLength(5)
|
|
destination: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Volume in cubic meters (CBM)',
|
|
example: 25.5,
|
|
minimum: 0.01,
|
|
})
|
|
@IsNumber()
|
|
@Min(0.01)
|
|
volumeCBM: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Weight in kilograms',
|
|
example: 3500,
|
|
minimum: 1,
|
|
})
|
|
@IsNumber()
|
|
@Min(1)
|
|
weightKG: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of pallets',
|
|
example: 10,
|
|
minimum: 0,
|
|
})
|
|
@IsNumber()
|
|
@Min(0)
|
|
palletCount: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Price in USD',
|
|
example: 1850.5,
|
|
minimum: 0,
|
|
})
|
|
@IsNumber()
|
|
@Min(0)
|
|
priceUSD: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Price in EUR',
|
|
example: 1665.45,
|
|
minimum: 0,
|
|
})
|
|
@IsNumber()
|
|
@Min(0)
|
|
priceEUR: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Primary currency',
|
|
enum: ['USD', 'EUR'],
|
|
example: 'USD',
|
|
})
|
|
@IsEnum(['USD', 'EUR'])
|
|
primaryCurrency: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Transit time in days',
|
|
example: 28,
|
|
minimum: 1,
|
|
})
|
|
@IsNumber()
|
|
@Min(1)
|
|
transitDays: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Container type',
|
|
example: 'LCL',
|
|
})
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(50)
|
|
containerType: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Additional notes or requirements',
|
|
example: 'Please handle with care - fragile goods',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(1000)
|
|
notes?: string;
|
|
|
|
// Documents will be handled via file upload interceptor
|
|
// Not included in DTO validation but processed separately
|
|
}
|
|
|
|
/**
|
|
* Document DTO for response
|
|
*/
|
|
export class CsvBookingDocumentDto {
|
|
@ApiProperty({
|
|
description: 'Document unique ID',
|
|
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
})
|
|
id: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Document type',
|
|
enum: [
|
|
'BILL_OF_LADING',
|
|
'PACKING_LIST',
|
|
'COMMERCIAL_INVOICE',
|
|
'CERTIFICATE_OF_ORIGIN',
|
|
'OTHER',
|
|
],
|
|
example: 'BILL_OF_LADING',
|
|
})
|
|
type: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Original file name',
|
|
example: 'bill-of-lading.pdf',
|
|
})
|
|
fileName: string;
|
|
|
|
@ApiProperty({
|
|
description: 'File storage path or URL',
|
|
example: '/uploads/documents/123e4567-e89b-12d3-a456-426614174000.pdf',
|
|
})
|
|
filePath: string;
|
|
|
|
@ApiProperty({
|
|
description: 'File MIME type',
|
|
example: 'application/pdf',
|
|
})
|
|
mimeType: string;
|
|
|
|
@ApiProperty({
|
|
description: 'File size in bytes',
|
|
example: 245678,
|
|
})
|
|
size: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Upload timestamp',
|
|
example: '2025-10-23T14:30:00Z',
|
|
})
|
|
uploadedAt: Date;
|
|
}
|
|
|
|
/**
|
|
* CSV Booking Response DTO
|
|
*
|
|
* Response when creating or retrieving a CSV booking
|
|
*/
|
|
export class CsvBookingResponseDto {
|
|
@ApiProperty({
|
|
description: 'Booking unique ID',
|
|
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
})
|
|
id: string;
|
|
|
|
@ApiProperty({
|
|
description: 'User ID who created the booking',
|
|
example: '987fcdeb-51a2-43e8-9c6d-8b9a1c2d3e4f',
|
|
})
|
|
userId: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Organization ID',
|
|
example: 'a1234567-0000-4000-8000-000000000001',
|
|
})
|
|
organizationId: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Carrier/Company name',
|
|
example: 'SSC Consolidation',
|
|
})
|
|
carrierName: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Carrier email address',
|
|
example: 'bookings@sscconsolidation.com',
|
|
})
|
|
carrierEmail: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Origin port code',
|
|
example: 'NLRTM',
|
|
})
|
|
origin: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Destination port code',
|
|
example: 'USNYC',
|
|
})
|
|
destination: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Volume in CBM',
|
|
example: 25.5,
|
|
})
|
|
volumeCBM: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Weight in KG',
|
|
example: 3500,
|
|
})
|
|
weightKG: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of pallets',
|
|
example: 10,
|
|
})
|
|
palletCount: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Price in USD',
|
|
example: 1850.5,
|
|
})
|
|
priceUSD: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Price in EUR',
|
|
example: 1665.45,
|
|
})
|
|
priceEUR: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Primary currency',
|
|
enum: ['USD', 'EUR'],
|
|
example: 'USD',
|
|
})
|
|
primaryCurrency: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Transit time in days',
|
|
example: 28,
|
|
})
|
|
transitDays: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Container type',
|
|
example: 'LCL',
|
|
})
|
|
containerType: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Booking status',
|
|
enum: ['PENDING', 'ACCEPTED', 'REJECTED', 'CANCELLED'],
|
|
example: 'PENDING',
|
|
})
|
|
status: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Uploaded documents',
|
|
type: [CsvBookingDocumentDto],
|
|
})
|
|
documents: CsvBookingDocumentDto[];
|
|
|
|
@ApiProperty({
|
|
description: 'Confirmation token for accept/reject actions',
|
|
example: 'abc123-def456-ghi789',
|
|
})
|
|
confirmationToken: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Booking request timestamp',
|
|
example: '2025-10-23T14:30:00Z',
|
|
})
|
|
requestedAt: Date;
|
|
|
|
@ApiProperty({
|
|
description: 'Response timestamp (when accepted/rejected)',
|
|
example: '2025-10-24T09:15:00Z',
|
|
nullable: true,
|
|
})
|
|
respondedAt: Date | null;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Additional notes',
|
|
example: 'Please handle with care',
|
|
})
|
|
notes?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Rejection reason (if rejected)',
|
|
example: 'No capacity available for requested dates',
|
|
})
|
|
rejectionReason?: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Route description (origin → destination)',
|
|
example: 'NLRTM → USNYC',
|
|
})
|
|
routeDescription: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Whether the booking is expired (7+ days pending)',
|
|
example: false,
|
|
})
|
|
isExpired: boolean;
|
|
|
|
@ApiProperty({
|
|
description: 'Price in the primary currency',
|
|
example: 1850.5,
|
|
})
|
|
price: number;
|
|
}
|
|
|
|
/**
|
|
* Update CSV Booking Status DTO
|
|
*
|
|
* Request body for accepting/rejecting a booking
|
|
*/
|
|
export class UpdateCsvBookingStatusDto {
|
|
@ApiPropertyOptional({
|
|
description: 'Rejection reason (required when rejecting)',
|
|
example: 'No capacity available',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
rejectionReason?: string;
|
|
}
|
|
|
|
/**
|
|
* CSV Booking List Response DTO
|
|
*
|
|
* Paginated list of bookings
|
|
*/
|
|
export class CsvBookingListResponseDto {
|
|
@ApiProperty({
|
|
description: 'Array of bookings',
|
|
type: [CsvBookingResponseDto],
|
|
})
|
|
bookings: CsvBookingResponseDto[];
|
|
|
|
@ApiProperty({
|
|
description: 'Total number of bookings',
|
|
example: 42,
|
|
})
|
|
total: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Current page number',
|
|
example: 1,
|
|
})
|
|
page: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of items per page',
|
|
example: 10,
|
|
})
|
|
limit: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Total number of pages',
|
|
example: 5,
|
|
})
|
|
totalPages: number;
|
|
}
|
|
|
|
/**
|
|
* CSV Booking Statistics DTO
|
|
*
|
|
* Statistics for user's or organization's bookings
|
|
*/
|
|
export class CsvBookingStatsDto {
|
|
@ApiProperty({
|
|
description: 'Number of pending bookings',
|
|
example: 5,
|
|
})
|
|
pending: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of accepted bookings',
|
|
example: 12,
|
|
})
|
|
accepted: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of rejected bookings',
|
|
example: 2,
|
|
})
|
|
rejected: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Number of cancelled bookings',
|
|
example: 1,
|
|
})
|
|
cancelled: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Total number of bookings',
|
|
example: 20,
|
|
})
|
|
total: number;
|
|
}
|