From 2f7de9b476bb81a38862366dce1223312ebb2ed1 Mon Sep 17 00:00:00 2001 From: imanuch Date: Mon, 15 Dec 2025 16:46:14 +0100 Subject: [PATCH 1/2] Gestion des acheteurs absents de SIRENE et nettoyage des SIRET titulaires MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout d'un dictionnaire ACHETEURS_NON_SIRENE pour les acheteurs non répertoriés dans SIRENE (ex: Ministère des Armées) pour raisons de sécurité - Fallback appliqué après la jointure SIRENE pour remplir acheteur_nom - Strip des espaces dans titulaire_id pour corriger les SIRET malformés (ex: " 33487372600239") Co-Authored-By: Claude Opus 4.5 --- src/config.py | 7 +++++++ src/tasks/clean.py | 3 +++ src/tasks/enrich.py | 31 ++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/config.py b/src/config.py index 5d29c52..e10f1d4 100644 --- a/src/config.py +++ b/src/config.py @@ -193,6 +193,13 @@ def make_sirene_data_dir(sirene_data_parent_dir) -> Path: SOLO_DATASET = os.getenv("SOLO_DATASET", "") print(f"{'SOLO_DATASET':<40}", SOLO_DATASET) +# Acheteurs absents de la base SIRENE (pour raisons de sécurité ou autre) +# Format: SIRET -> {"nom": "...", ...} +# Ces données sont utilisées en fallback si l'acheteur n'est pas trouvé dans SIRENE +ACHETEURS_NON_SIRENE = { + "13001536500013": {"nom": "Ministère des Armées"}, +} + with open( make_path_from_env( "DATASETS_REFERENCE_FILEPATH", REFERENCE_DIR / "source_datasets.json" diff --git a/src/tasks/clean.py b/src/tasks/clean.py index 54a567a..66334f0 100644 --- a/src/tasks/clean.py +++ b/src/tasks/clean.py @@ -125,6 +125,9 @@ def clean_decp(lf: pl.LazyFrame, decp_format: DecpFormat) -> pl.LazyFrame: .name.keep() ) + # Nettoyage des espaces dans titulaire_id (ex: " 33487372600239") + lf = lf.with_columns(pl.col("titulaire_id").str.strip_chars()) + # Type identifiant = SIRET si vide (marches-securises.fr) lf = lf.with_columns( pl.when( diff --git a/src/tasks/enrich.py b/src/tasks/enrich.py index 9fad829..78a7f92 100644 --- a/src/tasks/enrich.py +++ b/src/tasks/enrich.py @@ -3,7 +3,7 @@ from polars_ds import haversine from prefect import task -from src.config import SIRENE_DATA_DIR +from src.config import ACHETEURS_NON_SIRENE, SIRENE_DATA_DIR from src.tasks.transform import ( extract_unique_acheteurs_siret, extract_unique_titulaires_siret, @@ -136,6 +136,9 @@ def enrich_from_sirene(lf: pl.LazyFrame): lf = lf.join(lf_sirets_acheteurs, how="left", on="acheteur_id") + # Fallback pour les acheteurs absents de SIRENE (ex: Ministère des Armées) + lf = apply_acheteurs_non_sirene_fallback(lf) + # En joignant en utilisant à la fois le SIRET et le typeIdentifiant, on s'assure qu'on ne joint pas sur # des id de titulaires non-SIRET lf = lf.join( @@ -155,6 +158,32 @@ def enrich_from_sirene(lf: pl.LazyFrame): return lf +def apply_acheteurs_non_sirene_fallback(lf: pl.LazyFrame) -> pl.LazyFrame: + """Applique les données d'acheteurs non présents dans SIRENE en fallback. + + Les acheteurs absents de SIRENE ET du fallback conservent acheteur_nom = NULL. + """ + if not ACHETEURS_NON_SIRENE: + return lf + + # Créer un DataFrame de fallback à partir du dictionnaire + fallback_data = [ + {"acheteur_id": siret, "acheteur_nom_fallback": data["nom"]} + for siret, data in ACHETEURS_NON_SIRENE.items() + ] + lf_fallback = pl.LazyFrame(fallback_data) + + # Joindre avec les données de fallback + lf = lf.join(lf_fallback, on="acheteur_id", how="left") + + # Remplacer acheteur_nom NULL par la valeur de fallback (si disponible) + lf = lf.with_columns( + pl.coalesce("acheteur_nom", "acheteur_nom_fallback").alias("acheteur_nom") + ).drop("acheteur_nom_fallback") + + return lf + + def calculate_distance(lf: pl.LazyFrame) -> pl.LazyFrame: # Utilisation de polars_ds.haversine # https://polars-ds-extension.readthedocs.io/en/latest/num.html#polars_ds.exprs.num.haversine From 7a8d9aef73698fa58ee3d00c4b168f970c1d216e Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Tue, 23 Dec 2025 19:32:28 +0100 Subject: [PATCH 2/2] Changelog 2.6.4 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b555258..4c1873c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ #### 2.6.4 2025-12-19 - Tri et numérotation des modifications après la concaténation plutôt que par ressource, pour réduire le nombre de doublons ([#156](https://github.com/ColinMaudry/decp-processing/issues/156)) +- Utilisation du logger de prefect plûtot que `log_prints=True` #### 2.6.3 2025-12-16