import { Request, Response } from 'express'; import { AppError } from '../errors/app-error'; import { changerStatutAnomalieResponsableService, deciderEcartResponsableService, getDashboardResponsable, listerAnomaliesResponsable, listerHistoriqueResponsable, listerNotificationsResponsable, listerMaterielsResponsable, listerEmpruntsResponsable, listerEcartsResponsable, marquerNotificationResponsableLue, marquerToutesNotificationsResponsableLues, parseAnomalieId, parseAnneeEmprunt, parseEmpruntId, parseCategorieId, parseLu, parseNotificationId, parseOrdreTri, parseDateQuery, parsePositiveIntQuery, parseStatutAnomalie, parseStatutMateriel, parseStatutEmprunt, parseTriEmprunt, } from '../services/responsable.service'; import { toAnomalieResponsableResponse, toDashboardResponsableResponse, toEmpruntResponsableResponse, toEcartResponsableResponse, toHistoriqueResponsableResponse, toMaterielResponsableResponse, toNotificationResponsableResponse, } from '../dtos/responsable.dto'; function asBodyObject(value: unknown): Record { if (typeof value !== 'object' || value === null || Array.isArray(value)) { throw new AppError(400, 'Corps de requete invalide'); } return value as Record; } function getHistoriqueFiltres(req: Request) { const action = typeof req.query.action === 'string' ? req.query.action : undefined; return { action, utilisateurId: parsePositiveIntQuery(req.query.utilisateurId, 'utilisateurId'), materielId: parsePositiveIntQuery(req.query.materielId, 'materielId'), empruntId: parsePositiveIntQuery(req.query.empruntId, 'empruntId'), dateDebut: parseDateQuery(req.query.dateDebut, 'dateDebut'), dateFin: parseDateQuery(req.query.dateFin, 'dateFin'), }; } function escapeCsv(value: string | number | Date | null): string { if (value === null) { return ''; } const raw = value instanceof Date ? value.toISOString() : String(value); return `"${raw.replace(/"/g, '""')}"`; } export async function getDashboard(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const dashboard = await getDashboardResponsable(user.id, user.roleCode, user.campusId); res.json({ data: toDashboardResponsableResponse(dashboard) }); } export async function getEmprunts(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const statut = parseStatutEmprunt(req.query.statut); const annee = parseAnneeEmprunt(req.query.annee); const recherche = typeof req.query.q === 'string' ? req.query.q.trim() : undefined; const tri = parseTriEmprunt(req.query.tri); const ordre = parseOrdreTri(req.query.ordre); const emprunts = await listerEmpruntsResponsable(user.roleCode, user.campusId, { statut, annee, recherche: recherche || undefined, tri, ordre, }); res.json({ data: emprunts.map(toEmpruntResponsableResponse) }); } export async function getEcarts(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const ecarts = await listerEcartsResponsable(user.roleCode, user.campusId); res.json({ data: ecarts.map(toEcartResponsableResponse) }); } export async function patchEcartDecision(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const empruntId = parseEmpruntId(req.params.id); const body = asBodyObject(req.body); if (body.decision !== 'CONFIRMER' && body.decision !== 'REFUSER') { throw new AppError(400, 'decision invalide'); } const observation = typeof body.observation === 'string' ? body.observation : undefined; const statutMateriel = parseStatutMateriel(body.statutMateriel); const ecart = await deciderEcartResponsableService( user.id, user.roleCode, user.campusId, empruntId, { decision: body.decision, observation, statutMateriel, }, ); res.json({ data: toEcartResponsableResponse(ecart) }); } export async function getMateriels(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const statut = parseStatutMateriel(req.query.statut); const categorieId = parseCategorieId(req.query.categorieId); const recherche = typeof req.query.q === 'string' ? req.query.q : undefined; const materiels = await listerMaterielsResponsable(user.roleCode, user.campusId, { statut, categorieId, recherche, }); res.json({ data: materiels.map(toMaterielResponsableResponse) }); } export async function getAnomalies(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const statut = parseStatutAnomalie(req.query.statut); const type = typeof req.query.type === 'string' ? req.query.type : undefined; const anomalies = await listerAnomaliesResponsable(user.roleCode, user.campusId, { statut, type, }); res.json({ data: anomalies.map(toAnomalieResponsableResponse) }); } export async function patchAnomalieStatut(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const anomalieId = parseAnomalieId(req.params.id); const body = asBodyObject(req.body); const statut = parseStatutAnomalie(body.statut); if (!statut) { throw new AppError(400, 'statut requis'); } const observation = typeof body.observation === 'string' ? body.observation : undefined; const anomalie = await changerStatutAnomalieResponsableService( user.id, user.roleCode, user.campusId, anomalieId, { statut, observation }, ); res.json({ data: toAnomalieResponsableResponse(anomalie) }); } export async function getNotifications(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const lu = parseLu(req.query.lu); const notifications = await listerNotificationsResponsable(user.id, user.roleCode, { lu }); res.json({ data: notifications.map(toNotificationResponsableResponse) }); } export async function patchNotificationLue(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const notificationId = parseNotificationId(req.params.id); const notification = await marquerNotificationResponsableLue( user.id, user.roleCode, notificationId, ); res.json({ data: toNotificationResponsableResponse(notification) }); } export async function patchNotificationsLues(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const count = await marquerToutesNotificationsResponsableLues(user.id, user.roleCode); res.json({ data: { count } }); } export async function getHistorique(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const historique = await listerHistoriqueResponsable( user.roleCode, user.campusId, getHistoriqueFiltres(req), ); res.json({ data: historique.map(toHistoriqueResponsableResponse) }); } export async function getHistoriqueCsv(req: Request, res: Response): Promise { const user = req.user; if (!user) { throw new AppError(401, 'Authentification requise'); } const historique = await listerHistoriqueResponsable( user.roleCode, user.campusId, getHistoriqueFiltres(req), ); const lignes = [ ['id', 'dateAction', 'action', 'description', 'utilisateur', 'email', 'materiel', 'empruntId'] .map(escapeCsv) .join(','), ...historique.map((item) => [ item.id, item.dateAction, item.action, item.description, `${item.utilisateur.prenom} ${item.utilisateur.nom}`, item.utilisateur.email, item.materiel ? `${item.materiel.nom} (${item.materiel.reference})` : null, item.empruntId, ] .map(escapeCsv) .join(','), ), ]; res.setHeader('Content-Type', 'text/csv; charset=utf-8'); res.setHeader('Content-Disposition', 'attachment; filename="historique-responsable.csv"'); res.send(lignes.join('\n')); }