import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { BaseRepository } from '@edr/api-common'; import { IsNull, Repository } from 'typeorm'; import { MaintenanceInterval } from './entities/maintenance-interval.entity'; import { MaintenanceType } from './entities/maintenance-schedule.entity'; @Injectable() export class MaintenanceIntervalRepository extends BaseRepository { constructor( @InjectRepository(MaintenanceInterval) private readonly intervalRepository: Repository, ) { super(intervalRepository); } /** * Resolve the interval for a completed service. Prefers the exact * (type, serviceItem) match; a completion without an item falls back to the * type's item-less interval only, so "oil" completions never consume the * "tires" interval. */ async getByVehicleAndType( vehicleId: string, maintenanceType: MaintenanceType, serviceItem?: string | null, ): Promise { return this.intervalRepository.findOne({ where: { vehicleId, maintenanceType, isActive: true, serviceItem: serviceItem?.trim() ? serviceItem.trim() : IsNull(), }, }); } async getActiveIntervals(vehicleId: string): Promise { return this.intervalRepository.find({ where: { vehicleId, isActive: true }, order: { maintenanceType: 'ASC', serviceItem: 'ASC' }, }); } async upsertInterval( vehicleId: string, maintenanceType: MaintenanceType, serviceItem?: string | null, intervalKm?: number | null, intervalDays?: number | null, description?: string | null, ): Promise { const item = serviceItem?.trim() || null; const existing = await this.getByVehicleAndType(vehicleId, maintenanceType, item); if (existing) { await this.intervalRepository.update(existing.id, { intervalKm: intervalKm ?? existing.intervalKm, intervalDays: intervalDays ?? existing.intervalDays, description: description ?? existing.description, }); const updated = await this.intervalRepository.findOneBy({ id: existing.id }); return updated!; } return this.intervalRepository.save( this.intervalRepository.create({ vehicleId, maintenanceType, serviceItem: item, intervalKm, intervalDays, description, isActive: true, }), ); } /** Soft-disable: history keeps pointing at it, auto-scheduling stops. */ async deactivate(id: string): Promise { await this.intervalRepository.update(id, { isActive: false }); } }