Modulo reportes

This commit is contained in:
2026-07-01 14:59:52 +00:00
parent 43c85698c6
commit d84b8a3e67
4 changed files with 688 additions and 0 deletions

View File

@ -3,6 +3,10 @@ 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
@ -98,4 +102,209 @@ export class FuelRequestService {
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."
});
}
}

View File

@ -0,0 +1,252 @@
import { Request, Response } from "express";
import { ReportService } from "./report.service";
const service = new ReportService();
export class ReportController {
async getSummary(
req:Request,
res:Response
){
try{
const summary = await service.getSummary();
res.json(summary);
}catch(error){
res.status(500).json({
message:"Error al obtener reportes",
error
});
}
}
// Reporte de Fuel Request
async getFuelRequestsReport(
req: Request,
res: Response
) {
try {
const report =
await service.getFuelRequestReport();
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte de requisiciones.",
error
});
}
}
// Reporte de Facturas Externas
async getExternalInvoicesReport(
req: Request,
res: Response
) {
try {
const report =
await service.getExternalInvoiceReport();
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte de facturas externas.",
error
});
}
}
// Reporte de LPG
async getLpgReport(
req: Request,
res: Response
) {
try {
const report =
await service.getLpgReport();
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte de LPG.",
error
});
}
}
// Reporte de Anomalías
async getAnomaliesReport(
req: Request,
res: Response
) {
try {
const report =
await service.getAnomaliesReport();
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte de anomalías.",
error
});
}
}
// Reporte de Lecturas de Bomba
async getPumpReadingsReport(
req: Request,
res: Response
) {
try {
const report =
await service.getPumpReadingsReport();
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte de lecturas de bomba.",
error
});
}
}
// Reporte por Vehículo
async getVehicleReport(
req: Request,
res: Response
) {
try {
const report =
await service.getVehicleReport(
Number(req.params.vehicleId)
);
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte por vehículo.",
error
});
}
}
// Reporte por Empleado
async getEmployeeReport(
req: Request,
res: Response
) {
try {
const report =
await service.getEmployeeReport(
Number(req.params.employeeId)
);
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte por empleado.",
error
});
}
}
// Reporte por Departamento
async getDepartmentReport(
req: Request,
res: Response
) {
try {
const report =
await service.getDepartmentReport(
Number(req.params.departmentId)
);
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte por departamento.",
error
});
}
}
// Reporte por Ruta
async getRouteReport(
req: Request,
res: Response
) {
try {
const report =
await service.getRouteReport(
Number(req.params.routeId)
);
res.status(200).json(report);
} catch (error) {
res.status(500).json({
message: "Error al generar el reporte por ruta.",
error
});
}
}
}

View File

@ -0,0 +1,29 @@
import { Router } from "express";
import { ReportController } from "./report.controller";
import { authMiddleware } from "../auth/auth.middleware";
const reportRouter = Router();
const controller = new ReportController();
reportRouter.get("/summary", authMiddleware, controller.getSummary);
reportRouter.get("/fuel-request", authMiddleware, controller.getFuelRequestsReport);
reportRouter.get("/external-invoice", authMiddleware, controller.getExternalInvoicesReport);
reportRouter.get("/LPG", authMiddleware, controller.getLpgReport);
reportRouter.get("/anomalies", authMiddleware, controller.getAnomaliesReport);
reportRouter.get("/pump-readings", authMiddleware, controller.getPumpReadingsReport);
reportRouter.get("/vehicle/:vehicleId", authMiddleware, controller.getVehicleReport);
reportRouter.get("/employee/:employeeId", authMiddleware, controller.getEmployeeReport);
reportRouter.get("/department/:departmentId", authMiddleware, controller.getDepartmentReport);
reportRouter.get("/route/:routeId", authMiddleware, controller.getRouteReport);
export default reportRouter;

View File

@ -0,0 +1,198 @@
import fuelRequestModel from "../fuel-requests/fuelRequest.model";
import externalInvoiceModel from "../external-invoices/externalInvoice.model";
import lpgModel from "../lpg/lpg.model";
import approvalModel from "../approvals/approval.model";
import anomalyModel from "../anomalies/anomaly.model";
import pumpReadingModel from "../pump-reading/pumpReading.model";
export class ReportService{
async getSummary(){
//Total de requisiciones
const fuelRequests = await fuelRequestModel.countDocuments();
//Total de facturas externas
const externalInvoices = await externalInvoiceModel.countDocuments();
//Total de requisiciones LPG
const lpgRequests = await lpgModel.countDocuments();
//Total de galones solicitados
const pendingApprovals = await approvalModel.countDocuments({
status:"PENDIENTE"
});
//Total de anomalías abiertas
const openAnomalies = await anomalyModel.countDocuments({
status:"ABIERTA"
})
//Tootal de lecturas de bomba
const pumpReadings = await pumpReadingModel.countDocuments();
const gallons = await fuelRequestModel.aggregate([
{
$group:{
_id:null,
totalGallons:{
$sum: "$gallonQuantity"
}
}
}
]);
//Total invertido
const totalCost = await fuelRequestModel.aggregate([
{
$group:{
_id:null,
totalAmount:{
$sum: "$totalAmount"
}
}
}
]);
return{
fuelRequests,
externalInvoices,
lpgRequests,
pendingApprovals,
openAnomalies,
pumpReadings,
totalGallons:
gallons.length > 0
? gallons[0].totalGallons
:0,
totalCost:
totalCost.length > 0
? totalCost[0].totalAmount
:0
}
}
async getFuelRequestReport(){
return await fuelRequestModel
.find()
.populate("fuelPumpId")
.populate("fuelTypeId")
.populate("createdBy")
.populate("authorizedBy")
.sort({
createdAt:-1
});
}
async getExternalInvoiceReport(){
return await externalInvoiceModel
.find()
.populate("fuelTypeId")
.populate("createdBy")
.populate("authorizedBy")
.sort({
invoiceDate:-1
});
}
async getLpgReport(){
return await lpgModel
.find()
.populate("requestedBy")
.populate("approvedBy")
.sort({
requestDate:-1
});
}
async getAnomaliesReport(){
return await anomalyModel
.find()
.populate("reportedBy")
.populate("resolvedBy")
.sort({
createdAt:-1
});
}
async getPumpReadingsReport(){
return await pumpReadingModel
.find()
.populate("fuelPumpId")
.populate("fuelTypeId")
.populate("createdBy")
.sort({
readingDate:-1
});
}
async getVehicleReport(
vehicleId:number
){
return await fuelRequestModel
.find({
vehicleId
})
.populate("fuelPumpId")
.populate("fuelTypeId")
.sort({
createdAt:-1
});
}
async getEmployeeReport(
employeeId:number
){
return await fuelRequestModel
.find({
employeeId
})
.populate("fuelPumpId")
.populate("fuelTypeId")
.sort({
createdAt:-1
});
}
async getDepartmentReport(
departmentId:number
){
return await fuelRequestModel
.find({
departmentId
})
.populate("fuelPumpId")
.populate("fuelTypeId")
.sort({
createdAt:-1
});
}
async getRouteReport(
routeId:number
){
return await fuelRequestModel
.find({
routeId
})
.populate("fuelPumpId")
.populate("fuelTypeId")
.sort({
createdAt:-1
});
}
}