395 lines
8.0 KiB
TypeScript
395 lines
8.0 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import {
|
|
IsNotEmpty,
|
|
IsString,
|
|
IsNumber,
|
|
Min,
|
|
IsOptional,
|
|
ValidateNested,
|
|
IsBoolean,
|
|
} from 'class-validator';
|
|
import { Type } from 'class-transformer';
|
|
import { RateSearchFiltersDto } from './rate-search-filters.dto';
|
|
|
|
/**
|
|
* CSV Rate Search Request DTO
|
|
*
|
|
* Request body for searching rates in CSV-based system
|
|
* Includes basic search parameters + optional advanced filters
|
|
*/
|
|
export class CsvRateSearchDto {
|
|
@ApiProperty({
|
|
description: 'Origin port code (UN/LOCODE format)',
|
|
example: 'NLRTM',
|
|
pattern: '^[A-Z]{2}[A-Z0-9]{3}$',
|
|
})
|
|
@IsNotEmpty()
|
|
@IsString()
|
|
origin: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Destination port code (UN/LOCODE format)',
|
|
example: 'USNYC',
|
|
pattern: '^[A-Z]{2}[A-Z0-9]{3}$',
|
|
})
|
|
@IsNotEmpty()
|
|
@IsString()
|
|
destination: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Volume in cubic meters (CBM)',
|
|
minimum: 0.01,
|
|
example: 25.5,
|
|
})
|
|
@IsNotEmpty()
|
|
@IsNumber()
|
|
@Min(0.01)
|
|
volumeCBM: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Weight in kilograms',
|
|
minimum: 1,
|
|
example: 3500,
|
|
})
|
|
@IsNotEmpty()
|
|
@IsNumber()
|
|
@Min(1)
|
|
weightKG: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Number of pallets (0 if no pallets)',
|
|
minimum: 0,
|
|
example: 10,
|
|
default: 0,
|
|
})
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
palletCount?: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Container type filter (e.g., LCL, 20DRY, 40HC)',
|
|
example: 'LCL',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
containerType?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Advanced filters for narrowing results',
|
|
type: RateSearchFiltersDto,
|
|
})
|
|
@IsOptional()
|
|
@ValidateNested()
|
|
@Type(() => RateSearchFiltersDto)
|
|
filters?: RateSearchFiltersDto;
|
|
|
|
// Service requirements for detailed price calculation
|
|
@ApiPropertyOptional({
|
|
description: 'Cargo contains dangerous goods (DG)',
|
|
example: true,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
hasDangerousGoods?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Requires special handling',
|
|
example: true,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresSpecialHandling?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Requires tailgate lift',
|
|
example: false,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresTailgate?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Requires securing straps',
|
|
example: true,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresStraps?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Requires thermal protection cover',
|
|
example: false,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresThermalCover?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Contains regulated products requiring special documentation',
|
|
example: false,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
hasRegulatedProducts?: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Requires delivery appointment',
|
|
example: true,
|
|
default: false,
|
|
})
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresAppointment?: boolean;
|
|
}
|
|
|
|
/**
|
|
* CSV Rate Search Response DTO
|
|
*
|
|
* Response containing matching rates with calculated prices
|
|
*/
|
|
export class CsvRateSearchResponseDto {
|
|
@ApiProperty({
|
|
description: 'Array of matching rate results',
|
|
type: [Object], // Will be replaced with RateResultDto
|
|
})
|
|
results: CsvRateResultDto[];
|
|
|
|
@ApiProperty({
|
|
description: 'Total number of results found',
|
|
example: 15,
|
|
})
|
|
totalResults: number;
|
|
|
|
@ApiProperty({
|
|
description: 'CSV files that were searched',
|
|
type: [String],
|
|
example: ['ssc-consolidation.csv', 'ecu-worldwide.csv'],
|
|
})
|
|
searchedFiles: string[];
|
|
|
|
@ApiProperty({
|
|
description: 'Timestamp when search was executed',
|
|
example: '2025-10-23T10:30:00Z',
|
|
})
|
|
searchedAt: Date;
|
|
|
|
@ApiProperty({
|
|
description: 'Filters that were applied to the search',
|
|
type: RateSearchFiltersDto,
|
|
})
|
|
appliedFilters: RateSearchFiltersDto;
|
|
}
|
|
|
|
/**
|
|
* Surcharge Item DTO
|
|
*/
|
|
export class SurchargeItemDto {
|
|
@ApiProperty({
|
|
description: 'Surcharge code',
|
|
example: 'DG_FEE',
|
|
})
|
|
code: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Surcharge description',
|
|
example: 'Dangerous goods fee',
|
|
})
|
|
description: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Surcharge amount in currency',
|
|
example: 65.0,
|
|
})
|
|
amount: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Type of surcharge calculation',
|
|
enum: ['FIXED', 'PER_UNIT', 'PERCENTAGE'],
|
|
example: 'FIXED',
|
|
})
|
|
type: 'FIXED' | 'PER_UNIT' | 'PERCENTAGE';
|
|
}
|
|
|
|
/**
|
|
* Price Breakdown DTO
|
|
*/
|
|
export class PriceBreakdownDto {
|
|
@ApiProperty({
|
|
description: 'Base price before any charges',
|
|
example: 0,
|
|
})
|
|
basePrice: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Charge based on volume (CBM)',
|
|
example: 150.0,
|
|
})
|
|
volumeCharge: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Charge based on weight (KG)',
|
|
example: 25.0,
|
|
})
|
|
weightCharge: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Charge for pallets',
|
|
example: 125.0,
|
|
})
|
|
palletCharge: number;
|
|
|
|
@ApiProperty({
|
|
description: 'List of all surcharges',
|
|
type: [SurchargeItemDto],
|
|
})
|
|
surcharges: SurchargeItemDto[];
|
|
|
|
@ApiProperty({
|
|
description: 'Total of all surcharges',
|
|
example: 242.0,
|
|
})
|
|
totalSurcharges: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Total price including all charges',
|
|
example: 542.0,
|
|
})
|
|
totalPrice: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Currency of the pricing',
|
|
enum: ['USD', 'EUR'],
|
|
example: 'USD',
|
|
})
|
|
currency: string;
|
|
}
|
|
|
|
/**
|
|
* Single CSV Rate Result DTO
|
|
*/
|
|
export class CsvRateResultDto {
|
|
@ApiProperty({
|
|
description: 'Company name',
|
|
example: 'SSC Consolidation',
|
|
})
|
|
companyName: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Company email for booking requests',
|
|
example: 'bookings@sscconsolidation.com',
|
|
})
|
|
companyEmail: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Origin port code',
|
|
example: 'NLRTM',
|
|
})
|
|
origin: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Destination port code',
|
|
example: 'USNYC',
|
|
})
|
|
destination: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Container type',
|
|
example: 'LCL',
|
|
})
|
|
containerType: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Calculated price in USD',
|
|
example: 1850.5,
|
|
})
|
|
priceUSD: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Calculated price in EUR',
|
|
example: 1665.45,
|
|
})
|
|
priceEUR: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Primary currency of the rate',
|
|
enum: ['USD', 'EUR'],
|
|
example: 'USD',
|
|
})
|
|
primaryCurrency: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Detailed price breakdown with all charges',
|
|
type: PriceBreakdownDto,
|
|
})
|
|
priceBreakdown: PriceBreakdownDto;
|
|
|
|
@ApiProperty({
|
|
description: 'Whether this rate has separate surcharges',
|
|
example: true,
|
|
})
|
|
hasSurcharges: boolean;
|
|
|
|
@ApiProperty({
|
|
description: 'Details of surcharges if any',
|
|
example: 'BAF+CAF included',
|
|
nullable: true,
|
|
})
|
|
surchargeDetails: string | null;
|
|
|
|
@ApiProperty({
|
|
description: 'Transit time in days',
|
|
example: 28,
|
|
})
|
|
transitDays: number;
|
|
|
|
@ApiProperty({
|
|
description: 'Rate validity end date',
|
|
example: '2025-12-31',
|
|
})
|
|
validUntil: string;
|
|
|
|
@ApiProperty({
|
|
description: 'Source of the rate',
|
|
enum: ['CSV', 'API'],
|
|
example: 'CSV',
|
|
})
|
|
source: 'CSV' | 'API';
|
|
|
|
@ApiProperty({
|
|
description: 'Match score (0-100) indicating how well this rate matches the search',
|
|
minimum: 0,
|
|
maximum: 100,
|
|
example: 95,
|
|
})
|
|
matchScore: number;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Service level (only present when using search-csv-offers endpoint)',
|
|
enum: ['RAPID', 'STANDARD', 'ECONOMIC'],
|
|
example: 'RAPID',
|
|
})
|
|
serviceLevel?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Original price before service level adjustment',
|
|
example: { usd: 1500.0, eur: 1350.0 },
|
|
})
|
|
originalPrice?: {
|
|
usd: number;
|
|
eur: number;
|
|
};
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Original transit days before service level adjustment',
|
|
example: 20,
|
|
})
|
|
originalTransitDays?: number;
|
|
}
|