xpeditis2.0/apps/backend/src/application/mappers/csv-rate.mapper.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

128 lines
4.2 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { CsvRateResultDto, CsvRateSearchResponseDto } from '../dto/csv-rate-search.dto';
import {
CsvRateSearchOutput,
CsvRateSearchResult,
RateSearchFilters,
} from '@domain/ports/in/search-csv-rates.port';
import { RateSearchFiltersDto } from '../dto/rate-search-filters.dto';
import { CsvRateConfigDto } from '../dto/csv-rate-upload.dto';
import { CsvRateConfigOrmEntity } from '@infrastructure/persistence/typeorm/entities/csv-rate-config.orm-entity';
/**
* CSV Rate Mapper
*
* Maps between domain entities and DTOs
* Follows hexagonal architecture principles
*/
@Injectable()
export class CsvRateMapper {
/**
* Map DTO filters to domain filters
*/
mapFiltersDtoToDomain(dto?: RateSearchFiltersDto): RateSearchFilters | undefined {
if (!dto) {
return undefined;
}
return {
companies: dto.companies,
minVolumeCBM: dto.minVolumeCBM,
maxVolumeCBM: dto.maxVolumeCBM,
minWeightKG: dto.minWeightKG,
maxWeightKG: dto.maxWeightKG,
palletCount: dto.palletCount,
minPrice: dto.minPrice,
maxPrice: dto.maxPrice,
currency: dto.currency,
minTransitDays: dto.minTransitDays,
maxTransitDays: dto.maxTransitDays,
containerTypes: dto.containerTypes,
onlyAllInPrices: dto.onlyAllInPrices,
departureDate: dto.departureDate ? new Date(dto.departureDate) : undefined,
};
}
/**
* Map domain search result to DTO
*/
mapSearchResultToDto(result: CsvRateSearchResult): CsvRateResultDto {
const rate = result.rate;
return {
companyName: rate.companyName,
companyEmail: rate.companyEmail,
origin: rate.origin.getValue(),
destination: rate.destination.getValue(),
containerType: rate.containerType.getValue(),
priceUSD: result.calculatedPrice.usd,
priceEUR: result.calculatedPrice.eur,
primaryCurrency: result.calculatedPrice.primaryCurrency,
priceBreakdown: {
basePrice: result.priceBreakdown.basePrice,
volumeCharge: result.priceBreakdown.volumeCharge,
weightCharge: result.priceBreakdown.weightCharge,
palletCharge: result.priceBreakdown.palletCharge,
surcharges: result.priceBreakdown.surcharges.map(s => ({
code: s.code,
description: s.description,
amount: s.amount,
type: s.type,
})),
totalSurcharges: result.priceBreakdown.totalSurcharges,
totalPrice: result.priceBreakdown.totalPrice,
currency: result.priceBreakdown.currency,
},
hasSurcharges: rate.hasSurcharges(),
surchargeDetails: rate.hasSurcharges() ? rate.getSurchargeDetails() : null,
// Use adjusted transit days if available (service level offers), otherwise use original
transitDays: result.adjustedTransitDays ?? rate.transitDays,
validUntil: rate.validity.getEndDate().toISOString().split('T')[0],
source: result.source,
matchScore: result.matchScore,
// Include service level fields if present
serviceLevel: result.serviceLevel,
originalPrice: result.originalPrice,
originalTransitDays: result.originalTransitDays,
};
}
/**
* Map domain search output to response DTO
*/
mapSearchOutputToResponseDto(output: CsvRateSearchOutput): CsvRateSearchResponseDto {
return {
results: output.results.map(result => this.mapSearchResultToDto(result)),
totalResults: output.totalResults,
searchedFiles: output.searchedFiles,
searchedAt: output.searchedAt,
appliedFilters: output.appliedFilters as any, // Already matches DTO structure
};
}
/**
* Map ORM entity to DTO
*/
mapConfigEntityToDto(entity: CsvRateConfigOrmEntity): CsvRateConfigDto {
return {
id: entity.id,
companyName: entity.companyName,
csvFilePath: entity.csvFilePath,
type: entity.type,
hasApi: entity.hasApi,
apiConnector: entity.apiConnector,
isActive: entity.isActive,
uploadedAt: entity.uploadedAt,
rowCount: entity.rowCount,
metadata: entity.metadata,
};
}
/**
* Map multiple config entities to DTOs
*/
mapConfigEntitiesToDtos(entities: CsvRateConfigOrmEntity[]): CsvRateConfigDto[] {
return entities.map(entity => this.mapConfigEntityToDto(entity));
}
}