From 1c34d3f79ee72434ae3cb83c9f688b859b0a4278 Mon Sep 17 00:00:00 2001 From: marco370 <48531002-marco370@users.noreply.replit.com> Date: Tue, 21 Oct 2025 17:36:14 +0000 Subject: [PATCH] Enforce daily working hour limits for security guards Implement daily hour limit checks for guard assignments based on CCNL regulations, preventing assignments that exceed 9 hours per day. 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/Jxn533V --- .replit | 4 ++++ server/routes.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/.replit b/.replit index 90b1d94..b6a9521 100644 --- a/.replit +++ b/.replit @@ -39,6 +39,10 @@ externalPort = 5000 localPort = 43267 externalPort = 3003 +[[ports]] +localPort = 44575 +externalPort = 5173 + [env] PORT = "5000" diff --git a/server/routes.ts b/server/routes.ts index bcc19b1..48c0ea6 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1326,6 +1326,7 @@ export async function registerRoutes(app: Express): Promise { .from(shiftAssignments) .where(eq(shiftAssignments.guardId, guard.id)); + // Check for time overlaps for (const existing of existingAssignments) { const hasOverlap = plannedStart < existing.plannedEndTime && @@ -1338,6 +1339,34 @@ export async function registerRoutes(app: Express): Promise { } } + // CCNL: Check daily hour limit (max 9h/day) + const maxDailyHours = 9; + let dailyHoursAlreadyAssigned = 0; + + for (const existing of existingAssignments) { + // Check if assignment is on the same day + const existingDate = new Date(existing.plannedStartTime); + if ( + existingDate.getUTCFullYear() === actualYear && + existingDate.getUTCMonth() === actualMonth && + existingDate.getUTCDate() === actualDay + ) { + const assignmentHours = differenceInHours( + existing.plannedEndTime, + existing.plannedStartTime + ); + dailyHoursAlreadyAssigned += assignmentHours; + } + } + + // Check if new assignment would exceed daily limit + if (dailyHoursAlreadyAssigned + durationHours > maxDailyHours) { + throw new Error( + `Limite giornaliero superato: la guardia ha giĆ  ${dailyHoursAlreadyAssigned}h assegnate il ${shiftDate.toLocaleDateString('it-IT')}. ` + + `Aggiungendo ${durationHours}h si supererebbero le ${maxDailyHours}h massime giornaliere (CCNL).` + ); + } + // Create assignment for this day const [assignment] = await tx.insert(shiftAssignments).values({ shiftId: shift.id,