feat: correction automatique des données
parent
e906093d1d
commit
1a67b7888f
|
@ -4,7 +4,11 @@ import { arePeriodsOverlaping } from "../period/arePeriodsOverlaping";
|
|||
import { isPeriodContaining } from "../period/isPeriodContaining";
|
||||
import { ContexteEntreeDC } from "./ContexteEntreeDC";
|
||||
import { EvenementFamille } from "./EvenementFamille";
|
||||
import { StatutFamille } from "./StatutFamille";
|
||||
import {
|
||||
statutExResistant,
|
||||
StatutFamille,
|
||||
statutResistant,
|
||||
} from "./StatutFamille";
|
||||
import { StatutSocial } from "./StatutSocial";
|
||||
import { StatutPenal } from "./StatutPenal";
|
||||
|
||||
|
@ -27,7 +31,10 @@ export function periodOfResistance(
|
|||
family: Famille,
|
||||
atDate: Date = new Date(Date.now())
|
||||
): Period | null {
|
||||
if (family.Statut !== "Résistant·e" && family.Statut !== "Ex résistant·e") {
|
||||
if (
|
||||
family.Statut !== statutResistant &&
|
||||
family.Statut !== statutExResistant
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (!family.Integration || family.Integration > atDate) {
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
export const integrationAFinaliser =
|
||||
"Intégration à finaliser (vérification de la fiche)";
|
||||
|
||||
export const statutsIntegrationEnCours = [
|
||||
"Intégration à finaliser (vérification de la fiche)",
|
||||
integrationAFinaliser,
|
||||
"Intégration en cours",
|
||||
] as const;
|
||||
|
||||
export const statutsPreIntegration = ["en réflexion"] as const;
|
||||
|
||||
export const statutsIntegrationEnEchec = ["Abandon", "Incompatible"] as const;
|
||||
export const statutResistant = "Résistant·e";
|
||||
export const statutExResistant = "Ex résistant·e";
|
||||
export const statutsFamille = [
|
||||
...statutsPreIntegration,
|
||||
"Résistant·e",
|
||||
"Ex résistant·e",
|
||||
statutResistant,
|
||||
statutExResistant,
|
||||
...statutsIntegrationEnCours,
|
||||
...statutsIntegrationEnEchec,
|
||||
] as const;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { EvenementFamille } from "../EvenementFamille";
|
||||
import { Famille } from "../Famille";
|
||||
import { MessageDeNettoyage, msgDonneeIgnoree } from "./MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "./nettoyerDonneesFamilles";
|
||||
import { EvenementFamille } from "../../EvenementFamille";
|
||||
import { Famille } from "../../Famille";
|
||||
import {
|
||||
MessageDeNettoyage,
|
||||
msgDonneeIgnoree,
|
||||
} from "../fwk/MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function ignorerEvenements(
|
||||
familles: Famille[],
|
|
@ -1,6 +1,6 @@
|
|||
import { EvenementFamille } from "../EvenementFamille";
|
||||
import { Famille } from "../Famille";
|
||||
import { DonneesNettoyees } from "./nettoyerDonneesFamilles";
|
||||
import { EvenementFamille } from "../../EvenementFamille";
|
||||
import { Famille } from "../../Famille";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
import { ignorerEvenements } from "./ignorerEvenements";
|
||||
|
||||
export function supprimerLesEvenementsHorsResisstance(
|
|
@ -1,6 +1,6 @@
|
|||
import { EvenementFamille } from "../EvenementFamille";
|
||||
import { Famille } from "../Famille";
|
||||
import { DonneesNettoyees } from "./nettoyerDonneesFamilles";
|
||||
import { EvenementFamille } from "../../EvenementFamille";
|
||||
import { Famille } from "../../Famille";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
import { ignorerEvenements } from "./ignorerEvenements";
|
||||
|
||||
export function supprimerLesEvenementsSansDate(
|
|
@ -1,4 +1,5 @@
|
|||
import { Famille, isExResistant, isResistant } from "../Famille";
|
||||
import { Famille, isExResistant, isResistant } from "../../Famille";
|
||||
import { statutExResistant, statutResistant } from "../../StatutFamille";
|
||||
|
||||
export function checkDataConsistency(families: Famille[]): ConsistencyReport {
|
||||
const reports = families.map((family) => {
|
||||
|
@ -22,32 +23,7 @@ function checkFamilyDataConsistency(family: Famille): ConsistencyReport {
|
|||
const consistencyErrors: ConsistencyIssue[] = [];
|
||||
const consistencyWarnings: ConsistencyIssue[] = [];
|
||||
|
||||
if (family.Statut === "Résistant·e") {
|
||||
if (family.Integration === null) {
|
||||
consistencyErrors.push({
|
||||
familyId: family.Titre,
|
||||
issueType: "Résistant·e sans date d'Intégration",
|
||||
});
|
||||
}
|
||||
if (family.Sortie !== null) {
|
||||
consistencyErrors.push({
|
||||
familyId: family.Titre,
|
||||
issueType: "Résistant·e avec Date de Sortie",
|
||||
});
|
||||
}
|
||||
} else if (family.Statut === "Ex résistant·e") {
|
||||
if (family.Integration === null) {
|
||||
consistencyErrors.push({
|
||||
familyId: family.Titre,
|
||||
issueType: "Ex résistant·e sans date Intégration",
|
||||
});
|
||||
}
|
||||
if (family.Sortie === null) {
|
||||
consistencyErrors.push({
|
||||
familyId: family.Titre,
|
||||
issueType: "Ex résistant·e sans date Sortie",
|
||||
});
|
||||
}
|
||||
if (family.Statut === statutExResistant) {
|
||||
if (
|
||||
family.Integration &&
|
||||
family.Sortie &&
|
|
@ -0,0 +1,16 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { integrationAFinaliser, statutExResistant } from "../../StatutFamille";
|
||||
import { corrigerListeFamilles } from "./corrigerListeFamilles";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function corrigerFamilleExResistanteSansDateIntegration(
|
||||
familles: Famille[]
|
||||
): DonneesNettoyees {
|
||||
return corrigerListeFamilles(
|
||||
familles,
|
||||
(f) => f.Statut === statutExResistant && f.Integration === null,
|
||||
(f) => ({ ...f, Statut: integrationAFinaliser }),
|
||||
(f) =>
|
||||
`Famille ${f.Titre} - avec un statut Ex Résistant maos sans date d'intégration => Le statut est remplacé par "${integrationAFinaliser}" pour le calcul des statistics`
|
||||
);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import {
|
||||
integrationAFinaliser,
|
||||
statutExResistant,
|
||||
statutResistant,
|
||||
} from "../../StatutFamille";
|
||||
import { corrigerListeFamilles } from "./corrigerListeFamilles";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function corrigerFamilleExResistanteSansDateSortie(
|
||||
familles: Famille[]
|
||||
): DonneesNettoyees {
|
||||
return corrigerListeFamilles(
|
||||
familles,
|
||||
(f) => f.Statut === statutExResistant && f.Sortie === null,
|
||||
(f) => ({ ...f, Statut: statutResistant }),
|
||||
(f) =>
|
||||
`Famille ${f.Titre} - avec un statut Ex Résistant maos sans date de Sortie => Le statut est remplacé par "${statutResistant}" pour le calcul des statistics`
|
||||
);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { statutResistant } from "../../StatutFamille";
|
||||
import { corrigerListeFamilles } from "./corrigerListeFamilles";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function corrigerFamilleResistanteAvecDateSortie(
|
||||
familles: Famille[]
|
||||
): DonneesNettoyees {
|
||||
return corrigerListeFamilles(
|
||||
familles,
|
||||
(f) => f.Statut === statutResistant && f.Sortie !== null,
|
||||
(f) => ({ ...f, Sortie: null }),
|
||||
(f) =>
|
||||
`Famille ${f.Titre} - avec un statut Résistant mais avec une date de Sortie => La date de Sortie est mise a null pour le calcul des statistics`
|
||||
);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { integrationAFinaliser, statutResistant } from "../../StatutFamille";
|
||||
import { corrigerListeFamilles } from "./corrigerListeFamilles";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function corrigerFamilleResistanteSansDateIntegration(
|
||||
familles: Famille[]
|
||||
): DonneesNettoyees {
|
||||
return corrigerListeFamilles(
|
||||
familles,
|
||||
(f) => f.Statut === statutResistant && f.Integration === null,
|
||||
(f) => ({ ...f, Statut: integrationAFinaliser }),
|
||||
(f) =>
|
||||
`Famille ${f.Titre} - avec un statut Résistant maos sans date d'intégration => Le statut est remplacé par "${integrationAFinaliser}" pour le calcul des statistics`
|
||||
);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import {
|
||||
MessageDeNettoyage,
|
||||
msgDonneeCorrigee,
|
||||
} from "../fwk/MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
export function corrigerListeFamilles(
|
||||
familles: Famille[],
|
||||
conditionACorriger: (f: Famille) => boolean,
|
||||
fonctionDeCorrection: (f: Famille) => Famille,
|
||||
messageDescriptifCorrection: (f: Famille) => string
|
||||
): DonneesNettoyees {
|
||||
const messages: MessageDeNettoyage[] = [];
|
||||
const famillesNettoyees = familles.map((f) => {
|
||||
if (conditionACorriger(f)) {
|
||||
messages.push(msgDonneeCorrigee(messageDescriptifCorrection(f)));
|
||||
return fonctionDeCorrection(f);
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
familles: famillesNettoyees,
|
||||
messages,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { appliquerLesFonctionsDeNettoyages } from "../fwk/appliquerLesFonctionsDeNettoyages";
|
||||
import { checkDataConsistency } from "./checkDataConsistency";
|
||||
import { corrigerFamilleResistanteSansDateIntegration } from "./corrigerFamilleResistanteSansDateIntegration";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
import {
|
||||
MessageDeNettoyage,
|
||||
msgDonneeBloquante,
|
||||
msgDonneeSuspecte,
|
||||
} from "../fwk/MessageDeNettoyage";
|
||||
import { supprimerLesFamillesVide } from "./supprimerLesFamillesVide";
|
||||
import { supprimerLesEvenementsHorsResisstance } from "../evt/supprimerLesEvenementsHorsResisstance";
|
||||
import { supprimerLesEvenementsSansDate } from "../evt/supprimerLesEvenementsSansDate";
|
||||
import { corrigerFamilleResistanteAvecDateSortie } from "./corrigerFamilleResistanteAvecDateSortie";
|
||||
import { corrigerFamilleExResistanteSansDateIntegration } from "./corrigerFamilleExResistanteSansDateIntegration";
|
||||
import { corrigerFamilleExResistanteSansDateSortie } from "./corrigerFamilleExResistanteSansDateSortie";
|
||||
|
||||
export function nettoyerDonneesFamilles(
|
||||
donneesFamillesBrutes: Famille[]
|
||||
): DonneesNettoyees {
|
||||
const nettoyagePreConsistencyCheck = appliquerLesFonctionsDeNettoyages(
|
||||
donneesFamillesBrutes,
|
||||
[
|
||||
supprimerLesFamillesVide,
|
||||
corrigerFamilleResistanteSansDateIntegration,
|
||||
corrigerFamilleResistanteAvecDateSortie,
|
||||
corrigerFamilleExResistanteSansDateIntegration,
|
||||
corrigerFamilleExResistanteSansDateSortie,
|
||||
]
|
||||
);
|
||||
|
||||
// TODO convert checkDataConsistency to filters
|
||||
const consistencyReport = checkDataConsistency(
|
||||
nettoyagePreConsistencyCheck.familles
|
||||
);
|
||||
|
||||
// Adapte les message
|
||||
const consistencyCheckErrorMessages: MessageDeNettoyage[] =
|
||||
consistencyReport.errors.map((e) =>
|
||||
msgDonneeBloquante(`${e.familyId} - ${e.issueType}`)
|
||||
);
|
||||
const consistencyCheckWarnings: MessageDeNettoyage[] =
|
||||
consistencyReport.warnings.map((e) =>
|
||||
msgDonneeSuspecte(`${e.familyId} - ${e.issueType}`)
|
||||
);
|
||||
|
||||
const nettoyagePostConsistencyCheck = appliquerLesFonctionsDeNettoyages(
|
||||
nettoyagePreConsistencyCheck.familles,
|
||||
[supprimerLesEvenementsSansDate, supprimerLesEvenementsHorsResisstance]
|
||||
);
|
||||
|
||||
return {
|
||||
familles: nettoyagePostConsistencyCheck.familles,
|
||||
messages: [
|
||||
...nettoyagePreConsistencyCheck.messages,
|
||||
...consistencyCheckErrorMessages,
|
||||
...consistencyCheckWarnings,
|
||||
...nettoyagePostConsistencyCheck.messages,
|
||||
],
|
||||
};
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { Famille } from "../Famille";
|
||||
import { msgDonneeIgnoree } from "./MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "./nettoyerDonneesFamilles";
|
||||
import { Famille } from "../../Famille";
|
||||
import { msgDonneeIgnoree } from "../fwk/MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "../fwk/DonneesNettoyees";
|
||||
|
||||
/**
|
||||
* Supprime "Famille de résistant" qui sont souvent créé par erreur
|
||||
*/
|
||||
export function supprimerLesEntreesVide(familles: Famille[]): DonneesNettoyees {
|
||||
export function supprimerLesFamillesVide(
|
||||
familles: Famille[]
|
||||
): DonneesNettoyees {
|
||||
const nettoyees = familles.filter((f) => f.Titre !== "Famille de résistant");
|
||||
const ignorees = familles.filter((f) => f.Titre === "Famille de résistant");
|
||||
if (ignorees.length > 0) {
|
|
@ -0,0 +1,7 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { MessageDeNettoyage } from "./MessageDeNettoyage";
|
||||
|
||||
export type DonneesNettoyees = {
|
||||
familles: Famille[];
|
||||
messages: MessageDeNettoyage[];
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { DonneesNettoyees } from "./DonneesNettoyees";
|
||||
|
||||
export type FonctionNettoyage = (familles: Famille[]) => DonneesNettoyees;
|
|
@ -3,6 +3,7 @@ export type MessageDeNettoyage = {
|
|||
severite:
|
||||
| "Donnée ignorée"
|
||||
| "Donnée suspecte"
|
||||
| "Donnée corrigée"
|
||||
| "Donnée incohérente bloquante";
|
||||
};
|
||||
export function msgDonneeIgnoree(message: string): MessageDeNettoyage {
|
||||
|
@ -11,6 +12,12 @@ export function msgDonneeIgnoree(message: string): MessageDeNettoyage {
|
|||
severite: "Donnée ignorée",
|
||||
};
|
||||
}
|
||||
export function msgDonneeCorrigee(message: string): MessageDeNettoyage {
|
||||
return {
|
||||
message,
|
||||
severite: "Donnée corrigée",
|
||||
};
|
||||
}
|
||||
export function msgDonneeSuspecte(message: string): MessageDeNettoyage {
|
||||
return {
|
||||
message,
|
|
@ -0,0 +1,19 @@
|
|||
import { Famille } from "../../Famille";
|
||||
import { FonctionNettoyage } from "./FonctionNettoyage";
|
||||
import { MessageDeNettoyage } from "./MessageDeNettoyage";
|
||||
import { DonneesNettoyees } from "./DonneesNettoyees";
|
||||
|
||||
export function appliquerLesFonctionsDeNettoyages(
|
||||
familles: Famille[],
|
||||
fonctionsDeNettoyage: FonctionNettoyage[]
|
||||
): DonneesNettoyees {
|
||||
let famillesNettoyees = familles;
|
||||
let messages: MessageDeNettoyage[] = [];
|
||||
|
||||
for (const fn of fonctionsDeNettoyage) {
|
||||
const donneesNettoyees: DonneesNettoyees = fn.apply(null, [familles]);
|
||||
messages = [...messages, ...donneesNettoyees.messages];
|
||||
famillesNettoyees = donneesNettoyees.familles;
|
||||
}
|
||||
return { familles: famillesNettoyees, messages };
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
import { Famille } from "../Famille";
|
||||
import { checkDataConsistency } from "./checkDataConsistency";
|
||||
import {
|
||||
MessageDeNettoyage,
|
||||
msgDonneeBloquante,
|
||||
msgDonneeSuspecte,
|
||||
} from "./MessageDeNettoyage";
|
||||
import { supprimerLesEntreesVide } from "./supprimerLesEntreesVide";
|
||||
import { supprimerLesEvenementsHorsResisstance } from "./supprimerLesEvenementsHorsResisstance";
|
||||
import { supprimerLesEvenementsSansDate } from "./supprimerLesEvenementsSansDate";
|
||||
|
||||
export type DonneesNettoyees = {
|
||||
familles: Famille[];
|
||||
messages: MessageDeNettoyage[];
|
||||
};
|
||||
|
||||
export function nettoyerDonneesFamilles(
|
||||
donneesFamillesBrutes: Famille[]
|
||||
): DonneesNettoyees {
|
||||
let familles = donneesFamillesBrutes;
|
||||
|
||||
let messages: MessageDeNettoyage[] = [];
|
||||
|
||||
const output1 = supprimerLesEntreesVide(familles);
|
||||
messages = [...messages, ...output1.messages];
|
||||
familles = output1.familles;
|
||||
|
||||
// TODO convert checkDataConsistency to filters
|
||||
const consistencyReport = checkDataConsistency(familles);
|
||||
|
||||
// Adapte les message
|
||||
const errorMessages: MessageDeNettoyage[] = consistencyReport.errors.map(
|
||||
(e) => msgDonneeBloquante(`${e.familyId} - ${e.issueType}`)
|
||||
);
|
||||
const warnings: MessageDeNettoyage[] = consistencyReport.warnings.map((e) =>
|
||||
msgDonneeSuspecte(`${e.familyId} - ${e.issueType}`)
|
||||
);
|
||||
|
||||
messages = [...messages, ...errorMessages, ...warnings];
|
||||
|
||||
type FonctionNettoyage = (familles: Famille[]) => DonneesNettoyees;
|
||||
const fonctionsDeNettoyage: FonctionNettoyage[] = [
|
||||
supprimerLesEvenementsSansDate,
|
||||
supprimerLesEvenementsHorsResisstance,
|
||||
];
|
||||
|
||||
for (const fn of fonctionsDeNettoyage) {
|
||||
const donneesNettoyees: DonneesNettoyees = fn.apply(null, [familles]);
|
||||
messages = [...messages, ...donneesNettoyees.messages];
|
||||
familles = donneesNettoyees.familles;
|
||||
}
|
||||
|
||||
return {
|
||||
familles,
|
||||
messages,
|
||||
};
|
||||
}
|
11
src/index.ts
11
src/index.ts
|
@ -16,8 +16,8 @@ import { formatDate } from "date-fns";
|
|||
import { computeStatsGeneralesMensuelles } from "./statistiques/v2/generales/computeStatsGeneralesMensuelles";
|
||||
import { mermaidDiagramStatsGeneralesMensuelles } from "./statistiques/v2/generales/mermaidDiagramStatsGeneralesMensuelles";
|
||||
import { publishStatsGenerales } from "./notion/publish/v2/publishStatsGenerales";
|
||||
import { nettoyerDonneesFamilles } from "./data/nettoyage/nettoyerDonneesFamilles";
|
||||
import { typeEvenementsProcedurePenale } from "./data/TypeEvenementsPenal";
|
||||
import { nettoyerDonneesFamilles } from "./data/nettoyage/familles/nettoyerDonneesFamilles";
|
||||
|
||||
type ProcessOptions = {
|
||||
dryRun: boolean;
|
||||
|
@ -65,6 +65,9 @@ function buildProcessOptions(): ProcessOptions {
|
|||
const donneesSuspectes = messages.filter(
|
||||
(m) => m.severite === "Donnée suspecte"
|
||||
);
|
||||
const donneesCorrigees = messages.filter(
|
||||
(m) => m.severite === "Donnée corrigée"
|
||||
);
|
||||
const donneesIgnorees = messages.filter(
|
||||
(m) => m.severite === "Donnée ignorée"
|
||||
);
|
||||
|
@ -84,6 +87,12 @@ function buildProcessOptions(): ProcessOptions {
|
|||
console.warn(" - " + e.message);
|
||||
});
|
||||
}
|
||||
if (donneesCorrigees.length > 0) {
|
||||
console.warn(`${donneesCorrigees.length} Données corrigées:`);
|
||||
donneesCorrigees.forEach((e) => {
|
||||
console.warn(" - " + e.message);
|
||||
});
|
||||
}
|
||||
if (donneesIgnorees.length > 0) {
|
||||
console.warn(`${donneesIgnorees.length} Données ignorées:`);
|
||||
donneesIgnorees.forEach((e) => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
} from "../../data/EvenementFamille";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { percent } from "../../utils/math/percent";
|
||||
import { statutExResistant, statutResistant } from "../../data/StatutFamille";
|
||||
|
||||
type FamillesWithEventsConditionInEarlyPeriod = {
|
||||
[name: string]: {
|
||||
|
@ -32,7 +33,7 @@ export const computeFamillesWithEventsConditionInEarlyPeriod = (
|
|||
Object.entries(durations).map(([name, months]) => {
|
||||
const famillesWithAtLeastDurationOfDc = familles
|
||||
.filter(
|
||||
(f) => f.Statut === "Résistant·e" || f.Statut === "Ex résistant·e"
|
||||
(f) => f.Statut === statutResistant || f.Statut === statutExResistant
|
||||
)
|
||||
.filter(
|
||||
(f) =>
|
||||
|
|
Loading…
Reference in New Issue