const admin = require("firebase-admin"); const db = admin.firestore(); const logger = require("firebase-functions/logger"); const auth = require("../utils/auth"); const helpers = require("../utils/helpers"); // Créer une maintenance exports.createMaintenance = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_maintenances"); if (!hasAccess) { res.status(403).json({error: "Forbidden: Requires manage_maintenances permission"}); return; } const maintenanceData = req.body.data; const dataToSave = helpers.deserializeTimestamps(maintenanceData, [ "scheduledDate", "completedDate", "createdAt", "updatedAt", ]); const docRef = await db.collection("maintenances").add(dataToSave); const maintenanceId = docRef.id; if (maintenanceData.equipmentIds && Array.isArray(maintenanceData.equipmentIds)) { for (const equipmentId of maintenanceData.equipmentIds) { try { const equipmentDoc = await db.collection("equipments").doc(equipmentId).get(); if (equipmentDoc.exists) { const equipmentData = equipmentDoc.data(); const maintenanceIds = equipmentData.maintenanceIds || []; if (!maintenanceIds.includes(maintenanceId)) { maintenanceIds.push(maintenanceId); await db.collection("equipments").doc(equipmentId).update({ maintenanceIds: maintenanceIds, }); } } if (maintenanceData.scheduledDate) { const scheduledDate = maintenanceData.scheduledDate.toDate ? maintenanceData.scheduledDate.toDate() : new Date(maintenanceData.scheduledDate); const sevenDaysFromNow = new Date(); sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7); if (scheduledDate <= sevenDaysFromNow) { const existingAlerts = await db.collection("alerts") .where("equipmentId", "==", equipmentId) .where("type", "==", "maintenanceDue") .where("isRead", "==", false) .get(); let alertExists = false; for (const alertDoc of existingAlerts.docs) { const alertData = alertDoc.data(); if (alertData.message && alertData.message.includes(maintenanceData.name || "")) { alertExists = true; break; } } if (!alertExists) { const equipmentName = equipmentDoc.exists ? (equipmentDoc.data().name || equipmentId) : equipmentId; const daysUntil = Math.ceil((scheduledDate - new Date()) / (1000 * 60 * 60 * 24)); await db.collection("alerts").add({ type: "maintenanceDue", message: `Maintenance "${maintenanceData.name || "Sans nom"}" prévue dans ${daysUntil} jour(s) pour ${equipmentName}`, equipmentId: equipmentId, createdAt: admin.firestore.Timestamp.now(), isRead: false, }); } } } } catch (err) { logger.error(`Error updating equipment ${equipmentId} for maintenance:`, err); } } } res.status(201).json({id: maintenanceId, message: "Maintenance created successfully"}); } catch (error) { logger.error("Error creating maintenance:", error); res.status(500).json({error: error.message}); } }; // Mettre à jour une maintenance exports.updateMaintenance = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_maintenances"); if (!hasAccess) { res.status(403).json({error: "Forbidden: Requires manage_maintenances permission"}); return; } const {maintenanceId, data} = req.body.data; if (!maintenanceId) { res.status(400).json({error: "Maintenance ID is required"}); return; } delete data.id; data.updatedAt = admin.firestore.Timestamp.now(); const dataToSave = helpers.deserializeTimestamps(data, [ "scheduledDate", "completedDate", ]); await db.collection("maintenances").doc(maintenanceId).update(dataToSave); res.status(200).json({message: "Maintenance updated successfully"}); } catch (error) { logger.error("Error updating maintenance:", error); res.status(500).json({error: error.message}); } }; // Récupérer toutes les maintenances exports.getMaintenances = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const {equipmentId} = req.body.data || {}; const canView = await auth.hasPermission(decodedToken.uid, "view_equipment"); if (!canView) { res.status(403).json({error: "Forbidden: Requires equipment permissions"}); return; } let query = db.collection("maintenances"); if (equipmentId) { query = query.where("equipmentIds", "array-contains", equipmentId); } const snapshot = await query.get(); const maintenances = snapshot.docs.map((doc) => { const data = doc.data(); return { id: doc.id, ...helpers.serializeTimestamps(data, ["scheduledDate", "completedDate", "createdAt", "updatedAt"]), }; }); res.status(200).json({maintenances}); } catch (error) { logger.error("Error fetching maintenances:", error); res.status(500).json({error: error.message}); } }; // Supprimer une maintenance exports.deleteMaintenance = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const canManage = await auth.hasPermission(decodedToken.uid, "manage_equipment"); if (!canManage) { res.status(403).json({error: "Forbidden: Requires manage_equipment permission"}); return; } const maintenanceId = req.body.data?.maintenanceId; if (!maintenanceId) { res.status(400).json({error: "maintenanceId is required"}); return; } const maintenanceDoc = await db.collection("maintenances").doc(maintenanceId).get(); if (maintenanceDoc.exists) { const maintenance = maintenanceDoc.data(); if (maintenance.equipmentIds) { for (const equipmentId of maintenance.equipmentIds) { const equipmentDoc = await db.collection("equipments").doc(equipmentId).get(); if (equipmentDoc.exists) { const equipmentData = equipmentDoc.data(); const maintenanceIds = (equipmentData.maintenanceIds || []).filter((id) => id !== maintenanceId); await db.collection("equipments").doc(equipmentId).update({maintenanceIds}); } } } } await db.collection("maintenances").doc(maintenanceId).delete(); res.status(200).json({success: true}); } catch (error) { logger.error("Error deleting maintenance:", error); res.status(500).json({error: error.message}); } }; /** * Vérifier les maintenances à venir et créer des alertes */ exports.checkUpcomingMaintenances = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_equipment"); if (!hasAccess) { res.status(403).json({error: "Forbidden: Requires manage_equipment permission"}); return; } const sevenDaysFromNow = new Date(); sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7); const now = admin.firestore.Timestamp.now(); const sevenDaysTimestamp = admin.firestore.Timestamp.fromDate(sevenDaysFromNow); // Récupérer les maintenances planifiées dans les 7 prochains jours const maintenancesSnapshot = await db.collection("maintenances") .where("scheduledDate", "<=", sevenDaysTimestamp) .where("scheduledDate", ">=", now) .get(); const alertsCreated = []; for (const doc of maintenancesSnapshot.docs) { const maintenance = doc.data(); // Vérifier si une alerte existe déjà pour cette maintenance const existingAlertSnapshot = await db.collection("alerts") .where("type", "==", "MAINTENANCE_DUE") .where("relatedMaintenanceId", "==", doc.id) .get(); if (existingAlertSnapshot.empty) { // Créer une nouvelle alerte const alertData = { type: "MAINTENANCE_DUE", title: `Maintenance à venir`, message: `Une maintenance est prévue pour ${maintenance.equipmentIds?.length || 0} équipement(s)`, severity: "MEDIUM", isRead: false, relatedMaintenanceId: doc.id, createdAt: admin.firestore.Timestamp.now(), }; const alertRef = await db.collection("alerts").add(alertData); alertsCreated.push({id: alertRef.id, ...alertData}); } } res.status(200).json({ success: true, alertsCreated: alertsCreated.length, alerts: alertsCreated, }); } catch (error) { logger.error("Error checking upcoming maintenances:", error); res.status(500).json({error: error.message}); } }; /** * Compléter une maintenance */ exports.completeMaintenance = async (req, res) => { try { const decodedToken = await auth.authenticateUser(req); const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_equipment"); if (!hasAccess) { res.status(403).json({error: "Forbidden: Requires manage_equipment permission"}); return; } const {maintenanceId, performedBy, cost} = req.body.data; if (!maintenanceId) { res.status(400).json({error: "maintenanceId is required"}); return; } const now = admin.firestore.Timestamp.now(); const updateData = { completedDate: now, updatedAt: now, }; if (performedBy) { updateData.performedBy = performedBy; } if (cost !== undefined && cost !== null) { updateData.cost = cost; } // Mettre à jour la maintenance await db.collection("maintenances").doc(maintenanceId).update(updateData); // Récupérer la maintenance pour mettre à jour les équipements const maintenanceDoc = await db.collection("maintenances").doc(maintenanceId).get(); const maintenanceData = maintenanceDoc.data(); // Mettre à jour la date de dernière maintenance des équipements if (maintenanceData && maintenanceData.equipmentIds) { const updatePromises = maintenanceData.equipmentIds.map((equipmentId) => db.collection("equipments").doc(equipmentId).update({ lastMaintenanceDate: now, updatedAt: now, }), ); await Promise.all(updatePromises); } res.status(200).json({success: true}); } catch (error) { logger.error("Error completing maintenance:", error); res.status(500).json({error: error.message}); } };