From c8825a9b4cdb31810aa17e46e53cf93f8dd9077e Mon Sep 17 00:00:00 2001 From: marco370 <48531002-marco370@users.noreply.replit.com> Date: Wed, 29 Oct 2025 08:23:21 +0000 Subject: [PATCH] Add a page to view the weekly guard schedule by location Implement a new API endpoint `/api/weekly-guards-schedule` to retrieve and display guard assignments, including fixed shifts, mobile shifts, and absences, for a specified location and week. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e0b5b11c-5b75-4389-8ea9-5f3cd9332f88 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e0b5b11c-5b75-4389-8ea9-5f3cd9332f88/EPTvOHB --- server/routes.ts | 104 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/server/routes.ts b/server/routes.ts index df0e994..7b83b22 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -4,7 +4,7 @@ import { storage } from "./storage"; import { setupAuth as setupReplitAuth, isAuthenticated as isAuthenticatedReplit } from "./replitAuth"; import { setupLocalAuth, isAuthenticated as isAuthenticatedLocal } from "./localAuth"; import { db } from "./db"; -import { guards, certifications, sites, shifts, shiftAssignments, users, insertShiftSchema, contractParameters, vehicles, serviceTypes, createMultiDayShiftSchema, insertCustomerSchema, customers, patrolRoutes, patrolRouteStops, insertPatrolRouteSchema } from "@shared/schema"; +import { guards, certifications, sites, shifts, shiftAssignments, users, insertShiftSchema, contractParameters, vehicles, serviceTypes, createMultiDayShiftSchema, insertCustomerSchema, customers, patrolRoutes, patrolRouteStops, insertPatrolRouteSchema, absences } from "@shared/schema"; import { eq, and, gte, lte, desc, asc, ne, sql } from "drizzle-orm"; import { differenceInDays, differenceInHours, differenceInMinutes, startOfWeek, endOfWeek, startOfMonth, endOfMonth, isWithinInterval, startOfDay, isSameDay, parseISO, format, isValid, addDays } from "date-fns"; import { z } from "zod"; @@ -4521,6 +4521,108 @@ export async function registerRoutes(app: Express): Promise { return `${minutes}m`; } + // ============= WEEKLY GUARDS SCHEDULE ============= + + app.get("/api/weekly-guards-schedule", isAuthenticated, async (req: any, res) => { + try { + const location = req.query.location as string; + const startDate = req.query.startDate as string; + + if (!location || !startDate) { + return res.status(400).json({ message: "Location e startDate richiesti" }); + } + + // Calcola l'intervallo della settimana (7 giorni da startDate) + const weekStart = parseISO(startDate); + const weekEnd = addDays(weekStart, 6); + + // Recupera tutte le guardie della sede + const guardsInLocation = await db + .select() + .from(guards) + .where(eq(guards.location, location)) + .orderBy(guards.lastName, guards.firstName); + + // Prepara la struttura dati + const guardsSchedule = []; + + for (const guard of guardsInLocation) { + // Recupera turni fissi della settimana (shift_assignments) + const fixedShifts = await db + .select({ + assignmentId: shiftAssignments.id, + shiftId: shifts.id, + plannedStartTime: shiftAssignments.plannedStartTime, + plannedEndTime: shiftAssignments.plannedEndTime, + siteName: sites.name, + siteId: sites.id, + }) + .from(shiftAssignments) + .innerJoin(shifts, eq(shiftAssignments.shiftId, shifts.id)) + .innerJoin(sites, eq(shifts.siteId, sites.id)) + .where( + and( + eq(shiftAssignments.guardId, guard.id), + gte(shiftAssignments.plannedStartTime, weekStart), + lte(shiftAssignments.plannedStartTime, weekEnd) + ) + ); + + // Recupera turni mobili della settimana (patrol_routes) + const mobileShifts = await db + .select({ + routeId: patrolRoutes.id, + shiftDate: patrolRoutes.shiftDate, + startTime: patrolRoutes.startTime, + endTime: patrolRoutes.endTime, + }) + .from(patrolRoutes) + .where( + and( + eq(patrolRoutes.guardId, guard.id), + gte(sql`${patrolRoutes.shiftDate}`, startDate), + lte(sql`${patrolRoutes.shiftDate}`, format(weekEnd, 'yyyy-MM-dd')) + ) + ); + + // Recupera assenze della settimana + const absencesData = await db + .select() + .from(absences) + .where( + and( + eq(absences.guardId, guard.id), + lte(sql`${absences.startDate}`, format(weekEnd, 'yyyy-MM-dd')), + gte(sql`${absences.endDate}`, startDate) + ) + ); + + guardsSchedule.push({ + guard: { + id: guard.id, + firstName: guard.firstName, + lastName: guard.lastName, + badgeNumber: guard.badgeNumber, + }, + fixedShifts, + mobileShifts, + absences: absencesData, + }); + } + + res.json({ + weekStart: format(weekStart, 'yyyy-MM-dd'), + weekEnd: format(weekEnd, 'yyyy-MM-dd'), + location, + guards: guardsSchedule, + }); + + } catch (error) { + console.error("Error fetching weekly guards schedule:", error); + res.status(500).json({ message: "Errore nel recupero della pianificazione settimanale" }); + } + }); + const httpServer = createServer(app); return httpServer; }