110 lines
3.4 KiB
TypeScript
110 lines
3.4 KiB
TypeScript
/**
|
|
* Maersk Response Mapper
|
|
*
|
|
* Maps Maersk API response to domain entities
|
|
*/
|
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { RateQuote } from '../../../domain/entities/rate-quote.entity';
|
|
import { MaerskRateSearchResponse, MaerskRateResult, MaerskRouteSegment } from './maersk.types';
|
|
|
|
export class MaerskResponseMapper {
|
|
/**
|
|
* Map Maersk API response to domain RateQuote entities
|
|
*/
|
|
static toRateQuotes(
|
|
response: MaerskRateSearchResponse,
|
|
originCode: string,
|
|
destinationCode: string
|
|
): RateQuote[] {
|
|
return response.results.map(result => this.toRateQuote(result, originCode, destinationCode));
|
|
}
|
|
|
|
/**
|
|
* Map single Maersk rate result to RateQuote domain entity
|
|
*/
|
|
private static toRateQuote(
|
|
result: MaerskRateResult,
|
|
originCode: string,
|
|
destinationCode: string
|
|
): RateQuote {
|
|
const surcharges = result.pricing.charges.map(charge => ({
|
|
type: charge.chargeCode,
|
|
description: charge.chargeName,
|
|
amount: charge.amount,
|
|
currency: charge.currency,
|
|
}));
|
|
|
|
const route = result.schedule.routeSchedule.map(segment => this.mapRouteSegment(segment));
|
|
|
|
return RateQuote.create({
|
|
id: uuidv4(),
|
|
carrierId: 'maersk-carrier-id', // TODO: Get from carrier repository
|
|
carrierName: 'Maersk Line',
|
|
carrierCode: 'MAERSK',
|
|
origin: {
|
|
code: result.routeDetails.origin.unlocCode,
|
|
name: result.routeDetails.origin.cityName,
|
|
country: result.routeDetails.origin.countryName,
|
|
},
|
|
destination: {
|
|
code: result.routeDetails.destination.unlocCode,
|
|
name: result.routeDetails.destination.cityName,
|
|
country: result.routeDetails.destination.countryName,
|
|
},
|
|
pricing: {
|
|
baseFreight: result.pricing.oceanFreight,
|
|
surcharges,
|
|
totalAmount: result.pricing.totalAmount,
|
|
currency: result.pricing.currency,
|
|
},
|
|
containerType: this.mapContainerType(result.equipment.type),
|
|
mode: 'FCL', // Maersk typically handles FCL
|
|
etd: new Date(result.routeDetails.departureDate),
|
|
eta: new Date(result.routeDetails.arrivalDate),
|
|
transitDays: result.routeDetails.transitTime,
|
|
route,
|
|
availability: result.bookingDetails.equipmentAvailability,
|
|
frequency: result.schedule.frequency,
|
|
vesselType: result.vesselInfo?.type,
|
|
co2EmissionsKg: result.sustainability?.co2Emissions,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Map Maersk route segment to domain format
|
|
*/
|
|
private static mapRouteSegment(segment: MaerskRouteSegment): any {
|
|
return {
|
|
portCode: segment.portCode,
|
|
portName: segment.portName,
|
|
arrival: segment.arrivalDate ? new Date(segment.arrivalDate) : undefined,
|
|
departure: segment.departureDate ? new Date(segment.departureDate) : undefined,
|
|
vesselName: segment.vesselName,
|
|
voyageNumber: segment.voyageNumber,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Map Maersk container type to internal format
|
|
*/
|
|
private static mapContainerType(maerskType: string): string {
|
|
// Map Maersk container types to standard format
|
|
const typeMap: { [key: string]: string } = {
|
|
'20DRY': '20DRY',
|
|
'40DRY': '40DRY',
|
|
'40HC': '40HC',
|
|
'45HC': '45HC',
|
|
'20REEFER': '20REEFER',
|
|
'40REEFER': '40REEFER',
|
|
'40HCREEFER': '40HCREEFER',
|
|
'20OT': '20OT',
|
|
'40OT': '40OT',
|
|
'20FR': '20FR',
|
|
'40FR': '40FR',
|
|
};
|
|
|
|
return typeMap[maerskType] || maerskType;
|
|
}
|
|
}
|