mirror of
https://github.com/R0m1k3/Presencia.git
synced 2026-10-24 07:38:03 +02:00
Ajout de l'application Presencia (gestion des présences multi-sociétés)
Application complète : API Node/Express + PostgreSQL, frontend HTML/JS mono-page, et déploiement Docker sur ports non standards (8781/4790/6543). - Cadres : calendrier mensuel, saisie de présence par demi-journée (présent/absent/congé/RTT), validation de fin de mois qui verrouille leurs propres saisies. - Admin : gestion des sociétés et utilisateurs (rattachement société <-> cadre), consultation de tous les plannings, validation d'une société entière une fois tous ses cadres validés, réouverture en cas de correction, export PDF et Excel par société/mois.
This commit is contained in:
27 files changed
+5492
No files matched your search
@@ -0,0 +1,81 @@
|
||||
const express = require('express');
|
||||
const db = require('../db');
|
||||
const { requireAuth, requireAdmin } = require('../middleware/auth');
|
||||
const { buildCompanyWorkbook } = require('../utils/excel');
|
||||
const { buildCompanyPdf } = require('../utils/pdf');
|
||||
|
||||
const router = express.Router();
|
||||
router.use(requireAuth, requireAdmin);
|
||||
|
||||
async function loadCompanyData(companyId, year, month) {
|
||||
const { rows: companyRows } = await db.query('SELECT id, name FROM companies WHERE id = $1', [companyId]);
|
||||
const company = companyRows[0];
|
||||
if (!company) return null;
|
||||
|
||||
const { rows: cadreRows } = await db.query(
|
||||
`SELECT id, full_name FROM users WHERE company_id = $1 AND role = 'cadre' AND active = true ORDER BY full_name`,
|
||||
[companyId]
|
||||
);
|
||||
|
||||
const start = `${year}-${String(month).padStart(2, '0')}-01`;
|
||||
const cadres = [];
|
||||
for (const c of cadreRows) {
|
||||
const { rows: entries } = await db.query(
|
||||
`SELECT entry_date, period, status FROM attendance_entries
|
||||
WHERE user_id = $1 AND entry_date >= $2::date AND entry_date < ($2::date + INTERVAL '1 month')`,
|
||||
[c.id, start]
|
||||
);
|
||||
const map = new Map();
|
||||
for (const e of entries) {
|
||||
map.set(`${e.entry_date.toISOString().slice(0, 10)}:${e.period}`, e.status);
|
||||
}
|
||||
cadres.push({ id: c.id, fullName: c.full_name, entries: map });
|
||||
}
|
||||
|
||||
return { company, cadres };
|
||||
}
|
||||
|
||||
router.get('/excel/:companyId', async (req, res) => {
|
||||
const year = parseInt(req.query.year, 10);
|
||||
const month = parseInt(req.query.month, 10);
|
||||
if (!year || !month) return res.status(400).json({ error: 'year et month requis' });
|
||||
|
||||
const data = await loadCompanyData(req.params.companyId, year, month);
|
||||
if (!data) return res.status(404).json({ error: 'Société introuvable' });
|
||||
|
||||
const workbook = await buildCompanyWorkbook({
|
||||
companyName: data.company.name,
|
||||
year,
|
||||
month,
|
||||
cadres: data.cadres,
|
||||
});
|
||||
|
||||
const filename = `presences_${data.company.name.replace(/\s+/g, '_')}_${year}-${String(month).padStart(2, '0')}.xlsx`;
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
});
|
||||
|
||||
router.get('/pdf/:companyId', async (req, res) => {
|
||||
const year = parseInt(req.query.year, 10);
|
||||
const month = parseInt(req.query.month, 10);
|
||||
if (!year || !month) return res.status(400).json({ error: 'year et month requis' });
|
||||
|
||||
const data = await loadCompanyData(req.params.companyId, year, month);
|
||||
if (!data) return res.status(404).json({ error: 'Société introuvable' });
|
||||
|
||||
const filename = `presences_${data.company.name.replace(/\s+/g, '_')}_${year}-${String(month).padStart(2, '0')}.pdf`;
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
||||
|
||||
const doc = buildCompanyPdf({
|
||||
companyName: data.company.name,
|
||||
year,
|
||||
month,
|
||||
cadres: data.cadres,
|
||||
});
|
||||
doc.pipe(res);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in new issue
Block a user