diff --git a/.replit b/.replit index 90b1d94..e7887ba 100644 --- a/.replit +++ b/.replit @@ -19,6 +19,10 @@ externalPort = 80 localPort = 33035 externalPort = 3001 +[[ports]] +localPort = 33123 +externalPort = 5173 + [[ports]] localPort = 41343 externalPort = 3000 diff --git a/server/routes.ts b/server/routes.ts index 48c0ea6..7c492af 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -2153,6 +2153,275 @@ export async function registerRoutes(app: Express): Promise { } }); + // ============= DEV UTILITIES (Reset & Seed Data) ============= + + // DELETE all sites and guards (for testing) + app.delete("/api/dev/reset-data", isAuthenticated, async (req, res) => { + try { + // Delete all shift assignments first (foreign key constraints) + await db.delete(shiftAssignments); + + // Delete all shifts + await db.delete(shifts); + + // Delete all sites + await db.delete(sites); + + // Delete all certifications + await db.delete(certifications); + + // Delete all guards + await db.delete(guards); + + // Delete all vehicles + await db.delete(vehicles); + + res.json({ + success: true, + message: "Tutti i dati (siti, guardie, turni, veicoli) sono stati eliminati" + }); + } catch (error) { + console.error("Error resetting data:", error); + res.status(500).json({ message: "Errore durante reset dati" }); + } + }); + + // Create sample data (3 sites Milano + 3 Roccapiemonte, 10 guards each) + app.post("/api/dev/seed-data", isAuthenticated, async (req, res) => { + try { + // Create service types first + const [serviceTypePresidioFisso] = await db.insert(serviceTypes).values({ + name: "Presidio Fisso", + description: "Servizio di presidio fisso con guardia armata", + shiftType: "fixed_post", + fixedPostHours: 24, + }).returning(); + + const [serviceTypePattuglia] = await db.insert(serviceTypes).values({ + name: "Pattuglia Mobile", + description: "Servizio di pattuglia mobile con passaggi programmati", + shiftType: "patrol", + patrolPassages: 4, + }).returning(); + + // Create 3 sites for Milano + const [siteMilano1] = await db.insert(sites).values({ + name: "Banca Centrale Milano", + address: "Via Dante 45, Milano", + city: "Milano", + location: "milano", + serviceTypeId: serviceTypePresidioFisso.id, + shiftType: "fixed_post", + requiresArmed: true, + requiresDriverLicense: false, + minGuardsRequired: 1, + serviceStartTime: "00:00", + serviceEndTime: "24:00", + contractReference: "CTR-MI-001-2025", + contractStartDate: "2025-01-01", + contractEndDate: "2025-12-31", + }).returning(); + + const [siteMilano2] = await db.insert(sites).values({ + name: "Museo Arte Moderna Milano", + address: "Corso Magenta 12, Milano", + city: "Milano", + location: "milano", + serviceTypeId: serviceTypePattuglia.id, + shiftType: "patrol", + requiresArmed: false, + requiresDriverLicense: true, + minGuardsRequired: 1, + serviceStartTime: "08:00", + serviceEndTime: "20:00", + contractReference: "CTR-MI-002-2025", + contractStartDate: "2025-01-01", + contractEndDate: "2025-06-30", + }).returning(); + + const [siteMilano3] = await db.insert(sites).values({ + name: "Centro Commerciale Porta Nuova", + address: "Piazza Gae Aulenti 1, Milano", + city: "Milano", + location: "milano", + serviceTypeId: serviceTypePresidioFisso.id, + shiftType: "fixed_post", + requiresArmed: true, + requiresDriverLicense: false, + minGuardsRequired: 2, + serviceStartTime: "06:00", + serviceEndTime: "22:00", + contractReference: "CTR-MI-003-2025", + contractStartDate: "2025-01-01", + contractEndDate: "2025-12-31", + }).returning(); + + // Create 3 sites for Roccapiemonte + const [siteRocca1] = await db.insert(sites).values({ + name: "Deposito Logistica Roccapiemonte", + address: "Via Industriale 23, Roccapiemonte", + city: "Roccapiemonte", + location: "roccapiemonte", + serviceTypeId: serviceTypePresidioFisso.id, + shiftType: "fixed_post", + requiresArmed: true, + requiresDriverLicense: false, + minGuardsRequired: 1, + serviceStartTime: "00:00", + serviceEndTime: "24:00", + contractReference: "CTR-RC-001-2025", + contractStartDate: "2025-01-01", + contractEndDate: "2025-12-31", + }).returning(); + + const [siteRocca2] = await db.insert(sites).values({ + name: "Cantiere Edile Salerno Nord", + address: "SS 18 km 45, Roccapiemonte", + city: "Roccapiemonte", + location: "roccapiemonte", + serviceTypeId: serviceTypePattuglia.id, + shiftType: "patrol", + requiresArmed: false, + requiresDriverLicense: true, + minGuardsRequired: 1, + serviceStartTime: "18:00", + serviceEndTime: "06:00", + contractReference: "CTR-RC-002-2025", + contractStartDate: "2025-01-15", + contractEndDate: "2025-07-15", + }).returning(); + + const [siteRocca3] = await db.insert(sites).values({ + name: "Stabilimento Farmaceutico", + address: "Via delle Industrie 89, Roccapiemonte", + city: "Roccapiemonte", + location: "roccapiemonte", + serviceTypeId: serviceTypePresidioFisso.id, + shiftType: "fixed_post", + requiresArmed: true, + requiresDriverLicense: false, + minGuardsRequired: 2, + serviceStartTime: "00:00", + serviceEndTime: "24:00", + contractReference: "CTR-RC-003-2025", + contractStartDate: "2025-01-01", + contractEndDate: "2025-12-31", + }).returning(); + + // Create 10 guards for Milano + const milanNames = [ + { firstName: "Marco", lastName: "Rossi", badgeNumber: "MI-001" }, + { firstName: "Giulia", lastName: "Bianchi", badgeNumber: "MI-002" }, + { firstName: "Luca", lastName: "Ferrari", badgeNumber: "MI-003" }, + { firstName: "Sara", lastName: "Romano", badgeNumber: "MI-004" }, + { firstName: "Andrea", lastName: "Colombo", badgeNumber: "MI-005" }, + { firstName: "Elena", lastName: "Ricci", badgeNumber: "MI-006" }, + { firstName: "Francesco", lastName: "Marino", badgeNumber: "MI-007" }, + { firstName: "Chiara", lastName: "Greco", badgeNumber: "MI-008" }, + { firstName: "Matteo", lastName: "Bruno", badgeNumber: "MI-009" }, + { firstName: "Alessia", lastName: "Gallo", badgeNumber: "MI-010" }, + ]; + + for (let i = 0; i < milanNames.length; i++) { + await db.insert(guards).values({ + ...milanNames[i], + location: "milano", + isArmed: i % 2 === 0, // Alternare armati/non armati + hasDriverLicense: i % 3 === 0, // 1 su 3 con patente + hasFireSafety: true, + hasFirstAid: i % 2 === 1, + phone: `+39 333 ${String(i).padStart(3, '0')}${String(i).padStart(4, '0')}`, + email: `${milanNames[i].firstName.toLowerCase()}.${milanNames[i].lastName.toLowerCase()}@vigilanza.it`, + }); + } + + // Create 10 guards for Roccapiemonte + const roccaNames = [ + { firstName: "Antonio", lastName: "Esposito", badgeNumber: "RC-001" }, + { firstName: "Maria", lastName: "De Luca", badgeNumber: "RC-002" }, + { firstName: "Giuseppe", lastName: "Russo", badgeNumber: "RC-003" }, + { firstName: "Anna", lastName: "Costa", badgeNumber: "RC-004" }, + { firstName: "Vincenzo", lastName: "Ferrara", badgeNumber: "RC-005" }, + { firstName: "Rosa", lastName: "Gatti", badgeNumber: "RC-006" }, + { firstName: "Salvatore", lastName: "Leone", badgeNumber: "RC-007" }, + { firstName: "Lucia", lastName: "Longo", badgeNumber: "RC-008" }, + { firstName: "Michele", lastName: "Martino", badgeNumber: "RC-009" }, + { firstName: "Carmela", lastName: "Moretti", badgeNumber: "RC-010" }, + ]; + + for (let i = 0; i < roccaNames.length; i++) { + await db.insert(guards).values({ + ...roccaNames[i], + location: "roccapiemonte", + isArmed: i % 2 === 0, + hasDriverLicense: i % 3 === 0, + hasFireSafety: true, + hasFirstAid: i % 2 === 1, + phone: `+39 333 ${String(i + 10).padStart(3, '0')}${String(i + 10).padStart(4, '0')}`, + email: `${roccaNames[i].firstName.toLowerCase()}.${roccaNames[i].lastName.toLowerCase()}@vigilanza.it`, + }); + } + + // Create 5 vehicles for Milano + const vehiclesMilano = [ + { licensePlate: "MI123AB", brand: "Fiat", model: "Ducato", vehicleType: "van" as const }, + { licensePlate: "MI456CD", brand: "Volkswagen", model: "Transporter", vehicleType: "van" as const }, + { licensePlate: "MI789EF", brand: "Ford", model: "Transit", vehicleType: "van" as const }, + { licensePlate: "MI012GH", brand: "Renault", model: "Kangoo", vehicleType: "car" as const }, + { licensePlate: "MI345IJ", brand: "Opel", model: "Vivaro", vehicleType: "van" as const }, + ]; + + for (const vehicle of vehiclesMilano) { + await db.insert(vehicles).values({ + ...vehicle, + location: "milano", + year: 2022, + status: "available", + }); + } + + // Create 5 vehicles for Roccapiemonte + const vehiclesRocca = [ + { licensePlate: "SA123AB", brand: "Fiat", model: "Ducato", vehicleType: "van" as const }, + { licensePlate: "SA456CD", brand: "Volkswagen", model: "Caddy", vehicleType: "car" as const }, + { licensePlate: "SA789EF", brand: "Ford", model: "Transit", vehicleType: "van" as const }, + { licensePlate: "SA012GH", brand: "Renault", model: "Master", vehicleType: "van" as const }, + { licensePlate: "SA345IJ", brand: "Peugeot", model: "Partner", vehicleType: "car" as const }, + ]; + + for (const vehicle of vehiclesRocca) { + await db.insert(vehicles).values({ + ...vehicle, + location: "roccapiemonte", + year: 2023, + status: "available", + }); + } + + res.json({ + success: true, + message: "Dati di esempio creati con successo", + summary: { + sites: { + milano: 3, + roccapiemonte: 3, + }, + guards: { + milano: 10, + roccapiemonte: 10, + }, + vehicles: { + milano: 5, + roccapiemonte: 5, + }, + }, + }); + } catch (error) { + console.error("Error seeding data:", error); + res.status(500).json({ message: "Errore durante creazione dati di esempio" }); + } + }); + const httpServer = createServer(app); return httpServer; }