feat: Total Cost of Ownership (TCO) per Vehicle #28
@@ -9,7 +9,8 @@ import type {
|
||||
MaintenanceRecordResponse,
|
||||
MaintenanceScheduleResponse,
|
||||
MaintenanceCategory,
|
||||
ScheduleType
|
||||
ScheduleType,
|
||||
MaintenanceCostStats
|
||||
} from './maintenance.types';
|
||||
import { validateSubtypes } from './maintenance.types';
|
||||
import { MaintenanceRepository } from '../data/maintenance.repository';
|
||||
@@ -63,6 +64,19 @@ export class MaintenanceService {
|
||||
return records.map(r => this.toRecordResponse(r));
|
||||
}
|
||||
|
||||
async getVehicleMaintenanceCosts(vehicleId: string, userId: string): Promise<MaintenanceCostStats> {
|
||||
const records = await this.repo.findRecordsByVehicleId(vehicleId, userId);
|
||||
const totalCost = records.reduce((sum, r) => {
|
||||
if (r.cost === null || r.cost === undefined) return sum;
|
||||
const cost = Number(r.cost);
|
||||
if (isNaN(cost)) {
|
||||
throw new Error(`Invalid cost value for maintenance record ${r.id}`);
|
||||
}
|
||||
return sum + cost;
|
||||
}, 0);
|
||||
return { totalCost, recordCount: records.length };
|
||||
}
|
||||
|
||||
async updateRecord(userId: string, id: string, patch: UpdateMaintenanceRecordRequest): Promise<MaintenanceRecordResponse | null> {
|
||||
const existing = await this.repo.findRecordById(id, userId);
|
||||
if (!existing) return null;
|
||||
|
||||
@@ -162,6 +162,12 @@ export interface MaintenanceRecordResponse extends MaintenanceRecord {
|
||||
subtypeCount: number;
|
||||
}
|
||||
|
||||
// TCO aggregation stats
|
||||
export interface MaintenanceCostStats {
|
||||
totalCost: number;
|
||||
recordCount: number;
|
||||
}
|
||||
|
||||
export interface MaintenanceScheduleResponse extends MaintenanceSchedule {
|
||||
subtypeCount: number;
|
||||
isDueSoon?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user