Checkpoint: - Ajout table opex_bases_repartition (11e table) avec 58 bases de répartition 2026 seedées depuis le JSON source

- Ajout procédure tRPC opex.getBasesRepartition et opex.setBaseRepartition
- DsiOpex utilise maintenant les bases de répartition depuis la BDD (priorité BDD > JSON fallback pour 2025)
- Total en bas à droite de la vue établissements affiche totalGlobal (somme postes BDD = 1 257 678 €) au lieu de la somme des arrondis par établissement (1 259 641 €)
- 0 erreur TypeScript
This commit is contained in:
Manus
2026-06-11 06:24:31 +00:00
parent 7d4ac0721d
commit 14a660892a
9 changed files with 1066 additions and 9 deletions

View File

@@ -0,0 +1,45 @@
import mysql from 'mysql2/promise';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import dotenv from 'dotenv';
const __dirname = dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: join(__dirname, '..', '.env') });
const conn = await mysql.createConnection(process.env.DATABASE_URL);
const [rows] = await conn.execute('SELECT libelle, montant FROM opex_postes WHERE annee = 2026 ORDER BY colIdx');
const data = JSON.parse(readFileSync(join(__dirname, '../client/src/data_opex.json'), 'utf8'));
const libellesJson = new Set(data.postes.map(p => p.libelle));
const libellesBdd = new Set(rows.map(r => r.libelle));
console.log('Nb postes BDD:', rows.length);
console.log('Nb postes JSON:', libellesJson.size);
let totalBdd = 0;
rows.forEach(r => { totalBdd += parseFloat(r.montant || '0'); });
console.log('Total BDD:', totalBdd.toFixed(2));
console.log('\n=== En BDD mais PAS dans JSON ===');
for (const lib of libellesBdd) {
if (!libellesJson.has(lib)) {
const row = rows.find(r => r.libelle === lib);
console.log(' +', lib, ':', row.montant);
}
}
console.log('\n=== Dans JSON mais PAS en BDD ===');
for (const lib of libellesJson) {
if (!libellesBdd.has(lib)) {
console.log(' -', lib);
}
}
console.log('\n=== Tous les postes BDD avec montant ===');
rows.forEach(r => {
const m = parseFloat(r.montant || '0');
if (m > 0) console.log(` ${r.libelle}: ${m.toFixed(2)}`);
});
await conn.end();

View File

@@ -0,0 +1,53 @@
/**
* Seed des bases de répartition OPEX (charges classe 6) pour 2025 et 2026
* depuis les fichiers JSON sources.
*/
import mysql from 'mysql2/promise';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import dotenv from 'dotenv';
const __dirname = dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: join(__dirname, '..', '.env') });
const conn = await mysql.createConnection(process.env.DATABASE_URL);
const dataFiles = {
2025: join(__dirname, '../client/src/data_opex_2025.json'),
2026: join(__dirname, '../client/src/data_opex.json'),
};
for (const [annee, filePath] of Object.entries(dataFiles)) {
const data = JSON.parse(readFileSync(filePath, 'utf8'));
const etabs = data.etablissements || [];
if (etabs.length === 0) {
console.log(`Année ${annee}: aucun établissement trouvé dans le JSON`);
continue;
}
// Supprimer les bases existantes pour cette année
await conn.execute('DELETE FROM opex_bases_repartition WHERE annee = ?', [parseInt(annee)]);
// Insérer en batch
const values = etabs.map(e => [
parseInt(annee),
e.code,
e.nom || null,
e.base_repartition || 0,
]);
if (values.length > 0) {
await conn.query(
'INSERT INTO opex_bases_repartition (annee, etablissementCode, etablissementNom, baseRepartition) VALUES ?',
[values]
);
}
console.log(`Année ${annee}: ${values.length} bases de répartition insérées`);
console.log(` Total base: ${etabs.reduce((s, e) => s + (e.base_repartition || 0), 0).toLocaleString('fr-FR', { maximumFractionDigits: 0 })} €`);
}
await conn.end();
console.log('\nSeed bases de répartition terminé.');