From 1317781d7b74e17992ba9a17c1949b56c0ac43d2 Mon Sep 17 00:00:00 2001 From: donpat1to Date: Sun, 12 Oct 2025 20:52:48 +0200 Subject: [PATCH] can add and delete shiftplans from pressets --- backend/src/controllers/setupController.ts | 41 ++--- .../src/controllers/shiftPlanController.ts | 150 +++++++----------- .../src/models/defaults/shiftPlanDefaults.ts | 8 +- 3 files changed, 80 insertions(+), 119 deletions(-) diff --git a/backend/src/controllers/setupController.ts b/backend/src/controllers/setupController.ts index 8d50101..c2312c3 100644 --- a/backend/src/controllers/setupController.ts +++ b/backend/src/controllers/setupController.ts @@ -4,7 +4,7 @@ import bcrypt from 'bcrypt'; import { v4 as uuidv4 } from 'uuid'; import { randomUUID } from 'crypto'; import { db } from '../services/databaseService.js'; -import { initializeDefaultTemplates } from './shiftPlanController.js'; +//import { initializeDefaultTemplates } from './shiftPlanController.js'; export const checkSetupStatus = async (req: Request, res: Response): Promise => { try { @@ -15,7 +15,6 @@ export const checkSetupStatus = async (req: Request, res: Response): Promise => } const { password, name } = req.body; - const email = 'admin@instandhaltung.de'; // Fixed admin email + const email = 'admin@instandhaltung.de'; console.log('πŸ‘€ Creating admin with data:', { name, email }); @@ -68,6 +67,9 @@ export const setupAdmin = async (req: Request, res: Response): Promise => console.log('πŸ“ Inserting admin user with ID:', adminId); + // Start transaction for the entire setup process + await db.run('BEGIN TRANSACTION'); + try { // Create admin user await db.run( @@ -78,34 +80,35 @@ export const setupAdmin = async (req: Request, res: Response): Promise => console.log('βœ… Admin user created successfully'); + // Initialize default templates WITHOUT starting a new transaction + //console.log('πŸ”„ Initialisiere Standard-Vorlagen...'); + //await initializeDefaultTemplates(adminId, false); + + // Commit the entire setup transaction + await db.run('COMMIT'); + + console.log('βœ… Setup completed successfully'); + res.status(201).json({ success: true, message: 'Admin erfolgreich erstellt', email: email }); + } catch (dbError) { + await db.run('ROLLBACK'); console.error('❌ Database error during admin creation:', dbError); res.status(500).json({ error: 'Fehler beim Erstellen des Admin-Accounts' }); } - - // Nach erfolgreicher Admin-Erstellung: - console.log('πŸ”„ Initialisiere Standard-Vorlagen...'); - await initializeDefaultTemplates(adminId); - - console.log('βœ… Admin user created successfully with default templates'); - - res.status(201).json({ - success: true, - message: 'Admin erfolgreich erstellt', - email: email - }); - } catch (error) { console.error('❌ Error in setup:', error); - res.status(500).json({ - error: 'Ein unerwarteter Fehler ist aufgetreten' - }); + + if (!res.headersSent) { + res.status(500).json({ + error: 'Ein unerwarteter Fehler ist aufgetreten' + }); + } } }; \ No newline at end of file diff --git a/backend/src/controllers/shiftPlanController.ts b/backend/src/controllers/shiftPlanController.ts index f99b686..ac081cc 100644 --- a/backend/src/controllers/shiftPlanController.ts +++ b/backend/src/controllers/shiftPlanController.ts @@ -335,20 +335,20 @@ export const createFromPreset = async (req: Request, res: Response): Promise(); + // Create mapping from time slot names/IDs to database timeSlotId + const timeSlotMap = new Map(); // Insert time slots and create mapping - for (let i = 0; i < planRequest.timeSlots.length; i++) { - const timeSlot = planRequest.timeSlots[i]; - const presetTimeSlot = TEMPLATE_PRESETS[presetName as keyof typeof TEMPLATE_PRESETS].timeSlots[i]; + for (const timeSlot of preset.timeSlots) { const timeSlotId = uuidv4(); await db.run( @@ -378,17 +376,45 @@ export const createFromPreset = async (req: Request, res: Response): Promise ${timeSlotId}`); } + console.log(`πŸ” Time slot mapping:`, Array.from(timeSlotMap.entries())); + // Insert shifts using the mapping - for (const shift of planRequest.shifts) { + let shiftCount = 0; + for (const shift of preset.shifts) { const shiftId = uuidv4(); - const timeSlotId = timeSlotKeyToId.get((shift as any).timeSlotKey); + + // Try to find the timeSlotId using different strategies + let timeSlotId = timeSlotMap.get(shift.timeSlotId); if (!timeSlotId) { - throw new Error(`Time slot key ${(shift as any).timeSlotKey} not found in mapping`); + // Fallback: try to find by name or other properties + console.warn(`⚠️ Time slot not found by ID: ${shift.timeSlotId}, trying fallback...`); + + // Look for time slot by name or other matching logic + for (const [key, value] of timeSlotMap.entries()) { + if (key.includes(shift.timeSlotId) || shift.timeSlotId.includes(key)) { + timeSlotId = value; + console.log(`βœ… Found time slot via fallback: ${shift.timeSlotId} -> ${key} -> ${timeSlotId}`); + break; + } + } + } + + if (!timeSlotId) { + console.error(`❌ Could not find time slot for shift:`, shift); + // Use first time slot as fallback + timeSlotId = Array.from(timeSlotMap.values())[0]; + console.log(`πŸ”„ Using first time slot as fallback: ${timeSlotId}`); } await db.run( @@ -396,26 +422,33 @@ export const createFromPreset = async (req: Request, res: Response): Promise => { - try { - console.log('πŸ”„ Initialisiere Standard-Vorlagen...'); - - // Check if templates already exist - const existingTemplates = await db.all( - 'SELECT COUNT(*) as count FROM shift_plans WHERE is_template = 1' - ); - - if (existingTemplates[0].count > 0) { - console.log('βœ… Vorlagen existieren bereits'); - return; - } - - await db.run('BEGIN TRANSACTION'); - - try { - // Create all template presets from shiftPlanDefaults - for (const [presetKey, preset] of Object.entries(TEMPLATE_PRESETS)) { - const planId = uuidv4(); - - // Create the template plan - await db.run( - `INSERT INTO shift_plans (id, name, description, is_template, status, created_by) - VALUES (?, ?, ?, ?, ?, ?)`, - [planId, preset.name, preset.description, true, 'template', userId] - ); - - // Create time slots with new UUIDs - const timeSlotMap = new Map(); // Map original timeSlotId to new UUID - - for (const timeSlot of preset.timeSlots) { - const newTimeSlotId = uuidv4(); - await db.run( - `INSERT INTO time_slots (id, plan_id, name, start_time, end_time, description) - VALUES (?, ?, ?, ?, ?, ?)`, - [newTimeSlotId, planId, timeSlot.name, timeSlot.startTime, timeSlot.endTime, timeSlot.description || ''] - ); - - // Store mapping from original timeSlotId to new UUID - timeSlotMap.set((timeSlot as any).timeSlotId || timeSlot.name, newTimeSlotId); - } - - // Create shifts using the time slot mapping - for (const shift of preset.shifts) { - const shiftId = uuidv4(); - const timeSlotId = timeSlotMap.get(shift.timeSlotId); - - if (timeSlotId) { - await db.run( - `INSERT INTO shifts (id, plan_id, day_of_week, time_slot_id, required_employees, color) - VALUES (?, ?, ?, ?, ?, ?)`, - [shiftId, planId, shift.dayOfWeek, timeSlotId, shift.requiredEmployees, shift.color || '#3498db'] - ); - } - } - - console.log(`βœ… Vorlage erstellt: ${preset.name}`); - } - - await db.run('COMMIT'); - console.log('βœ… Alle Standard-Vorlagen wurden initialisiert'); - - } catch (error) { - await db.run('ROLLBACK'); - throw error; - } - - } catch (error) { - console.error('❌ Fehler beim Initialisieren der Vorlagen:', error); - throw error; - } }; \ No newline at end of file diff --git a/backend/src/models/defaults/shiftPlanDefaults.ts b/backend/src/models/defaults/shiftPlanDefaults.ts index 67bda6f..33a3980 100644 --- a/backend/src/models/defaults/shiftPlanDefaults.ts +++ b/backend/src/models/defaults/shiftPlanDefaults.ts @@ -71,7 +71,7 @@ export const TEMPLATE_PRESETS = { timeSlots: DEFAULT_ZEBRA_TIME_SLOTS, shifts: DEFAULT_ZEBRA_SHIFTS }, - ZEBRA_MINIMAL: { + /*ZEBRA_MINIMAL: { name: 'ZEBRA Minimal', description: 'ZEBRA mit minimaler Besetzung', timeSlots: DEFAULT_ZEBRA_TIME_SLOTS, @@ -92,14 +92,14 @@ export const TEMPLATE_PRESETS = { { timeSlotId: 'afternoon', dayOfWeek: day, requiredEmployees: 3, color: '#e74c3c' } ]) ] - }, + },*/ GENERAL_STANDARD: { name: 'Standard Wochenplan', description: 'Standard Vorlage: Mo-Fr Vormittag+Nachmittag+Abend', timeSlots: DEFAULT_TIME_SLOTS, shifts: DEFAULT_SHIFTS }, - ZEBRA_PART_TIME: { + /*ZEBRA_PART_TIME: { name: 'ZEBRA Teilzeit', description: 'ZEBRA Vorlage mit reduzierten Schichten', timeSlots: DEFAULT_ZEBRA_TIME_SLOTS, @@ -109,7 +109,7 @@ export const TEMPLATE_PRESETS = { timeSlotId: 'morning', dayOfWeek: day, requiredEmployees: 1, color: '#3498db' })) ] - } + }*/ } as const; // Helper function to create plan from preset