Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m53s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Has been cancelled
- Replace all ../../domain/ imports with @domain/ across 67 files - Configure NestJS to use tsconfig.build.json with rootDir - Add tsc-alias to resolve path aliases after build - This fixes 'Cannot find module' TypeScript compilation errors Fixed files: - 30 files in application layer - 37 files in infrastructure layer
148 lines
4.7 KiB
TypeScript
148 lines
4.7 KiB
TypeScript
/**
|
|
* Hapag-Lloyd Request/Response Mapper
|
|
*/
|
|
|
|
import { Injectable } from '@nestjs/common';
|
|
import { CarrierRateSearchInput } from '@domain/ports/out/carrier-connector.port';
|
|
import { RateQuote, RouteSegment, Surcharge } from '@domain/entities/rate-quote.entity';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
@Injectable()
|
|
export class HapagLloydRequestMapper {
|
|
toHapagRequest(input: CarrierRateSearchInput): any {
|
|
return {
|
|
place_of_receipt: input.origin,
|
|
place_of_delivery: input.destination,
|
|
container_type: this.mapContainerType(input.containerType),
|
|
cargo_cutoff_date: input.departureDate,
|
|
service_type: input.mode === 'FCL' ? 'CY-CY' : 'CFS-CFS',
|
|
hazardous: input.isHazmat || false,
|
|
imo_class: input.imoClass,
|
|
weight_metric_tons: input.weight ? input.weight / 1000 : undefined,
|
|
volume_cubic_meters: input.volume,
|
|
};
|
|
}
|
|
|
|
fromHapagResponse(hapagResponse: any, originalInput: CarrierRateSearchInput): RateQuote[] {
|
|
if (!hapagResponse.quotes || hapagResponse.quotes.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
return hapagResponse.quotes.map((quote: any) => {
|
|
const surcharges: Surcharge[] = [];
|
|
|
|
if (quote.bunker_charge) {
|
|
surcharges.push({
|
|
type: 'BAF',
|
|
description: 'Bunker Adjustment Factor',
|
|
amount: quote.bunker_charge,
|
|
currency: quote.currency || 'EUR',
|
|
});
|
|
}
|
|
|
|
if (quote.security_charge) {
|
|
surcharges.push({
|
|
type: 'SEC',
|
|
description: 'Security Charge',
|
|
amount: quote.security_charge,
|
|
currency: quote.currency || 'EUR',
|
|
});
|
|
}
|
|
|
|
if (quote.terminal_charge) {
|
|
surcharges.push({
|
|
type: 'THC',
|
|
description: 'Terminal Handling Charge',
|
|
amount: quote.terminal_charge,
|
|
currency: quote.currency || 'EUR',
|
|
});
|
|
}
|
|
|
|
const baseFreight = quote.ocean_freight_rate || 0;
|
|
const totalSurcharges = surcharges.reduce((sum, s) => sum + s.amount, 0);
|
|
const totalAmount = baseFreight + totalSurcharges;
|
|
|
|
// Build route segments
|
|
const route: RouteSegment[] = [];
|
|
|
|
// Origin port
|
|
route.push({
|
|
portCode: originalInput.origin,
|
|
portName: quote.origin_port_name || originalInput.origin,
|
|
departure: new Date(quote.estimated_time_of_departure),
|
|
vesselName: quote.vessel_name,
|
|
voyageNumber: quote.voyage_number,
|
|
});
|
|
|
|
// Transshipment ports
|
|
if (quote.transshipment_ports && Array.isArray(quote.transshipment_ports)) {
|
|
quote.transshipment_ports.forEach((port: any) => {
|
|
route.push({
|
|
portCode: port.code || port,
|
|
portName: port.name || port.code || port,
|
|
});
|
|
});
|
|
}
|
|
|
|
// Destination port
|
|
route.push({
|
|
portCode: originalInput.destination,
|
|
portName: quote.destination_port_name || originalInput.destination,
|
|
arrival: new Date(quote.estimated_time_of_arrival),
|
|
});
|
|
|
|
const transitDays =
|
|
quote.transit_time_days ||
|
|
this.calculateTransitDays(
|
|
quote.estimated_time_of_departure,
|
|
quote.estimated_time_of_arrival
|
|
);
|
|
|
|
return RateQuote.create({
|
|
id: uuidv4(),
|
|
carrierId: 'hapag-lloyd',
|
|
carrierName: 'Hapag-Lloyd',
|
|
carrierCode: 'HLCU',
|
|
origin: {
|
|
code: originalInput.origin,
|
|
name: quote.origin_port_name || originalInput.origin,
|
|
country: quote.origin_country || 'Unknown',
|
|
},
|
|
destination: {
|
|
code: originalInput.destination,
|
|
name: quote.destination_port_name || originalInput.destination,
|
|
country: quote.destination_country || 'Unknown',
|
|
},
|
|
pricing: {
|
|
baseFreight,
|
|
surcharges,
|
|
totalAmount,
|
|
currency: quote.currency || 'EUR',
|
|
},
|
|
containerType: originalInput.containerType,
|
|
mode: (originalInput.mode as 'FCL' | 'LCL') || 'FCL',
|
|
etd: new Date(quote.estimated_time_of_departure),
|
|
eta: new Date(quote.estimated_time_of_arrival),
|
|
transitDays,
|
|
route,
|
|
availability: quote.space_available || 0,
|
|
frequency: quote.service_frequency || 'Weekly',
|
|
vesselType: 'Container Ship',
|
|
co2EmissionsKg: quote.carbon_footprint,
|
|
});
|
|
});
|
|
}
|
|
|
|
private mapContainerType(type: string): string {
|
|
return type; // Hapag-Lloyd uses standard ISO codes
|
|
}
|
|
|
|
private calculateTransitDays(departure?: string, arrival?: string): number {
|
|
if (!departure || !arrival) return 0;
|
|
const depDate = new Date(departure);
|
|
const arrDate = new Date(arrival);
|
|
const diff = arrDate.getTime() - depDate.getTime();
|
|
return Math.ceil(diff / (1000 * 60 * 60 * 24));
|
|
}
|
|
}
|