fix: use company name from form instead of CSV column
Some checks failed
CI/CD Pipeline / Backend - Build, Test & Push (push) Failing after 1m33s
CI/CD Pipeline / Frontend - Build, Test & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Deployment Summary (push) Blocked by required conditions
CI/CD Pipeline / Discord Notification (Success) (push) Blocked by required conditions
CI/CD Pipeline / Discord Notification (Failure) (push) Blocked by required conditions

Fixed CSV rate upload to use the company name provided in the upload form instead of reading it from the CSV file's companyName column. This prevents "unknown" or incorrect company names from being used.

## Changes

**Domain Layer**
- Updated `CsvRateLoaderPort` interface to accept optional `companyNameOverride` parameter
- Modified `CsvRateSearchService.loadAllRates()` to pass company name from config when loading rates

**Infrastructure Layer**
- Updated `CsvRateLoaderAdapter.loadRatesFromCsv()` to accept `companyNameOverride` parameter
- Modified `mapToCsvRate()` to use override company name if provided, otherwise fallback to CSV column value
- Added logging to show which company name is being used (from override or CSV)

**Application Layer**
- Updated CSV upload controller to pass `dto.companyName` to the loader

## Impact
- When uploading a CSV file through the admin interface, the company name from the form is now correctly used
- Existing CSV files with "unknown" in the companyName column will now show the correct company name from the database configuration
- Backward compatible: if no override is provided, the CSV column value is still used

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
David 2025-11-17 19:53:45 +01:00
parent 27caca0734
commit aeb3d2a75d
4 changed files with 15 additions and 9 deletions

View File

@ -171,7 +171,8 @@ export class CsvRatesAdminController {
} }
// Load rates to verify parsing using the converted path // Load rates to verify parsing using the converted path
const rates = await this.csvLoader.loadRatesFromCsv(filePathToValidate, dto.companyEmail); // Pass company name from form to override CSV column value
const rates = await this.csvLoader.loadRatesFromCsv(filePathToValidate, dto.companyEmail, dto.companyName);
const ratesCount = rates.length; const ratesCount = rates.length;
this.logger.log(`Successfully parsed ${ratesCount} rates from ${file.filename}`); this.logger.log(`Successfully parsed ${ratesCount} rates from ${file.filename}`);

View File

@ -13,10 +13,11 @@ export interface CsvRateLoaderPort {
* Load all rates from a CSV file * Load all rates from a CSV file
* @param filePath - Absolute or relative path to CSV file * @param filePath - Absolute or relative path to CSV file
* @param companyEmail - Email address for the company (stored in config metadata) * @param companyEmail - Email address for the company (stored in config metadata)
* @param companyNameOverride - Optional company name to override the one in CSV file
* @returns Array of CSV rates * @returns Array of CSV rates
* @throws Error if file cannot be read or parsed * @throws Error if file cannot be read or parsed
*/ */
loadRatesFromCsv(filePath: string, companyEmail: string): Promise<CsvRate[]>; loadRatesFromCsv(filePath: string, companyEmail: string, companyNameOverride?: string): Promise<CsvRate[]>;
/** /**
* Load rates for a specific company * Load rates for a specific company

View File

@ -135,12 +135,13 @@ export class CsvRateSearchService implements SearchCsvRatesPort {
* Load all rates from all CSV files * Load all rates from all CSV files
*/ */
private async loadAllRates(): Promise<CsvRate[]> { private async loadAllRates(): Promise<CsvRate[]> {
// If config repository is available, load rates with emails from configs // If config repository is available, load rates with emails and company names from configs
if (this.configRepository) { if (this.configRepository) {
const configs = await this.configRepository.findActiveConfigs(); const configs = await this.configRepository.findActiveConfigs();
const ratePromises = configs.map(config => { const ratePromises = configs.map(config => {
const email = config.metadata?.companyEmail || 'bookings@example.com'; const email = config.metadata?.companyEmail || 'bookings@example.com';
return this.csvRateLoader.loadRatesFromCsv(config.csvFilePath, email); // Pass company name from config to override CSV column value
return this.csvRateLoader.loadRatesFromCsv(config.csvFilePath, email, config.companyName);
}); });
const rateArrays = await Promise.all(ratePromises); const rateArrays = await Promise.all(ratePromises);
return rateArrays.flat(); return rateArrays.flat();

View File

@ -79,8 +79,8 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort {
this.logger.log(`CSV directory initialized: ${this.csvDirectory}`); this.logger.log(`CSV directory initialized: ${this.csvDirectory}`);
} }
async loadRatesFromCsv(filePath: string, companyEmail: string): Promise<CsvRate[]> { async loadRatesFromCsv(filePath: string, companyEmail: string, companyNameOverride?: string): Promise<CsvRate[]> {
this.logger.log(`Loading rates from CSV: ${filePath} (email: ${companyEmail})`); this.logger.log(`Loading rates from CSV: ${filePath} (email: ${companyEmail}, company: ${companyNameOverride || 'from CSV'})`);
try { try {
// Read CSV file // Read CSV file
@ -105,7 +105,7 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort {
// Map to domain entities // Map to domain entities
const rates = records.map((record, index) => { const rates = records.map((record, index) => {
try { try {
return this.mapToCsvRate(record, companyEmail); return this.mapToCsvRate(record, companyEmail, companyNameOverride);
} catch (error) { } catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error); const errorMessage = error instanceof Error ? error.message : String(error);
this.logger.error(`Error mapping row ${index + 1} in ${filePath}: ${errorMessage}`); this.logger.error(`Error mapping row ${index + 1} in ${filePath}: ${errorMessage}`);
@ -255,7 +255,7 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort {
/** /**
* Map CSV row to CsvRate domain entity * Map CSV row to CsvRate domain entity
*/ */
private mapToCsvRate(record: CsvRow, companyEmail: string): CsvRate { private mapToCsvRate(record: CsvRow, companyEmail: string, companyNameOverride?: string): CsvRate {
// Parse surcharges // Parse surcharges
const surcharges = this.parseSurcharges(record); const surcharges = this.parseSurcharges(record);
@ -264,9 +264,12 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort {
const validUntil = new Date(record.validUntil); const validUntil = new Date(record.validUntil);
const validity = DateRange.create(validFrom, validUntil, true); const validity = DateRange.create(validFrom, validUntil, true);
// Use override company name if provided, otherwise use the one from CSV
const companyName = companyNameOverride || record.companyName.trim();
// Create CsvRate // Create CsvRate
return new CsvRate( return new CsvRate(
record.companyName.trim(), companyName,
companyEmail, companyEmail,
PortCode.create(record.origin), PortCode.create(record.origin),
PortCode.create(record.destination), PortCode.create(record.destination),