/** * GET /api/par-region * Agrégation des marchés par région */ const express = require('express'); const router = express.Router(); const { getMarches } = require('../services/baserow'); const { isCloture, parseNum, formatMontant, getDelaiRestant, niveauAlerte, DELAI_ATTENTION, } = require('../services/calc'); const ALL_REGIONS = ['Gabes', 'Gafsa', 'Kebili', 'Medenine', 'Sfax', 'Tataouine', 'Tozeur']; router.get('/', async (req, res) => { try { const { nature, entrepreneur, statut } = req.query; const regionFilter = req.regionFilter; let rows = await getMarches(); // Filtres complémentaires if (nature) rows = rows.filter(r => String(r.nature || '').toLowerCase().includes(nature.toLowerCase())); if (entrepreneur) rows = rows.filter(r => String(r.entrepreneur || '').toLowerCase().includes(entrepreneur.toLowerCase())); if (statut) rows = rows.filter(r => String(r.statut || '').toLowerCase().includes(statut.toLowerCase())); const activeRows = rows.filter(r => !isCloture(r)); const regions = (regionFilter ? [regionFilter] : ALL_REGIONS).map(reg => { const regRows = activeRows.filter(r => (r.region || r.region_csc || '') === reg); const regTotal = rows.filter(r => (r.region || r.region_csc || '') === reg); const clotures = regTotal.filter(r => isCloture(r)).length; const budget = regRows.reduce((s, r) => s + parseNum(r.tot_marche ?? r.totmarche ?? r.montant), 0); const tauxList = regRows.map(r => parseNum(r.taux_phy ?? r.avt_phy)).filter(v => v > 0); const tauxMoyen = tauxList.length ? Math.round(tauxList.reduce((a, b) => a + b, 0) / tauxList.length * 10) / 10 : 0; const alertes = regRows .map(r => ({ ...r, _delai: getDelaiRestant(r) })) .filter(r => r._delai !== null && r._delai <= DELAI_ATTENTION) .map(r => ({ id: r.id, ref: r.ref || '', projet: r.projet || '', delai_restant: r._delai, niveau: niveauAlerte(r._delai) })) .sort((a, b) => a.delai_restant - b.delai_restant); const parNature = {}; for (const r of regRows) { const n = r.nature || 'Non défini'; parNature[n] = (parNature[n] || 0) + 1; } return { region: reg, actifs: regRows.length, clotures, total: regTotal.length, budget_raw: budget, budget: formatMontant(budget), taux_moyen: tauxMoyen, alertes_count: alertes.length, alertes_critique: alertes.filter(a => a.niveau === 'critique').length, alertes, par_nature: parNature, }; }); res.json({ count: regions.length, regions }); } catch (err) { res.status(502).json({ error: 'Erreur Baserow', detail: err.message }); } }); module.exports = router;