Checkpoint: Fenêtre administrateur Salaires finalisée : import multipart limité, chiffrement AES-256-GCM avant stockage persistant hors conteneur, métadonnées/index métier minimisés en base, consultation PDF déchiffrée côté serveur avec no-store, filtres année/mois et comparaison M-1 expliquée. Réindexation sûre des archives partielles sans écrasement du PDF. Validation réelle sur deux liasses mensuelles : index partiel signalé sans invention de données, comparaison affichée et lecture après redémarrage. 55 tests Vitest, TypeScript et build de production validés.
Some checks failed
Validation applicative / TypeScript, tests et build (push) Failing after 1m54s
Some checks failed
Validation applicative / TypeScript, tests et build (push) Failing after 1m54s
This commit is contained in:
28
scripts/diagnosePayrollExtraction.ts
Normal file
28
scripts/diagnosePayrollExtraction.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import fs from "node:fs";
|
||||
import { extractPayrollBulletins } from "../server/payrollParser";
|
||||
import { extractPayrollPdfText } from "../server/payrollPdfText";
|
||||
|
||||
const filePath = process.argv[2];
|
||||
if (!filePath) throw new Error("Chemin PDF requis");
|
||||
|
||||
const text = await extractPayrollPdfText(fs.readFileSync(filePath));
|
||||
const extraction = extractPayrollBulletins(text);
|
||||
const lines = text.split(/\r?\n/);
|
||||
const redactStructure = (line: string) => line.replace(/[A-Za-zÀ-ÿ]/g, "x").replace(/\d/g, "#").slice(0, 240);
|
||||
const prohibitedPosteContent = extraction.bulletins.some((bulletin) => /iban|rib|n°\s*ss|adresse|fr\d{2}/i.test(bulletin.poste));
|
||||
console.log(JSON.stringify({
|
||||
bulletins: extraction.bulletins.length,
|
||||
statutExtraction: extraction.statutExtraction,
|
||||
hasExtractionWarning: Boolean(extraction.erreurExtraction),
|
||||
containsProhibitedPosteContent: prohibitedPosteContent,
|
||||
preservedPageSeparators: (text.match(/\f/g) ?? []).length,
|
||||
bulletinMarkers: (text.match(/##BULLETIN##/g) ?? []).length,
|
||||
matriculeMatchCount: (text.match(/Matricule\s*:\s*(?:M|N|N°)?\s*\d+/g) ?? []).length,
|
||||
emploiSameLineCount: lines.filter((line) => /Emploi\s*:.*(?:Monsieur|Madame)\b/i.test(line)).length,
|
||||
baseLineCount: lines.filter((line) => line.trim().startsWith("Salaire de base")).length,
|
||||
grossLineCount: lines.filter((line) => line.trim().startsWith("Salaire brut")).length,
|
||||
emploiVicinityStructures: lines
|
||||
.flatMap((line, index) => /Emploi\s*:/i.test(line) ? lines.slice(index, index + 4) : [])
|
||||
.slice(0, 8)
|
||||
.map(redactStructure),
|
||||
}));
|
||||
Reference in New Issue
Block a user