xpeditis2.0/apps/backend/src/application/dto/csv-booking.dto.ts
David a1e255e816
Some checks failed
CI/CD Pipeline / Discord Notification (Failure) (push) Blocked by required conditions
CI/CD Pipeline / Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Deployment Summary (push) Blocked by required conditions
CI/CD Pipeline / Deploy to Portainer (push) Blocked by required conditions
CI/CD Pipeline / Discord Notification (Success) (push) Blocked by required conditions
CI/CD Pipeline / Backend - Build, Test & Push (push) Failing after 1m20s
CI/CD Pipeline / Frontend - Build, Test & Push (push) Has been cancelled
fix v1.0.0
2025-12-23 11:49:57 +01:00

441 lines
8.3 KiB
TypeScript

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsString,
IsEmail,
IsNumber,
Min,
IsOptional,
IsEnum,
MinLength,
MaxLength,
} from 'class-validator';
/**
* 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;
}