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 a587cd6..b602343 100644 --- a/apps/backend/src/application/controllers/admin/csv-rates.controller.ts +++ b/apps/backend/src/application/controllers/admin/csv-rates.controller.ts @@ -70,14 +70,12 @@ export class CsvRatesAdminController { storage: diskStorage({ destination: './apps/backend/src/infrastructure/storage/csv-storage/rates', filename: (req, file, cb) => { - // Generate filename: company-name.csv - const companyName = req.body.companyName || 'unknown'; - const sanitized = companyName - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/[^a-z0-9-]/g, ''); - const filename = `${sanitized}.csv`; - cb(null, filename); + // Use timestamp + random string to avoid conflicts + // We'll rename it later once we have the company name from req.body + const timestamp = Date.now(); + const randomStr = Math.random().toString(36).substring(7); + const tempFilename = `temp-${timestamp}-${randomStr}.csv`; + cb(null, tempFilename); }, }), fileFilter: (req, file, cb) => { @@ -147,9 +145,16 @@ export class CsvRatesAdminController { } try { + // Generate final filename based on company name + const sanitizedCompanyName = dto.companyName + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/[^a-z0-9-]/g, ''); + const finalFilename = `${sanitizedCompanyName}.csv`; + // Auto-convert CSV if needed (FOB FRET → Standard format) const conversionResult = await this.csvConverter.autoConvert(file.path, dto.companyName); - const filePathToValidate = conversionResult.convertedPath; + let filePathToValidate = conversionResult.convertedPath; if (conversionResult.wasConverted) { this.logger.log( @@ -177,13 +182,28 @@ export class CsvRatesAdminController { this.logger.log(`Successfully parsed ${ratesCount} rates from ${file.filename}`); + // Rename file to final name (company-name.csv) + const fs = require('fs'); + const path = require('path'); + const finalPath = path.join(path.dirname(filePathToValidate), finalFilename); + + // Delete old file if exists + if (fs.existsSync(finalPath)) { + fs.unlinkSync(finalPath); + this.logger.log(`Deleted old file: ${finalFilename}`); + } + + // Rename temp file to final name + fs.renameSync(filePathToValidate, finalPath); + this.logger.log(`Renamed ${file.filename} to ${finalFilename}`); + // Check if config exists for this company const existingConfig = await this.csvConfigRepository.findByCompanyName(dto.companyName); if (existingConfig) { // Update existing configuration await this.csvConfigRepository.update(existingConfig.id, { - csvFilePath: file.filename, + csvFilePath: finalFilename, uploadedAt: new Date(), uploadedBy: user.id, rowCount: ratesCount, @@ -204,7 +224,7 @@ export class CsvRatesAdminController { // Create new configuration await this.csvConfigRepository.create({ companyName: dto.companyName, - csvFilePath: file.filename, + csvFilePath: finalFilename, type: 'CSV_ONLY', hasApi: false, apiConnector: null, @@ -226,7 +246,7 @@ export class CsvRatesAdminController { return { success: true, ratesCount, - csvFilePath: file.filename, + csvFilePath: finalFilename, companyName: dto.companyName, uploadedAt: new Date(), };