From aeb3d2a75d3f66282556134b3b9905fcf8c5932b Mon Sep 17 00:00:00 2001 From: David Date: Mon, 17 Nov 2025 19:53:45 +0100 Subject: [PATCH] fix: use company name from form instead of CSV column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../controllers/admin/csv-rates.controller.ts | 3 ++- .../src/domain/ports/out/csv-rate-loader.port.ts | 3 ++- .../src/domain/services/csv-rate-search.service.ts | 5 +++-- .../carriers/csv-loader/csv-rate-loader.adapter.ts | 13 ++++++++----- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/backend/src/application/controllers/admin/csv-rates.controller.ts b/apps/backend/src/application/controllers/admin/csv-rates.controller.ts index 67bda15..a587cd6 100644 --- a/apps/backend/src/application/controllers/admin/csv-rates.controller.ts +++ b/apps/backend/src/application/controllers/admin/csv-rates.controller.ts @@ -171,7 +171,8 @@ export class CsvRatesAdminController { } // 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; this.logger.log(`Successfully parsed ${ratesCount} rates from ${file.filename}`); diff --git a/apps/backend/src/domain/ports/out/csv-rate-loader.port.ts b/apps/backend/src/domain/ports/out/csv-rate-loader.port.ts index e9a691a..f6f59f4 100644 --- a/apps/backend/src/domain/ports/out/csv-rate-loader.port.ts +++ b/apps/backend/src/domain/ports/out/csv-rate-loader.port.ts @@ -13,10 +13,11 @@ export interface CsvRateLoaderPort { * Load all rates from a CSV file * @param filePath - Absolute or relative path to CSV file * @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 * @throws Error if file cannot be read or parsed */ - loadRatesFromCsv(filePath: string, companyEmail: string): Promise; + loadRatesFromCsv(filePath: string, companyEmail: string, companyNameOverride?: string): Promise; /** * Load rates for a specific company diff --git a/apps/backend/src/domain/services/csv-rate-search.service.ts b/apps/backend/src/domain/services/csv-rate-search.service.ts index 4a39694..ef61648 100644 --- a/apps/backend/src/domain/services/csv-rate-search.service.ts +++ b/apps/backend/src/domain/services/csv-rate-search.service.ts @@ -135,12 +135,13 @@ export class CsvRateSearchService implements SearchCsvRatesPort { * Load all rates from all CSV files */ private async loadAllRates(): Promise { - // 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) { const configs = await this.configRepository.findActiveConfigs(); const ratePromises = configs.map(config => { 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); return rateArrays.flat(); diff --git a/apps/backend/src/infrastructure/carriers/csv-loader/csv-rate-loader.adapter.ts b/apps/backend/src/infrastructure/carriers/csv-loader/csv-rate-loader.adapter.ts index cafa4bb..8888fd7 100644 --- a/apps/backend/src/infrastructure/carriers/csv-loader/csv-rate-loader.adapter.ts +++ b/apps/backend/src/infrastructure/carriers/csv-loader/csv-rate-loader.adapter.ts @@ -79,8 +79,8 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort { this.logger.log(`CSV directory initialized: ${this.csvDirectory}`); } - async loadRatesFromCsv(filePath: string, companyEmail: string): Promise { - this.logger.log(`Loading rates from CSV: ${filePath} (email: ${companyEmail})`); + async loadRatesFromCsv(filePath: string, companyEmail: string, companyNameOverride?: string): Promise { + this.logger.log(`Loading rates from CSV: ${filePath} (email: ${companyEmail}, company: ${companyNameOverride || 'from CSV'})`); try { // Read CSV file @@ -105,7 +105,7 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort { // Map to domain entities const rates = records.map((record, index) => { try { - return this.mapToCsvRate(record, companyEmail); + return this.mapToCsvRate(record, companyEmail, companyNameOverride); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); 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 */ - private mapToCsvRate(record: CsvRow, companyEmail: string): CsvRate { + private mapToCsvRate(record: CsvRow, companyEmail: string, companyNameOverride?: string): CsvRate { // Parse surcharges const surcharges = this.parseSurcharges(record); @@ -264,9 +264,12 @@ export class CsvRateLoaderAdapter implements CsvRateLoaderPort { const validUntil = new Date(record.validUntil); 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 return new CsvRate( - record.companyName.trim(), + companyName, companyEmail, PortCode.create(record.origin), PortCode.create(record.destination),