Add functionality to copy weekly shift assignments to the following week

Introduce a new POST API endpoint `/api/shift-assignments/copy-week` to duplicate existing shift assignments and their associated shifts for a specified location and week, automatically adjusting dates by adding 7 days.

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/EDxr1e6
This commit is contained in:
marco370 2025-10-24 15:36:54 +00:00
parent 36bfad3815
commit 0b64fd2f08

View File

@ -1337,6 +1337,129 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
// Copy weekly shift assignments to next week
app.post("/api/shift-assignments/copy-week", isAuthenticated, async (req, res) => {
try {
const { weekStart, location } = req.body;
if (!weekStart || !location) {
return res.status(400).json({ message: "Missing required fields: weekStart, location" });
}
// Parse week start date
const [year, month, day] = weekStart.split("-").map(Number);
if (!year || !month || !day) {
return res.status(400).json({ message: "Invalid weekStart format. Expected YYYY-MM-DD" });
}
// Calculate week boundaries (Monday to Sunday)
const weekStartDate = new Date(year, month - 1, day, 0, 0, 0, 0);
const weekEndDate = new Date(year, month - 1, day + 6, 23, 59, 59, 999);
console.log("📋 Copying weekly shifts:", {
weekStart: weekStartDate.toISOString(),
weekEnd: weekEndDate.toISOString(),
location
});
// Transaction: copy all shifts and assignments
const result = await db.transaction(async (tx) => {
// 1. Find all shifts in the source week filtered by location
const sourceShifts = await tx
.select({
shift: shifts,
site: sites
})
.from(shifts)
.innerJoin(sites, eq(shifts.siteId, sites.id))
.where(
and(
gte(shifts.startTime, weekStartDate),
lte(shifts.startTime, weekEndDate),
eq(sites.location, location)
)
);
if (sourceShifts.length === 0) {
throw new Error("Nessun turno trovato nella settimana selezionata");
}
console.log(`📋 Found ${sourceShifts.length} shifts to copy`);
let copiedShiftsCount = 0;
let copiedAssignmentsCount = 0;
// 2. For each shift, copy to next week (+7 days)
for (const { shift: sourceShift, site } of sourceShifts) {
// Calculate new dates (+7 days)
const newStartTime = new Date(sourceShift.startTime);
newStartTime.setDate(newStartTime.getDate() + 7);
const newEndTime = new Date(sourceShift.endTime);
newEndTime.setDate(newEndTime.getDate() + 7);
// Create new shift
const [newShift] = await tx
.insert(shifts)
.values({
siteId: sourceShift.siteId,
startTime: newStartTime,
endTime: newEndTime,
status: "planned",
vehicleId: sourceShift.vehicleId,
notes: sourceShift.notes,
})
.returning();
copiedShiftsCount++;
// 3. Copy all assignments for this shift
const sourceAssignments = await tx
.select()
.from(shiftAssignments)
.where(eq(shiftAssignments.shiftId, sourceShift.id));
for (const sourceAssignment of sourceAssignments) {
// Calculate new planned times (+7 days)
const newPlannedStart = new Date(sourceAssignment.plannedStartTime);
newPlannedStart.setDate(newPlannedStart.getDate() + 7);
const newPlannedEnd = new Date(sourceAssignment.plannedEndTime);
newPlannedEnd.setDate(newPlannedEnd.getDate() + 7);
// Create new assignment
await tx
.insert(shiftAssignments)
.values({
shiftId: newShift.id,
guardId: sourceAssignment.guardId,
plannedStartTime: newPlannedStart,
plannedEndTime: newPlannedEnd,
isArmedOnDuty: sourceAssignment.isArmedOnDuty,
assignedVehicleId: sourceAssignment.assignedVehicleId,
});
copiedAssignmentsCount++;
}
}
return { copiedShiftsCount, copiedAssignmentsCount };
});
res.json({
message: `Settimana copiata con successo: ${result.copiedShiftsCount} turni, ${result.copiedAssignmentsCount} assegnazioni`,
copiedShifts: result.copiedShiftsCount,
copiedAssignments: result.copiedAssignmentsCount,
});
} catch (error: any) {
console.error("❌ Error copying weekly shifts:", error);
res.status(500).json({
message: error.message || "Errore durante la copia dei turni settimanali",
error: String(error)
});
}
});
// Assign guard to site/date with specific time slot (supports multi-day assignments) // Assign guard to site/date with specific time slot (supports multi-day assignments)
app.post("/api/general-planning/assign-guard", isAuthenticated, async (req, res) => { app.post("/api/general-planning/assign-guard", isAuthenticated, async (req, res) => {
try { try {