From 57e9449a5891759249e15a8d87736b450764de4d Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Sun, 26 Apr 2026 09:28:51 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20nomenclature=20CA=20-=20valeurs=20absolu?= =?UTF-8?q?es,=20GenreMvt=20IN(3,4,9),=20travers=C3=A9e=20hi=C3=A9rarchie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CA était négatif (MntMvtTTC brut) → filtre mntmvtttc < 0 + ABS comme le endpoint /ca - GenreMvt=3 uniquement → IN(3,4,9) - Niveau 1/2 retournait vide (articles au niveau 3) → remontée via chemin_pere chemin_pere = "no_id_niv1.no_id_niv2" → SPLIT_PART + JOIN NOMENCLATURE parent - Ajout taux_marge dans la réponse Co-Authored-By: Claude Sonnet 4.6 --- src/routes/performance.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/routes/performance.js b/src/routes/performance.js index e1bcd4b..dba6a3f 100644 --- a/src/routes/performance.js +++ b/src/routes/performance.js @@ -91,33 +91,44 @@ router.get('/hitparade', async (req, res) => { }); // GET /api/performance/ca/nomenclature?dateDebut=&dateFin=&site=&niveau= +// Articles sont stockés au niveau 3. Pour niveau=1 ou 2, on remonte via chemin_pere (format "noid_niv1.noid_niv2"). router.get('/ca/nomenclature', async (req, res) => { try { const pool = getPool(); const { dateDebut = '2024-01-01', dateFin = '2099-12-31', site = '', niveau = 1 } = req.query; + const niv = Math.max(1, Math.min(parseInt(niveau) || 1, 3)); + + // Pour niveau 1 ou 2 : remonter la hiérarchie via chemin_pere de la nomenclature niveau 3 + // chemin_pere = "no_id_niv1.no_id_niv2" → SPLIT_PART(..., niv) + const joinNom = niv === 3 + ? `JOIN NOMENCLATURE n ON n.NO_ID = a.NOM_NO_ID` + : `JOIN NOMENCLATURE n3 ON n3.NO_ID = a.NOM_NO_ID + JOIN NOMENCLATURE n ON n.NO_ID = NULLIF(SPLIT_PART(n3.chemin_pere, '.', ${niv}), '')::bigint`; const result = await pool.query(` SELECT - n.CODE AS CODE_NOMEN, + n.CODE AS code_nomen, n.LIBELLE, - n.NIVEAU, - COUNT(DISTINCT m.ArtNoId) AS NB_ARTICLES, - SUM(m.QteMvt) AS QTE_VENDUE, - SUM(m.MntMvtHt) AS CA_HT, - SUM(m.MntMvtTTC) AS CA_TTC, - SUM(m.MargeMvt) AS MARGE + ${niv} AS niveau, + COUNT(DISTINCT m.ArtNoId) AS nb_articles, + ABS(SUM(CASE WHEN m.mntmvtttc < 0 THEN m.qtemvt ELSE 0 END)) AS qte_vendue, + ABS(SUM(CASE WHEN m.mntmvtttc < 0 THEN m.mntmvtht ELSE 0 END)) AS ca_ht, + ABS(SUM(CASE WHEN m.mntmvtttc < 0 THEN m.mntmvtttc ELSE 0 END)) AS ca_ttc, + SUM(m.MargeMvt) AS marge, + CASE WHEN SUM(m.mntmvtht) != 0 + THEN ROUND(SUM(m.margemvt) / ABS(SUM(m.mntmvtht)) * 100, 2) + ELSE 0 END AS taux_marge FROM MvtArt m JOIN ARTICLES a ON a.NO_ID = m.ArtNoId - JOIN NOMENCLATURE n ON n.NO_ID = a.NOM_NO_ID - WHERE m.GenreMvt = 3 + ${joinNom} + WHERE m.GenreMvt IN (3, 4, 9) AND m.DatMvt BETWEEN $1 AND $2 AND m.Site LIKE $3 - AND n.NIVEAU = $4 - GROUP BY n.CODE, n.LIBELLE, n.NIVEAU - ORDER BY CA_TTC DESC - `, [dateDebut, dateFin, `%${site}%`, parseInt(niveau)]); + GROUP BY n.CODE, n.LIBELLE + ORDER BY ca_ttc DESC + `, [dateDebut, dateFin, `%${site}%`]); - res.json({ dateDebut, dateFin, niveau: parseInt(niveau), ca_par_nomenclature: result.rows }); + res.json({ dateDebut, dateFin, niveau: niv, ca_par_nomenclature: result.rows }); } catch (err) { res.status(500).json({ error: err.message }); }