/** * routes/modernisation.js * Vue "Succession des marchés Modernisation" * Croise table 856 (marchés actifs, nature=Modernisation) avec table 872 (AO en lancement) * Lien : region commune entre les deux tables */ const express = require('express'); const router = express.Router(); const { getMarches, getPipeline } = require('../services/baserow'); const { normalizeMarche, isCloture, selectVal } = require('../services/calc'); const ALL_REGIONS = ['Gabes','Gafsa','Kebili','Medenine','Sfax','Tataouine','Tozeur']; function isModernisation(r) { const nature = selectVal(r.nature); return nature && nature.toLowerCase().includes('moderni'); } function pipelineRegions(r) { const v = r['Regions'] || r.regions || []; if (!Array.isArray(v)) return []; return v.map(x => (typeof x === 'object' ? x.value : x)).filter(Boolean); } function phaseAO(r) { const now = new Date(); const limit = r['date-limite'] ? new Date(r['date-limite']) : null; const ouv = r['date-ouverture-adm-tech'] ? new Date(r['date-ouverture-adm-tech']) : null; const clos = r['date-cloture-evaluation'] ? new Date(r['date-cloture-evaluation']) : null; if (clos && now > clos) return { label:'Attribué', code:'attribue', color:'#6b7280' }; if (ouv && now > ouv) return { label:'Évaluation', code:'evaluation', color:'#8b5cf6' }; if (limit && now > limit) return { label:'Dépouillé', code:'depouille', color:'#f59e0b' }; if (limit) return { label:'Ouvert', code:'ouvert', color:'#10b981' }; return { label:'Préparation', code:'preparation', color:'#3b82f6' }; } function fmtDate(d) { if (!d) return null; const dt = new Date(d); if (isNaN(dt.getTime())) return String(d); return `${String(dt.getDate()).padStart(2,'0')}/${String(dt.getMonth()+1).padStart(2,'0')}/${dt.getFullYear()}`; } // GET /api/modernisation router.get('/', async (req, res) => { try { const [rawMarches, rawPipeline] = await Promise.all([getMarches(), getPipeline()]); // Marchés modernisation actifs par région (non clôturés) const modActifs = rawMarches .filter(r => !isCloture(r) && isModernisation(r)) .map(normalizeMarche); // Pour chaque région, construire la chaîne actuel → suivant const regions = ALL_REGIONS.map(reg => { const actuels = modActifs.filter(r => (r.region || '') === reg); const suivants = rawPipeline.filter(r => pipelineRegions(r).includes(reg)); return { region: reg, actuels: actuels.map(r => ({ ref: r.ref, projet: r.projet, entrepreneur: r.entrepreneur, taux_phy: r.taux_phy, taux_fin: r.taux_fin, date_fin: r.date_fin, delai_restant: r.delai_restant, montant: r.montant, statut: r.statut, })), suivants: suivants.map(r => ({ num_ao: r['num-ao'] || '', description: r['Description du projet'] || '', estimation: parseFloat(r.Estimation || 0) || 0, duree: r['Duree'] || '', date_limite: fmtDate(r['date-limite']), date_ouverture: fmtDate(r['date-ouverture-adm-tech']), date_evaluation: fmtDate(r['date-cloture-evaluation']), phase: phaseAO(r), jours_limite: r['date-limite'] ? Math.ceil((new Date(r['date-limite']) - new Date()) / 86400000) : null, })), }; }).filter(r => r.actuels.length > 0 || r.suivants.length > 0); res.json({ count: regions.length, regions }); } catch (err) { res.status(502).json({ error: 'Erreur modernisation', detail: err.message }); } }); module.exports = router;