mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 01:20:55 +00:00
134 lines
4.6 KiB
TypeScript
134 lines
4.6 KiB
TypeScript
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<FuelPurchase>,
|
|
) {}
|
|
|
|
async recordFuelPurchase(dto: CreateFuelPurchaseDto): Promise<FuelPurchase> {
|
|
// 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<FuelPurchase[]> {
|
|
return this.purchaseRepository
|
|
.createQueryBuilder('purchase')
|
|
.leftJoinAndSelect('purchase.vehicle', 'vehicle')
|
|
.orderBy('purchase.purchaseDate', 'DESC')
|
|
.getMany();
|
|
}
|
|
|
|
async getFuelPurchases(
|
|
vehicleId: string,
|
|
startDate: Date,
|
|
endDate: Date,
|
|
): Promise<FuelPurchase[]> {
|
|
return this.fuelRepository.findByVehicleAndDateRange(vehicleId, startDate, endDate);
|
|
}
|
|
|
|
async getMonthlyConsumption(
|
|
vehicleId: string,
|
|
month: Date,
|
|
): Promise<FuelConsumption | null> {
|
|
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<void> {
|
|
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,
|
|
});
|
|
}
|
|
}
|