This repository has been archived by the owner on Oct 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into upgrade-sirene-import
- Loading branch information
Showing
46 changed files
with
789 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from collections import defaultdict | ||
|
||
# À une thématique DI correspond une thématique Dora | ||
THEMATIQUES_MAPPING_DI_TO_DORA = { | ||
"logement-hebergement--etre-accompagne-dans-son-projet-accession": "logement-hebergement--etre-accompagne-pour-se-loger", | ||
"logement-hebergement--etre-accompagne-en cas-de-difficultes-financieres": "logement-hebergement--gerer-son-budget", | ||
"logement-hebergement--financer-son-projet-travaux": "logement-hebergement--autre", | ||
} | ||
|
||
# Inversion du dictionnaire | ||
# À une thématique Dora correspond une liste de thématiques DI | ||
THEMATIQUES_MAPPING_DORA_TO_DI = defaultdict(list) | ||
for key, value in THEMATIQUES_MAPPING_DI_TO_DORA.items(): | ||
if not value.endswith("--autre"): | ||
THEMATIQUES_MAPPING_DORA_TO_DI[value].append(key) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,36 @@ | ||
import unittest | ||
from .constants import THEMATIQUES_MAPPING_DI_TO_DORA, THEMATIQUES_MAPPING_DORA_TO_DI | ||
from .mappings import map_service | ||
from .test_utils import FakeDataInclusionClient, make_di_service_data | ||
|
||
from django.conf import settings | ||
from rest_framework.test import APITestCase | ||
|
||
from dora import data_inclusion | ||
def test_map_service_thematiques_mapping(): | ||
input_thematiques = [ | ||
"logement-hebergement", | ||
"logement-hebergement--connaissance-de-ses-droits-et-interlocuteurs", | ||
"logement-hebergement--besoin-dadapter-mon-logement", | ||
] + list(THEMATIQUES_MAPPING_DI_TO_DORA.keys()) | ||
|
||
expected_categories = ["logement-hebergement"] | ||
expected_subcategories = [ | ||
"logement-hebergement--connaissance-de-ses-droits-et-interlocuteurs", | ||
"logement-hebergement--besoin-dadapter-mon-logement", | ||
] + list(THEMATIQUES_MAPPING_DI_TO_DORA.values()) | ||
|
||
class DataInclusionIntegrationTestCase(APITestCase): | ||
"""These integration-level tests check the connection to data.inclusion. | ||
di_service_data = make_di_service_data(thematiques=input_thematiques) | ||
service = map_service(di_service_data, False) | ||
|
||
They depend on the data.inclusion api and should not be run | ||
systematically, because of their inherent high cost and instability. | ||
""" | ||
assert sorted(service["categories"]) == sorted(expected_categories) | ||
assert sorted(service["subcategories"]) == sorted(expected_subcategories) | ||
|
||
def setUp(self): | ||
self.di_client = data_inclusion.di_client_factory() | ||
|
||
@unittest.skipIf( | ||
settings.SKIP_DI_INTEGRATION_TESTS, "data.inclusion api not available" | ||
) | ||
def test_search_services(self): | ||
self.di_client.search_services( | ||
code_insee="91223", | ||
thematiques=["mobilite--comprendre-et-utiliser-les-transports-en-commun"], | ||
) | ||
def test_di_client_search_thematiques_mapping(): | ||
input_thematique = list(THEMATIQUES_MAPPING_DORA_TO_DI.keys())[0] | ||
output_thematique = list(THEMATIQUES_MAPPING_DORA_TO_DI.values())[0][0] | ||
|
||
@unittest.skipIf( | ||
settings.SKIP_DI_INTEGRATION_TESTS, "data.inclusion api not available" | ||
) | ||
def test_list_services(self): | ||
self.di_client.list_services(source="dora") | ||
di_client = FakeDataInclusionClient() | ||
di_service_data = make_di_service_data(thematiques=[output_thematique]) | ||
di_client.services.append(di_service_data) | ||
|
||
@unittest.skipIf( | ||
settings.SKIP_DI_INTEGRATION_TESTS, "data.inclusion api not available" | ||
) | ||
def test_retrieve_service(self): | ||
services = self.di_client.list_services(source="dora") | ||
results = di_client.search_services(thematiques=[input_thematique]) | ||
|
||
self.di_client.retrieve_service( | ||
source="dora", | ||
id=services[0]["id"], | ||
) | ||
assert len(results) == 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
from unittest.mock import Mock, patch | ||
|
||
import pytest | ||
from django.conf import settings | ||
from django.urls import reverse | ||
|
||
from dora.core.test_utils import make_structure, make_user | ||
from dora.users.enums import MainActivity | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"main_activity,expected_sib_list", | ||
[ | ||
(MainActivity.OFFREUR, settings.SIB_ONBOARDING_LIST), | ||
(MainActivity.ACCOMPAGNATEUR, settings.SIB_ONBOARDING_PUTATIVE_MEMBER_LIST), | ||
( | ||
MainActivity.ACCOMPAGNATEUR_OFFREUR, | ||
settings.SIB_ONBOARDING_PUTATIVE_MEMBER_LIST, | ||
), | ||
], | ||
) | ||
@patch("dora.onboarding._create_or_update_sib_contact") | ||
@patch("dora.onboarding._setup_sib_client", Mock(return_value=True)) | ||
def test_onboard_other_activities( | ||
mock_create_contact, main_activity, expected_sib_list, api_client | ||
): | ||
# Les utilisateurs ayant offreurs ou autre pour activité principale | ||
# sont redirigés vers l'ancienne liste Brevo (onboarding "traditionnel"). | ||
|
||
# Les utilisateurs accompagnateurs ou accompagnateurs/offreurs | ||
# sont "onboardés" sur la bonne liste Brevo des invités lors de leur première invitation. | ||
|
||
# note : le deuxième patch n'est pas pris en compte comme un paramètre du test | ||
# (à cause de l'association directe/explicite à un nouveau mock) | ||
|
||
structure = make_structure() | ||
# La création d'un admin de la structure est nécessaire pour que l'utilisateur | ||
# soit rattaché en tant qu'invité (sinon il en devient le premier membre et admin). | ||
make_user(structure=structure, is_admin=True) | ||
invited_user = make_user(main_activity=main_activity) | ||
|
||
api_client.force_authenticate(user=invited_user) | ||
api_client.post( | ||
reverse("join-structure"), | ||
data={ | ||
# Utiliser le slug, car le SIRET sera invalide (random). | ||
"structure_slug": structure.slug, | ||
"cgu_version": "1", | ||
}, | ||
) | ||
|
||
assert ( | ||
invited_user in structure.putative_members.all() | ||
), "L'utilisateur n'est pas un invité de la structure" | ||
assert mock_create_contact.called, "Le contact Brevo n'a pas été créé" | ||
|
||
_, user, attrs, sib_list = mock_create_contact.call_args.args | ||
|
||
assert user == invited_user, "L'utilisateur ne correspond pas" | ||
assert attrs, "Les attributs Brevo ne sont pas définis" | ||
assert ( | ||
str(sib_list) == expected_sib_list | ||
), "L'utilisateur n'est pas rattaché à la bonne liste Brevo" | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"main_activity,expected_sib_list", | ||
[ | ||
(MainActivity.ACCOMPAGNATEUR, settings.SIB_ONBOARDING_MEMBER_LIST), | ||
(MainActivity.ACCOMPAGNATEUR_OFFREUR, settings.SIB_ONBOARDING_MEMBER_LIST), | ||
], | ||
) | ||
@patch("dora.onboarding._remove_from_sib_list") | ||
@patch("dora.onboarding._create_or_update_sib_contact") | ||
@patch("dora.onboarding._setup_sib_client", Mock(return_value=True)) | ||
def test_onboard_new_member( | ||
mock_create_contact, | ||
mock_remove_from_list, | ||
main_activity, | ||
expected_sib_list, | ||
api_client, | ||
): | ||
# Les utilisateurs accompagnateurs ou accompagnateurs/offreurs | ||
# sont "onboardés" sur la liste Brevo des membres lors de leur premier rattachement à une structure. | ||
|
||
member = make_user(main_activity=main_activity) | ||
structure = make_structure(putative_member=member) | ||
admin = make_user(structure=structure, is_admin=True) | ||
|
||
# Cette action doit-être effectuée par un admin de la structure. | ||
api_client.force_authenticate(user=admin) | ||
|
||
# L'utilisateur accepte l'invitation. | ||
r = api_client.post( | ||
reverse( | ||
"structure-putative-member-accept-membership-request", | ||
kwargs={"pk": structure.putative_membership.first().pk}, | ||
), | ||
) | ||
|
||
# Etant différent du traditionnel 200, on teste le statut de retour. | ||
assert 201 == r.status_code, "Code de status invalide (201 attendu)" | ||
|
||
assert ( | ||
member in structure.members.all() | ||
), "L'utilisateur n'est pas membre de la structure" | ||
assert mock_create_contact.called, "Le contact Brevo n'a pas été créé" | ||
|
||
_, user, attrs, sib_list = mock_create_contact.call_args.args | ||
|
||
assert user == member, "L'utilisateur ne correspond pas" | ||
assert attrs, "Les attributs Brevo ne sont pas définis" | ||
assert ( | ||
str(sib_list) == expected_sib_list | ||
), "L'utilisateur n'est pas rattaché à la bonne liste Brevo" | ||
|
||
# On retire un utilisateur de la liste Brevo "invité" après qu'il soit devenu membre. | ||
assert ( | ||
mock_remove_from_list.called | ||
), "Pas de retrait de l'utilisateur de la liste Brevo des invités" | ||
mock_remove_from_list.assert_called_with( | ||
True, user, int(settings.SIB_ONBOARDING_PUTATIVE_MEMBER_LIST) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.