xpeditis2.0/apps/backend/src/application/dto/csv-rate-search.dto.ts
2026-05-12 01:11:04 +02:00

203 lines
5.7 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';
export class CsvRateSearchDto {
@ApiProperty({ description: 'Origin UN/LOCODE', example: 'FRFOS' })
@IsNotEmpty()
@IsString()
origin: string;
@ApiProperty({ description: 'Destination UN/LOCODE', example: 'CNSHA' })
@IsNotEmpty()
@IsString()
destination: string;
@ApiProperty({ description: 'Volume in cubic meters (CBM)', minimum: 0.01, example: 10.5 })
@IsNotEmpty()
@IsNumber()
@Min(0.01)
volumeCBM: number;
@ApiProperty({ description: 'Weight in kilograms', minimum: 1, example: 2500 })
@IsNotEmpty()
@IsNumber()
@Min(1)
weightKG: number;
@ApiPropertyOptional({ description: 'Container type filter', example: 'LCL' })
@IsOptional()
@IsString()
containerType?: string;
@ApiPropertyOptional({ description: 'Cargo contains dangerous goods', example: false })
@IsOptional()
@IsBoolean()
hasDangerousGoods?: boolean;
@ApiPropertyOptional({ description: 'Advanced filters', type: RateSearchFiltersDto })
@IsOptional()
@ValidateNested()
@Type(() => RateSearchFiltersDto)
filters?: RateSearchFiltersDto;
}
export class CsvRateSearchResponseDto {
@ApiProperty({ description: 'Array of matching rate results', type: [Object] })
results: CsvRateResultDto[];
@ApiProperty({ description: 'Total number of results', example: 12 })
totalResults: number;
@ApiProperty({ description: 'CSV files searched', type: [String] })
searchedFiles: string[];
@ApiProperty({ description: 'Timestamp of search', example: '2026-05-11T10:30:00Z' })
searchedAt: Date;
@ApiProperty({ description: 'Applied filters' })
appliedFilters: RateSearchFiltersDto;
}
export class FobBreakdownDto {
documentation: number;
isps: number;
handling: number;
solas: number;
customs: number;
ams_aci: number;
isf5: number;
dgAdmin: number;
}
export class PriceBreakdownDto {
@ApiProperty({ description: 'Freight charge', example: 420.0 })
freightCharge: number;
@ApiProperty({ description: 'Freight currency', example: 'USD' })
freightCurrency: string;
@ApiProperty({ description: 'Fixed FOB charges (doc+ISPS+solas+customs+AMS+ISF5)', example: 185 })
fobFixed: number;
@ApiProperty({ description: 'FOB handling charge', example: 60 })
fobHandling: number;
@ApiProperty({ description: 'DG admin fee (FOB currency, 0 if non-DG)', example: 0 })
fobDG: number;
@ApiProperty({ description: 'FOB currency', example: 'EUR' })
fobCurrency: string;
@ApiProperty({ description: 'Itemized FOB breakdown', type: FobBreakdownDto })
fobBreakdown: FobBreakdownDto;
@ApiPropertyOptional({
description: 'DG surcharge amount (null if on_request/not_accepted)',
example: null,
})
dgSurchargeAmount: number | null;
@ApiProperty({ description: 'DG surcharge currency', example: 'EUR' })
dgSurchargeCurrency: string;
@ApiProperty({
description: 'DG surcharge status',
enum: ['computed', 'on_request', 'not_accepted'],
example: 'computed',
})
dgSurchargeStatus: string;
@ApiProperty({ description: 'Total freight in freightCurrency', example: 420.0 })
totalFreight: number;
@ApiProperty({ description: 'Total FOB in fobCurrency', example: 245 })
totalFob: number;
@ApiProperty({ description: 'Sum for sorting (currency-naive)', example: 665.0 })
totalPriceForSorting: number;
@ApiProperty({ description: 'Primary currency', example: 'USD' })
primaryCurrency: string;
}
export class CsvRateResultDto {
@ApiProperty({ example: 'SSC Consolidation' })
companyName: string;
@ApiProperty({ example: 'bookings@ssc.com' })
companyEmail: string;
@ApiProperty({ description: 'Origin CFS name', example: 'Fos Sur Mer' })
originCFS: string;
@ApiProperty({ description: 'Origin UN/LOCODE', example: 'FRFOS' })
origin: string;
@ApiProperty({ description: 'Port of loading', example: 'FOS SUR MER' })
portOfLoading: string;
@ApiProperty({ description: 'Routing type', example: 'Direct' })
routing: string;
@ApiProperty({ description: 'Destination CFS name', example: 'Shanghai' })
destinationCFS: string;
@ApiProperty({ description: 'Destination UN/LOCODE', example: 'CNSHA' })
destination: string;
@ApiProperty({ description: 'Destination country', example: 'China' })
destinationCountry: string;
@ApiProperty({ example: 'LCL' })
containerType: string;
@ApiProperty({ description: 'Detailed price breakdown', type: PriceBreakdownDto })
priceBreakdown: PriceBreakdownDto;
@ApiProperty({ description: 'Departure frequency', example: 'Weekly' })
frequency: string;
@ApiProperty({ description: 'Transit time (adjusted if service level)', example: 28 })
transitDays: number;
@ApiProperty({ description: 'Rate validity end date', example: '2026-12-31' })
validUntil: string;
@ApiProperty({ description: 'Whether DG cargo is accepted', example: true })
dgAccepted: boolean;
@ApiProperty({ description: 'DG surcharge status', example: 'computed' })
dgSurchargeStatus: string;
@ApiProperty({ description: 'Internal remarks', example: 'GR1/GR2' })
remarks: string;
@ApiProperty({ example: 'CSV' })
source: 'CSV';
@ApiProperty({ description: 'Match score 0-100', example: 95 })
matchScore: number;
@ApiPropertyOptional({ enum: ['RAPID', 'STANDARD', 'ECONOMIC'] })
serviceLevel?: string;
@ApiPropertyOptional({ description: 'Price multiplier for service level', example: 1.0 })
priceMultiplier?: number;
@ApiPropertyOptional({
description: 'Original transit days before service level adjustment',
example: 28,
})
originalTransitDays?: number;
}