diff --git a/config/tests/test_urls.py b/config/tests/test_urls.py
index 19439fcdd..74e16e842 100644
--- a/config/tests/test_urls.py
+++ b/config/tests/test_urls.py
@@ -30,7 +30,6 @@ def site() -> Site:
HAIE_URLS = [
"triage",
- "triage_result",
]
AMENAGEMENT_URLS = [
diff --git a/config/urls_haie.py b/config/urls_haie.py
index 18480b12d..ef5f62a91 100644
--- a/config/urls_haie.py
+++ b/config/urls_haie.py
@@ -1,8 +1,9 @@
from django.urls import include, path
+from django.utils.translation import gettext_lazy as _
from .urls import urlpatterns as common_urlpatterns
urlpatterns = [
path("", include("envergo.pages.urls_haie")),
- path("indre/", include("envergo.moulinette.urls_haie")),
+ path(_("moulinette/"), include("envergo.moulinette.urls_haie")),
] + common_urlpatterns
diff --git a/envergo/evaluations/forms.py b/envergo/evaluations/forms.py
index 3b3c4d18b..ac156be02 100644
--- a/envergo/evaluations/forms.py
+++ b/envergo/evaluations/forms.py
@@ -8,7 +8,7 @@
from phonenumber_field.formfields import PhoneNumberField
from envergo.evaluations.models import USER_TYPES, Request
-from envergo.evaluations.utils import extract_department
+from envergo.evaluations.utils import extract_department_from_address
from envergo.evaluations.validators import application_number_validator
from envergo.geodata.models import Department
from envergo.utils.fields import NoIdnEmailField
@@ -119,7 +119,7 @@ def clean(self):
department_input = data.get("department", None)
if not department_input:
# extract department from address
- department_input = extract_department(address)
+ department_input = extract_department_from_address(address)
if department_input and department_input not in address:
# when a town is selected on its own, without a complete address, there is no zip code.
@@ -128,10 +128,10 @@ def clean(self):
department = (
Department.objects.filter(department=department_input)
- .select_related("moulinette_config")
+ .select_related("configamenagement")
.first()
)
- if department and not department.is_activated():
+ if department and not department.is_amenagement_activated():
self.add_error(
"department",
ValidationError(
diff --git a/envergo/evaluations/models.py b/envergo/evaluations/models.py
index 3e82d63cb..61f92eaa3 100644
--- a/envergo/evaluations/models.py
+++ b/envergo/evaluations/models.py
@@ -262,7 +262,7 @@ def get_moulinette_config(self):
lng, lat = params["lng"], params["lat"]
coords = Point(float(lng), float(lat), srid=EPSG_WGS84)
department = Department.objects.filter(geometry__contains=coords).first()
- return department.moulinette_config if department else None
+ return department.configamenagement if department else None
def get_moulinette(self):
"""Return the moulinette instance for this evaluation."""
diff --git a/envergo/evaluations/tests/test_admin.py b/envergo/evaluations/tests/test_admin.py
index 28d142eb1..47df0c2b9 100644
--- a/envergo/evaluations/tests/test_admin.py
+++ b/envergo/evaluations/tests/test_admin.py
@@ -7,7 +7,10 @@
generate_reference,
)
from envergo.evaluations.tests.factories import EvaluationFactory, RequestFactory
-from envergo.moulinette.tests.factories import CriterionFactory, MoulinetteConfigFactory
+from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
+ CriterionFactory,
+)
pytestmark = pytest.mark.django_db
@@ -92,7 +95,7 @@ def test_create_eval_fails_when_it_already_exists(client, admin_user, eval_reque
def test_evaluation_email_sending(admin_client, evaluation, mailoutbox):
# Make sure the "loi sur l'eau" result will be set
CriterionFactory()
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("admin:evaluations_evaluation_email_avis", args=[evaluation.pk])
res = admin_client.get(url)
@@ -126,7 +129,7 @@ def test_evaluation_email_sending(admin_client, evaluation, mailoutbox):
def test_evaluation_email_throttling(admin_client, evaluation, mailoutbox):
# Make sure the "loi sur l'eau" result will be set
CriterionFactory()
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("admin:evaluations_evaluation_email_avis", args=[evaluation.pk])
res = admin_client.get(url)
@@ -156,7 +159,7 @@ def test_evaluation_email_throttling(admin_client, evaluation, mailoutbox):
def test_evaluation_email_recipient_overriding(admin_client, evaluation, mailoutbox):
# Make sure the "loi sur l'eau" result will be set
CriterionFactory()
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("admin:evaluations_evaluation_email_avis", args=[evaluation.pk])
res = admin_client.get(url)
@@ -180,7 +183,7 @@ def test_evaluation_email_recipient_overriding(admin_client, evaluation, mailout
def test_evaluation_email_with_empty_recipients(admin_client, evaluation, mailoutbox):
# Make sure the "loi sur l'eau" result will be set
CriterionFactory()
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("admin:evaluations_evaluation_email_avis", args=[evaluation.pk])
res = admin_client.get(url)
diff --git a/envergo/evaluations/tests/test_eval_emails.py b/envergo/evaluations/tests/test_eval_emails.py
index a1beea03d..7a5330eba 100644
--- a/envergo/evaluations/tests/test_eval_emails.py
+++ b/envergo/evaluations/tests/test_eval_emails.py
@@ -9,8 +9,8 @@
from envergo.geodata.conftest import bizous_town_center, france_map, france_zh # noqa
from envergo.moulinette.regulations import RequiredAction, Stake
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
PerimeterFactory,
RegulationFactory,
)
@@ -25,7 +25,7 @@ def override_settings(settings):
@pytest.fixture(autouse=True)
def moulinette_config(france_map, france_zh, loire_atlantique_department): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
department=loire_atlantique_department,
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
diff --git a/envergo/evaluations/tests/test_forms.py b/envergo/evaluations/tests/test_forms.py
index 5b4af7541..f2fb2179c 100644
--- a/envergo/evaluations/tests/test_forms.py
+++ b/envergo/evaluations/tests/test_forms.py
@@ -2,7 +2,7 @@
from envergo.evaluations.forms import WizardAddressForm
from envergo.geodata.conftest import loire_atlantique_department # noqa
-from envergo.moulinette.tests.factories import MoulinetteConfigFactory
+from envergo.moulinette.tests.factories import ConfigAmenagementFactory
pytestmark = pytest.mark.django_db
@@ -17,7 +17,7 @@ def form_data():
@pytest.fixture(autouse=True)
def moulinette_config(loire_atlantique_department): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
department=loire_atlantique_department,
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
diff --git a/envergo/evaluations/tests/test_models.py b/envergo/evaluations/tests/test_models.py
index 43234cd58..aab24a686 100644
--- a/envergo/evaluations/tests/test_models.py
+++ b/envergo/evaluations/tests/test_models.py
@@ -8,8 +8,8 @@
from envergo.geodata.conftest import loire_atlantique_department # noqa
from envergo.geodata.conftest import bizous_town_center, france_map # noqa
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
PerimeterFactory,
RegulationFactory,
)
@@ -19,7 +19,7 @@
@pytest.fixture(autouse=True)
def moulinette_config(france_map, loire_atlantique_department): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
department=loire_atlantique_department,
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
diff --git a/envergo/evaluations/tests/test_views.py b/envergo/evaluations/tests/test_views.py
index 0a4aa2ac0..b36123fa9 100644
--- a/envergo/evaluations/tests/test_views.py
+++ b/envergo/evaluations/tests/test_views.py
@@ -14,7 +14,7 @@
VersionFactory,
)
from envergo.geodata.conftest import loire_atlantique_department # noqa
-from envergo.moulinette.tests.factories import MoulinetteConfigFactory
+from envergo.moulinette.tests.factories import ConfigAmenagementFactory
pytestmark = pytest.mark.django_db
@@ -26,7 +26,7 @@ def autouse_site(site):
@pytest.fixture()
def moulinette_config(loire_atlantique_department): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
department=loire_atlantique_department,
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
@@ -37,7 +37,7 @@ def moulinette_config(loire_atlantique_department): # noqa
@pytest.fixture()
def unactivated_moulinette_config(loire_atlantique_department): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
department=loire_atlantique_department,
is_activated=False,
ddtm_water_police_email="ddtm_email_test@example.org",
diff --git a/envergo/evaluations/utils.py b/envergo/evaluations/utils.py
index 6a7ec5f87..e83160554 100644
--- a/envergo/evaluations/utils.py
+++ b/envergo/evaluations/utils.py
@@ -14,11 +14,15 @@ def extract_postal_code(address):
return None
-def extract_department(address):
+def extract_department_from_address(address):
"""Extract the department as two (or three) digits from a stringified address.
return None if no department is found.
"""
postal_code = extract_postal_code(address)
+ return extract_department_from_postal_code(postal_code)
+
+
+def extract_department_from_postal_code(postal_code):
department = None
if postal_code:
department = postal_code[:2]
@@ -33,5 +37,4 @@ def extract_department(address):
department = "2A" # Corse-du-Sud
elif 20200 <= code_number <= 20620:
department = "2B" # Haute-Corse
-
return department
diff --git a/envergo/geodata/models.py b/envergo/geodata/models.py
index 88a849032..441a1f782 100644
--- a/envergo/geodata/models.py
+++ b/envergo/geodata/models.py
@@ -160,8 +160,8 @@ class Meta:
def __str__(self):
return self.get_department_display()
- def is_activated(self):
- config = getattr(self, "moulinette_config", None)
+ def is_amenagement_activated(self):
+ config = getattr(self, "configamenagement", None)
return config and config.is_activated
diff --git a/envergo/moulinette/admin.py b/envergo/moulinette/admin.py
index 9d2e0c665..00a616a41 100644
--- a/envergo/moulinette/admin.py
+++ b/envergo/moulinette/admin.py
@@ -8,8 +8,9 @@
from envergo.geodata.admin import DepartmentsListFilter
from envergo.moulinette.models import (
REGULATIONS,
+ ConfigAmenagement,
+ ConfigHaie,
Criterion,
- MoulinetteConfig,
MoulinetteTemplate,
Perimeter,
Regulation,
@@ -250,7 +251,7 @@ def departments(self, obj):
return obj.activation_map.departments
-class MoulinetteConfigForm(forms.ModelForm):
+class ConfigAmenagementForm(forms.ModelForm):
regulations_available = forms.MultipleChoiceField(
label=_("Regulations available"), required=False, choices=REGULATIONS
)
@@ -276,7 +277,7 @@ def clean_criteria_values(self):
class MoulinetteConfigTemplateForm(forms.ModelForm):
- """Form to edit a MoulinetteTemplate in a MoulinetteConfig.
+ """Form to edit a MoulinetteTemplate in a ConfigAmenagement.
We remove every key that is not a real template (autorisation_urba_*, etc.)
"""
@@ -295,10 +296,10 @@ class MoulinetteConfigTemplateInline(MoulinetteTemplateInline):
form = MoulinetteConfigTemplateForm
-@admin.register(MoulinetteConfig)
-class MoulinetteConfigAdmin(admin.ModelAdmin):
+@admin.register(ConfigAmenagement)
+class ConfigAmenagementAdmin(admin.ModelAdmin):
list_display = ["department", "is_activated", "zh_doubt"]
- form = MoulinetteConfigForm
+ form = ConfigAmenagementForm
inlines = [MoulinetteConfigTemplateInline]
list_filter = ["is_activated", "zh_doubt"]
@@ -315,3 +316,17 @@ def get_queryset(self, request):
class MoulinetteTemplateAdmin(admin.ModelAdmin):
list_display = ["config", "key"]
search_fields = ["content"]
+
+
+@admin.register(ConfigHaie)
+class ConfigHaieAdmin(admin.ModelAdmin):
+ list_display = ["department", "is_activated", "department_guichet_unique_url"]
+ list_filter = ["is_activated"]
+
+ def get_queryset(self, request):
+ qs = super().get_queryset(request)
+ return (
+ qs.select_related("department")
+ .order_by("department__department")
+ .defer("department__geometry")
+ )
diff --git a/envergo/moulinette/forms/__init__.py b/envergo/moulinette/forms/__init__.py
index d0bcf0cde..67d86d8c1 100644
--- a/envergo/moulinette/forms/__init__.py
+++ b/envergo/moulinette/forms/__init__.py
@@ -229,7 +229,6 @@ class TriageFormHaie(forms.Form):
department = DisplayCharField(
label="Département",
required=True,
- initial="36",
get_display_value=lambda x: dict(DEPARTMENT_CHOICES).get(x, "Inconnu"),
)
element = DisplayChoiceField(
diff --git a/envergo/moulinette/migrations/0059_alter_moulinettetemplate_key_haiedepartmentconfig.py b/envergo/moulinette/migrations/0059_alter_moulinettetemplate_key_haiedepartmentconfig.py
new file mode 100644
index 000000000..d94f02de2
--- /dev/null
+++ b/envergo/moulinette/migrations/0059_alter_moulinettetemplate_key_haiedepartmentconfig.py
@@ -0,0 +1,584 @@
+# Generated by Django 4.2.13 on 2024-09-30 13:55
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("geodata", "0016_alter_department_geometry"),
+ ("moulinette", "0058_alter_moulinetteconfig_regulations_available_and_more"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="moulinettetemplate",
+ name="key",
+ field=models.CharField(
+ choices=[
+ ("autorisation_urba_pa", "autorisation_urba_pa"),
+ (
+ "autorisation_urba_pa_lotissement",
+ "autorisation_urba_pa_lotissement",
+ ),
+ ("autorisation_urba_pc", "autorisation_urba_pc"),
+ (
+ "autorisation_urba_amenagement_dp",
+ "autorisation_urba_amenagement_dp",
+ ),
+ (
+ "autorisation_urba_construction_dp",
+ "autorisation_urba_construction_dp",
+ ),
+ ("autorisation_urba_none", "autorisation_urba_none"),
+ ("autorisation_urba_other", "autorisation_urba_other"),
+ (
+ "conditionnalite_pac/bcae8_interdit_amenagement.html",
+ "conditionnalite_pac/bcae8_interdit_amenagement.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_interdit_autre.html",
+ "conditionnalite_pac/bcae8_interdit_autre.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_interdit_chemin_acces.html",
+ "conditionnalite_pac/bcae8_interdit_chemin_acces.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_interdit_meilleur_emplacement.html",
+ "conditionnalite_pac/bcae8_interdit_meilleur_emplacement.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_interdit_transfert_parcelles.html",
+ "conditionnalite_pac/bcae8_interdit_transfert_parcelles.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_non_soumis.html",
+ "conditionnalite_pac/bcae8_non_soumis.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_non_soumis_petit.html",
+ "conditionnalite_pac/bcae8_non_soumis_petit.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_amenagement.html",
+ "conditionnalite_pac/bcae8_soumis_amenagement.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_autre.html",
+ "conditionnalite_pac/bcae8_soumis_autre.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_chemin_acces.html",
+ "conditionnalite_pac/bcae8_soumis_chemin_acces.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_meilleur_emplacement.html",
+ "conditionnalite_pac/bcae8_soumis_meilleur_emplacement.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_remplacement.html",
+ "conditionnalite_pac/bcae8_soumis_remplacement.html",
+ ),
+ (
+ "conditionnalite_pac/bcae8_soumis_transfert_parcelles.html",
+ "conditionnalite_pac/bcae8_soumis_transfert_parcelles.html",
+ ),
+ ("dep/dep_soumis.html", "dep/dep_soumis.html"),
+ (
+ "eval_env/aire_de_stationnement_cas_par_cas.html",
+ "eval_env/aire_de_stationnement_cas_par_cas.html",
+ ),
+ (
+ "eval_env/aire_de_stationnement_non_soumis.html",
+ "eval_env/aire_de_stationnement_non_soumis.html",
+ ),
+ (
+ "eval_env/autres_rubriques_non_disponible.html",
+ "eval_env/autres_rubriques_non_disponible.html",
+ ),
+ (
+ "eval_env/camping_cas_par_cas.html",
+ "eval_env/camping_cas_par_cas.html",
+ ),
+ (
+ "eval_env/camping_non_soumis.html",
+ "eval_env/camping_non_soumis.html",
+ ),
+ (
+ "eval_env/camping_systematique.html",
+ "eval_env/camping_systematique.html",
+ ),
+ (
+ "eval_env/clause_filet_clause_filet.html",
+ "eval_env/clause_filet_clause_filet.html",
+ ),
+ (
+ "eval_env/defrichement_deboisement_cas_par_cas.html",
+ "eval_env/defrichement_deboisement_cas_par_cas.html",
+ ),
+ (
+ "eval_env/defrichement_deboisement_non_soumis.html",
+ "eval_env/defrichement_deboisement_non_soumis.html",
+ ),
+ (
+ "eval_env/emprise_cas_par_cas.html",
+ "eval_env/emprise_cas_par_cas.html",
+ ),
+ (
+ "eval_env/emprise_non_soumis.html",
+ "eval_env/emprise_non_soumis.html",
+ ),
+ (
+ "eval_env/emprise_systematique.html",
+ "eval_env/emprise_systematique.html",
+ ),
+ (
+ "eval_env/photovoltaique_cas_par_cas_sol.html",
+ "eval_env/photovoltaique_cas_par_cas_sol.html",
+ ),
+ (
+ "eval_env/photovoltaique_cas_par_cas_toiture.html",
+ "eval_env/photovoltaique_cas_par_cas_toiture.html",
+ ),
+ (
+ "eval_env/photovoltaique_non_soumis.html",
+ "eval_env/photovoltaique_non_soumis.html",
+ ),
+ (
+ "eval_env/photovoltaique_non_soumis_ombriere.html",
+ "eval_env/photovoltaique_non_soumis_ombriere.html",
+ ),
+ (
+ "eval_env/photovoltaique_non_soumis_toiture.html",
+ "eval_env/photovoltaique_non_soumis_toiture.html",
+ ),
+ (
+ "eval_env/photovoltaique_systematique_sol.html",
+ "eval_env/photovoltaique_systematique_sol.html",
+ ),
+ (
+ "eval_env/photovoltaique_systematique_toiture.html",
+ "eval_env/photovoltaique_systematique_toiture.html",
+ ),
+ (
+ "eval_env/piste_cyclable_cas_par_cas.html",
+ "eval_env/piste_cyclable_cas_par_cas.html",
+ ),
+ (
+ "eval_env/piste_cyclable_non_soumis.html",
+ "eval_env/piste_cyclable_non_soumis.html",
+ ),
+ (
+ "eval_env/premier_boisement_cas_par_cas.html",
+ "eval_env/premier_boisement_cas_par_cas.html",
+ ),
+ (
+ "eval_env/premier_boisement_non_soumis.html",
+ "eval_env/premier_boisement_non_soumis.html",
+ ),
+ (
+ "eval_env/result_cas_par_cas.html",
+ "eval_env/result_cas_par_cas.html",
+ ),
+ (
+ "eval_env/result_non_active.html",
+ "eval_env/result_non_active.html",
+ ),
+ (
+ "eval_env/result_non_disponible.html",
+ "eval_env/result_non_disponible.html",
+ ),
+ (
+ "eval_env/result_non_soumis.html",
+ "eval_env/result_non_soumis.html",
+ ),
+ (
+ "eval_env/result_systematique.html",
+ "eval_env/result_systematique.html",
+ ),
+ (
+ "eval_env/route_publique_cas_par_cas.html",
+ "eval_env/route_publique_cas_par_cas.html",
+ ),
+ (
+ "eval_env/route_publique_non_soumis.html",
+ "eval_env/route_publique_non_soumis.html",
+ ),
+ (
+ "eval_env/route_publique_systematique.html",
+ "eval_env/route_publique_systematique.html",
+ ),
+ (
+ "eval_env/sport_loisir_culture_cas_par_cas.html",
+ "eval_env/sport_loisir_culture_cas_par_cas.html",
+ ),
+ (
+ "eval_env/sport_loisir_culture_non_soumis.html",
+ "eval_env/sport_loisir_culture_non_soumis.html",
+ ),
+ (
+ "eval_env/sport_loisir_culture_non_soumis_lt1000.html",
+ "eval_env/sport_loisir_culture_non_soumis_lt1000.html",
+ ),
+ (
+ "eval_env/surface_plancher_cas_par_cas.html",
+ "eval_env/surface_plancher_cas_par_cas.html",
+ ),
+ (
+ "eval_env/surface_plancher_non_soumis.html",
+ "eval_env/surface_plancher_non_soumis.html",
+ ),
+ (
+ "eval_env/terrain_assiette_cas_par_cas.html",
+ "eval_env/terrain_assiette_cas_par_cas.html",
+ ),
+ (
+ "eval_env/terrain_assiette_non_concerne.html",
+ "eval_env/terrain_assiette_non_concerne.html",
+ ),
+ (
+ "eval_env/terrain_assiette_non_soumis.html",
+ "eval_env/terrain_assiette_non_soumis.html",
+ ),
+ (
+ "eval_env/terrain_assiette_systematique.html",
+ "eval_env/terrain_assiette_systematique.html",
+ ),
+ (
+ "eval_env/voie_privee_cas_par_cas.html",
+ "eval_env/voie_privee_cas_par_cas.html",
+ ),
+ (
+ "eval_env/voie_privee_non_soumis.html",
+ "eval_env/voie_privee_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/autres_rubriques_non_disponible.html",
+ "loi_sur_leau/autres_rubriques_non_disponible.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_avec_bv_action_requise.html",
+ "loi_sur_leau/ecoulement_avec_bv_action_requise.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_avec_bv_action_requise_probable_1ha.html",
+ "loi_sur_leau/ecoulement_avec_bv_action_requise_probable_1ha.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_avec_bv_non_soumis.html",
+ "loi_sur_leau/ecoulement_avec_bv_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_avec_bv_soumis.html",
+ "loi_sur_leau/ecoulement_avec_bv_soumis.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_sans_bv_action_requise.html",
+ "loi_sur_leau/ecoulement_sans_bv_action_requise.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_sans_bv_non_soumis.html",
+ "loi_sur_leau/ecoulement_sans_bv_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/ecoulement_sans_bv_soumis.html",
+ "loi_sur_leau/ecoulement_sans_bv_soumis.html",
+ ),
+ (
+ "loi_sur_leau/result_action_requise.html",
+ "loi_sur_leau/result_action_requise.html",
+ ),
+ (
+ "loi_sur_leau/result_non_active.html",
+ "loi_sur_leau/result_non_active.html",
+ ),
+ (
+ "loi_sur_leau/result_non_disponible.html",
+ "loi_sur_leau/result_non_disponible.html",
+ ),
+ (
+ "loi_sur_leau/result_non_soumis.html",
+ "loi_sur_leau/result_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/result_soumis.html",
+ "loi_sur_leau/result_soumis.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_action_requise.html",
+ "loi_sur_leau/zone_humide_action_requise.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_action_requise_dans_doute.html",
+ "loi_sur_leau/zone_humide_action_requise_dans_doute.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_action_requise_proche.html",
+ "loi_sur_leau/zone_humide_action_requise_proche.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_action_requise_tout_dpt.html",
+ "loi_sur_leau/zone_humide_action_requise_tout_dpt.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_non_concerne.html",
+ "loi_sur_leau/zone_humide_non_concerne.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_non_soumis.html",
+ "loi_sur_leau/zone_humide_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/zone_humide_soumis.html",
+ "loi_sur_leau/zone_humide_soumis.html",
+ ),
+ (
+ "loi_sur_leau/zone_inondable_action_requise.html",
+ "loi_sur_leau/zone_inondable_action_requise.html",
+ ),
+ (
+ "loi_sur_leau/zone_inondable_action_requise_dans_doute.html",
+ "loi_sur_leau/zone_inondable_action_requise_dans_doute.html",
+ ),
+ (
+ "loi_sur_leau/zone_inondable_non_concerne.html",
+ "loi_sur_leau/zone_inondable_non_concerne.html",
+ ),
+ (
+ "loi_sur_leau/zone_inondable_non_soumis.html",
+ "loi_sur_leau/zone_inondable_non_soumis.html",
+ ),
+ (
+ "loi_sur_leau/zone_inondable_soumis.html",
+ "loi_sur_leau/zone_inondable_soumis.html",
+ ),
+ (
+ "natura2000/autorisation_urba_a_verifier.html",
+ "natura2000/autorisation_urba_a_verifier.html",
+ ),
+ (
+ "natura2000/autorisation_urba_non_soumis.html",
+ "natura2000/autorisation_urba_non_soumis.html",
+ ),
+ (
+ "natura2000/autorisation_urba_non_soumis_lotissement.html",
+ "natura2000/autorisation_urba_non_soumis_lotissement.html",
+ ),
+ (
+ "natura2000/autorisation_urba_soumis.html",
+ "natura2000/autorisation_urba_soumis.html",
+ ),
+ (
+ "natura2000/eval_env_non_soumis.html",
+ "natura2000/eval_env_non_soumis.html",
+ ),
+ (
+ "natura2000/eval_env_soumis_cas_par_cas.html",
+ "natura2000/eval_env_soumis_cas_par_cas.html",
+ ),
+ (
+ "natura2000/eval_env_soumis_systematique.html",
+ "natura2000/eval_env_soumis_systematique.html",
+ ),
+ (
+ "natura2000/iota_iota_a_verifier.html",
+ "natura2000/iota_iota_a_verifier.html",
+ ),
+ (
+ "natura2000/iota_non_soumis.html",
+ "natura2000/iota_non_soumis.html",
+ ),
+ ("natura2000/iota_soumis.html", "natura2000/iota_soumis.html"),
+ (
+ "natura2000/result_a_verifier.html",
+ "natura2000/result_a_verifier.html",
+ ),
+ (
+ "natura2000/result_action_requise.html",
+ "natura2000/result_action_requise.html",
+ ),
+ (
+ "natura2000/result_iota_a_verifier.html",
+ "natura2000/result_iota_a_verifier.html",
+ ),
+ (
+ "natura2000/result_non_active.html",
+ "natura2000/result_non_active.html",
+ ),
+ (
+ "natura2000/result_non_concerne.html",
+ "natura2000/result_non_concerne.html",
+ ),
+ (
+ "natura2000/result_non_disponible.html",
+ "natura2000/result_non_disponible.html",
+ ),
+ (
+ "natura2000/result_non_soumis.html",
+ "natura2000/result_non_soumis.html",
+ ),
+ ("natura2000/result_soumis.html", "natura2000/result_soumis.html"),
+ (
+ "natura2000/zone_humide_action_requise_dans_doute.html",
+ "natura2000/zone_humide_action_requise_dans_doute.html",
+ ),
+ (
+ "natura2000/zone_humide_action_requise_proche.html",
+ "natura2000/zone_humide_action_requise_proche.html",
+ ),
+ (
+ "natura2000/zone_humide_non_concerne.html",
+ "natura2000/zone_humide_non_concerne.html",
+ ),
+ (
+ "natura2000/zone_humide_non_soumis.html",
+ "natura2000/zone_humide_non_soumis.html",
+ ),
+ (
+ "natura2000/zone_humide_non_soumis_dans_doute.html",
+ "natura2000/zone_humide_non_soumis_dans_doute.html",
+ ),
+ (
+ "natura2000/zone_humide_non_soumis_proche.html",
+ "natura2000/zone_humide_non_soumis_proche.html",
+ ),
+ (
+ "natura2000/zone_humide_soumis.html",
+ "natura2000/zone_humide_soumis.html",
+ ),
+ (
+ "natura2000/zone_inondable_non_concerne.html",
+ "natura2000/zone_inondable_non_concerne.html",
+ ),
+ (
+ "natura2000/zone_inondable_non_soumis.html",
+ "natura2000/zone_inondable_non_soumis.html",
+ ),
+ (
+ "natura2000/zone_inondable_soumis.html",
+ "natura2000/zone_inondable_soumis.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_action_requise_dans_doute_interdit.html",
+ "sage/interdiction_impact_zh_action_requise_dans_doute_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_action_requise_interdit.html",
+ "sage/interdiction_impact_zh_action_requise_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_action_requise_proche_interdit.html",
+ "sage/interdiction_impact_zh_action_requise_proche_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_action_requise_tout_dpt_interdit.html",
+ "sage/interdiction_impact_zh_action_requise_tout_dpt_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_interdit.html",
+ "sage/interdiction_impact_zh_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_a_verifier.html",
+ "sage/interdiction_impact_zh_iota_a_verifier.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_action_requise_dans_doute_interdit.html",
+ "sage/interdiction_impact_zh_iota_action_requise_dans_doute_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_action_requise_interdit.html",
+ "sage/interdiction_impact_zh_iota_action_requise_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_action_requise_proche_interdit.html",
+ "sage/interdiction_impact_zh_iota_action_requise_proche_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_action_requise_tout_dpt_interdit.html",
+ "sage/interdiction_impact_zh_iota_action_requise_tout_dpt_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_interdit.html",
+ "sage/interdiction_impact_zh_iota_interdit.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_non_soumis.html",
+ "sage/interdiction_impact_zh_iota_non_soumis.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_iota_non_soumis_dehors.html",
+ "sage/interdiction_impact_zh_iota_non_soumis_dehors.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_non_soumis.html",
+ "sage/interdiction_impact_zh_non_soumis.html",
+ ),
+ (
+ "sage/interdiction_impact_zh_non_soumis_dehors.html",
+ "sage/interdiction_impact_zh_non_soumis_dehors.html",
+ ),
+ ("sage/result_a_verifier.html", "sage/result_a_verifier.html"),
+ (
+ "sage/result_action_requise.html",
+ "sage/result_action_requise.html",
+ ),
+ ("sage/result_interdit.html", "sage/result_interdit.html"),
+ ("sage/result_non_active.html", "sage/result_non_active.html"),
+ ("sage/result_non_concerne.html", "sage/result_non_concerne.html"),
+ (
+ "sage/result_non_disponible.html",
+ "sage/result_non_disponible.html",
+ ),
+ ("sage/result_non_soumis.html", "sage/result_non_soumis.html"),
+ ],
+ max_length=512,
+ verbose_name="Key",
+ ),
+ ),
+ migrations.CreateModel(
+ name="HaieDepartmentConfig",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "is_activated",
+ models.BooleanField(
+ default=False,
+ help_text="Le guichet unique de la haie est-il disponible pour ce département ?",
+ verbose_name="Is activated",
+ ),
+ ),
+ (
+ "department_guichet_unique_url",
+ models.URLField(
+ blank=True,
+ verbose_name="Url du guichet unique de la haie du département (si existant)",
+ ),
+ ),
+ (
+ "contacts_and_links",
+ models.TextField(
+ blank=True, verbose_name="Liste des contacts et liens utiles"
+ ),
+ ),
+ (
+ "department",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="haie_config",
+ to="geodata.department",
+ verbose_name="Department",
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/envergo/moulinette/migrations/0060_merge_20241007_1441.py b/envergo/moulinette/migrations/0060_merge_20241007_1441.py
new file mode 100644
index 000000000..ceb0d9d3e
--- /dev/null
+++ b/envergo/moulinette/migrations/0060_merge_20241007_1441.py
@@ -0,0 +1,13 @@
+# Generated by Django 4.2.13 on 2024-10-07 12:41
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("moulinette", "0059_alter_moulinettetemplate_key_haiedepartmentconfig"),
+ ("moulinette", "0059_n2000_zh_criterion_add_threshold"),
+ ]
+
+ operations = []
diff --git a/envergo/moulinette/migrations/0061_rename_haiedepartmentconfig_confighaie_and_more.py b/envergo/moulinette/migrations/0061_rename_haiedepartmentconfig_confighaie_and_more.py
new file mode 100644
index 000000000..c22428b98
--- /dev/null
+++ b/envergo/moulinette/migrations/0061_rename_haiedepartmentconfig_confighaie_and_more.py
@@ -0,0 +1,35 @@
+# Generated by Django 4.2.13 on 2024-10-07 12:54
+
+import django.contrib.postgres.fields
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("geodata", "0016_alter_department_geometry"),
+ ("moulinette", "0060_merge_20241007_1441"),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name="HaieDepartmentConfig",
+ new_name="ConfigHaie",
+ ),
+ migrations.RenameModel(
+ old_name="MoulinetteConfig",
+ new_name="ConfigAmenagement",
+ ),
+ migrations.AlterField(
+ model_name="moulinettetemplate",
+ name="config",
+ field=models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="templates",
+ to="moulinette.configamenagement",
+ verbose_name="Config",
+ ),
+ ),
+ ]
diff --git a/envergo/moulinette/migrations/0062_alter_configamenagement_options_and_more.py b/envergo/moulinette/migrations/0062_alter_configamenagement_options_and_more.py
new file mode 100644
index 000000000..c29025175
--- /dev/null
+++ b/envergo/moulinette/migrations/0062_alter_configamenagement_options_and_more.py
@@ -0,0 +1,58 @@
+# Generated by Django 4.2.13 on 2024-10-07 13:13
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("geodata", "0016_alter_department_geometry"),
+ ("moulinette", "0061_rename_haiedepartmentconfig_confighaie_and_more"),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name="configamenagement",
+ options={
+ "verbose_name": "Config amenagement",
+ "verbose_name_plural": "Configs amenagement",
+ },
+ ),
+ migrations.AlterModelOptions(
+ name="confighaie",
+ options={
+ "verbose_name": "Config haie",
+ "verbose_name_plural": "Configs haie",
+ },
+ ),
+ migrations.AlterField(
+ model_name="configamenagement",
+ name="department",
+ field=models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="%(class)s",
+ to="geodata.department",
+ verbose_name="Department",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="confighaie",
+ name="department",
+ field=models.OneToOneField(
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name="%(class)s",
+ to="geodata.department",
+ verbose_name="Department",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="confighaie",
+ name="is_activated",
+ field=models.BooleanField(
+ default=False,
+ help_text="Is the moulinette available for this department?",
+ verbose_name="Is activated",
+ ),
+ ),
+ ]
diff --git a/envergo/moulinette/migrations/haie_department_configs.json b/envergo/moulinette/migrations/haie_department_configs.json
new file mode 100644
index 000000000..d70b84742
--- /dev/null
+++ b/envergo/moulinette/migrations/haie_department_configs.json
@@ -0,0 +1,53 @@
+[
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 30,
+ "is_activated": true
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 46,
+ "is_activated": true
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 70,
+ "is_activated": true
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 71,
+ "is_activated": true
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 82,
+ "is_activated": true
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 10,
+ "is_activated": false,
+ "department_guichet_unique_url": "https://www.demarches-simplifiees.fr/commencer/guichet-haies-76-demandes-d-informations-sur-la-pr"
+ }
+ },
+ {
+ "model": "moulinette.ConfigHaie",
+ "fields": {
+ "department": 63,
+ "is_activated": false,
+ "contacts_and_links": "
\r\n DDTM de Loire-Atlantique \r\n Unité Police de l’eau \r\n Email : ddtm-see-guichet-unique@loire-atlantique.gouv.fr \r\n "
+ }
+ }
+]
diff --git a/envergo/moulinette/models.py b/envergo/moulinette/models.py
index 5925aa7c6..6110b12eb 100644
--- a/envergo/moulinette/models.py
+++ b/envergo/moulinette/models.py
@@ -44,6 +44,7 @@
logger = logging.getLogger(__name__)
+HAIE_REGULATIONS = ["conditionnalite_pac", "dep"]
# A list of required action stakes.
# For example, a user might learn that an action is required, to check if the
@@ -657,20 +658,32 @@ def contact(self):
return mark_safe(contact)
-class MoulinetteConfig(models.Model):
- """Some moulinette content depends on the department."""
-
+class ConfigBase(models.Model):
department = models.OneToOneField(
"geodata.Department",
verbose_name=_("Department"),
on_delete=models.PROTECT,
- related_name="moulinette_config",
+ related_name="%(class)s",
)
is_activated = models.BooleanField(
_("Is activated"),
help_text=_("Is the moulinette available for this department?"),
default=False,
)
+
+ class Meta:
+ abstract = True
+
+ def __str__(self):
+ return self.department.get_department_display()
+
+
+class ConfigAmenagement(ConfigBase):
+ """Some moulinette content depends on the department.
+
+ This object is dedicated to the Amenagement moulinette. For Haie, see ConfigHaie.
+ """
+
regulations_available = ArrayField(
base_field=models.CharField(max_length=64, choices=REGULATIONS),
blank=True,
@@ -702,12 +715,33 @@ class MoulinetteConfig(models.Model):
)
class Meta:
- verbose_name = _("Moulinette config")
- verbose_name_plural = _("Moulinette configs")
+ verbose_name = _("Config amenagement")
+ verbose_name_plural = _("Configs amenagement")
+
+
+class ConfigHaie(ConfigBase):
+ """Some moulinette content depends on the department.
+
+ This object is dedicated to the Haie moulinette. For Amenagement, see ConfigAmenagement.
+ """
+
+ regulations_available = HAIE_REGULATIONS
+
+ department_guichet_unique_url = models.URLField(
+ "Url du guichet unique de la haie du département (si existant)", blank=True
+ )
+
+ contacts_and_links = models.TextField(
+ "Liste des contacts et liens utiles", blank=True
+ )
def __str__(self):
return self.department.get_department_display()
+ class Meta:
+ verbose_name = "Config haie"
+ verbose_name_plural = "Configs haie"
+
TEMPLATE_KEYS = [
"autorisation_urba_pa",
@@ -728,12 +762,12 @@ def get_all_template_keys():
class MoulinetteTemplate(models.Model):
"""A custom moulinette template that can be admin edited.
- Templates can be associated to departments (through MoulinetteConfig) or
+ Templates can be associated to departments (through ConfigAmenagement) or
criteria.
"""
config = models.ForeignKey(
- "moulinette.MoulinetteConfig",
+ "moulinette.ConfigAmenagement",
verbose_name=_("Config"),
on_delete=models.PROTECT,
related_name="templates",
@@ -822,10 +856,10 @@ def __init__(self, data, raw_data, activate_optional_criteria=True):
# Some criteria must be hidden to normal users in the
self.activate_optional_criteria = activate_optional_criteria
- self.load_specific_data()
+ self.department = self.get_department()
self.config = self.catalog["config"] = self.get_config()
- if self.config and self.config.id:
+ if self.config and self.config.id and hasattr(self.config, "templates"):
self.templates = {t.key: t for t in self.config.templates.all()}
else:
self.templates = {}
@@ -846,11 +880,6 @@ def evaluate(self):
for regulation in self.regulations:
regulation.evaluate(self)
- @abstractmethod
- def load_specific_data(self):
- """Load data specific for a given moulinette instance."""
- pass
-
def has_config(self):
return bool(self.config)
@@ -877,6 +906,20 @@ def get_debug_result_template(self):
raise AttributeError("No result template found.")
return self.debug_result_template
+ def get_result_non_disponible_template(self):
+ """Return the template to display the result_non_disponible page."""
+
+ if not hasattr(self, "result_non_disponible"):
+ raise AttributeError("No result_non_disponible template found.")
+ return self.result_non_disponible
+
+ def get_result_available_soon_template(self):
+ """Return the template to display the result_available_soon page."""
+
+ if not hasattr(self, "result_available_soon"):
+ raise AttributeError("No result_available_soon template found.")
+ return self.result_available_soon
+
@classmethod
def get_main_form_class(cls):
"""Return the form class for the main questions."""
@@ -1153,6 +1196,8 @@ class MoulinetteAmenagement(Moulinette):
REGULATIONS = ["loi_sur_leau", "natura2000", "eval_env", "sage"]
result_template = "amenagement/moulinette/result.html"
debug_result_template = "amenagement/moulinette/result_debug.html"
+ result_available_soon = "amenagement/moulinette/result_available_soon.html"
+ result_non_disponible = "amenagement/moulinette/result_non_disponible.html"
form_template = "amenagement/moulinette/form.html"
main_form_class = MoulinetteFormAmenagement
@@ -1330,21 +1375,18 @@ def summary(self):
return summary
- def load_specific_data(self):
- self.department = self.get_department()
-
def get_department(self):
lng_lat = self.catalog["lng_lat"]
department = (
Department.objects.filter(geometry__contains=lng_lat)
- .select_related("moulinette_config")
- .prefetch_related("moulinette_config__templates")
+ .select_related("configamenagement")
+ .prefetch_related("configamenagement__templates")
.first()
)
return department
def get_config(self):
- return getattr(self.department, "moulinette_config", None)
+ return getattr(self.department, "configamenagement", None)
def get_debug_context(self):
# In the debug page, we want to factorize the maps we display, so we order them
@@ -1377,16 +1419,16 @@ def get_triage_params(cls):
class MoulinetteHaie(Moulinette):
- REGULATIONS = ["conditionnalite_pac", "dep"]
+ REGULATIONS = HAIE_REGULATIONS
result_template = "haie/moulinette/result.html"
debug_result_template = "haie/moulinette/result.html"
+ result_available_soon = "haie/moulinette/result_non_disponible.html"
+ result_non_disponible = "haie/moulinette/result_non_disponible.html"
form_template = "haie/moulinette/form.html"
main_form_class = MoulinetteFormHaie
def get_config(self):
- return MoulinetteConfig(
- is_activated=True, regulations_available=self.REGULATIONS
- )
+ return getattr(self.department, "confighaie", None)
def summary(self):
"""Build a data summary, for analytics purpose."""
@@ -1401,10 +1443,6 @@ def summary(self):
return summary
- def load_specific_data(self):
- """There is no specific needs for the Haie moulinette."""
- pass
-
def get_debug_context(self):
return {}
@@ -1425,8 +1463,36 @@ def get_extra_context(cls, request):
context["triage_form"] = triage_form
else:
context["redirect_url"] = context["triage_url"]
+
+ department_code = request.GET.get("department", None)
+ department = (
+ (
+ Department.objects.defer("geometry")
+ .filter(confighaie__is_activated=True, department=department_code)
+ .first()
+ )
+ if department_code
+ else None
+ )
+ context["department"] = department
+
return context
+ def get_department(self):
+ department_code = self.raw_data.get("department", None)
+ department = (
+ (
+ Department.objects.defer("geometry")
+ .select_related("confighaie")
+ .filter(department=department_code)
+ .first()
+ )
+ if department_code
+ else None
+ )
+
+ return department
+
def get_moulinette_class_from_site(site):
"""Return the correct Moulinette class depending on the current site."""
diff --git a/envergo/moulinette/templatetags/moulinette.py b/envergo/moulinette/templatetags/moulinette.py
index 5ffc1edc2..98f96e11c 100644
--- a/envergo/moulinette/templatetags/moulinette.py
+++ b/envergo/moulinette/templatetags/moulinette.py
@@ -84,7 +84,7 @@ def show_criterion_body(context, regulation, criterion):
def criterion_value(config, criterion, field):
"""Display a criterion static value.
- If this value is overriden in the MoulinetteConfig instance,
+ If this value is overriden in the ConfigAmenagement or ConfigHaie instance,
display the config value instead.
"""
values = config.criteria_values
diff --git a/envergo/moulinette/tests/factories.py b/envergo/moulinette/tests/factories.py
index 8d10b908e..444b64128 100644
--- a/envergo/moulinette/tests/factories.py
+++ b/envergo/moulinette/tests/factories.py
@@ -2,12 +2,18 @@
from factory.django import DjangoModelFactory
from envergo.geodata.tests.factories import DepartmentFactory, MapFactory
-from envergo.moulinette.models import Criterion, MoulinetteConfig, Perimeter, Regulation
+from envergo.moulinette.models import (
+ ConfigAmenagement,
+ ConfigHaie,
+ Criterion,
+ Perimeter,
+ Regulation,
+)
-class MoulinetteConfigFactory(DjangoModelFactory):
+class ConfigAmenagementFactory(DjangoModelFactory):
class Meta:
- model = MoulinetteConfig
+ model = ConfigAmenagement
department = factory.SubFactory(DepartmentFactory)
is_activated = True
@@ -40,3 +46,11 @@ class Meta:
activation_map = factory.SubFactory(MapFactory)
regulation = factory.SubFactory(RegulationFactory)
is_activated = True
+
+
+class ConfigHaieFactory(DjangoModelFactory):
+ class Meta:
+ model = ConfigHaie
+
+ department = factory.SubFactory(DepartmentFactory)
+ is_activated = True
diff --git a/envergo/moulinette/tests/test_conditionnalite_pac.py b/envergo/moulinette/tests/test_conditionnalite_pac.py
index 9d06f80d3..4acb6743b 100644
--- a/envergo/moulinette/tests/test_conditionnalite_pac.py
+++ b/envergo/moulinette/tests/test_conditionnalite_pac.py
@@ -2,7 +2,11 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteHaie
-from envergo.moulinette.tests.factories import CriterionFactory, RegulationFactory
+from envergo.moulinette.tests.factories import (
+ ConfigHaieFactory,
+ CriterionFactory,
+ RegulationFactory,
+)
pytestmark = pytest.mark.django_db
@@ -22,10 +26,12 @@ def conditionnalite_pac_criteria(france_map): # noqa
def test_conditionnalite_pac_only_for_agri_pac():
+ ConfigHaieFactory()
data = {
"profil": "autre",
"motif": "chemin_acces",
"reimplantation": "remplacement",
+ "department": "44",
}
for motif_choice in [
"transfert_parcelles",
@@ -46,10 +52,12 @@ def test_conditionnalite_pac_only_for_agri_pac():
def test_conditionnalite_pac_for_agri_pac():
+ ConfigHaieFactory()
data = {
"profil": "agri_pac",
"motif": "chemin_acces",
"reimplantation": "remplacement",
+ "department": "44",
}
moulinette = MoulinetteHaie(data, data, False)
diff --git a/envergo/moulinette/tests/test_dep.py b/envergo/moulinette/tests/test_dep.py
index 9badbf548..6f4ecf259 100644
--- a/envergo/moulinette/tests/test_dep.py
+++ b/envergo/moulinette/tests/test_dep.py
@@ -2,7 +2,11 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteHaie
-from envergo.moulinette.tests.factories import CriterionFactory, RegulationFactory
+from envergo.moulinette.tests.factories import (
+ ConfigHaieFactory,
+ CriterionFactory,
+ RegulationFactory,
+)
pytestmark = pytest.mark.django_db
@@ -22,10 +26,12 @@ def dep_criteria(france_map): # noqa
def test_dep_is_soumis():
+ ConfigHaieFactory()
data = {
"profil": "autre",
"motif": "chemin_acces",
"reimplantation": "remplacement",
+ "department": "44",
}
for motif_choice in [
"transfert_parcelles",
diff --git a/envergo/moulinette/tests/test_evalenv.py b/envergo/moulinette/tests/test_evalenv.py
index 81ff3b9ff..97b3b16bc 100644
--- a/envergo/moulinette/tests/test_evalenv.py
+++ b/envergo/moulinette/tests/test_evalenv.py
@@ -5,8 +5,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteAmenagement
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
RegulationFactory,
)
@@ -236,7 +236,7 @@ def test_evalenv_terrain_assiette_systematique(moulinette_data):
def test_evalenv_non_soumis_no_optional_criteria(admin_client):
"""When no optional form is activated, we can show the result."""
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("moulinette_result")
params = "created_surface=500&final_surface=500&lng=-1.54394&lat=47.21381"
@@ -261,7 +261,7 @@ def test_evalenv_non_soumis_no_optional_criteria(admin_client):
def test_evalenv_non_soumis_missing_optional_criteria(admin_client):
"""When optional data is missing, we don't show the result page."""
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("moulinette_result")
params = (
@@ -276,7 +276,7 @@ def test_evalenv_non_soumis_missing_optional_criteria(admin_client):
def test_evalenv_non_soumis_optional_criteria(admin_client):
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("moulinette_result")
params = (
@@ -302,7 +302,7 @@ def test_evalenv_non_soumis_optional_criteria(admin_client):
def test_evalenv_rubrique44(admin_client):
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
# Type d'equipement concerné et capacité d'accueil >= 1000 => Cas par cas
url = reverse("moulinette_result")
diff --git a/envergo/moulinette/tests/test_loisurleau.py b/envergo/moulinette/tests/test_loisurleau.py
index ceafc383a..6f65d70b1 100644
--- a/envergo/moulinette/tests/test_loisurleau.py
+++ b/envergo/moulinette/tests/test_loisurleau.py
@@ -3,8 +3,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteAmenagement
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
RegulationFactory,
)
@@ -174,7 +174,7 @@ def test_3310_large_footprint_outside_wetlands(moulinette_data):
def test_3310_large_footprint_inside_doubt_department(moulinette_data):
"""Project with footprint > 1000m² inside a whole zh department."""
- MoulinetteConfigFactory(zh_doubt=True)
+ ConfigAmenagementFactory(zh_doubt=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["within_potential_wetlands_deprartment"] = True
moulinette.evaluate()
diff --git a/envergo/moulinette/tests/test_models.py b/envergo/moulinette/tests/test_models.py
index b88e0aca4..e10ef774c 100644
--- a/envergo/moulinette/tests/test_models.py
+++ b/envergo/moulinette/tests/test_models.py
@@ -12,8 +12,9 @@
get_moulinette_class_from_url,
)
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
+ ConfigHaieFactory,
CriterionFactory,
- MoulinetteConfigFactory,
PerimeterFactory,
RegulationFactory,
)
@@ -82,7 +83,7 @@ def test_moulinette_config(moulinette_data):
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
assert not moulinette.has_config()
- MoulinetteConfigFactory(is_activated=False)
+ ConfigAmenagementFactory(is_activated=False)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
assert moulinette.has_config()
@@ -91,7 +92,7 @@ def test_moulinette_config(moulinette_data):
def test_result_with_inactive_contact_data(moulinette_data):
"""Dept contact info is not activated, we cannot run the eval."""
- MoulinetteConfigFactory(is_activated=False)
+ ConfigAmenagementFactory(is_activated=False)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
assert not moulinette.is_evaluation_available()
@@ -100,7 +101,7 @@ def test_result_with_inactive_contact_data(moulinette_data):
def test_result_with_contact_data(moulinette_data):
"""Dept contact info is set, we can run the eval."""
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
assert moulinette.is_evaluation_available()
@@ -108,7 +109,7 @@ def test_result_with_contact_data(moulinette_data):
@pytest.mark.parametrize("footprint", [50])
def test_moulinette_amenagement_has_specific_behavior(moulinette_data):
site = SiteFactory()
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
MoulinetteClass = get_moulinette_class_from_site(site)
moulinette = MoulinetteClass(moulinette_data, moulinette_data)
assert moulinette.is_evaluation_available()
@@ -121,10 +122,11 @@ def test_moulinette_amenagement_has_specific_behavior(moulinette_data):
def test_moulinette_haie_has_specific_behavior():
+ ConfigHaieFactory()
site = SiteFactory()
site.domain = "haie.beta.gouv.fr"
MoulinetteClass = get_moulinette_class_from_site(site)
- moulinette = MoulinetteClass({}, {})
+ moulinette = MoulinetteClass({}, {"department": "44"})
assert moulinette.is_evaluation_available()
assert moulinette.get_main_form_class() == MoulinetteFormHaie
assert moulinette.get_form_template() == "haie/moulinette/form.html"
diff --git a/envergo/moulinette/tests/test_n2000_evalenv.py b/envergo/moulinette/tests/test_n2000_evalenv.py
index bc65669a5..a3f176d26 100644
--- a/envergo/moulinette/tests/test_n2000_evalenv.py
+++ b/envergo/moulinette/tests/test_n2000_evalenv.py
@@ -3,8 +3,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteAmenagement
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
RegulationFactory,
)
@@ -18,7 +18,7 @@ def autouse_site(site):
@pytest.fixture(autouse=True)
def evalenv_criteria(france_map): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
)
diff --git a/envergo/moulinette/tests/test_n2000_iota.py b/envergo/moulinette/tests/test_n2000_iota.py
index 1d3c40414..5360a9e5e 100644
--- a/envergo/moulinette/tests/test_n2000_iota.py
+++ b/envergo/moulinette/tests/test_n2000_iota.py
@@ -3,8 +3,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import MoulinetteAmenagement
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
RegulationFactory,
)
@@ -18,7 +18,7 @@ def autouse_site(site):
@pytest.fixture(autouse=True)
def loisurleau_criteria(france_map): # noqa
- MoulinetteConfigFactory(
+ ConfigAmenagementFactory(
is_activated=True,
ddtm_water_police_email="ddtm_email_test@example.org",
)
diff --git a/envergo/moulinette/tests/test_optional_criteria.py b/envergo/moulinette/tests/test_optional_criteria.py
index fc801584e..7edc4665e 100644
--- a/envergo/moulinette/tests/test_optional_criteria.py
+++ b/envergo/moulinette/tests/test_optional_criteria.py
@@ -4,8 +4,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
RegulationFactory,
)
@@ -19,7 +19,7 @@ def autouse_site(site):
@pytest.fixture(autouse=True)
def evalenv_criteria(france_map): # noqa
- _config = MoulinetteConfigFactory(is_activated=True) # noqa
+ _config = ConfigAmenagementFactory(is_activated=True) # noqa
regulation = RegulationFactory(regulation="eval_env")
criteria = [
CriterionFactory(
diff --git a/envergo/moulinette/tests/test_sage.py b/envergo/moulinette/tests/test_sage.py
index 02463f8a1..aeb1459ce 100644
--- a/envergo/moulinette/tests/test_sage.py
+++ b/envergo/moulinette/tests/test_sage.py
@@ -6,8 +6,8 @@
from envergo.geodata.conftest import france_map # noqa
from envergo.moulinette.models import Criterion, MoulinetteAmenagement
from envergo.moulinette.tests.factories import (
+ ConfigAmenagementFactory,
CriterionFactory,
- MoulinetteConfigFactory,
Perimeter,
PerimeterFactory,
RegulationFactory,
@@ -55,7 +55,7 @@ def moulinette_data(footprint):
def test_result_interdit(moulinette_data):
"""Test the default criterion result"""
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["forbidden_wetlands_within_25m"] = True
moulinette.evaluate()
@@ -67,7 +67,7 @@ def test_result_interdit(moulinette_data):
def test_deactivated_regulation(moulinette_data):
"""Test single regulation deactivation in moulinette config."""
- MoulinetteConfigFactory(is_activated=True, regulations_available=[])
+ ConfigAmenagementFactory(is_activated=True, regulations_available=[])
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["forbidden_wetlands_within_25m"] = True
moulinette.evaluate()
@@ -79,7 +79,7 @@ def test_deactivated_regulation(moulinette_data):
def test_default_result_when_a_perimeter_is_found(moulinette_data):
Criterion.objects.all().delete()
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["forbidden_wetlands_within_25m"] = True
moulinette.evaluate()
@@ -92,7 +92,7 @@ def test_default_result_when_a_perimeter_is_found(moulinette_data):
def test_default_result_when_a_perimeter_is_deactivated(moulinette_data):
Criterion.objects.all().delete()
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["forbidden_wetlands_within_25m"] = True
@@ -109,7 +109,7 @@ def test_default_result_when_a_perimeter_is_not_found(moulinette_data):
Criterion.objects.all().delete()
Perimeter.objects.all().delete()
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
moulinette = MoulinetteAmenagement(moulinette_data, moulinette_data)
moulinette.catalog["forbidden_wetlands_within_25m"] = True
moulinette.evaluate()
@@ -122,7 +122,7 @@ def test_default_result_when_a_perimeter_is_not_found(moulinette_data):
def test_perimeter_map_display(moulinette_data, client):
"""The perimeter map should be displayed in the result page."""
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
url = reverse("moulinette_result")
params = urlencode(moulinette_data)
@@ -143,7 +143,7 @@ def test_several_perimeter_maps_display(
):
"""When several perimeters are found, they are all displayed."""
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
PerimeterFactory(
name="Sage Test",
activation_map=france_map,
diff --git a/envergo/moulinette/tests/test_views.py b/envergo/moulinette/tests/test_views.py
index 4bcd57dd5..0075d2cc7 100644
--- a/envergo/moulinette/tests/test_views.py
+++ b/envergo/moulinette/tests/test_views.py
@@ -2,7 +2,7 @@
from django.urls import reverse
from pytest_django.asserts import assertTemplateUsed
-from envergo.moulinette.tests.factories import MoulinetteConfigFactory
+from envergo.moulinette.tests.factories import ConfigAmenagementFactory
pytestmark = pytest.mark.django_db
@@ -49,7 +49,7 @@ def test_moulinette_result_without_config(client):
res = client.get(full_url)
assert res.status_code == 200
- assertTemplateUsed(res, "moulinette/result_non_disponible.html")
+ assertTemplateUsed(res, "amenagement/moulinette/result_non_disponible.html")
def test_moulinette_result_without_config_admin_access(client, admin_user):
@@ -62,11 +62,11 @@ def test_moulinette_result_without_config_admin_access(client, admin_user):
res = client.get(full_url)
assert res.status_code == 200
- assertTemplateUsed(res, "moulinette/result_non_disponible.html")
+ assertTemplateUsed(res, "amenagement/moulinette/result_non_disponible.html")
def test_moulinette_result_with_deactivated_config(client):
- MoulinetteConfigFactory(is_activated=False)
+ ConfigAmenagementFactory(is_activated=False)
url = reverse("moulinette_result")
params = "created_surface=500&final_surface=500&lng=-1.54394&lat=47.21381"
@@ -78,7 +78,7 @@ def test_moulinette_result_with_deactivated_config(client):
def test_moulinette_result_with_deactivated_config_admin_access(client, admin_user):
- MoulinetteConfigFactory(is_activated=False)
+ ConfigAmenagementFactory(is_activated=False)
client.force_login(admin_user)
url = reverse("moulinette_result")
@@ -92,7 +92,7 @@ def test_moulinette_result_with_deactivated_config_admin_access(client, admin_us
def test_moulinette_result_with_activated_config(client):
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
url = reverse("moulinette_result")
params = "created_surface=500&final_surface=500&lng=-1.54394&lat=47.21381"
@@ -113,7 +113,7 @@ def test_moulinette_result_without_params_redirects_to_home(client):
def test_moulinette_result_form_error(client):
"""Bad params are cleaned from the result url."""
- MoulinetteConfigFactory()
+ ConfigAmenagementFactory()
url = reverse("moulinette_result")
params = (
@@ -131,7 +131,7 @@ def test_moulinette_result_form_error(client):
def test_moulinette_result_mtm_keywords_are_not_bad_params(client):
"""Analytics params are not cleaned from the result url."""
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
url = reverse("moulinette_result")
params = "created_surface=500&final_surface=500&lng=-1.54394&lat=47.21381&mtm_campaign=test"
@@ -143,7 +143,7 @@ def test_moulinette_result_mtm_keywords_are_not_bad_params(client):
def test_moulinette_result_custom_matomo_tracking_url(client):
- MoulinetteConfigFactory(is_activated=True)
+ ConfigAmenagementFactory(is_activated=True)
url = reverse("moulinette_result")
params = "created_surface=500&final_surface=500&lng=-1.54394&lat=47.21381&mtm_campaign=test"
diff --git a/envergo/moulinette/urls_haie.py b/envergo/moulinette/urls_haie.py
index ba11db094..759e90fd8 100644
--- a/envergo/moulinette/urls_haie.py
+++ b/envergo/moulinette/urls_haie.py
@@ -1,7 +1,8 @@
-from django.urls import include, path
-from django.utils.translation import gettext_lazy as _
+from django.urls import path
-from envergo.moulinette.views import Triage, TriageResult
+from envergo.moulinette.views import Triage
+
+from .urls import urlpatterns as common_urlpatterns
urlpatterns = [
path(
@@ -9,10 +10,4 @@
Triage.as_view(),
name="triage",
),
- path(
- _("result/"),
- TriageResult.as_view(),
- name="triage_result",
- ),
- path(_("moulinette/"), include("envergo.moulinette.urls")),
-]
+] + common_urlpatterns
diff --git a/envergo/moulinette/views.py b/envergo/moulinette/views.py
index bbc746fbe..021a0beca 100644
--- a/envergo/moulinette/views.py
+++ b/envergo/moulinette/views.py
@@ -5,11 +5,12 @@
from django.conf import settings
from django.http import HttpResponseRedirect, QueryDict
from django.urls import reverse
-from django.views.generic import FormView, TemplateView
+from django.views.generic import FormView
from envergo.analytics.forms import FeedbackFormUseful, FeedbackFormUseless
from envergo.analytics.utils import is_request_from_a_bot, log_event
from envergo.evaluations.models import RESULTS
+from envergo.geodata.models import Department
from envergo.geodata.utils import get_address_from_coords
from envergo.moulinette.forms import TriageFormHaie
from envergo.moulinette.models import get_moulinette_class_from_site
@@ -144,6 +145,7 @@ def render_to_response(self, context, **response_kwargs):
# We have to store the moulinette since there are no other way
# to give parameters to `get_template_names`
self.moulinette = context.get("moulinette", None)
+ self.triage_form = context.get("triage_form", None)
return super().render_to_response(context, **response_kwargs)
def get_additional_forms(self, moulinette):
@@ -216,9 +218,6 @@ def get_all_optional_form_classes(self):
return form_classes
- def form_valid(self, form):
- return HttpResponseRedirect(self.get_results_url(form))
-
def get_results_url(self, form):
"""Generates the GET url corresponding to the POST'ed moulinette query.
@@ -308,6 +307,9 @@ def get(self, request, *args, **kwargs):
else:
return res
+ def form_valid(self, form):
+ return HttpResponseRedirect(self.get_results_url(form))
+
class MoulinetteResult(MoulinetteMixin, FormView):
event_category = "simulateur"
@@ -317,20 +319,23 @@ def get_template_names(self):
"""Check which template to use depending on the moulinette result."""
moulinette = self.moulinette
+ triage_form = self.triage_form
is_debug = bool(self.request.GET.get("debug", False))
is_edit = bool(self.request.GET.get("edit", False))
is_admin = self.request.user.is_staff
- if moulinette is None:
+ if moulinette is None and triage_form is None:
template_name = "moulinette/home.html"
+ elif moulinette is None:
+ template_name = "haie/moulinette/triage_result.html"
elif is_debug:
template_name = moulinette.get_debug_result_template()
elif is_edit:
template_name = "moulinette/home.html"
elif not moulinette.has_config():
- template_name = "moulinette/result_non_disponible.html"
+ template_name = moulinette.get_result_non_disponible_template()
elif not (moulinette.is_evaluation_available() or is_admin):
- template_name = "moulinette/result_available_soon.html"
+ template_name = moulinette.get_result_available_soon_template()
elif moulinette.has_missing_data():
template_name = "moulinette/home.html"
else:
@@ -343,6 +348,7 @@ def get(self, request, *args, **kwargs):
context = self.get_context_data()
res = self.render_to_response(context)
moulinette = self.moulinette
+ triage_form = self.triage_form
if "redirect_url" in context:
return HttpResponseRedirect(context["redirect_url"])
@@ -361,6 +367,8 @@ def get(self, request, *args, **kwargs):
):
self.log_moulinette_event(moulinette)
+ return res
+ elif triage_form is not None:
return res
else:
return HttpResponseRedirect(reverse("moulinette_home"))
@@ -384,6 +392,8 @@ def validate_results_url(self, request, context):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
+
+ moulinette = context.get("moulinette", None)
# Let's build custom uris for better matomo tracking
# Depending on the moulinette result, we want to track different uris
# as if they were distinct pages.
@@ -392,7 +402,11 @@ def get_context_data(self, **kwargs):
share_print_url = update_qs(current_url, {"mtm_campaign": "print-simu"})
debug_result_url = update_qs(current_url, {"debug": "true"})
result_url = remove_from_qs(current_url, "debug")
- edit_url = update_qs(result_url, {"edit": "true"})
+ edit_url = (
+ update_qs(result_url, {"edit": "true"})
+ if moulinette
+ else context.get("triage_url", None)
+ )
# Url without any query parameters
# We want to build "fake" urls for matomo tracking
# For example, if the current url is /simulateur/resultat/?debug=true,
@@ -417,8 +431,6 @@ def get_context_data(self, **kwargs):
context["share_print_url"] = share_print_url
context["envergo_url"] = self.request.build_absolute_uri("/")
context["base_result"] = "moulinette/base_result.html"
-
- moulinette = context.get("moulinette", None)
is_debug = bool(self.request.GET.get("debug", False))
is_edit = bool(self.request.GET.get("edit", False))
@@ -468,6 +480,29 @@ class Triage(FormView):
form_class = TriageFormHaie
template_name = "haie/moulinette/triage.html"
+ def get(self, request, *args, **kwargs):
+ """This page should always have a department to be displayed."""
+ context = self.get_context_data()
+ if not context.get("department", None):
+ return HttpResponseRedirect(reverse("home"))
+ return self.render_to_response(self.get_context_data())
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ department_code = self.request.GET.get("department", None)
+ department = (
+ (
+ Department.objects.defer("geometry")
+ .filter(department=department_code)
+ .first()
+ )
+ if department_code
+ else None
+ )
+ context["department"] = department
+
+ return context
+
def get_initial(self):
"""Populate the form with data from the query string."""
return self.request.GET.dict()
@@ -477,36 +512,8 @@ def form_valid(self, form):
if query_params["element"] == "haie" and query_params["travaux"] == "arrachage":
url = reverse("moulinette_home")
else:
- url = reverse("triage_result")
+ url = reverse("moulinette_result")
query_string = urlencode(query_params)
url_with_params = f"{url}?{query_string}"
return HttpResponseRedirect(url_with_params)
-
-
-class TriageResult(TemplateView):
- template_name = "haie/moulinette/triage_result.html"
-
- def get(self, request, *args, **kwargs):
- context = self.get_context_data(**kwargs)
- form = context["form"]
- if not form.is_valid():
- return HttpResponseRedirect(reverse("triage"))
- return self.render_to_response(context)
-
- def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
- form_data = self.request.GET
- context["form"] = TriageFormHaie(data=form_data)
-
- envergo_url = self.request.build_absolute_uri("/")
- current_url = self.request.build_absolute_uri()
- share_print_url = update_qs(current_url, {"mtm_campaign": "print-simu"})
- edit_url = update_qs(reverse("triage"), form_data)
-
- context["current_url"] = current_url
- context["share_print_url"] = share_print_url
- context["envergo_url"] = envergo_url
- context["edit_url"] = edit_url
-
- return context
diff --git a/envergo/pages/templatetags/pages.py b/envergo/pages/templatetags/pages.py
index 5d15d8da5..747ce1f05 100644
--- a/envergo/pages/templatetags/pages.py
+++ b/envergo/pages/templatetags/pages.py
@@ -1,16 +1,19 @@
import random
+from typing import Literal
+from urllib.parse import urlencode
from django import template
+from django.core.cache import cache
from django.urls import reverse
from django.utils.safestring import mark_safe
-from envergo.moulinette.models import MoulinetteConfig
+from envergo.geodata.models import Department
+from envergo.moulinette.models import ConfigAmenagement, ConfigHaie
register = template.Library()
-def nav_link(route, label, *event_data, aria_current=False):
- url = reverse(route)
+def nav_link(url, label, *event_data, aria_current=False):
aria_current = 'aria-current="page"' if aria_current else ""
data_attrs = ""
@@ -41,7 +44,7 @@ def menu_item(context, route, label, *event_data, subroutes=[]):
current_route = ""
aria_current = route == current_route or current_route in subroutes
- return nav_link(route, label, *event_data, aria_current=aria_current)
+ return nav_link(reverse(route), label, *event_data, aria_current=aria_current)
@register.simple_tag(takes_context=True)
@@ -99,8 +102,8 @@ def faq_menu(context):
def evaluation_menu(context):
"""Generate html for the "Mes avis réglementaires" collapsible menu."""
links = (
- ("evaluation_search", "Retrouver un avis", []),
- ("dashboard", "Tableau de bord", []),
+ (reverse("evaluation_search"), "Retrouver un avis", []),
+ (reverse("dashboard"), "Tableau de bord", []),
)
# Other urls that can be reached from the menu
@@ -116,7 +119,7 @@ def project_owner_menu(context, is_slim=False):
"""Generate html for the "Equipes projet" collapsible menu."""
links = (
(
- "geometricians",
+ reverse("geometricians"),
"Géomètres-experts",
["GeometrePage", "SimulationClick", "Nav"],
),
@@ -129,13 +132,27 @@ def project_owner_menu(context, is_slim=False):
@register.simple_tag(takes_context=True)
def pilote_departments_menu(context, is_slim=False):
- """Generate html for the "Equipes projet" collapsible menu."""
+ """Generate html for the "Départements pilotes" collapsible menu."""
+ cache_key = "activated_departments"
+ activated_departments = cache.get(cache_key)
+
+ if not activated_departments:
+ activated_departments = (
+ Department.objects.defer("geometry")
+ .filter(confighaie__is_activated=True)
+ .all()
+ )
+ cache.set(
+ cache_key, activated_departments, timeout=60 * 15
+ ) # Cache for 15 minutes
+
links = (
(
- "triage",
- "Indre",
+ f"{reverse('triage')}?{urlencode({'department': department.department})}",
+ department,
[],
- ),
+ )
+ for department in activated_departments
)
return collapsible_menu(
@@ -188,10 +205,10 @@ def collapsible_menu(
@register.simple_tag()
-def nb_available_depts():
+def nb_available_depts(site: Literal["haie", "amenagement"] = "amenagement"):
"""Return nb of depts where EnvErgo is available."""
-
- return MoulinetteConfig.objects.filter(is_activated=True).count()
+ Config = {"haie": ConfigHaie, "amenagement": ConfigAmenagement}.get(site)
+ return Config.objects.filter(is_activated=True).count()
@register.simple_tag(takes_context=True)
diff --git a/envergo/pages/views.py b/envergo/pages/views.py
index 6726de2da..ef55fb40e 100644
--- a/envergo/pages/views.py
+++ b/envergo/pages/views.py
@@ -1,16 +1,19 @@
from datetime import date, timedelta
+from urllib.parse import urlencode
import requests
from django.conf import settings
from django.contrib import messages
from django.contrib.syndication.views import Feed
+from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.html import mark_safe
from django.views.generic import FormView, ListView, TemplateView
from config.settings.base import GEOMETRICIAN_WEBINAR_FORM_URL
-from envergo.moulinette.models import MoulinetteConfig
+from envergo.geodata.models import Department
+from envergo.moulinette.models import ConfigAmenagement
from envergo.moulinette.views import MoulinetteMixin
from envergo.pages.models import NewsItem
@@ -19,9 +22,52 @@ class HomeAmenagementView(MoulinetteMixin, FormView):
template_name = "amenagement/pages/home.html"
-class HomeHaieView(MoulinetteMixin, FormView):
+class HomeHaieView(TemplateView):
template_name = "haie/pages/home.html"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ departments = (
+ Department.objects.defer("geometry").select_related("confighaie").all()
+ )
+ context["departments"] = departments
+ context["activated_departments"] = [
+ department
+ for department in departments
+ if department
+ and hasattr(department, "confighaie")
+ and department.confighaie.is_activated
+ ]
+ return context
+
+ def post(self, request, *args, **kwargs):
+ data = request.POST
+ department_id = data.get("department")
+ department = None
+ if department_id:
+ department = (
+ Department.objects.select_related("confighaie")
+ .defer("geometry")
+ .get(id=department_id)
+ )
+
+ config = (
+ department.confighaie
+ if department and hasattr(department, "confighaie")
+ else None
+ )
+
+ if config and config.is_activated:
+ query_params = {"department": department.department}
+ return HttpResponseRedirect(
+ f"{reverse('triage')}?{urlencode(query_params)}"
+ )
+
+ context = self.get_context_data()
+ context["department"] = department
+ context["config"] = config
+ return self.render_to_response(context)
+
class GeometriciansView(MoulinetteMixin, FormView):
template_name = "pages/geometricians.html"
@@ -190,11 +236,11 @@ class AvailabilityInfo(TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context["configs_available"] = MoulinetteConfig.objects.filter(
+ context["configs_available"] = ConfigAmenagement.objects.filter(
is_activated=True
).order_by("department")
- context["configs_soon"] = MoulinetteConfig.objects.filter(
+ context["configs_soon"] = ConfigAmenagement.objects.filter(
is_activated=False
).order_by("department")
diff --git a/envergo/static/sass/project.scss b/envergo/static/sass/project.scss
index 4dc8dde37..84c1e8ec5 100644
--- a/envergo/static/sass/project.scss
+++ b/envergo/static/sass/project.scss
@@ -1433,7 +1433,6 @@ main.home {
}
section#simulateur {
- background-color: #e8edff;
background-color: var(--info-950-100);
h2 {
@@ -1887,3 +1886,11 @@ main.demonstrateur_2150 {
#moulinette-submit-button {
min-width: 8em;
}
+
+#department-search-title {
+ color: var(--blue-france-sun-113-625);
+}
+
+#contacts_and_links {
+ background-color: var(--grey-975-100);
+}
diff --git a/envergo/static/sass/project_haie.scss b/envergo/static/sass/project_haie.scss
index 0967d35fc..29f5f2251 100644
--- a/envergo/static/sass/project_haie.scss
+++ b/envergo/static/sass/project_haie.scss
@@ -8,3 +8,9 @@ div#moulinette {
font-weight: bold !important;
}
}
+
+main.home {
+ section#simulateur {
+ background-color: var(--blue-france-850-200);
+ }
+}
diff --git a/envergo/templates/amenagement/moulinette/form.html b/envergo/templates/amenagement/moulinette/form.html
index 332a3cc8c..dae011fec 100644
--- a/envergo/templates/amenagement/moulinette/form.html
+++ b/envergo/templates/amenagement/moulinette/form.html
@@ -9,7 +9,7 @@ Simulez votre projet en phase a
method="post"
novalidate
autocomplete="off"
- action="{% url "moulinette_result" %}"
+ action="{% url "moulinette_home" %}"
id="moulinette-form">
{% csrf_token %}
diff --git a/envergo/templates/amenagement/moulinette/result_available_soon.html b/envergo/templates/amenagement/moulinette/result_available_soon.html
new file mode 100644
index 000000000..05dc3cdbd
--- /dev/null
+++ b/envergo/templates/amenagement/moulinette/result_available_soon.html
@@ -0,0 +1,31 @@
+{% extends "moulinette/result_available_soon.html" %}
+
+{% block result %}
+
+ Simulation réglementaire du projet
+
+
+
Le simulateur Envergo est en cours de déploiement dans votre département.
+
Il sera disponible d'ici à quelques semaines au plus tard.
+
+
+
+ 👉 Testez le simulateur avec
+ cet exemple de projet : une extension de
+ 1250 m² d'un bâtiment près des rives de la Loire, soumise à
+ la Loi sur l'eau .
+
+
+ 💡 Inscrivez-vous pour être informé·e de l’ouverture d’EnvErgo à votre département.
+
+ Signaler mon intérêt
+
+
+ ⏱ Vous pouvez également demander un avis réglementaire
+ sur un projet, réalisé par l'équipe EnvErgo. Réponse en trois jours ouvrés.
+
+
+{% endblock %}
diff --git a/envergo/templates/amenagement/moulinette/result_debug.html b/envergo/templates/amenagement/moulinette/result_debug.html
index 67cd0e451..11a4c8d10 100644
--- a/envergo/templates/amenagement/moulinette/result_debug.html
+++ b/envergo/templates/amenagement/moulinette/result_debug.html
@@ -14,7 +14,7 @@ Données initiales
Surface créée: {{ created_surface }} m²
Surface finale: {{ final_surface }} m²
- Département : {{ moulinette.department }}
+ Département : {{ moulinette.department }}
diff --git a/envergo/templates/amenagement/moulinette/result_non_disponible.html b/envergo/templates/amenagement/moulinette/result_non_disponible.html
new file mode 100644
index 000000000..2f7b9897b
--- /dev/null
+++ b/envergo/templates/amenagement/moulinette/result_non_disponible.html
@@ -0,0 +1,23 @@
+{% extends "moulinette/result_non_disponible.html" %}
+
+{% load evaluations static pages %}
+
+{% block result %}
+
+ Simulation réglementaire du projet
+
+
+
+
+ 👉 Testez le simulateur avec
+ cet exemple de projet : une extension de 1250 m² d'un bâtiment près des rives de la Loire, soumise à la Loi sur l'eau .
+
+
+ {% include "_department_opt_in.html" %}
+
+{% endblock %}
diff --git a/envergo/templates/haie/moulinette/_form_introduction.html b/envergo/templates/haie/moulinette/_form_introduction.html
index 286b64638..ff522b648 100644
--- a/envergo/templates/haie/moulinette/_form_introduction.html
+++ b/envergo/templates/haie/moulinette/_form_introduction.html
@@ -4,4 +4,4 @@
Il est anonyme et sans création de compte
-Département : Indre (36)
+Département : {{ department|default_if_none:"Inconnu" }}
diff --git a/envergo/templates/haie/moulinette/form.html b/envergo/templates/haie/moulinette/form.html
index ce916d908..489b67b1b 100644
--- a/envergo/templates/haie/moulinette/form.html
+++ b/envergo/templates/haie/moulinette/form.html
@@ -11,7 +11,7 @@ Commencez à décrire votre projet de
method="post"
novalidate
autocomplete="off"
- action="{% url 'moulinette_result' %}"
+ action="{% url 'moulinette_home' %}?{{ request.GET.urlencode }}"
id="moulinette-form">
{% csrf_token %}
@@ -28,11 +28,6 @@ Commencez à décrire votre projet de
name="travaux"
value="{{ request.GET.travaux|default:'' }}" />
-
-
-
-
-