Add operational planning view for vehicle and guard availability
Implement GET /api/operational-planning/availability endpoint to fetch and sort vehicles and guards based on their availability and CCNL rules for a given date. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/EEOXc3D
This commit is contained in:
parent
278419c4ff
commit
181de6a028
4
.replit
4
.replit
@ -19,6 +19,10 @@ externalPort = 80
|
||||
localPort = 33035
|
||||
externalPort = 3001
|
||||
|
||||
[[ports]]
|
||||
localPort = 34977
|
||||
externalPort = 4200
|
||||
|
||||
[[ports]]
|
||||
localPort = 41343
|
||||
externalPort = 3000
|
||||
|
||||
121
server/routes.ts
121
server/routes.ts
@ -534,6 +534,127 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
// ============= OPERATIONAL PLANNING ROUTES =============
|
||||
app.get("/api/operational-planning/availability", isAuthenticated, async (req, res) => {
|
||||
try {
|
||||
const { getGuardAvailabilityReport } = await import("./ccnlRules");
|
||||
const date = req.query.date ? new Date(req.query.date as string) : new Date();
|
||||
|
||||
// Imposta inizio e fine giornata
|
||||
const startOfDay = new Date(date);
|
||||
startOfDay.setHours(0, 0, 0, 0);
|
||||
const endOfDay = new Date(date);
|
||||
endOfDay.setHours(23, 59, 59, 999);
|
||||
|
||||
// Ottieni tutti i veicoli
|
||||
const allVehicles = await storage.getAllVehicles();
|
||||
|
||||
// Ottieni turni del giorno per trovare veicoli assegnati
|
||||
const dayShifts = await db
|
||||
.select()
|
||||
.from(shifts)
|
||||
.where(
|
||||
and(
|
||||
gte(shifts.startTime, startOfDay),
|
||||
lte(shifts.startTime, endOfDay)
|
||||
)
|
||||
);
|
||||
|
||||
// Mappa veicoli con disponibilità
|
||||
const vehiclesWithAvailability = await Promise.all(
|
||||
allVehicles.map(async (vehicle) => {
|
||||
const assignedShift = dayShifts.find((shift: any) => shift.vehicleId === vehicle.id);
|
||||
|
||||
return {
|
||||
...vehicle,
|
||||
isAvailable: !assignedShift,
|
||||
assignedShift: assignedShift ? {
|
||||
id: assignedShift.id,
|
||||
startTime: assignedShift.startTime,
|
||||
endTime: assignedShift.endTime,
|
||||
siteId: assignedShift.siteId
|
||||
} : null
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
// Ottieni tutte le guardie
|
||||
const allGuards = await storage.getAllGuards();
|
||||
|
||||
// Ottieni assegnazioni turni del giorno
|
||||
const dayShiftAssignments = await db
|
||||
.select()
|
||||
.from(shiftAssignments)
|
||||
.innerJoin(shifts, eq(shiftAssignments.shiftId, shifts.id))
|
||||
.where(
|
||||
and(
|
||||
gte(shifts.startTime, startOfDay),
|
||||
lte(shifts.startTime, endOfDay)
|
||||
)
|
||||
);
|
||||
|
||||
// Calcola disponibilità agenti con report CCNL
|
||||
const guardsWithAvailability = await Promise.all(
|
||||
allGuards.map(async (guard) => {
|
||||
const assignedShift = dayShiftAssignments.find(
|
||||
(assignment: any) => assignment.shift_assignments.guardId === guard.id
|
||||
);
|
||||
|
||||
// Calcola report disponibilità CCNL
|
||||
const availabilityReport = await getGuardAvailabilityReport(
|
||||
guard.id,
|
||||
startOfDay,
|
||||
endOfDay
|
||||
);
|
||||
|
||||
return {
|
||||
...guard,
|
||||
isAvailable: !assignedShift,
|
||||
assignedShift: assignedShift ? {
|
||||
id: assignedShift.shifts.id,
|
||||
startTime: assignedShift.shifts.startTime,
|
||||
endTime: assignedShift.shifts.endTime,
|
||||
siteId: assignedShift.shifts.siteId
|
||||
} : null,
|
||||
availability: {
|
||||
weeklyHours: availabilityReport.weeklyHours.current,
|
||||
remainingWeeklyHours: availabilityReport.remainingWeeklyHours,
|
||||
remainingMonthlyHours: availabilityReport.remainingMonthlyHours,
|
||||
consecutiveDaysWorked: availabilityReport.consecutiveDaysWorked
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
// Ordina veicoli: disponibili prima, poi per targa
|
||||
const sortedVehicles = vehiclesWithAvailability.sort((a, b) => {
|
||||
if (a.isAvailable && !b.isAvailable) return -1;
|
||||
if (!a.isAvailable && b.isAvailable) return 1;
|
||||
return a.licensePlate.localeCompare(b.licensePlate);
|
||||
});
|
||||
|
||||
// Ordina agenti: disponibili prima, poi per ore settimanali (meno ore = più disponibili)
|
||||
const sortedGuards = guardsWithAvailability.sort((a, b) => {
|
||||
if (a.isAvailable && !b.isAvailable) return -1;
|
||||
if (!a.isAvailable && b.isAvailable) return 1;
|
||||
// Se entrambi disponibili, ordina per ore settimanali (meno ore = prima)
|
||||
if (a.isAvailable && b.isAvailable) {
|
||||
return a.availability.weeklyHours - b.availability.weeklyHours;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
res.json({
|
||||
date: date.toISOString(),
|
||||
vehicles: sortedVehicles,
|
||||
guards: sortedGuards
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching operational planning availability:", error);
|
||||
res.status(500).json({ message: "Failed to fetch availability" });
|
||||
}
|
||||
});
|
||||
|
||||
// ============= CERTIFICATION ROUTES =============
|
||||
app.post("/api/certifications", isAuthenticated, async (req, res) => {
|
||||
try {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user