import { ConflictException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { FuelRepository } from './fuel.repository'; import { FuelPurchase } from './entities/fuel-purchase.entity'; import { FuelConsumption } from './entities/fuel-consumption.entity'; import { CreateFuelPurchaseDto } from './dto/create-fuel-purchase.dto'; @Injectable() export class FuelService { constructor( private readonly fuelRepository: FuelRepository, @InjectRepository(FuelPurchase) private readonly purchaseRepository: Repository, ) {} async recordFuelPurchase(dto: CreateFuelPurchaseDto): Promise { // Reject a re-submitted receipt for the same vehicle (double-entry guard). if (dto.receiptNumber) { const duplicate = await this.purchaseRepository.findOne({ where: { vehicleId: dto.vehicleId, receiptNumber: dto.receiptNumber }, }); if (duplicate) { throw new ConflictException( `A fuel purchase with receipt number ${dto.receiptNumber} already exists for this vehicle`, ); } } const totalCost = dto.liters * dto.costPerLiter; const purchase = this.purchaseRepository.create({ ...dto, totalCost, }); const saved = await this.purchaseRepository.save(purchase); // Update monthly consumption await this.updateMonthlyConsumption(dto.vehicleId, new Date(dto.purchaseDate)); return saved; } async getAllFuelPurchases(): Promise { return this.purchaseRepository .createQueryBuilder('purchase') .leftJoinAndSelect('purchase.vehicle', 'vehicle') .orderBy('purchase.purchaseDate', 'DESC') .getMany(); } async getFuelPurchases( vehicleId: string, startDate: Date, endDate: Date, ): Promise { return this.fuelRepository.findByVehicleAndDateRange(vehicleId, startDate, endDate); } async getMonthlyConsumption( vehicleId: string, month: Date, ): Promise { return this.fuelRepository.getMonthlyConsumption(vehicleId, month); } async getFleetFuelStats(monthsBack: number = 12) { const endDate = new Date(); const startDate = new Date(endDate.getFullYear(), endDate.getMonth() - monthsBack, 1); const purchases = await this.purchaseRepository .createQueryBuilder('purchase') .where('purchase.purchaseDate BETWEEN :startDate AND :endDate', { startDate, endDate }) .getMany(); const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0); const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0); const averagePrice = totalLiters > 0 ? totalCost / totalLiters : 0; return { totalPurchases: purchases.length, totalLiters, totalCost, averagePricePerLiter: averagePrice, averageEfficiency: 0, // Placeholder - would need distance data dateRange: { startDate, endDate }, }; } async getVehicleFuelStats(vehicleId: string, monthsBack: number = 12) { const endDate = new Date(); const startDate = new Date(endDate.getFullYear(), endDate.getMonth() - monthsBack, 1); const purchases = await this.getFuelPurchases(vehicleId, startDate, endDate); const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0); const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0); const averagePrice = totalLiters > 0 ? totalCost / totalLiters : 0; return { vehicleId, totalPurchases: purchases.length, totalLiters, totalCost, averagePricePerLiter: averagePrice, dateRange: { startDate, endDate }, }; } private async updateMonthlyConsumption(vehicleId: string, date: Date): Promise { const monthStart = new Date(date.getFullYear(), date.getMonth(), 1); const monthEnd = new Date(monthStart.getFullYear(), monthStart.getMonth() + 1, 1); const purchases = await this.fuelRepository.findByVehicleAndDateRange( vehicleId, monthStart, monthEnd, ); const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0); const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0); const numberOfPurchases = purchases.length; const averageCostPerLiter = totalLiters > 0 ? totalCost / totalLiters : 0; await this.fuelRepository.updateMonthlyConsumption(vehicleId, monthStart, { totalLiters, totalCost, numberOfPurchases, averageCostPerLiter, }); } }