From 9c28befcb16da990865efcd1a94bc9970ef5635b Mon Sep 17 00:00:00 2001 From: marco370 <48531002-marco370@users.noreply.replit.com> Date: Thu, 23 Oct 2025 07:41:34 +0000 Subject: [PATCH] Allow overriding daily hour limits for guard assignments Update the general planning API endpoint to include a 'force' option, enabling the assignment of guards even if they exceed the daily hour limit. This change adds a confirmation prompt for such cases and refactors error handling to provide more specific messages. 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/2w7P7NW --- server/routes.ts | 65 +++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/server/routes.ts b/server/routes.ts index cb7c541..d871a00 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1241,7 +1241,7 @@ export async function registerRoutes(app: Express): Promise { // Assign guard to site/date with specific time slot (supports multi-day assignments) app.post("/api/general-planning/assign-guard", isAuthenticated, async (req, res) => { try { - const { siteId, date, guardId, startTime, durationHours, consecutiveDays = 1, vehicleId } = req.body; + const { siteId, date, guardId, startTime, durationHours, consecutiveDays = 1, vehicleId, force = false } = req.body; if (!siteId || !date || !guardId || !startTime || !durationHours) { return res.status(400).json({ @@ -1369,32 +1369,35 @@ 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; + // CCNL: Check daily hour limit (max 9h/day) - skip if force=true + if (!force) { + 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) { + const excessHours = (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 di ${excessHours}h le ${maxDailyHours}h massime giornaliere (CCNL).` + ); } - } - - // 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 @@ -1423,8 +1426,14 @@ export async function registerRoutes(app: Express): Promise { if (errorMessage.includes('overlap') || errorMessage.includes('conflict') || errorMessage.includes('conflitto') || - errorMessage.includes('già assegnata')) { - return res.status(409).json({ message: error.message }); + errorMessage.includes('già assegnata') || + errorMessage.includes('limite giornaliero') || + errorMessage.includes('limite settimanale') || + errorMessage.includes('ccnl')) { + return res.status(409).json({ + message: error.message, + type: errorMessage.includes('limite') ? 'CCNL_VIOLATION' : 'CONFLICT' + }); } res.status(500).json({ message: "Failed to assign guard", error: String(error) }); }