feat: implement advertising data synchronization and API endpoints for performance tracking
This commit is contained in:
1 parent
de69370d9e
commit
9e993b3559
6 files changed
+506
-5
No files matched your search
+5
-1
@@ -10,7 +10,8 @@ const stockRouter = require('./routes/stock');
|
||||
const mouvementsRouter = require('./routes/mouvements');
|
||||
const performanceRouter = require('./routes/performance');
|
||||
const syncRouter = require('./routes/sync');
|
||||
const rankingRouter = require('./routes/ranking');
|
||||
const rankingRouter = require('./routes/ranking');
|
||||
const publicitesRouter = require('./routes/publicites');
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
@@ -36,6 +37,7 @@ app.use('/api/mouvements', mouvementsRouter);
|
||||
app.use('/api/performance', performanceRouter);
|
||||
app.use('/api/sync', syncRouter);
|
||||
app.use('/api/ranking', rankingRouter);
|
||||
app.use('/api/publicites', publicitesRouter);
|
||||
|
||||
// 404
|
||||
app.use((req, res) => {
|
||||
@@ -72,5 +74,7 @@ app.listen(PORT, () => {
|
||||
console.log(' GET /api/performance/hitparade[?dateDebut=&dateFin=&site=&limit=&groupBy=qte|ca|marge]');
|
||||
console.log(' GET /api/performance/ca/nomenclature[?dateDebut=&dateFin=&site=&niveau=]');
|
||||
console.log(' GET /api/performance/ca/gamme[?dateDebut=&dateFin=&site=]');
|
||||
console.log(' GET /api/publicites[?search=&site=&dateDebut=&dateFin=&page=&limit=]');
|
||||
console.log(' GET /api/publicites/:code[?site=]');
|
||||
console.log(' GET /api/sync/status');
|
||||
});
|
||||
@@ -0,0 +1,154 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getPool } = require('../config/database');
|
||||
|
||||
// GET /api/publicites?search=&site=&dateDebut=&dateFin=&page=&limit=
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const {
|
||||
search = '',
|
||||
site = '',
|
||||
dateDebut = '2000-01-01',
|
||||
dateFin = '2099-12-31',
|
||||
page = 1,
|
||||
limit = 50,
|
||||
} = req.query;
|
||||
|
||||
const pageNum = Math.max(1, parseInt(page) || 1);
|
||||
const limitNum = Math.max(1, Math.min(parseInt(limit) || 50, 500));
|
||||
const offset = (pageNum - 1) * limitNum;
|
||||
|
||||
// Synthèse par pub (agrégat multi-sites)
|
||||
const result = await pool.query(`
|
||||
SELECT
|
||||
e.tcr_code,
|
||||
e.tcr_libelle AS intitule,
|
||||
e.tcrd_datedeb AS date_debut,
|
||||
e.tcrd_datefin AS date_fin,
|
||||
e.datecalcul,
|
||||
e.site,
|
||||
e.ca_pub_periode_pub,
|
||||
e.qte_vendue_pub,
|
||||
e.ca_total_periode_pub,
|
||||
ROUND(e.pourc_capub_catotal::NUMERIC, 2) AS pourc_capub_catotal,
|
||||
e.client_pub_periode,
|
||||
e.client_total_periode,
|
||||
e.stock_datedebut,
|
||||
e.stock_datefin,
|
||||
e.ca_pub_30_jours,
|
||||
e.ca_pub_60_jours,
|
||||
e.ca_pub_90_jours,
|
||||
e.ca_pub_180_jours,
|
||||
e.ca_depuis_finpub,
|
||||
ROUND(e.taux_sortie::NUMERIC, 2) AS taux_sortie,
|
||||
ROUND(e.marge::NUMERIC, 4) AS marge,
|
||||
ROUND(e.taux_marge::NUMERIC, 2) AS taux_marge,
|
||||
(SELECT COUNT(DISTINCT d.artnoid)
|
||||
FROM pub_ecoulement_detail d
|
||||
WHERE d.tcr_code = e.tcr_code AND d.site = e.site) AS nb_articles
|
||||
FROM pub_ecoulement e
|
||||
WHERE ($1 = '' OR e.tcr_libelle ILIKE '%' || $1 || '%' OR e.tcr_code ILIKE '%' || $1 || '%')
|
||||
AND ($2 = '' OR e.site ILIKE '%' || $2 || '%')
|
||||
AND e.tcrd_datedeb >= $3
|
||||
AND e.tcrd_datedeb <= $4
|
||||
ORDER BY e.tcrd_datedeb DESC, e.tcr_code, e.site
|
||||
LIMIT $5 OFFSET $6
|
||||
`, [search, site, dateDebut, dateFin, limitNum, offset]);
|
||||
|
||||
res.json({
|
||||
page: pageNum,
|
||||
limit: limitNum,
|
||||
publicites: result.rows,
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/publicites/:code — synthèse par site + articles
|
||||
router.get('/:code', async (req, res) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const { code } = req.params;
|
||||
const { site = '' } = req.query;
|
||||
|
||||
// Synthèse par site
|
||||
const synthese = await pool.query(`
|
||||
SELECT
|
||||
e.tcr_code,
|
||||
e.tcr_libelle AS intitule,
|
||||
e.tcrd_datedeb AS date_debut,
|
||||
e.tcrd_datefin AS date_fin,
|
||||
e.datecalcul,
|
||||
e.site,
|
||||
e.ca_pub_periode_pub,
|
||||
e.qte_vendue_pub,
|
||||
e.ca_total_periode_pub,
|
||||
ROUND(e.pourc_capub_catotal::NUMERIC, 2) AS pourc_capub_catotal,
|
||||
e.client_pub_periode,
|
||||
e.client_total_periode,
|
||||
e.stock_datedebut,
|
||||
e.stock_datefin,
|
||||
e.ca_pub_30_jours,
|
||||
e.ca_pub_60_jours,
|
||||
e.ca_pub_90_jours,
|
||||
e.ca_pub_180_jours,
|
||||
e.ca_depuis_finpub,
|
||||
ROUND(e.taux_sortie::NUMERIC, 2) AS taux_sortie,
|
||||
ROUND(e.marge::NUMERIC, 4) AS marge,
|
||||
ROUND(e.taux_marge::NUMERIC, 2) AS taux_marge
|
||||
FROM pub_ecoulement e
|
||||
WHERE e.tcr_code = $1
|
||||
AND ($2 = '' OR e.site ILIKE '%' || $2 || '%')
|
||||
ORDER BY e.site
|
||||
`, [code, site]);
|
||||
|
||||
if (!synthese.rows.length) {
|
||||
return res.status(404).json({ error: 'Publication introuvable' });
|
||||
}
|
||||
|
||||
// Articles de la pub
|
||||
const articles = await pool.query(`
|
||||
SELECT
|
||||
d.site,
|
||||
d.artnoid,
|
||||
d.codein,
|
||||
d.libelle,
|
||||
d.prmp,
|
||||
d.pa,
|
||||
d.pv,
|
||||
d.prixpub,
|
||||
d.qte_vendue_pub,
|
||||
ROUND(d.ca_pub_periode_pub::NUMERIC, 4) AS ca_pub_periode_pub,
|
||||
d.stock_datedebut,
|
||||
d.stock_datefin,
|
||||
d.ca_pub_30_jours,
|
||||
d.ca_pub_60_jours,
|
||||
d.ca_pub_90_jours,
|
||||
d.ca_pub_180_jours,
|
||||
d.ca_depuis_finpub,
|
||||
ROUND(d.taux_sortie::NUMERIC, 2) AS taux_sortie,
|
||||
ROUND(d.marge::NUMERIC, 4) AS marge,
|
||||
ROUND(d.taux_marge::NUMERIC, 2) AS taux_marge
|
||||
FROM pub_ecoulement_detail d
|
||||
WHERE d.tcr_code = $1
|
||||
AND ($2 = '' OR d.site ILIKE '%' || $2 || '%')
|
||||
ORDER BY d.site, d.ca_pub_periode_pub DESC
|
||||
`, [code, site]);
|
||||
|
||||
res.json({
|
||||
tcr_code: synthese.rows[0].tcr_code,
|
||||
intitule: synthese.rows[0].intitule,
|
||||
date_debut: synthese.rows[0].date_debut,
|
||||
date_fin: synthese.rows[0].date_fin,
|
||||
datecalcul: synthese.rows[0].datecalcul,
|
||||
synthese_par_site: synthese.rows,
|
||||
articles: articles.rows,
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in new issue
Block a user