339 lines
7.7 KiB
TypeScript
339 lines
7.7 KiB
TypeScript
import fuelRequestModel from "./fuelRequest.model";
|
|
import { IFuelRequest } from "./fuelRequest.interface";
|
|
|
|
import { generateRequestNumber } from "../../utils/requestNumber";
|
|
|
|
import vehiclesConfigModel from "../vehicles-config/vehiclesConfig.model";
|
|
import anomalyModel from "../anomalies/anomaly.model";
|
|
import { IAnomaly } from "../anomalies/anomaly.interface";
|
|
|
|
export class FuelRequestService {
|
|
//Obtener todas las requisiciones
|
|
|
|
async getAll() {
|
|
return await fuelRequestModel
|
|
.find()
|
|
.populate("fuelPumpId")
|
|
.populate("fuelTypeId")
|
|
.populate("createdBy")
|
|
.populate("authorizedBy")
|
|
.sort({ createdAt: -1 });
|
|
}
|
|
|
|
//Obtener reauisición por ID
|
|
|
|
async getById(
|
|
id:string
|
|
) {
|
|
|
|
return await fuelRequestModel
|
|
.findById(id)
|
|
.populate("fuelPumpId")
|
|
.populate("fuelTypeId")
|
|
.populate("createdBy")
|
|
.populate("authorizedBy");
|
|
|
|
}
|
|
|
|
//Crear una nueva requisición
|
|
|
|
async create (
|
|
data:IFuelRequest
|
|
){
|
|
///Validar kilometraje
|
|
if(data.currentMileage < data.previousMileage) {
|
|
throw new Error ("El kilometraje no puede ser menor que el anterior");
|
|
}
|
|
|
|
//Validar que los galones sean mayor a 0
|
|
if(data.gallonQuantity <= 0){
|
|
throw new Error ("La cantidad de galones debe ser mayor que 0");
|
|
}
|
|
|
|
//Generar número automático
|
|
data.requestNumber = generateRequestNumber();
|
|
|
|
//Calcular distancia recorrida
|
|
data.distanceTraveled = data.currentMileage - data.previousMileage;
|
|
|
|
//Calcular monto total
|
|
data.totalAmount = data.gallonQuantity * data.pricePerGallon;
|
|
|
|
//Estado inicial
|
|
data.status = "PENDIENTE";
|
|
|
|
//Crear documento
|
|
const request = new fuelRequestModel(data);
|
|
|
|
//Guardar en DB
|
|
const fuelRequest = await request.save();
|
|
|
|
//Validaciones automáticas
|
|
await this.detectAnomalies(
|
|
fuelRequest
|
|
);
|
|
|
|
return fuelRequest;
|
|
|
|
}
|
|
|
|
async update(
|
|
id:string,
|
|
data:Partial<IFuelRequest>
|
|
){
|
|
//Buscar la requisición actual
|
|
const request = await fuelRequestModel.findById(id);
|
|
|
|
if(!request){
|
|
return null;
|
|
}
|
|
|
|
const previousMileage = data.previousMileage ?? request.previousMileage;
|
|
|
|
const currentMileage = data.currentMileage ?? request.currentMileage;
|
|
|
|
const gallonQuantity = data.gallonQuantity ?? request.gallonQuantity;
|
|
|
|
const pricePerGallon = data.pricePerGallon ?? request.pricePerGallon;
|
|
|
|
//Recalcular distancia recorrida
|
|
data.distanceTraveled = currentMileage - previousMileage;
|
|
|
|
//Validar kilometraje
|
|
|
|
if(data.distanceTraveled < 0){
|
|
throw new Error("El kilometraje actual no puede ser menor que el anterior");
|
|
}
|
|
|
|
//Recalcular monto total
|
|
|
|
data.totalAmount = gallonQuantity * pricePerGallon;
|
|
|
|
//Actualizar la requisición
|
|
const updateRequest = await fuelRequestModel.findByIdAndUpdate(
|
|
id,
|
|
data,
|
|
{
|
|
new:true
|
|
}
|
|
);
|
|
|
|
return updateRequest;
|
|
|
|
}
|
|
|
|
//Eliminar requisición
|
|
|
|
async delete(
|
|
id:string
|
|
){
|
|
|
|
return await fuelRequestModel
|
|
.findByIdAndDelete(id);
|
|
}
|
|
|
|
private async detectAnomalies(
|
|
fuelRequest:any
|
|
){
|
|
await this.validateMileage(
|
|
fuelRequest
|
|
);
|
|
|
|
await this.validateFuelConsumption(
|
|
fuelRequest
|
|
);
|
|
|
|
await this.validateTankCapacity(
|
|
fuelRequest
|
|
);
|
|
|
|
await this.validatePreviousFuelRequest(
|
|
fuelRequest
|
|
);
|
|
}
|
|
|
|
private async validateMileage(
|
|
data:any
|
|
){
|
|
|
|
//Kilometraje menor que el anterior
|
|
if (
|
|
data.currentMileage <
|
|
data.previousMileage
|
|
){
|
|
await this.createAnomaly(
|
|
data,
|
|
"KILOMETRAJE FUERA DE RANGO",
|
|
"El kilometraje actual es menor que el anterior"
|
|
);
|
|
}
|
|
|
|
//Odomentro en mal estado
|
|
if(data.currentMileage === data.previousMileage){
|
|
await this.createAnomaly(
|
|
data,
|
|
"ODOMETRO EN MAL ESTADO",
|
|
"El kilometraje no cambió respecto al anterior"
|
|
);
|
|
}
|
|
|
|
//Diferencia mayor a 500km
|
|
if(data.distanceTraveled>500){
|
|
await this.createAnomaly(
|
|
data,
|
|
"KILOMETRAJE FUERA DE RANGO",
|
|
"La distancia recorrida supera los 500 kilometros"
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//Validar rendimiento de combustible
|
|
private async validateFuelConsumption(
|
|
data:any
|
|
){
|
|
//Evitar división entre 0}
|
|
if(
|
|
data.gallonQuantity <=0
|
|
){
|
|
return;
|
|
}
|
|
|
|
//Calcular distancia recorrida
|
|
|
|
const distance =
|
|
data.currentMileage - data.previousMileage;
|
|
|
|
//Calcular rendimiento
|
|
|
|
const performance =
|
|
|
|
distance/
|
|
data.gallonQuantity;
|
|
|
|
//Bajo rendimiento
|
|
|
|
if (performance < 10){
|
|
await this.createAnomaly(
|
|
data,
|
|
"RENDIMIENTO BAJO",
|
|
`El vehículo tiene un rendimiento de ${performance.toFixed(2)} km por galón.`
|
|
)
|
|
}
|
|
}
|
|
|
|
//Validar capacidad del tanque
|
|
private async validateTankCapacity(
|
|
data:any
|
|
){
|
|
const vehicleConfig = await vehiclesConfigModel.findOne({
|
|
vehicleId:data.vehicleId
|
|
});
|
|
|
|
//Sino existe configuración no validar
|
|
if(!vehicleConfig){
|
|
return;
|
|
}
|
|
|
|
//Validar capacidad del tanque
|
|
|
|
if(
|
|
data.gallonQuantity >
|
|
vehicleConfig.tankCapacity
|
|
){
|
|
await this.createAnomaly(
|
|
data,
|
|
"CONSUMO ELEVADO",
|
|
`Se solicitaron ${data.gallonQuantity} galones, pero la capacidad del tanque es de ${vehicleConfig.tankCapacity} galones.`
|
|
)
|
|
}
|
|
}
|
|
|
|
// Validar contra la carga anterior
|
|
|
|
private async validatePreviousFuelRequest(
|
|
data:any
|
|
) {
|
|
|
|
// Buscar la última requisición del vehículo
|
|
const previousRequest =
|
|
await fuelRequestModel
|
|
.findOne({
|
|
|
|
vehicleId: data.vehicleId,
|
|
|
|
_id: { $ne: data._id }
|
|
|
|
})
|
|
.sort({
|
|
createdAt: -1
|
|
});
|
|
|
|
// Si no existe una carga anterior, salir
|
|
if (!previousRequest) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Calcular diferencia de galones
|
|
const difference = Math.abs(
|
|
|
|
data.gallonQuantity -
|
|
|
|
previousRequest.gallonQuantity
|
|
|
|
);
|
|
|
|
// Si la diferencia es mayor a 5 galones
|
|
if (difference > 5) {
|
|
|
|
await this.createAnomaly(
|
|
|
|
data,
|
|
|
|
"CONSUMO ELEVADO",
|
|
|
|
`La carga actual difiere en ${difference} galones respecto a la carga anterior.`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//Crear anomalía
|
|
private async createAnomaly(
|
|
|
|
fuelRequest: any,
|
|
|
|
anomalyType: IAnomaly["anomalyType"],
|
|
|
|
description: string
|
|
|
|
) {
|
|
|
|
return await anomalyModel.create({
|
|
|
|
vehicleId: fuelRequest.vehicleId,
|
|
|
|
employeeId: fuelRequest.employeeId,
|
|
|
|
fuelRequestId: fuelRequest._id,
|
|
|
|
anomalyType,
|
|
|
|
description,
|
|
|
|
detectedBy: "SISTEMA",
|
|
|
|
status: "ABIERTA",
|
|
|
|
comments:
|
|
"Anomalía generada automáticamente por el sistema."
|
|
|
|
});
|
|
|
|
}
|
|
} |