From 7c0a400318ea37ce8956291d9a4143fadca14bab Mon Sep 17 00:00:00 2001 From: Patrick Nguyen Date: Tue, 21 Jul 2026 16:03:31 +0200 Subject: [PATCH] feat: sports equipment draft --- .talismanrc | 18 +- erp/forms.py | 110 ++++ erp/imports/serializers.py | 22 +- ...anitaires_presence_consistency_and_more.py | 428 +++++++++++++++ erp/models.py | 220 +++++++- erp/schema.py | 493 +++++++++++++++++- static/img/contrib/tribunes-places.png | Bin 0 -> 38613 bytes static/img/contrib/zone-depose-pmr.png | Bin 0 -> 43244 bytes static/js/ui/ConditionalForm.js | 59 ++- templates/contrib/3-transport.html | 3 + templates/contrib/4-exterieur.html | 3 + templates/contrib/6-accueil.html | 100 ++++ tests/api/tests.py | 108 ++++ tests/erp/imports/test_serializers.py | 209 ++++++++ tests/erp/test_forms.py | 66 ++- tests/erp/test_tasks.py | 175 +++++++ 16 files changed, 1976 insertions(+), 38 deletions(-) create mode 100644 erp/migrations/0191_remove_accessibilite_erp_accessibilite_sanitaires_presence_consistency_and_more.py create mode 100644 static/img/contrib/tribunes-places.png create mode 100644 static/img/contrib/zone-depose-pmr.png diff --git a/.talismanrc b/.talismanrc index 9fd8faed40..dd804e7037 100644 --- a/.talismanrc +++ b/.talismanrc @@ -16,7 +16,7 @@ fileignoreconfig: - filename: erp/export/static/schema.json checksum: 888e09b1fe8ead28a4561b05842cd852be1ca8a3b86264aa48469514f93cfdd2 - filename: templates/contrib/6-accueil.html - checksum: 6a2b50478a202eb35bf49d50ff156110eeed68287d545626753b7343bd3e3074 + checksum: 8aaacce11ed6b610a2bd7556d5f42b5035747d994eb103ccdfe0fdec0ae1c708 - filename: templates/contrib/2-a-propos.html checksum: 674d89a3766a1df233648b7de14a5116de651bfea5b4db7f4f9f05f95629a32a - filename: templates/contrib/0-start.html @@ -28,7 +28,7 @@ fileignoreconfig: - filename: templates/contrib/4-exterieur.html checksum: 4e6911a34b51f640e0fb6a2dad359628daf63459f2b3d868ce0d80ce094f8538 - filename: templates/contrib/3-transport.html - checksum: 31cb1838db8607f44c92e00e0841c18f7454943ea3a600d79f943fae2f967874 + checksum: 68334d56087d71ffb7443ca8917ed32c553786a8b1c9852bec1adec03aa138fe - filename: .circleci/config.yml checksum: 9c50da347ce5a9602eb25d2c192597343c50e062f465c0e8ae6e4aed1034407e - filename: erp/imports/mapper/service_public.py @@ -52,7 +52,13 @@ fileignoreconfig: - filename: erp/management/commands/flush_widget_stats.py checksum: 07f7fb0fbd7c587d43aad69f87e892107a6e80c8d5a5145d608905485a4f2011 - filename: tests/stats/tests.py - checksum: 3d899b94bc836e0f97b282d569ca27b513be6df54cf718e96a944a99b634444d + checksum: 14316ca4cb3801fde82de4647e7c3df271a7c5b962e3526fa06e5d190caceb27 +- filename: tests/api/tests.py + checksum: 19cc87e6a7c33d056a2c85831e86af11ba1fff4935b9fc4b786faee0c88552c9 +- filename: tests/erp/test_tasks.py + checksum: 5af076ad122ca09cd7a76c75a11c3094c70d15fa928a827a3180c8c43177a9f5 +- filename: tests/erp/imports/test_serializers.py + checksum: ec01ecc27f54e45f02eae36db0369b353e069426f19eeac2025d776760f94fec - filename: .env.sample checksum: aa3f02c8f5d30f989986f9eafaca8bc57d99d09361b9fa9c2158638bcc263f15 - filename: erp/management/commands/import_apidae.py @@ -93,3 +99,9 @@ fileignoreconfig: checksum: 40161683c6d36b3a1d5bb3c0b05594fa48ada9dd88ecc379294fa10f64743eb2 - filename: core/settings.py checksum: 541b4298f5183e65805309ef55140f6b1da02f62a1fbf196fba3cc8d7c5dab58 +- filename: erp/models.py + checksum: 7399cf142d418045c6167e0ed5b83c3f61a9102015d994929e0584f288508e67 +- filename: erp/schema.py + checksum: 319eee5047b7058a601da24eb201f2ed8fd4ece23e9dc47a92f05f2e956e7ae2 +- filename: erp/migrations/0191_remove_accessibilite_erp_accessibilite_sanitaires_presence_consistency_and_more.py + checksum: 9549fe2888e7d35c031c145eca2235510545a0b69774201c1365f466ca42f649 \ No newline at end of file diff --git a/erp/forms.py b/erp/forms.py index 2f0f8a1967..1a92224b51 100644 --- a/erp/forms.py +++ b/erp/forms.py @@ -316,6 +316,115 @@ def clean_accueil_soignant_experience(self): return self.cleaned_data["accueil_soignant_experience"] +class ContribAccessibiliteSportsEquipmentForm(ContribAccessibiliteForm): + accueil_casiers_fermeture = forms.MultipleChoiceField( + required=False, + choices=schema.ACCUEIL_SYSTEME_FERMETURE_CHOICES, + widget=forms.CheckboxSelectMultiple, + label=schema.get_label("accueil_casiers_fermeture"), + help_text=schema.get_help_text("accueil_casiers_fermeture"), + ) + + accueil_prestations_complementaires = forms.MultipleChoiceField( + required=False, + choices=schema.ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_CHOICES, + widget=forms.CheckboxSelectMultiple, + label=schema.get_label("accueil_prestations_complementaires"), + help_text=schema.get_help_text("accueil_prestations_complementaires"), + ) + + accueil_presence_espaces_specifiques = forms.MultipleChoiceField( + required=False, + choices=schema.ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHOICES, + widget=forms.CheckboxSelectMultiple, + label=schema.get_label("accueil_presence_espaces_specifiques"), + help_text=schema.get_help_text("accueil_presence_espaces_specifiques"), + ) + + fields_to_remove = ( + "accueil_personnels", # Root + "accueil_audiodescription_presence", # Root + "accueil_audiodescription", # Child + "accueil_ascenseur_etage", # Root + "accueil_ascenseur_etage_pmr", # Child + "labels", # Root + "labels_familles_handicap", # Root + "labels_autre", # Root + ) + + large_establishments_fields_to_keep = ["accueil_signaletique_interieure", "cheminement_ext_signaletique_exterieure"] + conditionals_to_add = get_conditional_fields_in(["sports_equipment"]) + large_establishments_fields_to_keep + conditionals_to_remove = get_conditional_fields_not_in(["sports_equipment"]) + + class Meta: + model = Accessibilite + exclude = ("pk",) + widgets = get_widgets_for_accessibilite() + labels = schema.get_labels(include_conditional=["sports_equipment", "large_establishments"]) + help_texts = schema.get_help_texts(include_conditional=["sports_equipment", "large_establishments"]) + required = schema.get_required_fields() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + allowed_fields = set(schema.get_help_texts(include_conditional=["sports_equipment"]).keys()) | set( + self.large_establishments_fields_to_keep + ) + for field in copy(self.fields): + if field not in allowed_fields: + self.fields.pop(field, None) + + def clean_accueil_casiers_adaptes(self): + if self.cleaned_data.get("accueil_casiers") is not True: + return None + return self.cleaned_data["accueil_casiers_adaptes"] + + def clean_accueil_casiers_fermeture(self): + if self.cleaned_data.get("accueil_casiers") is not True: + return None + return self.cleaned_data["accueil_casiers_fermeture"] + + def clean_accueil_tribunes_localisation_places(self): + if (self.cleaned_data.get("accueil_tribunes_places") or 0) < 1: + return None + return self.cleaned_data["accueil_tribunes_localisation_places"] + + def clean_accueil_tribunes_places_avec_accompagnants(self): + if (self.cleaned_data.get("accueil_tribunes_places") or 0) < 1: + return None + return self.cleaned_data["accueil_tribunes_places_avec_accompagnants"] + + def clean_accueil_vestiaires_largeur_passage(self): + if self.cleaned_data.get("accueil_vestiaires") is not True: + return None + return self.cleaned_data["accueil_vestiaires_largeur_passage"] + + def clean_accueil_douches_collectives_adaptees(self): + if self.cleaned_data.get("accueil_douches_collectives") is not True: + return None + return self.cleaned_data["accueil_douches_collectives_adaptees"] + + def clean_accueil_douches_individuelles_adaptees(self): + if self.cleaned_data.get("accueil_douches_individuelles") is not True: + return None + return self.cleaned_data["accueil_douches_individuelles_adaptees"] + + def clean_sanitaires_urinoirs(self): + if self.cleaned_data.get("sanitaires_presence") is not True: + return None + return self.cleaned_data["sanitaires_urinoirs"] + + def clean_sanitaires_largeur_porte(self): + if self.cleaned_data.get("sanitaires_adaptes") is not True: + return None + return self.cleaned_data["sanitaires_largeur_porte"] + + def clean_sanitaires_sens_transfert(self): + if self.cleaned_data.get("sanitaires_adaptes") is not True: + return None + return self.cleaned_data["sanitaires_sens_transfert"] + + class AdminAccessibiliteForm(ContribAccessibiliteForm): # Note: defining `labels` and `help_texts` in `Meta` doesn't work with custom # fields, hence why we set them up manually for each fields. @@ -942,6 +1051,7 @@ def get_contrib_forms_for_activity(activity: Activite): ACTIVITY_GROUPS["LARGE_ESTABLISHMENTS"]: ContribAccessibiliteLargeEstablishmentsForm, ACTIVITY_GROUPS["POLLING_STATION"]: ContribAccessibilitePollingStationForm, ACTIVITY_GROUPS["HEALTHCARE"]: ContribAccessibiliteHealthcareForm, + ACTIVITY_GROUPS["SPORTS_EQUIPMENT"]: ContribAccessibiliteSportsEquipmentForm, } groups = activity.groups.all() diff --git a/erp/imports/serializers.py b/erp/imports/serializers.py index 5cc43fadea..0027e98a7f 100644 --- a/erp/imports/serializers.py +++ b/erp/imports/serializers.py @@ -53,6 +53,7 @@ class AccessibilityImportSerializer(serializers.ModelSerializer): stationnement_pmr = NullBooleanField(required=False, allow_null=True) stationnement_ext_presence = NullBooleanField(required=False, allow_null=True) stationnement_ext_pmr = NullBooleanField(required=False, allow_null=True) + stationnement_zone_depose_pmr = NullBooleanField(required=False, allow_null=True) cheminement_ext_presence = NullBooleanField(required=False, allow_null=True) cheminement_ext_terrain_stable = NullBooleanField(required=False, allow_null=True) cheminement_ext_plain_pied = NullBooleanField(required=False, allow_null=True) @@ -95,8 +96,18 @@ class AccessibilityImportSerializer(serializers.ModelSerializer): accueil_soignant = NullBooleanField(required=False, allow_null=True) accueil_salle_consultation_accessible = NullBooleanField(required=False, allow_null=True) accueil_consultation_domicile = NullBooleanField(required=False, allow_null=True) + accueil_aire_de_jeux = NullBooleanField(required=False, allow_null=True) + accueil_tribunes = NullBooleanField(required=False, allow_null=True) + accueil_vestiaires = NullBooleanField(required=False, allow_null=True) + accueil_douches_collectives = NullBooleanField(required=False, allow_null=True) + accueil_douches_collectives_adaptees = NullBooleanField(required=False, allow_null=True) + accueil_douches_individuelles = NullBooleanField(required=False, allow_null=True) + accueil_douches_individuelles_adaptees = NullBooleanField(required=False, allow_null=True) + accueil_casiers = NullBooleanField(required=False, allow_null=True) + accueil_casiers_adaptes = NullBooleanField(required=False, allow_null=True) sanitaires_presence = NullBooleanField(required=False, allow_null=True) sanitaires_adaptes = NullBooleanField(required=False, allow_null=True) + sanitaires_urinoirs = NullBooleanField(required=False, allow_null=True) conformite = NullBooleanField(required=False, allow_null=True) class Meta: @@ -222,15 +233,22 @@ def validate_accessibilite(self, obj): return obj + @staticmethod + def _should_display_children(field_config, current_value): + min_value = field_config.get("min_value_to_display_children") + if min_value is not None: + return current_value is not None and current_value >= min_value + + return str(current_value) in field_config.get("value_to_display_children", []) + def _handle_children_reinit(self, accessibilite_instance, field_name): field_config = FIELDS.get(field_name) if not field_config or not field_config.get("children"): return current_value = getattr(accessibilite_instance, field_name) - trigger_values = field_config.get("value_to_display_children", []) - if str(current_value) not in trigger_values: + if not self._should_display_children(field_config, current_value): for child_name in field_config.get("children"): field_obj = accessibilite_instance._meta.get_field(child_name) default_value = field_obj.get_default() diff --git a/erp/migrations/0191_remove_accessibilite_erp_accessibilite_sanitaires_presence_consistency_and_more.py b/erp/migrations/0191_remove_accessibilite_erp_accessibilite_sanitaires_presence_consistency_and_more.py new file mode 100644 index 0000000000..a77c0147c2 --- /dev/null +++ b/erp/migrations/0191_remove_accessibilite_erp_accessibilite_sanitaires_presence_consistency_and_more.py @@ -0,0 +1,428 @@ +# Generated by Django 6.0.7 on 2026-08-03 20:32 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("erp", "0190_rpa"), + ] + + operations = [ + migrations.RemoveConstraint( + model_name="accessibilite", + name="erp_accessibilite_sanitaires_presence_consistency", + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_aire_de_jeux", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Accessibilité de l'aire de jeux à une personne en fauteuil", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_casiers", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Présence de casiers", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_casiers_adaptes", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Casiers adaptés", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_casiers_fermeture", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + blank=True, + choices=[ + ("serrure_avec_cle", "Serrure avec clé"), + ("serrure_electronique_a_code", "Serrure électronique à code"), + ("serrure_mecanique_a_code", "Serrure mécanique à code"), + ("verrou_cadenas", "Verrou pour cadenas personnel"), + ("autre", "Autre"), + ], + max_length=255, + ), + blank=True, + default=list, + null=True, + verbose_name="Système de fermeture des casiers", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_douches_collectives", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Présence de douches collectives", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_douches_collectives_adaptees", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Accessibilité des douches collectives", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_douches_individuelles", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Présence de douches individuelles", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_douches_individuelles_adaptees", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Accessibilité des douches individuelles", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_physique", + field=models.CharField( + blank=True, + choices=[ + ("inexistant", "Aucun personnel"), + ("non_forme", "Personnel non formé"), + ("sensibilise_ou_forme", "Personne sensibilisé ou formé"), + (None, "Inconnu"), + ], + max_length=25, + null=True, + verbose_name="Accueil physique", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_presence_espaces_specifiques", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + blank=True, + choices=[ + ( + "presence_espace_depose_equipements", + "Espace de dépose d'équipements (fauteuils, déambulateurs...)", + ), + ( + "presence_espace_repos_sensoriel", + "Espace de repos sensoriel (hyposensoriel, d'apaisement...)", + ), + ("presence_espace_chiens_guides", "Espace destiné aux chiens guides et d'assistance"), + ( + "presence_espace_salle_de_change", + "Salle de change destinée aux personnes ayant des handicaps multiples ou complexes", + ), + ], + max_length=255, + ), + blank=True, + default=list, + null=True, + verbose_name="Présence d’espaces spécifiques", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_prestations_complementaires", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + blank=True, + choices=[ + ("sonorisation_arbitrage", "Sonorisation de l'arbitrage possible"), + ("score_visible", "Score visible depuis les places assises"), + ( + "prestation_espace_depose_equipements", + "Espace de dépose d'équipements (fauteuils, déambulateurs...)", + ), + ("reservation_place_facile_d_acces", "Réservation possible de places facile d'accès"), + ], + max_length=255, + ), + blank=True, + default=list, + null=True, + verbose_name="Prestations complémentaires", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_tribunes", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Accessibilité des places des tribunes", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_tribunes_localisation_places", + field=models.CharField( + blank=True, + choices=[ + ("niveau_aire_de_jeux", "Places situées au niveau de l'aire de jeux"), + ("reparti_differents_niveaux", "Places répartis différents niveaux des tribunes"), + (None, "Inconnu"), + ], + max_length=100, + null=True, + verbose_name="Localisation des places dans les tribunes", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_tribunes_places", + field=models.PositiveSmallIntegerField( + blank=True, + null=True, + verbose_name="Nombre de places accessibles pour les personnes en fauteuil roulant", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_tribunes_places_avec_accompagnants", + field=models.PositiveSmallIntegerField( + blank=True, null=True, verbose_name="Nombre de places pour les accompagnants dans les tribunes" + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_vestiaires", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Accessibilité des vestiaires", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="accueil_vestiaires_largeur_passage", + field=models.CharField( + blank=True, + choices=[ + ("entre_90_et_110", "Entre 90 et 110 cm"), + ("superieur_a_110", "Supérieure à 110 cm"), + (None, "Inconnu"), + ], + max_length=40, + null=True, + verbose_name="Largeur de passage pour se rendre dans les vestiaires", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="sanitaires_largeur_porte", + field=models.CharField( + blank=True, + choices=[ + ("entre_80_et_90", "Entre 80 et 90 cm"), + ("entre_90_et_110", "Entre 90 et 110 cm"), + (None, "Inconnu"), + ], + max_length=40, + null=True, + verbose_name="Largeur de porte des toilettes", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="sanitaires_sens_transfert", + field=models.CharField( + blank=True, + choices=[ + ("gauche", "Gauche"), + ("droite", "Droite"), + ("gauche_et_droite", "Gauche et droite"), + (None, "Inconnu"), + ], + max_length=40, + null=True, + verbose_name="Sens du transfert", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="sanitaires_urinoirs", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Hauteur des urinoirs", + ), + ), + migrations.AddField( + model_name="accessibilite", + name="stationnement_zone_depose_pmr", + field=models.BooleanField( + blank=True, + choices=[(True, "Oui"), (False, "Non"), (None, "Inconnu")], + null=True, + verbose_name="Aire de dépose PMR", + ), + ), + migrations.AlterField( + model_name="accessibilite", + name="accueil_prise_en_charge_patients", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + blank=True, + choices=[ + ("preparation", "Préparation à la consultation ou visite préalable"), + ("organisation", "Organisation spécifique pour réduire le temps d’attente"), + ("outils_communication", "Outils de communication simplifiés pour expliquer les actes"), + ("materiel_auscultation", "Matériel médical adapté aux personnes obèses"), + ], + max_length=255, + ), + blank=True, + default=list, + null=True, + verbose_name="Prise en charge des patients", + ), + ), + migrations.AlterField( + model_name="accessibilite", + name="accueil_soignant_experience", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + blank=True, + choices=[ + ("visuel", "Visuel"), + ("auditif", "Auditif"), + ("moteur", "Moteur"), + ("mental", "Mental (déficience intellectuelle)"), + ("psychique", "Psychique (psychose, trouble bipolaire)"), + ("cognitif", "Cognitif (trouble du spectre de l'autisme, TDAH...)"), + ], + max_length=255, + ), + blank=True, + default=list, + null=True, + verbose_name="Expérience du soignant concernant les types de handicap", + ), + ), + migrations.AlterField( + model_name="erp", + name="checked_up_to_date_at", + field=models.DateTimeField( + auto_now_add=True, null=True, verbose_name="Dernière vérification des informations" + ), + ), + migrations.AddConstraint( + model_name="accessibilite", + constraint=models.CheckConstraint( + condition=models.Q( + models.Q(("sanitaires_presence", True), ("sanitaires_presence__isnull", False)), + models.Q(("sanitaires_adaptes", None), ("sanitaires_urinoirs", None)), + _connector="OR", + ), + name="erp_accessibilite_sanitaires_presence_consistency", + ), + ), + migrations.AddConstraint( + model_name="accessibilite", + constraint=models.CheckConstraint( + condition=models.Q( + models.Q(("sanitaires_adaptes", True), ("sanitaires_adaptes__isnull", False)), + models.Q( + models.Q( + ("sanitaires_largeur_porte__isnull", True), + ("sanitaires_largeur_porte", ""), + _connector="OR", + ), + models.Q( + ("sanitaires_sens_transfert__isnull", True), + ("sanitaires_sens_transfert", ""), + _connector="OR", + ), + ), + _connector="OR", + ), + name="erp_accessibilite_sanitaires_adaptes_consistency", + ), + ), + migrations.AddConstraint( + model_name="accessibilite", + constraint=models.CheckConstraint( + condition=models.Q( + models.Q(("accueil_casiers", True), ("accueil_casiers__isnull", False)), + models.Q( + ("accueil_casiers_adaptes", None), + models.Q( + ("accueil_casiers_fermeture__isnull", True), + ("accueil_casiers_fermeture", []), + _connector="OR", + ), + ), + _connector="OR", + ), + name="erp_accessibilite_accueil_casiers_consistency", + ), + ), + migrations.AddConstraint( + model_name="accessibilite", + constraint=models.CheckConstraint( + condition=models.Q( + models.Q( + ("accueil_tribunes_places", 0), + ("accueil_tribunes_places__isnull", True), + _connector="OR", + _negated=True, + ), + models.Q( + models.Q( + ("accueil_tribunes_localisation_places__isnull", True), + ("accueil_tribunes_localisation_places", ""), + _connector="OR", + ), + ("accueil_tribunes_places_avec_accompagnants__isnull", True), + ), + _connector="OR", + ), + name="erp_accessibilite_accueil_tribunes_places_consistency", + ), + ), + migrations.AddConstraint( + model_name="accessibilite", + constraint=models.CheckConstraint( + condition=models.Q( + models.Q(("accueil_vestiaires", True), ("accueil_vestiaires__isnull", False)), + ("accueil_vestiaires_largeur_passage__isnull", True), + ("accueil_vestiaires_largeur_passage", ""), + _connector="OR", + ), + name="erp_accessibilite_accueil_vestiaires_consistency", + ), + ), + ] diff --git a/erp/models.py b/erp/models.py index 901cfcc16b..3151323599 100644 --- a/erp/models.py +++ b/erp/models.py @@ -44,6 +44,7 @@ "LARGE_ESTABLISHMENTS": "Grands établissements", "POLLING_STATION": "Bureau de vote", "HEALTHCARE": "Santé", + "SPORTS_EQUIPMENT": "Équipements sportifs", } @@ -1265,7 +1266,15 @@ class Meta: CheckConstraint( name="%(app_label)s_%(class)s_sanitaires_presence_consistency", condition=(Q(sanitaires_presence=True) & Q(sanitaires_presence__isnull=False)) - | Q(sanitaires_adaptes=None), + | (Q(sanitaires_adaptes=None) & Q(sanitaires_urinoirs=None)), + ), + CheckConstraint( + name="%(app_label)s_%(class)s_sanitaires_adaptes_consistency", + condition=(Q(sanitaires_adaptes=True) & Q(sanitaires_adaptes__isnull=False)) + | ( + (Q(sanitaires_largeur_porte__isnull=True) | Q(sanitaires_largeur_porte="")) + & (Q(sanitaires_sens_transfert__isnull=True) | Q(sanitaires_sens_transfert="")) + ), ), CheckConstraint( name="%(app_label)s_%(class)s_labels_consistency", @@ -1297,6 +1306,36 @@ class Meta: | (Q(accueil_soignant_experience__isnull=True) | Q(accueil_soignant_experience=[])) ), ), + CheckConstraint( + name="%(app_label)s_%(class)s_accueil_casiers_consistency", + condition=( + (Q(accueil_casiers=True) & Q(accueil_casiers__isnull=False)) + | ( + Q(accueil_casiers_adaptes=None) + & (Q(accueil_casiers_fermeture__isnull=True) | Q(accueil_casiers_fermeture=[])) + ) + ), + ), + CheckConstraint( + name="%(app_label)s_%(class)s_accueil_tribunes_places_consistency", + condition=( + ~(Q(accueil_tribunes_places=0) | Q(accueil_tribunes_places__isnull=True)) + | ( + ( + Q(accueil_tribunes_localisation_places__isnull=True) + | Q(accueil_tribunes_localisation_places="") + ) + & Q(accueil_tribunes_places_avec_accompagnants__isnull=True) + ) + ), + ), + CheckConstraint( + name="%(app_label)s_%(class)s_accueil_vestiaires_consistency", + condition=( + (Q(accueil_vestiaires=True) & Q(accueil_vestiaires__isnull=False)) + | (Q(accueil_vestiaires_largeur_passage__isnull=True) | Q(accueil_vestiaires_largeur_passage="")) + ), + ), ] erp = models.OneToOneField( @@ -1361,6 +1400,12 @@ class Meta: choices=schema.get_field_choices("stationnement_ext_pmr"), verbose_name=translate_lazy("Stationnements PMR à proximité de l'ERP"), ) + stationnement_zone_depose_pmr = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("stationnement_zone_depose_pmr"), + verbose_name=translate_lazy("Aire de dépose PMR"), + ) ################################### # Espace et Cheminement extérieur # @@ -1897,6 +1942,112 @@ class Meta: blank=True, verbose_name=translate_lazy("Prise en charge des patients"), ) + accueil_physique = models.CharField( + max_length=25, + null=True, + blank=True, + verbose_name=translate_lazy("Accueil physique"), + choices=schema.ACCUEIL_PHYSIQUE_CHOICES, + ) + accueil_aire_de_jeux = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_aire_de_jeux"), + verbose_name=translate_lazy("Accessibilité de l'aire de jeux à une personne en fauteuil"), + ) + accueil_tribunes = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_tribunes"), + verbose_name=translate_lazy("Accessibilité des places des tribunes"), + ) + accueil_tribunes_places = models.PositiveSmallIntegerField( + null=True, + blank=True, + verbose_name=translate_lazy("Nombre de places accessibles pour les personnes en fauteuil roulant"), + ) + accueil_tribunes_localisation_places = models.CharField( + max_length=100, + null=True, + blank=True, + verbose_name=translate_lazy("Localisation des places dans les tribunes"), + choices=schema.ACCUEIL_TRIBUNES_PLACES_CHOICES, + ) + accueil_tribunes_places_avec_accompagnants = models.PositiveSmallIntegerField( + null=True, + blank=True, + verbose_name=translate_lazy("Nombre de places pour les accompagnants dans les tribunes"), + ) + accueil_vestiaires = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_vestiaires"), + verbose_name=translate_lazy("Accessibilité des vestiaires"), + ) + accueil_vestiaires_largeur_passage = models.CharField( + max_length=40, + null=True, + blank=True, + verbose_name=translate_lazy("Largeur de passage pour se rendre dans les vestiaires"), + choices=schema.ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_CHOICES, + ) + accueil_douches_collectives = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_douches_collectives"), + verbose_name=translate_lazy("Présence de douches collectives"), + ) + accueil_douches_collectives_adaptees = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_douches_collectives_adaptees"), + verbose_name=translate_lazy("Accessibilité des douches collectives"), + ) + accueil_douches_individuelles = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_douches_individuelles"), + verbose_name=translate_lazy("Présence de douches individuelles"), + ) + accueil_douches_individuelles_adaptees = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_douches_individuelles_adaptees"), + verbose_name=translate_lazy("Accessibilité des douches individuelles"), + ) + accueil_casiers = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_casiers"), + verbose_name=translate_lazy("Présence de casiers"), + ) + accueil_casiers_adaptes = models.BooleanField( + null=True, + blank=True, + choices=schema.get_field_choices("accueil_casiers_adaptes"), + verbose_name=translate_lazy("Casiers adaptés"), + ) + accueil_casiers_fermeture = ArrayField( + models.CharField(max_length=255, blank=True, choices=schema.ACCUEIL_SYSTEME_FERMETURE_CHOICES), + default=list, + null=True, + blank=True, + verbose_name=translate_lazy("Système de fermeture des casiers"), + ) + accueil_prestations_complementaires = ArrayField( + models.CharField(max_length=255, blank=True, choices=schema.ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_CHOICES), + verbose_name=translate_lazy("Prestations complémentaires"), + default=list, + null=True, + blank=True, + ) + accueil_presence_espaces_specifiques = ArrayField( + models.CharField(max_length=255, blank=True, choices=schema.ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHOICES), + verbose_name=translate_lazy("Présence d’espaces spécifiques"), + default=list, + null=True, + blank=True, + ) ############## # Sanitaires # ############## @@ -1906,14 +2057,32 @@ class Meta: choices=schema.get_field_choices("sanitaires_presence"), verbose_name=translate_lazy("Sanitaires"), ) - sanitaires_adaptes = models.BooleanField( null=True, blank=True, choices=schema.get_field_choices("sanitaires_adaptes"), verbose_name=translate_lazy("Nombre de sanitaires adaptés"), ) - + sanitaires_largeur_porte = models.CharField( + max_length=40, + null=True, + blank=True, + verbose_name=translate_lazy("Largeur de porte des toilettes"), + choices=schema.SANITAIRES_LARGEUR_PORTE_CHOICES, + ) + sanitaires_sens_transfert = models.CharField( + max_length=40, + null=True, + blank=True, + verbose_name=translate_lazy("Sens du transfert"), + choices=schema.SANITAIRES_SENS_TRANSFERT_CHOICES, + ) + sanitaires_urinoirs = models.BooleanField( + null=True, + blank=True, + verbose_name=translate_lazy("Hauteur des urinoirs"), + choices=schema.get_field_choices("sanitaires_urinoirs"), + ) ########## # labels # ########## @@ -2138,6 +2307,51 @@ def get_accueil_soignant_experience(self): for soignant_experience in self.accueil_soignant_experience ] + def get_accueil_tribunes_places_avec_accompagnants(self): + field = schema.FIELDS["accueil_tribunes_places_avec_accompagnants"] + if not self.accueil_tribunes_places_avec_accompagnants: + return str(field["help_text_ui_neg"]) + + return "{} : {}".format(field["help_text_ui"], self.accueil_tribunes_places_avec_accompagnants) + + def get_sanitaires_largeur_porte(self): + text = schema.FIELDS["sanitaires_largeur_porte"]["help_text_ui"] + " " + self.sanitaires_largeur_porte + return text + + def get_accueil_tribunes_places(self): + return "{} {}".format(self.accueil_tribunes_places, schema.FIELDS["accueil_tribunes_places"]["help_text_ui"]) + + def get_accueil_casiers_fermeture(self): + if not self.accueil_casiers_fermeture: + return + accueil_casiers_fermeture_text = {k: str(v) for k, v in schema.ACCUEIL_SYSTEME_FERMETURE_CHOICES} + return [ + accueil_casiers_fermeture_text.get(casiers_fermeture) + for casiers_fermeture in self.accueil_casiers_fermeture + ] + + def get_accueil_prestations_complementaires(self): + if not self.accueil_prestations_complementaires: + return + accueil_prestations_complementaires_text = { + k: str(v) for k, v in schema.ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_CHOICES + } + return [ + accueil_prestations_complementaires_text.get(prestations_complementaires) + for prestations_complementaires in self.accueil_prestations_complementaires + ] + + def get_accueil_presence_espaces_specifiques(self): + if not self.accueil_presence_espaces_specifiques: + return + accueil_presence_espaces_specifiques_text = { + k: str(v) for k, v in schema.ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHOICES + } + return [ + accueil_presence_espaces_specifiques_text.get(presence_espaces_specifiques) + for presence_espaces_specifiques in self.accueil_presence_espaces_specifiques + ] + def get_accueil_prise_en_charge_patients(self): if not self.accueil_prise_en_charge_patients: return diff --git a/erp/schema.py b/erp/schema.py index 29de896f69..2a9693762a 100644 --- a/erp/schema.py +++ b/erp/schema.py @@ -151,6 +151,106 @@ ), ] +ACCUEIL_PHYSIQUE_INEXISTANT = "inexistant" +ACCUEIL_PHYSIQUE_NON_FORME = "non_forme" +ACCUEIL_PHYSIQUE_SENSIBILISE_OU_FORME = "sensibilise_ou_forme" +ACCUEIL_PHYSIQUE_CHOICES = [ + (ACCUEIL_PHYSIQUE_INEXISTANT, translate_lazy("Aucun personnel")), + (ACCUEIL_PHYSIQUE_NON_FORME, translate_lazy("Personnel non formé")), + (ACCUEIL_PHYSIQUE_SENSIBILISE_OU_FORME, translate_lazy("Personne sensibilisé ou formé")), + (None, UNKNOWN), +] + +ACCUEIL_TRIBUNES_PLACES_AIRE_DE_JEUX = "niveau_aire_de_jeux" +ACCUEIL_TRIBUNES_PLACES_REPARTIES_DIFFERENTS_NIVEAUX = "reparti_differents_niveaux" +ACCUEIL_TRIBUNES_PLACES_CHOICES = [ + (ACCUEIL_TRIBUNES_PLACES_AIRE_DE_JEUX, translate_lazy("Places situées au niveau de l'aire de jeux")), + ( + ACCUEIL_TRIBUNES_PLACES_REPARTIES_DIFFERENTS_NIVEAUX, + translate_lazy("Places répartis différents niveaux des tribunes"), + ), + (None, UNKNOWN), +] + +ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_ENTRE_90_ET_110 = "entre_90_et_110" +ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_SUPERIEUR_A_110 = "superieur_a_110" +ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_CHOICES = [ + (ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_ENTRE_90_ET_110, translate_lazy("Entre 90 et 110 cm")), + (ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_SUPERIEUR_A_110, translate_lazy("Supérieure à 110 cm")), + (None, UNKNOWN), +] + +SANITAIRES_LARGEUR_PORTE_ENTRE_80_et_90 = "entre_80_et_90" +SANITAIRES_LARGEUR_PORTE_ENTRE_90_ET_110 = "entre_90_et_110" +SANITAIRES_LARGEUR_PORTE_CHOICES = [ + (SANITAIRES_LARGEUR_PORTE_ENTRE_80_et_90, translate_lazy("Entre 80 et 90 cm")), + (SANITAIRES_LARGEUR_PORTE_ENTRE_90_ET_110, translate_lazy("Entre 90 et 110 cm")), + (None, UNKNOWN), +] + +SANITAIRES_SENS_TRANSFERT_GAUCHE = "gauche" +SANITAIRES_SENS_TRANSFERT_DROITE = "droite" +SANITAIRES_SENS_TRANSFERT_GAUCHE_ET_DROITE = "gauche_et_droite" +SANITAIRES_SENS_TRANSFERT_CHOICES = [ + (SANITAIRES_SENS_TRANSFERT_GAUCHE, translate_lazy("Gauche")), + (SANITAIRES_SENS_TRANSFERT_DROITE, translate_lazy("Droite")), + (SANITAIRES_SENS_TRANSFERT_GAUCHE_ET_DROITE, translate_lazy("Gauche et droite")), + (None, UNKNOWN), +] + +ACCUEIL_SYSTEME_FERMETURE_SERRURE_AVEC_CLE = "serrure_avec_cle" +ACCUEIL_SYSTEME_FERMETURE_ELECTRONIQUE_A_CODE = "serrure_electronique_a_code" +ACCUEIL_SYSTEME_FERMETURE_MECANIQUE_A_CODE = "serrure_mecanique_a_code" +ACCUEIL_SYSTEME_FERMETURE_VERROU_CADENAS = "verrou_cadenas" +ACCUEIL_SYSTEME_FERMETURE_AUTRE = "autre" +ACCUEIL_SYSTEME_FERMETURE_CHOICES = [ + (ACCUEIL_SYSTEME_FERMETURE_SERRURE_AVEC_CLE, translate_lazy("Serrure avec clé")), + (ACCUEIL_SYSTEME_FERMETURE_ELECTRONIQUE_A_CODE, translate_lazy("Serrure électronique à code")), + (ACCUEIL_SYSTEME_FERMETURE_MECANIQUE_A_CODE, translate_lazy("Serrure mécanique à code")), + (ACCUEIL_SYSTEME_FERMETURE_VERROU_CADENAS, translate_lazy("Verrou pour cadenas personnel")), + (ACCUEIL_SYSTEME_FERMETURE_AUTRE, translate_lazy("Autre")), +] + +ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_SONORISATION = "sonorisation_arbitrage" +ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_SCORE_VISIBLE = "score_visible" +ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_ESPACE_DEPOSE_EQUIPEMENTS = "prestation_espace_depose_equipements" +ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_RESERVATION_PLACE_FACILE_ACCES = "reservation_place_facile_d_acces" +ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_CHOICES = [ + (ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_SONORISATION, translate_lazy("Sonorisation de l'arbitrage possible")), + (ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_SCORE_VISIBLE, translate_lazy("Score visible depuis les places assises")), + ( + ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_ESPACE_DEPOSE_EQUIPEMENTS, + translate_lazy("Espace de dépose d'équipements (fauteuils, déambulateurs...)"), + ), + ( + ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_RESERVATION_PLACE_FACILE_ACCES, + translate_lazy("Réservation possible de places facile d'accès"), + ), +] + +ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_DEPOSE_EQUIPEMENTS = "presence_espace_depose_equipements" +ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_REPOS_SENSORIEL = "presence_espace_repos_sensoriel" +ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHIENS_GUIDES = "presence_espace_chiens_guides" +ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_SALLE_DE_CHANGE = "presence_espace_salle_de_change" +ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHOICES = [ + ( + ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_DEPOSE_EQUIPEMENTS, + translate_lazy("Espace de dépose d'équipements (fauteuils, déambulateurs...)"), + ), + ( + ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_REPOS_SENSORIEL, + translate_lazy("Espace de repos sensoriel (hyposensoriel, d'apaisement...)"), + ), + ( + ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHIENS_GUIDES, + translate_lazy("Espace destiné aux chiens guides et d'assistance"), + ), + ( + ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_SALLE_DE_CHANGE, + translate_lazy("Salle de change destinée aux personnes ayant des handicaps multiples ou complexes"), + ), +] + HANDICAP_AUDITIF = "auditif" HANDICAP_MENTAL = "mental" HANDICAP_MOTEUR = "moteur" @@ -963,6 +1063,33 @@ "free_text": False, "root": False, }, + "stationnement_zone_depose_pmr": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Aire de dépose PMR"), + "help_text": mark_safe( + translate_lazy( + "Existe-t-il une zone de dépose PMR pour les grands véhicules adaptés à proximité de l'entrée du gymnase ? (au moins 8m de longueur)" + ) + ), + "help_text_ui": translate_lazy("Présence d'une zone de dépose PMR"), + "help_text_ui_v2": translate_lazy("Présence d'une zone de dépose PMR"), + "help_text_ui_neg": translate_lazy("Pas de zone de dépose PMR"), + "help_text_ui_neg_v2": translate_lazy("Pas de zone de dépose PMR"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "choices_images": ( + ("/static/img/contrib/zone-depose-pmr.png"), + ("/static/img/contrib/no.png"), + ("/static/img/contrib/unknown.png"), + ), + "conditional": "sports_equipment", + "section": SECTION_TRANSPORT, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "root": True, + }, # Cheminement extérieur "cheminement_ext_presence": { "type": "boolean", @@ -2688,6 +2815,320 @@ "root": True, "excluded_from_completion_rate": True, }, + "accueil_physique": { + "type": "string", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Accueil physique"), + "help_text": mark_safe( + translate_lazy("Y a-t-il du personnel présent pendant les heures d’ouverture de l'établissement ?") + ), + "help_text_ui": translate_lazy("Présence de personnel pendant les heures d'ouverture"), + "help_text_ui_neg": translate_lazy("Pas de personnel dans l'établisement"), + "choices": ACCUEIL_PHYSIQUE_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": None, + "free_text": False, + "conditional": "sports_equipment", + "root": True, + }, + "accueil_aire_de_jeux": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Aire de jeux"), + "help_text": mark_safe(translate_lazy("L'aire de jeux est-elle accessible à une personne en fauteuil ?")), + "help_text_ui": translate_lazy("L'aire de jeux est accessible à une personne en fauteuil"), + "help_text_ui_neg": translate_lazy("L'aire de jeux n'est pas accessible à une personne en fauteuil"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "root": True, + }, + "accueil_tribunes": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Tribunes"), + "help_text": mark_safe(translate_lazy("Les places destinées aux spectateurs ont-elles un dossier ?")), + "help_text_ui": translate_lazy("Places spectateurs avec dossier"), + "help_text_ui_neg": translate_lazy("Places spectateurs sans dossier"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "root": True, + }, + "accueil_tribunes_places": { + "type": "number", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Places accessibles en tribunes"), + "help_text": mark_safe( + translate_lazy("Combien y a-t-il de places accessibles pour les personnes en fauteuil roulant ?") + ), + "help_text_ui": translate_lazy("Places accessibles pour les personnes en fauteuil roulant"), + "help_text_ui_neg": translate_lazy("Places accessibles pour les personnes en fauteuil roulant"), + "choices": None, + "unit": "place", + "section": SECTION_ACCUEIL, + "nullable_bool": False, + "free_text": False, + "should_display_label": False, + "conditional": "sports_equipment", + "min_value_to_display_children": 1, + "children": ["accueil_tribunes_localisation_places", "accueil_tribunes_places_avec_accompagnants"], + "root": True, + }, + "accueil_tribunes_localisation_places": { + "type": "string", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Où sont elles localisées ?")), + "help_text_ui": translate_lazy("Localisation des places"), + "help_text_ui_neg": translate_lazy("Localisation des places"), + "choices": ACCUEIL_TRIBUNES_PLACES_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_tribunes_places_avec_accompagnants": { + "type": "number", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe( + translate_lazy( + "Est-ce que des places pour les accompagnants sont proposées à côté des places pour les personnes en fauteuil roulant ?" + ) + ), + "help_text_ui": translate_lazy("Places accompagnant à côté des places pour les personnes en fauteuil roulant"), + "help_text_ui_neg": translate_lazy( + "Pas de place accompagnant à côté des places pour les personnes en fauteuil roulant" + ), + "choices": None, + "unit": "place", + "section": SECTION_ACCUEIL, + "nullable_bool": False, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_vestiaires": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Vestiaires"), + "help_text": mark_safe( + translate_lazy( + "Les vestiaires sont-ils accessibles à une personne en fauteuil roulant (cheminement et porte) ?" + ) + ), + "help_text_ui": translate_lazy("Vestiaires accessibles"), + "help_text_ui_neg": translate_lazy( + "Les vestiaires ne sont pas accessibles aux personnes en fauteuil roulant par un passage d'une largeur entre 90 et 110 cm/ supérieure à 110 cm" + ), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "value_to_display_children": ["True"], + "children": ["accueil_vestiaires_largeur_passage"], + "root": True, + }, + "accueil_vestiaires_largeur_passage": { + "type": "string", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Quelle est la largeur de passage pour se rendre dans les vestiaires ?")), + "help_text_ui": translate_lazy("Largeur du passage d'au moins 90 cm"), + "help_text_ui_neg": translate_lazy("Largeur inférieure à 90 cm"), + "choices": ACCUEIL_VESTIAIRES_LARGEUR_PASSAGE_CHOICES, + "unit": "centimètre", + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_douches_collectives": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Douches collectives"), + "help_text": mark_safe(translate_lazy("Présence de douches collectives ?")), + "help_text_ui": translate_lazy("Présence de douches collectives"), + "help_text_ui_neg": translate_lazy("Pas de douches collectives"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "value_to_display_children": ["True"], + "children": ["accueil_douches_collectives_adaptees"], + "root": True, + }, + "accueil_douches_collectives_adaptees": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe( + translate_lazy( + "Les douches sont-elles accessibles pour une personne en fauteuil roulant ? (accès de plain pied, largeur minimale de 90cm, espace de giration)" + ) + ), + "help_text_ui": translate_lazy("Présence de douches collectives accessibles"), + "help_text_ui_neg": translate_lazy("Pas de douches collectives accessibles aux personnes en fauteuil roulant"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_douches_individuelles": { + "type": "boolean", + "label": translate_lazy("Douches individuelles"), + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Présence de cabines de douche individuelles ?")), + "help_text_ui": translate_lazy("Présence de cabines de douche individuelles accessibles"), + "help_text_ui_neg": translate_lazy( + "Pas de cabine de douche individuelles accessibles aux personnes en fauteuil roulant" + ), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "value_to_display_children": ["True"], + "children": ["accueil_douches_individuelles_adaptees"], + "root": True, + }, + "accueil_douches_individuelles_adaptees": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe( + translate_lazy( + "Est-ce qu'il y a des cabines de douches accessibles ? (Espace de giration, diamètre de 1m50, espace d'usage, espace derrière la porte.)" + ) + ), + "help_text_ui": translate_lazy("Présence de cabines de douche individuelles accessibles"), + "help_text_ui_neg": translate_lazy( + "Pas de cabines de douche individuelles accessibles aux personnes en fauteuil roulant" + ), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_casiers": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "label": translate_lazy("Casiers"), + "help_text": mark_safe(translate_lazy("Y a-t-il des casiers mis à disposition du public?")), + "help_text_ui": translate_lazy("Casiers à disposition du public"), + "help_text_ui_neg": translate_lazy("Pas de casiers à disposition du public"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "value_to_display_children": ["True"], + "children": ["accueil_casiers_adaptes", "accueil_casiers_fermeture"], + "root": True, + }, + "accueil_casiers_adaptes": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe( + translate_lazy( + "Le contraste et/ou le relief des casiers et de leur numérotation permettent-ils une bonne lisibilité pour une personne malvoyante ?" + ) + ), + "help_text_ui": translate_lazy("Le contraste et le relief des casiers permettent une bonne lisibilité."), + "help_text_ui_neg": translate_lazy( + "Le contraste et le relief des casiers ne permettent pas une bonne lisibilité." + ), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "accueil_casiers_fermeture": { + "type": "array", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Quel est leur système de fermeture ?")), + "help_text_ui": translate_lazy("Système de fermeture présent"), + "help_text_ui_neg": translate_lazy("Système de fermeture absent"), + "choices": ACCUEIL_SYSTEME_FERMETURE_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": False, + "warn_if": False, + "conditional": "sports_equipment", + "should_display_label": False, + "free_text": False, + "root": False, + }, + "accueil_prestations_complementaires": { + "type": "array", + "nullable": True, + "is_a11y": True, + "label": mark_safe(translate_lazy("Prestations complémentaires")), + "help_text_ui": translate_lazy("Prestations complémentaires disponibles"), + "help_text_ui_neg": translate_lazy("Pas de prestations complémentaires"), + "choices": ACCUEIL_PRESTATIONS_COMPLEMENTAIRES_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": False, + "warn_if": False, + "conditional": "sports_equipment", + "free_text": False, + "root": True, + }, + "accueil_presence_espaces_specifiques": { + "type": "array", + "nullable": True, + "is_a11y": True, + "label": mark_safe(translate_lazy("Présence d'espaces spécifiques")), + "help_text_ui": translate_lazy("Présence d'espaces spécifiques"), + "help_text_ui_neg": translate_lazy("Pas d'espaces spécifiques à disposition"), + "choices": ACCUEIL_PRESENCE_ESPACES_SPECIFIQUES_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": False, + "warn_if": False, + "conditional": "sports_equipment", + "free_text": False, + "root": True, + }, # Sanitaires "sanitaires_presence": { "type": "boolean", @@ -2705,7 +3146,7 @@ "free_text": False, "root": True, "value_to_display_children": ["True"], - "children": ["sanitaires_adaptes"], + "children": ["sanitaires_adaptes", "sanitaires_urinoirs"], }, "sanitaires_adaptes": { "type": "boolean", @@ -2726,6 +3167,56 @@ "nullable_bool": True, "warn_if": False, "free_text": False, + "value_to_display_children": ["True"], + "children": ["sanitaires_largeur_porte", "sanitaires_sens_transfert"], + }, + "sanitaires_largeur_porte": { + "type": "string", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Quelle est la largeur de porte des toilettes ?")), + "help_text_ui": translate_lazy("Toilettes adaptées avec une largeur de passage entre"), + "help_text_ui_neg": translate_lazy("Toilettes adaptées avec une largeur de passage entre"), + "choices": SANITAIRES_LARGEUR_PORTE_CHOICES, + "unit": "centimètre", + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "sanitaires_sens_transfert": { + "type": "string", + "nullable": True, + "is_a11y": True, + "help_text": mark_safe(translate_lazy("Quel est le sens du transfert ?")), + "help_text_ui": translate_lazy("Sens du transfert"), + "help_text_ui_neg": translate_lazy("Sens du transfert"), + "choices": SANITAIRES_SENS_TRANSFERT_CHOICES, + "unit": "centimètre", + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, + }, + "sanitaires_urinoirs": { + "type": "boolean", + "nullable": True, + "is_a11y": True, + "help_text": translate_lazy("Est ce que les urinoirs sont positionnés à différentes hauteurs ?"), + "help_text_ui": translate_lazy("Urinoirs à différentes hauteurs"), + "help_text_ui_neg": translate_lazy("Les urinoirs sont tous à la même hauteur"), + "choices": NULLABLE_BOOLEAN_CHOICES, + "section": SECTION_ACCUEIL, + "nullable_bool": True, + "warn_if": False, + "free_text": False, + "conditional": "sports_equipment", + "should_display_label": False, + "root": False, }, # Labels "labels": { diff --git a/static/img/contrib/tribunes-places.png b/static/img/contrib/tribunes-places.png new file mode 100644 index 0000000000000000000000000000000000000000..3e636ecd2e9c6d271b76e568fa20a53bf8a5f695 GIT binary patch literal 38613 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 +
+ {% include "fields/boolradio.html" with field=form.stationnement_zone_depose_pmr key="stationnement_zone_depose_pmr" inline=True %} +
{% endblock fields_content %} diff --git a/templates/contrib/4-exterieur.html b/templates/contrib/4-exterieur.html index bbad6a3609..3f7cff95ca 100644 --- a/templates/contrib/4-exterieur.html +++ b/templates/contrib/4-exterieur.html @@ -26,6 +26,9 @@ noindex, nofollow {% endblock robots %} {% block fields_content %} +
+    {{ form.cheminement_ext_signaletique_exterieure.label }}
+    
{% include "fields/boolradio.html" with field=form.cheminement_ext_presence inline=True key="cheminement_ext_presence" %} diff --git a/templates/contrib/6-accueil.html b/templates/contrib/6-accueil.html index 87c006a124..9cc9ce6f88 100644 --- a/templates/contrib/6-accueil.html +++ b/templates/contrib/6-accueil.html @@ -35,6 +35,66 @@ {% include "fields/boolradio.html" with field=form.accueil_signaletique_interieure inline=True key="accueil_signaletique_interieure" %}
{% endif %} + {% if form.accueil_physique %} +
+ {% include "fields/boolradio.html" with field=form.accueil_physique inline=True key="accueil_physique" %} +
+ {% endif %} + {% if form.accueil_aire_de_jeux %} +
+ {% include "fields/boolradio.html" with field=form.accueil_aire_de_jeux inline=True key="accueil_aire_de_jeux" %} +
+ {% endif %} + {% if form.accueil_tribunes %} +
+ {% include "fields/boolradio.html" with field=form.accueil_tribunes inline=True key="accueil_tribunes" %} + {% if form.accueil_tribunes_places %} +
+ {% include "fields/textarea.html" with field=form.accueil_tribunes_places key="accueil_tribunes_places" %} +
+ {% if form.accueil_tribunes_localisation_places %} +
+ {% include "fields/boolradio.html" with field=form.accueil_tribunes_localisation_places inline=True key="accueil_tribunes_localisation_places" %} +
+ {% endif %} + {% if form.accueil_tribunes_places_avec_accompagnants %} +
+ {% include "fields/textarea.html" with field=form.accueil_tribunes_places_avec_accompagnants key="accueil_tribunes_places_avec_accompagnants" %} +
+ {% endif %} + {% endif %} +
+ {% endif %} + {% if form.accueil_vestiaires %} +
+ {% include "fields/boolradio.html" with field=form.accueil_vestiaires inline=True key="accueil_vestiaires" %} + {% if form.accueil_vestiaires_largeur_passage %} +
+ {% include "fields/boolradio.html" with field=form.accueil_vestiaires_largeur_passage inline=True key="accueil_vestiaires_largeur_passage" %} +
+ {% endif %} +
+ {% endif %} + {% if form.accueil_douches_collectives %} +
+ {% include "fields/boolradio.html" with field=form.accueil_douches_collectives inline=True key="accueil_douches_collectives" %} + {% if form.accueil_douches_collectives_adaptees %} +
+ {% include "fields/boolradio.html" with field=form.accueil_douches_collectives_adaptees inline=True key="accueil_douches_collectives_adaptees" %} +
+ {% endif %} +
+ {% endif %} + {% if form.accueil_douches_individuelles %} +
+ {% include "fields/boolradio.html" with field=form.accueil_douches_individuelles inline=True key="accueil_douches_individuelles" %} + {% if form.accueil_douches_individuelles_adaptees %} +
+ {% include "fields/boolradio.html" with field=form.accueil_douches_individuelles_adaptees inline=True key="accueil_douches_individuelles_adaptees" %} +
+ {% endif %} +
+ {% endif %} {% if form.accueil_isoloir_accessibilite %}
{% include "fields/boolradio.html" with field=form.accueil_isoloir_accessibilite inline=True key="accueil_isoloir_accessibilite" %} @@ -99,10 +159,50 @@ {% endif %}
{% include "fields/boolradio.html" with field=form.sanitaires_presence inline=True %} + {% if form.sanitaires_urinoirs %} +
+ {% include "fields/boolradio.html" with field=form.sanitaires_urinoirs inline=True key="sanitaires_urinoirs" %} +
+ {% endif %}
{% include "fields/boolradio.html" with field=form.sanitaires_adaptes inline=True key="sanitaires_adaptes" %}
+ {% if form.sanitaires_largeur_porte %} +
+ {% include "fields/boolradio.html" with field=form.sanitaires_largeur_porte inline=True key="sanitaires_largeur_porte" %} +
+ {% endif %} + {% if form.sanitaires_sens_transfert %} +
+ {% include "fields/boolradio.html" with field=form.sanitaires_sens_transfert inline=True key="sanitaires_sens_transfert" %} +
+ {% endif %}
+ {% if form.accueil_casiers %} +
+ {% include "fields/boolradio.html" with field=form.accueil_casiers inline=True %} + {% if form.accueil_casiers_adaptes %} +
+ {% include "fields/boolradio.html" with field=form.accueil_casiers_adaptes inline=True key="accueil_casiers_adaptes" %} +
+ {% endif %} + {% if form.accueil_casiers_fermeture %} +
+ {% include "fields/checkbox.html" with field=form.accueil_casiers_fermeture inline=True key="accueil_casiers_fermeture" %} +
+ {% endif %} +
+ {% endif %} + {% if form.accueil_prestations_complementaires %} +
+ {% include "fields/checkbox.html" with field=form.accueil_prestations_complementaires inline=True %} +
+ {% endif %} + {% if form.accueil_presence_espaces_specifiques %} +
+ {% include "fields/checkbox.html" with field=form.accueil_presence_espaces_specifiques inline=True %} +
+ {% endif %} {% if form.accueil_ascenseur_etage %}
{% include "fields/boolradio.html" with field=form.accueil_ascenseur_etage key="accueil_ascenseur_etage" %} diff --git a/tests/api/tests.py b/tests/api/tests.py index 634b863f4b..7671a10e21 100644 --- a/tests/api/tests.py +++ b/tests/api/tests.py @@ -125,6 +125,72 @@ def test_list(self, api_client, initial_erp): ) assert "transport" not in erp_json["accessibilite"]["datas"] + def test_list_sports_equipment(self, api_client): + gymnase = ActiviteFactory(nom="Gymnase") + ErpFactory( + nom="Gymnase Jean Moulin", + activite=gymnase, + accessibilite__stationnement_zone_depose_pmr=True, + accessibilite__accueil_physique="non_forme", + accessibilite__accueil_tribunes=True, + accessibilite__accueil_tribunes_places=3, + accessibilite__accueil_tribunes_localisation_places="niveau_aire_de_jeux", + accessibilite__accueil_tribunes_places_avec_accompagnants=1, + accessibilite__accueil_vestiaires=True, + accessibilite__accueil_vestiaires_largeur_passage="superieur_a_110", + accessibilite__accueil_casiers=True, + accessibilite__accueil_casiers_adaptes=False, + accessibilite__accueil_casiers_fermeture=["serrure_avec_cle", "autre"], + accessibilite__accueil_prestations_complementaires=["score_visible"], + accessibilite__accueil_presence_espaces_specifiques=["presence_espace_chiens_guides"], + accessibilite__sanitaires_presence=True, + accessibilite__sanitaires_adaptes=True, + accessibilite__sanitaires_largeur_porte="entre_90_et_110", + accessibilite__sanitaires_sens_transfert="gauche_et_droite", + accessibilite__sanitaires_urinoirs=True, + ) + + response = api_client.get(reverse("erp-list") + "?clean=true") + access = response.json()["results"][0]["accessibilite"] + assert access["transport"]["stationnement_zone_depose_pmr"] is True + assert access["accueil"]["accueil_physique"] == "non_forme" + assert access["accueil"]["accueil_vestiaires_largeur_passage"] == "superieur_a_110" + assert access["accueil"]["sanitaires_largeur_porte"] == "entre_90_et_110" + assert access["accueil"]["sanitaires_sens_transfert"] == "gauche_et_droite" + assert access["accueil"]["accueil_tribunes"] is True + assert access["accueil"]["accueil_tribunes_places"] == 3 + assert access["accueil"]["accueil_tribunes_localisation_places"] == "niveau_aire_de_jeux" + assert access["accueil"]["accueil_tribunes_places_avec_accompagnants"] == 1 + assert access["accueil"]["accueil_vestiaires"] is True + assert access["accueil"]["accueil_casiers"] is True + assert access["accueil"]["accueil_casiers_adaptes"] is False + assert access["accueil"]["accueil_casiers_fermeture"] == ["serrure_avec_cle", "autre"] + assert access["accueil"]["accueil_prestations_complementaires"] == ["score_visible"] + assert access["accueil"]["accueil_presence_espaces_specifiques"] == ["presence_espace_chiens_guides"] + assert access["accueil"]["sanitaires_urinoirs"] is True + + response = api_client.get(reverse("erp-list") + "?readable=true&clean=true") + datas = response.json()["results"][0]["accessibilite"]["datas"] + assert datas["transport"]["stationnement_zone_depose_pmr"] == "Présence d'une zone de dépose PMR" + assert ( + datas["accueil"]["accueil_physique"] + == "Présence de personnel pendant les heures d'ouverture : Personnel non formé" + ) + assert datas["accueil"]["accueil_tribunes"] == "Places spectateurs avec dossier" + assert ( + datas["accueil"]["accueil_tribunes_places"] + == "Places accessibles pour les personnes en fauteuil roulant : 3" + ) + assert ( + datas["accueil"]["accueil_tribunes_localisation_places"] + == "Localisation des places : Places situées au niveau de l'aire de jeux" + ) + assert datas["accueil"]["accueil_tribunes_places_avec_accompagnants"] == ( + "Places accompagnant à côté des places pour les personnes en fauteuil roulant : 1" + ) + assert datas["accueil"]["accueil_casiers_fermeture"] == "Système de fermeture présent : Serrure avec clé, Autre" + assert datas["accueil"]["sanitaires_urinoirs"] == "Urinoirs à différentes hauteurs" + def test_list_geojson(self, api_client, initial_erp): geojson_expected_for_erp = { "type": "FeatureCollection", @@ -326,6 +392,7 @@ def test_detail(self, api_client, initial_erp): "stationnement_pmr": None, "stationnement_ext_presence": None, "stationnement_ext_pmr": None, + "stationnement_zone_depose_pmr": None, "transport_bureau_de_vote_accessibilite": None, }, "cheminement_ext": { @@ -398,6 +465,8 @@ def test_detail(self, api_client, initial_erp): "accueil_equipements_malentendants": [], "sanitaires_presence": True, "sanitaires_adaptes": False, + "sanitaires_largeur_porte": None, + "sanitaires_sens_transfert": None, "accueil_ascenseur_etage": None, "accueil_ascenseur_etage_pmr": None, "accueil_classes_accessibilite": None, @@ -409,6 +478,24 @@ def test_detail(self, api_client, initial_erp): "accueil_salle_consultation_accessible": None, "accueil_consultation_domicile": None, "accueil_prise_en_charge_patients": [], + "accueil_physique": None, + "accueil_aire_de_jeux": None, + "accueil_tribunes": None, + "accueil_tribunes_places": None, + "accueil_tribunes_localisation_places": None, + "accueil_tribunes_places_avec_accompagnants": None, + "accueil_vestiaires": None, + "accueil_vestiaires_largeur_passage": None, + "accueil_douches_collectives": None, + "accueil_douches_collectives_adaptees": None, + "accueil_douches_individuelles": None, + "accueil_douches_individuelles_adaptees": None, + "accueil_casiers": None, + "accueil_casiers_adaptes": None, + "accueil_casiers_fermeture": [], + "accueil_prestations_complementaires": [], + "accueil_presence_espaces_specifiques": [], + "sanitaires_urinoirs": None, }, "registre": {"registre_url": None}, "conformite": {"conformite": None}, @@ -658,6 +745,7 @@ def test_get(self, api_client, initial_erp): "stationnement_pmr": None, "stationnement_ext_presence": None, "stationnement_ext_pmr": None, + "stationnement_zone_depose_pmr": None, }, "cheminement_ext": { "cheminement_ext_presence": None, @@ -729,6 +817,8 @@ def test_get(self, api_client, initial_erp): "accueil_equipements_malentendants": [], "sanitaires_presence": True, "sanitaires_adaptes": False, + "sanitaires_largeur_porte": None, + "sanitaires_sens_transfert": None, "accueil_ascenseur_etage": None, "accueil_ascenseur_etage_pmr": None, "accueil_classes_accessibilite": None, @@ -740,6 +830,24 @@ def test_get(self, api_client, initial_erp): "accueil_salle_consultation_accessible": None, "accueil_consultation_domicile": None, "accueil_prise_en_charge_patients": [], + "accueil_physique": None, + "accueil_aire_de_jeux": None, + "accueil_tribunes": None, + "accueil_tribunes_places": None, + "accueil_tribunes_localisation_places": None, + "accueil_tribunes_places_avec_accompagnants": None, + "accueil_vestiaires": None, + "accueil_vestiaires_largeur_passage": None, + "accueil_douches_collectives": None, + "accueil_douches_collectives_adaptees": None, + "accueil_douches_individuelles": None, + "accueil_douches_individuelles_adaptees": None, + "accueil_casiers": None, + "accueil_casiers_adaptes": None, + "accueil_casiers_fermeture": [], + "accueil_prestations_complementaires": [], + "accueil_presence_espaces_specifiques": [], + "sanitaires_urinoirs": None, }, "registre": {"registre_url": None}, "conformite": {"conformite": None}, diff --git a/tests/erp/imports/test_serializers.py b/tests/erp/imports/test_serializers.py index d948713c04..0266440804 100644 --- a/tests/erp/imports/test_serializers.py +++ b/tests/erp/imports/test_serializers.py @@ -61,6 +61,56 @@ None, id="array", ), + pytest.param( + { + "accessibilite": { + "stationnement_zone_depose_pmr": "oui", + "accueil_physique": "sensibilise_ou_forme", + "accueil_aire_de_jeux": "non", + "accueil_tribunes": 1, + "accueil_tribunes_places": 3, + "accueil_tribunes_localisation_places": "niveau_aire_de_jeux", + "accueil_tribunes_places_avec_accompagnants": 2, + "accueil_vestiaires": "vrai", + "accueil_vestiaires_largeur_passage": "superieur_a_110", + "accueil_douches_collectives": True, + "accueil_douches_collectives_adaptees": True, + "accueil_douches_individuelles": "faux", + "accueil_casiers": "1", + "accueil_casiers_adaptes": "0", + "accueil_casiers_fermeture": ["serrure_avec_cle", "verrou_cadenas"], + "accueil_prestations_complementaires": ["score_visible"], + "accueil_presence_espaces_specifiques": ["presence_espace_repos_sensoriel"], + "sanitaires_presence": True, + "sanitaires_adaptes": True, + "sanitaires_largeur_porte": "entre_90_et_110", + "sanitaires_sens_transfert": "gauche_et_droite", + "sanitaires_urinoirs": True, + } + }, + True, + None, + id="sports_equipment", + ), + pytest.param( + {"accessibilite": {"accueil_casiers_fermeture": ["unknown_lock"]}}, + False, + None, + id="sports_equipment_invalid_array_choice", + ), + pytest.param( + {"accessibilite": {"accueil_physique": "unknown"}}, + False, + None, + id="sports_equipment_invalid_choice", + ), + pytest.param( + # sanitaires_adaptes is not True, so its children must stay empty + {"accessibilite": {"sanitaires_presence": True, "sanitaires_largeur_porte": "entre_80_et_90"}}, + False, + None, + id="sports_equipment_inconsistent_sanitaires", + ), ), ) def test_erp_import_serializer(mocker, erp_values, is_valid, geocoder_result): @@ -179,6 +229,165 @@ def test_erp_update_serializer_inconsistencies(): assert erp.accessibilite.accueil_cheminement_ascenseur_pmr is True, "control, should not be reinit" +@pytest.mark.django_db +def test_erp_import_serializer_sports_equipment(mocker): + ActiviteFactory(nom="Gymnase") + CommuneFactory(nom="Jacou") + mocker.patch( + "erp.provider.geocoder.geocode", + return_value={ + "geom": Point((0, 0), srid=4326), + "numero": "4", + "voie": "Rue de la Paix", + "lieu_dit": None, + "code_postal": "34830", + "commune": "Jacou", + "code_insee": "34120", + "provider": "ban", + }, + ) + + serializer = ErpImportSerializer( + data={ + "voie": "Rue de la Coquille", + "code_postal": 34830, + "commune": "Jacou", + "nom": "Gymnase Jean Moulin", + "activite": "Gymnase", + "accessibilite": { + "stationnement_zone_depose_pmr": "oui", + "accueil_physique": "non_forme", + "accueil_aire_de_jeux": "non", + "accueil_tribunes": "vrai", + "accueil_tribunes_places": 3, + "accueil_tribunes_localisation_places": "reparti_differents_niveaux", + "accueil_tribunes_places_avec_accompagnants": 1, + "accueil_vestiaires": 1, + "accueil_vestiaires_largeur_passage": "entre_90_et_110", + "accueil_douches_collectives": "1", + "accueil_douches_collectives_adaptees": "0", + "accueil_douches_individuelles": "faux", + "accueil_casiers": True, + "accueil_casiers_adaptes": "oui", + "accueil_casiers_fermeture": ["serrure_electronique_a_code", "autre"], + "accueil_prestations_complementaires": ["sonorisation_arbitrage", "score_visible"], + "accueil_presence_espaces_specifiques": ["presence_espace_chiens_guides"], + "sanitaires_presence": "oui", + "sanitaires_adaptes": "oui", + "sanitaires_largeur_porte": "entre_80_et_90", + "sanitaires_sens_transfert": "gauche_et_droite", + "sanitaires_urinoirs": "non", + }, + } + ) + + assert serializer.is_valid(), serializer.errors + erp = serializer.save() + + access = erp.accessibilite + assert access.stationnement_zone_depose_pmr is True + assert access.accueil_physique == "non_forme" + assert access.accueil_aire_de_jeux is False + assert access.accueil_tribunes is True + assert access.accueil_tribunes_places == 3 + assert access.accueil_tribunes_localisation_places == "reparti_differents_niveaux" + assert access.accueil_tribunes_places_avec_accompagnants == 1 + assert access.accueil_vestiaires is True + assert access.accueil_vestiaires_largeur_passage == "entre_90_et_110" + assert access.accueil_douches_collectives is True + assert access.accueil_douches_collectives_adaptees is False + assert access.accueil_douches_individuelles is False + assert access.accueil_casiers is True + assert access.accueil_casiers_adaptes is True + assert access.accueil_casiers_fermeture == ["serrure_electronique_a_code", "autre"] + assert access.accueil_prestations_complementaires == ["sonorisation_arbitrage", "score_visible"] + assert access.accueil_presence_espaces_specifiques == ["presence_espace_chiens_guides"] + assert access.sanitaires_presence is True + assert access.sanitaires_adaptes is True + assert access.sanitaires_largeur_porte == "entre_80_et_90" + assert access.sanitaires_sens_transfert == "gauche_et_droite" + assert access.sanitaires_urinoirs is False + + +@pytest.mark.django_db +def test_erp_update_serializer_sports_equipment_inconsistencies(): + erp = ErpFactory( + accessibilite__accueil_tribunes=True, + accessibilite__accueil_tribunes_places=4, + accessibilite__accueil_tribunes_localisation_places="niveau_aire_de_jeux", + accessibilite__accueil_tribunes_places_avec_accompagnants=2, + accessibilite__accueil_vestiaires=True, + accessibilite__accueil_vestiaires_largeur_passage="superieur_a_110", + accessibilite__accueil_casiers=True, + accessibilite__accueil_casiers_adaptes=True, + accessibilite__accueil_casiers_fermeture=["serrure_avec_cle"], + accessibilite__accueil_douches_collectives=True, # control + accessibilite__accueil_douches_collectives_adaptees=True, # control + accessibilite__sanitaires_presence=True, + accessibilite__sanitaires_adaptes=True, + accessibilite__sanitaires_largeur_porte="entre_90_et_110", + accessibilite__sanitaires_sens_transfert="gauche", + accessibilite__sanitaires_urinoirs=True, + ) + + serializer = ErpImportSerializer( + instance=erp, + data={ + "accessibilite": { + "accueil_tribunes_places": 0, + "accueil_vestiaires": False, + "accueil_casiers": "non", + # sanitaires_presence is repeated as a partial payload is validated on its own + "sanitaires_presence": True, + "sanitaires_adaptes": False, + } + }, + partial=True, + ) + assert serializer.is_valid(), serializer.errors + serializer.save() + + erp.refresh_from_db() + access = erp.accessibilite + assert access.accueil_tribunes_places == 0 + assert access.accueil_tribunes_localisation_places is None, "should have reinit child of attr switched to 0" + assert access.accueil_tribunes_places_avec_accompagnants is None, "should have reinit child of attr switched to 0" + assert access.accueil_vestiaires is False + assert access.accueil_vestiaires_largeur_passage is None, "should have reinit child" + assert access.accueil_casiers is False + assert access.accueil_casiers_adaptes is None, "should have reinit child" + assert access.accueil_casiers_fermeture == [], "should have reinit array child" + assert access.sanitaires_adaptes is False + assert access.sanitaires_largeur_porte is None, "should have reinit child" + assert access.sanitaires_sens_transfert is None, "should have reinit child" + assert access.accueil_douches_collectives is True, "control, should not be reinit" + assert access.accueil_douches_collectives_adaptees is True, "control, should not be reinit" + + +@pytest.mark.django_db +def test_erp_update_serializer_keeps_children_above_min_value(): + erp = ErpFactory( + accessibilite__accueil_tribunes=True, + accessibilite__accueil_tribunes_places=4, + accessibilite__accueil_tribunes_localisation_places="niveau_aire_de_jeux", + accessibilite__accueil_tribunes_places_avec_accompagnants=2, + ) + + serializer = ErpImportSerializer( + instance=erp, + data={"accessibilite": {"accueil_tribunes_places": 8}}, + partial=True, + ) + assert serializer.is_valid(), serializer.errors + serializer.save() + + erp.refresh_from_db() + access = erp.accessibilite + assert access.accueil_tribunes_places == 8 + assert access.accueil_tribunes_localisation_places == "niveau_aire_de_jeux", "children must be kept above min value" + assert access.accueil_tribunes_places_avec_accompagnants == 2, "children must be kept above min value" + + @pytest.mark.django_db def test_erp_duplicate(): boulangerie = ActiviteFactory(nom="Boulangerie") diff --git a/tests/erp/test_forms.py b/tests/erp/test_forms.py index e70345eb65..962cddc547 100644 --- a/tests/erp/test_forms.py +++ b/tests/erp/test_forms.py @@ -1,7 +1,14 @@ import pytest from erp import forms, schema -from tests.factories import CommuneFactory, ErpFactory +from erp.models import ACTIVITY_GROUPS +from tests.factories import ( + AccessibiliteFactory, + ActiviteFactory, + ActivitiesGroupFactory, + CommuneFactory, + ErpFactory, +) @pytest.mark.django_db @@ -47,3 +54,60 @@ def test_ProviderGlobalSearchForm(): assert form.initial["commune_search"] == "Jacou (34 - Hérault)" assert form.initial["code_insee"] == commune.code_insee + + +def _combined_form_for(access, section): + return forms.CombinedAccessibiliteForm( + forms.get_contrib_forms_for_activity(access.erp.activite), + schema.get_section_fields(section), + instance=access, + ) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "section,field", + ( + (schema.SECTION_ACCUEIL, "accueil_signaletique_interieure"), + (schema.SECTION_CHEMINEMENT_EXT, "cheminement_ext_signaletique_exterieure"), + ), +) +def test_sports_equipment_form_keeps_whitelisted_large_establishments_fields(section, field): + activity = ActiviteFactory(slug="gymnase", nom="Gymnase") + + ActivitiesGroupFactory(activities=[activity], name=ACTIVITY_GROUPS["SPORTS_EQUIPMENT"]) + + access = AccessibiliteFactory(erp=ErpFactory(activite=activity)) + form = _combined_form_for(access, section) + + assert field in form.fields + assert form.fields[field].label == schema.get_label(field) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "section,field", + ( + (schema.SECTION_ACCUEIL, "accueil_signaletique_interieure"), + (schema.SECTION_CHEMINEMENT_EXT, "cheminement_ext_signaletique_exterieure"), + ), +) +def test_school_form_excludes_non_whitelisted_large_establishments_fields(section, field): + activity = ActiviteFactory(slug="ecole", nom="École") + ActivitiesGroupFactory(activities=[activity], name=ACTIVITY_GROUPS["SCHOOL"]) + access = AccessibiliteFactory(erp=ErpFactory(activite=activity)) + form = _combined_form_for(access, section) + + assert field not in form.fields + + +@pytest.mark.django_db +def test_school_form_keeps_whitelisted_large_establishments_fields(): + activity = ActiviteFactory(slug="ecole", nom="École") + ActivitiesGroupFactory(activities=[activity], name=ACTIVITY_GROUPS["SCHOOL"]) + access = AccessibiliteFactory(erp=ErpFactory(activite=activity)) + form = _combined_form_for(access, schema.SECTION_ACCUEIL) + + for field in forms.ContribAccessibiliteSchoolsForm.large_establishments_fields_to_keep: + assert field in form.fields + assert form.fields[field].label == schema.get_label(field) diff --git a/tests/erp/test_tasks.py b/tests/erp/test_tasks.py index 973c863757..576ab70905 100644 --- a/tests/erp/test_tasks.py +++ b/tests/erp/test_tasks.py @@ -3,6 +3,34 @@ from erp.tasks import compute_access_completion_rate from tests.factories import AccessibiliteFactory, ActiviteFactory, ActivitiesGroupFactory, ErpFactory +# Roots of the "sports_equipment" conditional, always exposed for that activity group +SPORTS_EQUIPMENT_ROOT_FIELDS = ( + "stationnement_zone_depose_pmr", + "accueil_physique", + "accueil_aire_de_jeux", + "accueil_tribunes", + "accueil_tribunes_places", + "accueil_vestiaires", + "accueil_douches_collectives", + "accueil_douches_individuelles", + "accueil_casiers", + "accueil_prestations_complementaires", + "accueil_presence_espaces_specifiques", +) +# Only exposed once their parent is filled in with a value triggering the children +SPORTS_EQUIPMENT_CHILD_FIELDS = ( + "accueil_tribunes_localisation_places", + "accueil_tribunes_places_avec_accompagnants", + "accueil_vestiaires_largeur_passage", + "accueil_douches_collectives_adaptees", + "accueil_douches_individuelles_adaptees", + "accueil_casiers_adaptes", + "accueil_casiers_fermeture", + "sanitaires_urinoirs", + "sanitaires_largeur_porte", + "sanitaires_sens_transfert", +) + @mark.django_db def test_compute_completion_rate(): @@ -134,6 +162,153 @@ def test_compute_completion_rate_healthcare(): assert access.completion_rate == 15 +def _sports_equipment_access(**kwargs): + activity = ActiviteFactory(slug="gymnase", nom="Gymnase") + ActivitiesGroupFactory(activities=[activity], name="Équipements sportifs") + return AccessibiliteFactory(erp=ErpFactory(activite=activity), **kwargs) + + +@mark.django_db +def test_compute_completion_rate_sports_equipment_without_children(): + access = _sports_equipment_access() + + exposed_fields = access.get_exposed_fields() + for field in SPORTS_EQUIPMENT_ROOT_FIELDS: + assert field in exposed_fields, f"{field} should be exposed for sports equipments" + # no parent is filled in yet, so no child is exposed + for field in SPORTS_EQUIPMENT_CHILD_FIELDS: + assert field not in exposed_fields, f"{field} should not be exposed without its parent" + + compute_access_completion_rate(access.pk) + access.refresh_from_db() + assert access.completion_rate == 0 + + # fill in every root, keeping all parents falsy so that no child gets exposed + access.stationnement_zone_depose_pmr = True + access.accueil_physique = "inexistant" + access.accueil_aire_de_jeux = False + access.accueil_tribunes = False + access.accueil_tribunes_places = 0 + access.accueil_vestiaires = False + access.accueil_douches_collectives = False + access.accueil_douches_individuelles = False + access.accueil_casiers = False + access.accueil_prestations_complementaires = ["score_visible"] + access.accueil_presence_espaces_specifiques = ["presence_espace_chiens_guides"] + access.sanitaires_presence = False + access.save() + + compute_access_completion_rate(access.pk) + access.refresh_from_db() + + exposed_fields = access.get_exposed_fields() + assert set(SPORTS_EQUIPMENT_ROOT_FIELDS).issubset(exposed_fields) + assert not set(SPORTS_EQUIPMENT_CHILD_FIELDS) & exposed_fields + assert access.completion_rate == 41 + + +@mark.django_db +def test_compute_completion_rate_sports_equipment_with_children(): + access = _sports_equipment_access( + accueil_tribunes=False, + accueil_vestiaires=False, + accueil_douches_collectives=False, + accueil_douches_individuelles=False, + accueil_casiers=False, + sanitaires_presence=False, + ) + + # each child is exposed only once its own parent displays it + exposed_fields = access.get_exposed_fields() + + for field in SPORTS_EQUIPMENT_CHILD_FIELDS: + assert field not in exposed_fields, f"{field} should not be exposed while its parent is False" + + access.accueil_tribunes = True + access.accueil_vestiaires = True + access.accueil_douches_collectives = True + access.accueil_douches_individuelles = True + access.accueil_casiers = True + access.sanitaires_presence = True + access.save() + + exposed_fields = access.get_exposed_fields() + + # direct children of the truthy roots + assert "accueil_vestiaires_largeur_passage" in exposed_fields + assert "accueil_douches_collectives_adaptees" in exposed_fields + assert "accueil_douches_individuelles_adaptees" in exposed_fields + assert "accueil_casiers_adaptes" in exposed_fields + assert "accueil_casiers_fermeture" in exposed_fields + assert "sanitaires_urinoirs" in exposed_fields + + # children of "sanitaires_adaptes", which is not truthy yet + assert "sanitaires_largeur_porte" not in exposed_fields + assert "sanitaires_sens_transfert" not in exposed_fields + + # nested children of "accueil_tribunes_places", not exposed below its min value + assert "accueil_tribunes_localisation_places" not in exposed_fields + assert "accueil_tribunes_places_avec_accompagnants" not in exposed_fields + + compute_access_completion_rate(access.pk) + access.refresh_from_db() + assert access.completion_rate == 16 + + access.sanitaires_adaptes = True + access.save() + + compute_access_completion_rate(access.pk) + access.refresh_from_db() + exposed_fields = access.get_exposed_fields() + + assert "sanitaires_largeur_porte" in exposed_fields + assert "sanitaires_sens_transfert" in exposed_fields + assert access.completion_rate == 18 + + access.accueil_tribunes_places = 4 + access.save() + + compute_access_completion_rate(access.pk) + access.refresh_from_db() + exposed_fields = access.get_exposed_fields() + + assert "accueil_tribunes_localisation_places" in exposed_fields + assert "accueil_tribunes_places_avec_accompagnants" in exposed_fields + assert access.completion_rate == 20 + + # fill in every remaining sports equipment field + access.stationnement_zone_depose_pmr = True + access.accueil_physique = "sensibilise_ou_forme" + access.accueil_aire_de_jeux = True + access.accueil_prestations_complementaires = ["score_visible"] + access.accueil_presence_espaces_specifiques = ["presence_espace_chiens_guides"] + access.accueil_tribunes_localisation_places = "niveau_aire_de_jeux" + access.accueil_tribunes_places_avec_accompagnants = 2 + access.accueil_vestiaires_largeur_passage = "superieur_a_110" + access.accueil_douches_collectives_adaptees = True + access.accueil_douches_individuelles_adaptees = False + access.accueil_casiers_adaptes = True + access.accueil_casiers_fermeture = ["serrure_avec_cle"] + access.sanitaires_urinoirs = True + access.sanitaires_largeur_porte = "entre_90_et_110" + access.sanitaires_sens_transfert = "gauche_et_droite" + access.save() + + compute_access_completion_rate(access.pk) + + access.refresh_from_db() + exposed_fields = access.get_exposed_fields() + + assert set(SPORTS_EQUIPMENT_ROOT_FIELDS + SPORTS_EQUIPMENT_CHILD_FIELDS).issubset(exposed_fields) + + filled_in = access.get_filled_in_fields() + + for field in SPORTS_EQUIPMENT_ROOT_FIELDS + SPORTS_EQUIPMENT_CHILD_FIELDS: + assert field in filled_in, f"{field} should count as filled in" + + assert access.completion_rate == 57 + + @mark.django_db def test_compute_completion_rate_large_establishments(): activity = ActiviteFactory(slug="centre-commercial", nom="Centre commercial")