Compare commits

..

3 Commits

Author SHA1 Message Date
Marco Lanzara
fc63a3a081 🚀 Release v1.0.45
- Tipo: patch
- Database backup: database-backups/vigilanzaturni_v1.0.45_20251023_145254.sql.gz
- Data: 2025-10-23 14:53:12
2025-10-23 14:53:12 +00:00
marco370
ef7b7f8723 Add functionality to assign guards to patrol and fixed services
Implement logic to prevent assigning a guard to both patrol and fixed services simultaneously.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/ZaT6tFl
2025-10-23 14:51:39 +00:00
marco370
62b5cb997f Add patrol routes and related entities for guard scheduling
Introduces new database tables and relations for `patrolRoutes`, `patrolRouteStops`, and updates `shiftAssignments` with new fields like `isArmedOnDuty` and `assignedVehicleId`. Also updates relations for `guards` and `sites`.

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/ZaT6tFl
2025-10-23 14:51:16 +00:00
4 changed files with 92 additions and 2 deletions

View File

@ -297,6 +297,50 @@ export const shiftAssignments = pgTable("shift_assignments", {
// Actual check-in/out times (recorded when guard clocks in/out)
checkInTime: timestamp("check_in_time"),
checkOutTime: timestamp("check_out_time"),
// Dotazioni operative per questo turno specifico
isArmedOnDuty: boolean("is_armed_on_duty").default(false), // Guardia armata per questo turno
assignedVehicleId: varchar("assigned_vehicle_id").references(() => vehicles.id, { onDelete: "set null" }), // Automezzo assegnato
});
// ============= PATROL ROUTES (TURNI PATTUGLIA) =============
export const patrolRoutes = pgTable("patrol_routes", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
guardId: varchar("guard_id").notNull().references(() => guards.id, { onDelete: "cascade" }),
// Data e orari del turno pattuglia
shiftDate: date("shift_date").notNull(), // Data del turno
startTime: varchar("start_time").notNull(), // Orario inizio (HH:MM)
endTime: varchar("end_time").notNull(), // Orario fine (HH:MM)
status: shiftStatusEnum("status").notNull().default("planned"),
location: locationEnum("location").notNull(), // Sede di riferimento
// Dotazioni
vehicleId: varchar("vehicle_id").references(() => vehicles.id, { onDelete: "set null" }),
isArmedRoute: boolean("is_armed_route").default(false), // Percorso con guardia armata
notes: text("notes"),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),
});
export const patrolRouteStops = pgTable("patrol_route_stops", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
patrolRouteId: varchar("patrol_route_id").notNull().references(() => patrolRoutes.id, { onDelete: "cascade" }),
siteId: varchar("site_id").notNull().references(() => sites.id, { onDelete: "cascade" }),
sequenceOrder: integer("sequence_order").notNull(), // Ordine nel percorso (1, 2, 3...)
estimatedArrivalTime: varchar("estimated_arrival_time"), // Orario stimato arrivo (HH:MM)
actualArrivalTime: timestamp("actual_arrival_time"), // Orario effettivo arrivo
// Check completamento tappa
isCompleted: boolean("is_completed").default(false),
completedAt: timestamp("completed_at"),
notes: text("notes"), // Note specifiche per questa tappa
createdAt: timestamp("created_at").defaultNow(),
});
// ============= CCNL SETTINGS =============
@ -518,6 +562,7 @@ export const guardsRelations = relations(guards, ({ one, many }) => ({
}),
certifications: many(certifications),
shiftAssignments: many(shiftAssignments),
patrolRoutes: many(patrolRoutes),
constraints: one(guardConstraints),
sitePreferences: many(sitePreferences),
trainingCourses: many(trainingCourses),
@ -549,6 +594,7 @@ export const sitesRelations = relations(sites, ({ one, many }) => ({
references: [customers.id],
}),
shifts: many(shifts),
patrolRouteStops: many(patrolRouteStops),
preferences: many(sitePreferences),
}));
@ -573,6 +619,33 @@ export const shiftAssignmentsRelations = relations(shiftAssignments, ({ one }) =
fields: [shiftAssignments.guardId],
references: [guards.id],
}),
assignedVehicle: one(vehicles, {
fields: [shiftAssignments.assignedVehicleId],
references: [vehicles.id],
}),
}));
export const patrolRoutesRelations = relations(patrolRoutes, ({ one, many }) => ({
guard: one(guards, {
fields: [patrolRoutes.guardId],
references: [guards.id],
}),
vehicle: one(vehicles, {
fields: [patrolRoutes.vehicleId],
references: [vehicles.id],
}),
stops: many(patrolRouteStops),
}));
export const patrolRouteStopsRelations = relations(patrolRouteStops, ({ one }) => ({
patrolRoute: one(patrolRoutes, {
fields: [patrolRouteStops.patrolRouteId],
references: [patrolRoutes.id],
}),
site: one(sites, {
fields: [patrolRouteStops.siteId],
references: [sites.id],
}),
}));
export const notificationsRelations = relations(notifications, ({ one }) => ({
@ -731,6 +804,17 @@ export const insertShiftSchema = createInsertSchema(shifts).omit({
updatedAt: true,
});
export const insertPatrolRouteSchema = createInsertSchema(patrolRoutes).omit({
id: true,
createdAt: true,
updatedAt: true,
});
export const insertPatrolRouteStopSchema = createInsertSchema(patrolRouteStops).omit({
id: true,
createdAt: true,
});
// Form schema that accepts datetime strings and transforms to Date
export const insertShiftFormSchema = z.object({
siteId: z.string().min(1, "Sito obbligatorio"),

View File

@ -1,7 +1,13 @@
{
"version": "1.0.44",
"lastUpdate": "2025-10-23T14:38:03.431Z",
"version": "1.0.45",
"lastUpdate": "2025-10-23T14:53:12.164Z",
"changelog": [
{
"version": "1.0.45",
"date": "2025-10-23",
"type": "patch",
"description": "Deployment automatico v1.0.45"
},
{
"version": "1.0.44",
"date": "2025-10-23",