From 7ade97e161a37c2fe8760029b106aaa3e5cf69f2 Mon Sep 17 00:00:00 2001 From: Nicolas Oudard Date: Thu, 5 Dec 2024 15:25:40 +0100 Subject: [PATCH] Ajout de la notion de SIREN (#1105) --- dags/create_final_actors.py | 1 + dags/sources/config/airflow_params.py | 12 +++++- dags/sources/dags/source_aliapur.py | 16 ++++---- dags/sources/dags/source_citeo.py | 7 ++++ dags/sources/dags/source_cma.py | 7 ++++ dags/sources/dags/source_corepile.py | 17 ++++---- dags/sources/dags/source_ecodds.py | 5 --- dags/sources/dags/source_ecologic.py | 9 ----- dags/sources/dags/source_ecomaison.py | 19 ++++----- dags/sources/dags/source_ecosystem.py | 12 ++++++ dags/sources/dags/source_ocab.py | 17 ++++---- dags/sources/dags/source_ocad3e.py | 12 ++++++ dags/sources/dags/source_pyreo.py | 16 ++++---- dags/sources/dags/source_refashion.py | 19 ++++----- dags/sources/dags/source_soren.py | 11 +----- dags/sources/dags/source_valdelia.py | 12 ++++++ .../business_logic/propose_acteur_changes.py | 9 ++--- .../tasks/transform/transform_column.py | 37 +++++++++++++++++- dags/sources/tasks/transform/transform_df.py | 20 ++++++++++ .../tasks/transform/test_transform_column.py | 39 +++++++++++++++++++ .../tasks/transform/test_transform_df.py | 19 ++++++++- dags_unit_tests/utils/test_mapping_utils.py | 33 ---------------- qfdmo/admin/acteur.py | 12 ++++-- qfdmo/fixtures/acteurs.json | 1 + ...ur_siren_displayedacteur_siren_and_more.py | 33 ++++++++++++++++ qfdmo/models/acteur.py | 1 + qfdmo/models/data.py | 1 + ...t_open_source_displayedacteur_ressource.py | 1 + 28 files changed, 266 insertions(+), 132 deletions(-) create mode 100644 dags_unit_tests/sources/tasks/transform/test_transform_column.py create mode 100644 qfdmo/migrations/0103_acteur_siren_displayedacteur_siren_and_more.py diff --git a/dags/create_final_actors.py b/dags/create_final_actors.py index bf67012a6..105ab3bf0 100755 --- a/dags/create_final_actors.py +++ b/dags/create_final_actors.py @@ -261,6 +261,7 @@ def write_data_to_postgres(**kwargs): "telephone", "nom_commercial", "nom_officiel", + "siren", "siret", "identifiant_externe", "acteur_type_id", diff --git a/dags/sources/config/airflow_params.py b/dags/sources/config/airflow_params.py index 2e245b5fd..263f43cae 100644 --- a/dags/sources/config/airflow_params.py +++ b/dags/sources/config/airflow_params.py @@ -2,7 +2,11 @@ from pathlib import Path import requests -from sources.tasks.transform.transform_column import convert_opening_hours +from sources.tasks.transform.transform_column import ( + clean_siren, + clean_siret, + convert_opening_hours, +) PATH_NOMENCLARURE_DECHET = ( "https://data.ademe.fr/data-fair/api/v1/datasets/sinoe-r-nomenclature-dechets/lines" @@ -13,7 +17,11 @@ KEY_LIBELLE_DECHET_ALT = "LST_TYP_DECHET" -TRANSFORMATION_MAPPING = {"convert_opening_hours": convert_opening_hours} +TRANSFORMATION_MAPPING = { + "convert_opening_hours": convert_opening_hours, + "clean_siren": clean_siren, + "clean_siret": clean_siret, +} # TODO: dataclass à implémenter pour la validation des paramètres des DAGs diff --git a/dags/sources/dags/source_aliapur.py b/dags/sources/dags/source_aliapur.py index 7f8494b68..2a7dbf0a8 100755 --- a/dags/sources/dags/source_aliapur.py +++ b/dags/sources/dags/source_aliapur.py @@ -11,20 +11,18 @@ " for Aliapur dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_citeo.py b/dags/sources/dags/source_citeo.py index 39d935aac..ac2da486a 100755 --- a/dags/sources/dags/source_citeo.py +++ b/dags/sources/dags/source_citeo.py @@ -11,6 +11,13 @@ " sur de Koumoul" ), params={ + "column_transformations": [ + { + "origin": "siren", + "transformation": "clean_siren", + "destination": "siren", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", diff --git a/dags/sources/dags/source_cma.py b/dags/sources/dags/source_cma.py index aab8b8276..d7fdb7d35 100755 --- a/dags/sources/dags/source_cma.py +++ b/dags/sources/dags/source_cma.py @@ -12,6 +12,13 @@ " for CMA reparacteur dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "name": "nom", "reparactor_description": "description", diff --git a/dags/sources/dags/source_corepile.py b/dags/sources/dags/source_corepile.py index 8ab83d3ad..48cd0af71 100755 --- a/dags/sources/dags/source_corepile.py +++ b/dags/sources/dags/source_corepile.py @@ -11,22 +11,19 @@ " for Corepile dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "siret": "siret", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", "enseigne_commerciale": "nom_commercial", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_ecodds.py b/dags/sources/dags/source_ecodds.py index 17997938c..17a1cbcf2 100755 --- a/dags/sources/dags/source_ecodds.py +++ b/dags/sources/dags/source_ecodds.py @@ -15,11 +15,6 @@ "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", "nom_de_lorganisme": "nom", "enseigne_commerciale": "nom_commercial", "longitudewgs84": "longitude", diff --git a/dags/sources/dags/source_ecologic.py b/dags/sources/dags/source_ecologic.py index 46df64152..2632fc79a 100755 --- a/dags/sources/dags/source_ecologic.py +++ b/dags/sources/dags/source_ecologic.py @@ -14,17 +14,8 @@ "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_ecomaison.py b/dags/sources/dags/source_ecomaison.py index dc53f39e6..012b8c9a9 100755 --- a/dags/sources/dags/source_ecomaison.py +++ b/dags/sources/dags/source_ecomaison.py @@ -11,25 +11,20 @@ " for Ecomaison dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", "enseigne_commerciale": "nom_commercial", - "telephone": "telephone", - "email": "email", - "siret": "siret", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", "site_web": "url", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_ecosystem.py b/dags/sources/dags/source_ecosystem.py index 0d21b065f..4171bfb94 100755 --- a/dags/sources/dags/source_ecosystem.py +++ b/dags/sources/dags/source_ecosystem.py @@ -11,6 +11,18 @@ " for Ecosystem dataset" ), params={ + "column_transformations": [ + { + "origin": "siren", + "transformation": "clean_siren", + "destination": "siren", + }, + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", diff --git a/dags/sources/dags/source_ocab.py b/dags/sources/dags/source_ocab.py index 06bed6684..2c0311c72 100755 --- a/dags/sources/dags/source_ocab.py +++ b/dags/sources/dags/source_ocab.py @@ -11,21 +11,18 @@ " for OCAB dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "siret": "siret", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_ocad3e.py b/dags/sources/dags/source_ocad3e.py index 42645b30f..136a04822 100755 --- a/dags/sources/dags/source_ocad3e.py +++ b/dags/sources/dags/source_ocad3e.py @@ -11,6 +11,18 @@ " for OCAD3E dataset" ), params={ + "column_transformations": [ + { + "origin": "siren", + "transformation": "clean_siren", + "destination": "siren", + }, + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", diff --git a/dags/sources/dags/source_pyreo.py b/dags/sources/dags/source_pyreo.py index d84bae48b..d3ed02126 100755 --- a/dags/sources/dags/source_pyreo.py +++ b/dags/sources/dags/source_pyreo.py @@ -11,20 +11,18 @@ " for Pyreo dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_refashion.py b/dags/sources/dags/source_refashion.py index 06baaae8c..90dae776f 100755 --- a/dags/sources/dags/source_refashion.py +++ b/dags/sources/dags/source_refashion.py @@ -11,26 +11,21 @@ " for Refashion dataset" ), params={ + "column_transformations": [ + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "adresse_complement": "adresse_complement", "type_de_point_de_collecte": "acteur_type_id", - "telephone": "telephone", - "siret": "siret", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "reprise": "reprise", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", "enseigne_commerciale": "nom_commercial", "site_web": "url", - "email": "email", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", "horaires_douverture": "horaires_description", diff --git a/dags/sources/dags/source_soren.py b/dags/sources/dags/source_soren.py index cef87bbde..c2721786a 100755 --- a/dags/sources/dags/source_soren.py +++ b/dags/sources/dags/source_soren.py @@ -16,22 +16,13 @@ "origin": "horaires_douverture", "transformation": "convert_opening_hours", "destination": "horaires_description", - } + }, ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", - "exclusivite_de_reprisereparation": "exclusivite_de_reprisereparation", - "uniquement_sur_rdv": "uniquement_sur_rdv", - "public_accueilli": "public_accueilli", - "reprise": "reprise", - "produitsdechets_acceptes": "produitsdechets_acceptes", - "labels_etou_bonus": "labels_etou_bonus", - "point_de_reparation": "point_de_reparation", "ecoorganisme": "source_id", - "adresse_format_ban": "adresse_format_ban", "nom_de_lorganisme": "nom", - "perimetre_dintervention": "perimetre_dintervention", "longitudewgs84": "longitude", "latitudewgs84": "latitude", }, diff --git a/dags/sources/dags/source_valdelia.py b/dags/sources/dags/source_valdelia.py index 9f405b22a..75c72cf11 100755 --- a/dags/sources/dags/source_valdelia.py +++ b/dags/sources/dags/source_valdelia.py @@ -11,6 +11,18 @@ " for Valdelia dataset" ), params={ + "column_transformations": [ + { + "origin": "siren", + "transformation": "clean_siren", + "destination": "siren", + }, + { + "origin": "siret", + "transformation": "clean_siret", + "destination": "siret", + }, + ], "column_mapping": { "id_point_apport_ou_reparation": "identifiant_externe", "type_de_point_de_collecte": "acteur_type_id", diff --git a/dags/sources/tasks/business_logic/propose_acteur_changes.py b/dags/sources/tasks/business_logic/propose_acteur_changes.py index a4f55172d..26093b99c 100644 --- a/dags/sources/tasks/business_logic/propose_acteur_changes.py +++ b/dags/sources/tasks/business_logic/propose_acteur_changes.py @@ -3,8 +3,9 @@ import numpy as np import pandas as pd +from sources.tasks.transform.transform_df import clean_phone_number from utils.base_utils import transform_location -from utils.mapping_utils import parse_float, process_phone_number, process_siret +from utils.mapping_utils import parse_float logger = logging.getLogger(__name__) @@ -49,15 +50,11 @@ def propose_acteur_changes( # On met à jour le modifie_le de qfdmo_acteur df["modifie_le"] = datetime.now() - # TODO : à déplacer dans la source_data_normalize - if "siret" in df.columns: - df["siret"] = df["siret"].apply(process_siret) - # TODO : à déplacer dans la source_data_normalize if "telephone" in df.columns and "code_postal" in df.columns: df["telephone"] = df.apply( lambda row: pd.Series( - process_phone_number(row["telephone"], row["code_postal"]) + clean_phone_number(row["telephone"], row["code_postal"]) ), axis=1, ) diff --git a/dags/sources/tasks/transform/transform_column.py b/dags/sources/tasks/transform/transform_column.py index 8e82a431d..40b81ed66 100644 --- a/dags/sources/tasks/transform/transform_column.py +++ b/dags/sources/tasks/transform/transform_column.py @@ -1,4 +1,5 @@ -from typing import Union +import re +from typing import Any, Union import pandas as pd @@ -57,3 +58,37 @@ def process_entry(entry): return "" return process_entry(opening_hours) + + +def clean_siren(siren: int | str | None) -> str | None: + siren = clean_number(siren) + + if len(siren) == 9: + return siren + return None + + +def clean_siret(siret: int | str | None) -> str | None: + siret = clean_number(siret) + + if len(siret) == 9: + return siret + + if len(siret) == 13: + return "0" + siret + + if len(siret) == 14: + return siret + + return None + + +def clean_number(number: Any) -> str: + if pd.isna(number) or number is None: + return "" + + # suppression des 2 derniers chiffres si le caractère si == .0 + number = re.sub(r"\.0$", "", str(number)) + # suppression de tous les caractères autre que digital + number = re.sub(r"[^\d+]", "", number) + return number diff --git a/dags/sources/tasks/transform/transform_df.py b/dags/sources/tasks/transform/transform_df.py index 535fa4a70..24af7a819 100644 --- a/dags/sources/tasks/transform/transform_df.py +++ b/dags/sources/tasks/transform/transform_df.py @@ -1,4 +1,5 @@ import pandas as pd +from sources.tasks.transform.transform_column import clean_number def merge_duplicates( @@ -34,3 +35,22 @@ def merge_produits_accepter(group): for produits in group: produits_sets.update([produit.strip() for produit in produits.split("|")]) return "|".join(sorted(produits_sets)) + + +def clean_phone_number(number, code_postal): + + number = clean_number(number) + + if number is None: + return None + + if len(number) == 9 and code_postal and int(code_postal) < 96000: + number = "0" + number + + if number.startswith("33"): + number = "0" + number[2:] + + if len(number) < 6: + return None + + return number diff --git a/dags_unit_tests/sources/tasks/transform/test_transform_column.py b/dags_unit_tests/sources/tasks/transform/test_transform_column.py new file mode 100644 index 000000000..962a0affd --- /dev/null +++ b/dags_unit_tests/sources/tasks/transform/test_transform_column.py @@ -0,0 +1,39 @@ +import numpy as np +import pandas as pd +import pytest +from sources.tasks.transform.transform_column import clean_siren, clean_siret + + +class TestCleanSiret: + @pytest.mark.parametrize( + "siret, expected_siret", + [ + (np.nan, None), + (pd.NA, None), + (None, None), + ("", None), + ("123456789012345", None), + ("98765432109876", "98765432109876"), + ("8765432109876", "08765432109876"), + ("AB123", None), + ], + ) + def test_clean_siret(self, siret, expected_siret): + assert clean_siret(siret) == expected_siret + + +class TestCleanSiren: + @pytest.mark.parametrize( + "siren, expected_siren", + [ + (np.nan, None), + (pd.NA, None), + (None, None), + ("", None), + ("1234567890", None), + ("123456789", "123456789"), + ("12345678", None), + ], + ) + def test_clean_siren(self, siren, expected_siren): + assert clean_siren(siren) == expected_siren diff --git a/dags_unit_tests/sources/tasks/transform/test_transform_df.py b/dags_unit_tests/sources/tasks/transform/test_transform_df.py index 05cb5608b..02809015a 100644 --- a/dags_unit_tests/sources/tasks/transform/test_transform_df.py +++ b/dags_unit_tests/sources/tasks/transform/test_transform_df.py @@ -1,6 +1,7 @@ +import numpy as np import pandas as pd import pytest -from sources.tasks.transform.transform_df import merge_duplicates +from sources.tasks.transform.transform_df import clean_phone_number, merge_duplicates class TestMergeDuplicates: @@ -124,3 +125,19 @@ def test_merge_duplicates(self, df, expected_df): ) pd.testing.assert_frame_equal(result_df, expected_df) + + +class TestCleanPhoneNumber: + @pytest.mark.parametrize( + "phone_number, code_postal, expected_phone_number", + [ + (None, None, None), + (np.NaN, None, None), + ("1 23 45 67 89", "75001", "0123456789"), + ("33 1 23 45 67 89", "75001", "0123456789"), + ("0612345678", "75001", "0612345678"), + ("+33612345678", "75001", "+33612345678"), + ], + ) + def test_clean_phone_number(self, phone_number, code_postal, expected_phone_number): + assert clean_phone_number(phone_number, code_postal) == expected_phone_number diff --git a/dags_unit_tests/utils/test_mapping_utils.py b/dags_unit_tests/utils/test_mapping_utils.py index 98b416e4b..a7b039770 100755 --- a/dags_unit_tests/utils/test_mapping_utils.py +++ b/dags_unit_tests/utils/test_mapping_utils.py @@ -1,4 +1,3 @@ -import numpy as np import pandas as pd import pytest from utils import mapping_utils @@ -49,38 +48,6 @@ def test_without_service_a_domicile_only(self): assert mapping_utils.create_identifiant_unique(row), "ecoorg_123AbC" -@pytest.mark.parametrize( - "siret, expected_siret", - [ - (None, None), - ("123456789012345", None), - ("98765432109876", "98765432109876"), - ("8765432109876", "08765432109876"), - ("AB123", None), - ], -) -def test_process_siret(siret, expected_siret): - assert mapping_utils.process_siret(siret) == expected_siret - - -@pytest.mark.parametrize( - "phone_number, code_postal, expected_phone_number", - [ - (None, None, None), - (np.NaN, None, None), - ("1 23 45 67 89", "75001", "0123456789"), - ("33 1 23 45 67 89", "75001", "0123456789"), - ("0612345678", "75001", "0612345678"), - ("+33612345678", "75001", "+33612345678"), - ], -) -def test_process_phone_number(phone_number, code_postal, expected_phone_number): - assert ( - mapping_utils.process_phone_number(phone_number, code_postal) - == expected_phone_number - ) - - class TestTransformFloat: def test_float(self): assert mapping_utils.transform_float(1.0) == 1.0 diff --git a/qfdmo/admin/acteur.py b/qfdmo/admin/acteur.py index c9e94de89..1608503c7 100644 --- a/qfdmo/admin/acteur.py +++ b/qfdmo/admin/acteur.py @@ -168,6 +168,7 @@ class BaseActeurAdmin(admin.GISModelAdmin): list_display = ( "nom", "siret", + "siren", "identifiant_unique", "code_postal", "ville", @@ -179,10 +180,11 @@ class BaseActeurAdmin(admin.GISModelAdmin): "identifiant_unique", "nom__unaccent", "siret", + "siren", "ville", ] search_help_text = ( - "Recherche sur le nom, le code postal, la ville, le siret ou" + "Recherche sur le nom, le code postal, la ville, le siret, le siren ou" " l'identifiant unique" ) list_filter = ["statut"] @@ -194,6 +196,7 @@ class BaseActeurAdmin(admin.GISModelAdmin): "nom_commercial", "nom_officiel", "siret", + "siren", "naf_principal", "description", "acteur_type", @@ -428,7 +431,7 @@ def get_form( if field_name == "siret" and ( siret := obj.siret or acteur.siret ): # and siret is not null - siren = siret[:9] + siren = obj.siren or siret[:9] form_field.help_text += ( '
ENTREPRISE : bool: return False @@ -588,6 +592,7 @@ def dehydrate_sources(self, acteur): nom_commercial = fields.Field( column_name="Nom commercial", attribute="nom_commercial", readonly=True ) + siren = fields.Field(column_name="SIREN", attribute="siren", readonly=True) siret = fields.Field(column_name="SIRET", attribute="siret", readonly=True) description = fields.Field(column_name="Description", attribute="description") acteur_type = fields.Field( @@ -709,6 +714,7 @@ class Meta: "sources", "nom", "nom_commercial", + "siren", "siret", "description", "acteur_type", diff --git a/qfdmo/fixtures/acteurs.json b/qfdmo/fixtures/acteurs.json index d25803e7f..c7e39c5f8 100644 --- a/qfdmo/fixtures/acteurs.json +++ b/qfdmo/fixtures/acteurs.json @@ -17,6 +17,7 @@ "nom_commercial":"Ressourcerie des Biscottes", "nom_officiel":null, "siret":null, + "siren":null, "source":null, "identifiant_externe":null, "statut":"ACTIF", diff --git a/qfdmo/migrations/0103_acteur_siren_displayedacteur_siren_and_more.py b/qfdmo/migrations/0103_acteur_siren_displayedacteur_siren_and_more.py new file mode 100644 index 000000000..b28c8fd6d --- /dev/null +++ b/qfdmo/migrations/0103_acteur_siren_displayedacteur_siren_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.1.1 on 2024-12-03 18:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmo", "0102_alter_action_couleur_alter_groupeaction_couleur_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="acteur", + name="siren", + field=models.CharField(blank=True, max_length=9, null=True), + ), + migrations.AddField( + model_name="displayedacteur", + name="siren", + field=models.CharField(blank=True, max_length=9, null=True), + ), + migrations.AddField( + model_name="displayedacteurtemp", + name="siren", + field=models.CharField(blank=True, max_length=9, null=True), + ), + migrations.AddField( + model_name="revisionacteur", + name="siren", + field=models.CharField(blank=True, max_length=9, null=True), + ), + ] diff --git a/qfdmo/models/acteur.py b/qfdmo/models/acteur.py index 1dd17bb77..8b1027960 100644 --- a/qfdmo/models/acteur.py +++ b/qfdmo/models/acteur.py @@ -271,6 +271,7 @@ class Meta: nom_officiel = models.CharField(max_length=255, blank=True, null=True) labels = models.ManyToManyField(LabelQualite) acteur_services = models.ManyToManyField(ActeurService, blank=True) + siren = models.CharField(max_length=9, blank=True, null=True) siret = models.CharField(max_length=14, blank=True, null=True) source = models.ForeignKey(Source, on_delete=models.CASCADE, blank=True, null=True) identifiant_externe = models.CharField(max_length=255, blank=True, null=True) diff --git a/qfdmo/models/data.py b/qfdmo/models/data.py index 3d9fffd4e..a300034ef 100644 --- a/qfdmo/models/data.py +++ b/qfdmo/models/data.py @@ -102,6 +102,7 @@ def display_acteur_details(self) -> dict: "nom": "Nom", "nom_commercial": "Nom commercial", "siret": "SIRET", + "siren": "SIREN", "url": "Site web", "email": "Email", "telephone": "Téléphone", diff --git a/unit_tests/qfdmo/test_open_source_displayedacteur_ressource.py b/unit_tests/qfdmo/test_open_source_displayedacteur_ressource.py index aa77c2e71..ccbb42d76 100644 --- a/unit_tests/qfdmo/test_open_source_displayedacteur_ressource.py +++ b/unit_tests/qfdmo/test_open_source_displayedacteur_ressource.py @@ -25,6 +25,7 @@ def test_export_columns(self): "Contributeurs", "Nom", "Nom commercial", + "SIREN", "SIRET", "Description", "Type d'acteur",