diff --git a/backend/src/features/user-import/domain/user-import.service.ts b/backend/src/features/user-import/domain/user-import.service.ts index 6458cbb..da176d0 100644 --- a/backend/src/features/user-import/domain/user-import.service.ts +++ b/backend/src/features/user-import/domain/user-import.service.ts @@ -9,6 +9,7 @@ import { Pool, PoolClient } from 'pg'; import { logger } from '../../../core/logging/logger'; import { getStorageService } from '../../../core/storage/storage.service'; import { VehiclesRepository } from '../../vehicles/data/vehicles.repository'; +import { VehiclesService, VehicleLimitExceededError } from '../../vehicles/domain/vehicles.service'; import { FuelLogsRepository } from '../../fuel-logs/data/fuel-logs.repository'; import { DocumentsRepository } from '../../documents/data/documents.repository'; import { MaintenanceRepository } from '../../maintenance/data/maintenance.repository'; @@ -18,6 +19,7 @@ import { ImportPreview, ImportResult, USER_IMPORT_CONFIG } from './user-import.t export class UserImportService { private readonly archiveService: UserImportArchiveService; private readonly vehiclesRepo: VehiclesRepository; + private readonly vehiclesService: VehiclesService; private readonly fuelLogsRepo: FuelLogsRepository; private readonly maintenanceRepo: MaintenanceRepository; private readonly documentsRepo: DocumentsRepository; @@ -26,6 +28,7 @@ export class UserImportService { constructor(private pool: Pool) { this.archiveService = new UserImportArchiveService(); this.vehiclesRepo = new VehiclesRepository(pool); + this.vehiclesService = new VehiclesService(this.vehiclesRepo, pool); this.fuelLogsRepo = new FuelLogsRepository(pool); this.maintenanceRepo = new MaintenanceRepository(pool); this.documentsRepo = new DocumentsRepository(pool); @@ -219,7 +222,7 @@ export class UserImportService { } /** - * Merge vehicles: UPDATE existing by VIN, INSERT new + * Merge vehicles: UPDATE existing by VIN or license plate, INSERT new with limit enforcement */ private async mergeVehicles( userId: string, @@ -239,39 +242,69 @@ export class UserImportService { for (const vehicle of chunk) { try { - // Check if vehicle exists by VIN - if (vehicle.vin && vehicle.vin.trim().length > 0) { - const existing = await this.vehiclesRepo.findByUserAndVIN(userId, vehicle.vin.trim()); + let existing = null; - if (existing) { - // Update existing vehicle - await this.vehiclesRepo.update(existing.id, { - make: vehicle.make, - model: vehicle.model, - year: vehicle.year, - engine: vehicle.engine, - transmission: vehicle.transmission, - trimLevel: vehicle.trimLevel, - driveType: vehicle.driveType, - fuelType: vehicle.fuelType, - nickname: vehicle.nickname, - color: vehicle.color, - licensePlate: vehicle.licensePlate, - odometerReading: vehicle.odometerReading, - }); - summary.updated++; - continue; - } + // Try to find existing vehicle by VIN first + if (vehicle.vin && vehicle.vin.trim().length > 0) { + existing = await this.vehiclesRepo.findByUserAndVIN(userId, vehicle.vin.trim()); } - // Insert new vehicle - await this.vehiclesRepo.create({ - ...vehicle, - userId, - }); + // If not found by VIN and license plate exists, try license plate + if (!existing && vehicle.licensePlate && vehicle.licensePlate.trim().length > 0) { + const allUserVehicles = await this.vehiclesRepo.findByUserId(userId); + existing = allUserVehicles.find( + (v) => v.licensePlate && v.licensePlate.toLowerCase() === vehicle.licensePlate.toLowerCase() + ) || null; + } + + if (existing) { + // Update existing vehicle + await this.vehiclesRepo.update(existing.id, { + make: vehicle.make, + model: vehicle.model, + year: vehicle.year, + engine: vehicle.engine, + transmission: vehicle.transmission, + trimLevel: vehicle.trimLevel, + driveType: vehicle.driveType, + fuelType: vehicle.fuelType, + nickname: vehicle.nickname, + color: vehicle.color, + licensePlate: vehicle.licensePlate, + odometerReading: vehicle.odometerReading, + }); + summary.updated++; + continue; + } + + // Insert new vehicle using service (enforces tier limits) + await this.vehiclesService.createVehicle( + { + vin: vehicle.vin || '', + make: vehicle.make, + model: vehicle.model, + year: vehicle.year, + engine: vehicle.engine, + transmission: vehicle.transmission, + trimLevel: vehicle.trimLevel, + driveType: vehicle.driveType, + fuelType: vehicle.fuelType, + nickname: vehicle.nickname, + color: vehicle.color, + licensePlate: vehicle.licensePlate, + odometerReading: vehicle.odometerReading, + }, + userId + ); summary.imported++; } catch (error) { - summary.errors.push(`Vehicle import failed: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof VehicleLimitExceededError) { + summary.errors.push( + `Vehicle limit exceeded: ${error.upgradePrompt} (current: ${error.currentCount}/${error.limit})` + ); + } else { + summary.errors.push(`Vehicle import failed: ${error instanceof Error ? error.message : String(error)}`); + } } } }