Skip to content

Commit

Permalink
Merge pull request #256 from MTES-MCT/icpe2
Browse files Browse the repository at this point in the history
Possibilité de stipuler qu'e avis réglementaire concerne un projet ICPE
  • Loading branch information
thibault authored Dec 4, 2023
2 parents 5495371 + 677cf93 commit 889c33a
Show file tree
Hide file tree
Showing 26 changed files with 578 additions and 255 deletions.
79 changes: 35 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,46 @@ Pour VSCode, il est recommandé d'utiliser la configuration suivante.
Installer les extensions :

- [EditorConfig pour vscode](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)
- [External formatter](https://marketplace.visualstudio.com/items?itemName=SteefH.external-formatters) (pour djhtml)
- [Flake8 pour le linting](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)
- [Black pour le formattage](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter)
- [Isort pour l'organisation des imports](https://marketplace.visualstudio.com/items?itemName=ms-python.isort)

Pour activer le formatage à l'enregistrement et correctement affecter les bons "linters" aux bons types de fichiers :

Voici un fichier `settings.json` à enregistres dans `.vscode/settings.json` pour configurer
correctement VSCode :

```json
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"editor.rulers": [
88
],
},
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
},
"[django-html]": {
"editor.rulers": [
120,
],
"editor.defaultFormatter": "monosans.djlint",
"editor.wordWrap": "wordWrapColumn"
},
"[css][scss][less]": {
"editor.defaultFormatter": "vscode.css-language-features"
},
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"isort.args": [
"--profile",
"black"
],
"black-formatter.args": [
"--line-length=88"
],
"files.associations": {
"**/templates/*.html": "django-html",
"**/templates/*": "django-txt",
Expand All @@ -105,43 +133,6 @@ Pour activer le formatage à l'enregistrement et correctement affecter les bons
"emmet.includeLanguages": {
"django-html": "html"
},
"[django-html]": {
"editor.defaultFormatter": "SteefH.external-formatters"
},
"externalFormatters.languages": {
"django-html": {
"command": "djhtml",
"arguments": [
"-t 2"
],
},
},
"beautify.language": {
"html": [
"htm",
"html",
"django-html"
]
},
"beautify.config": {
"brace_style": "collapse,preserve-inline",
"indent_size": 2,
"indent_style": "space",
},
"[python]": {
"pythonPath": ".venv/bin/python",
"linting.enabled": true,
"linting.flake8Enabled": true,
"linting.pylintEnabled": false,
"formatting.provider": "black",
"formatting.blackArgs": [
"--line-length=88"
],
"sortImports.args": [
"--profile",
"black"
],
}
}
```

Expand Down
2 changes: 1 addition & 1 deletion envergo/evaluations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class Media:
),
(
"Contenu de l'avis réglementaire",
{"fields": ("moulinette_url", "details_md")},
{"fields": ("moulinette_url", "is_icpe", "details_md")},
),
(
_("Sent emails"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-10-23 14:17

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
("evaluations", "0019_alter_evaluation_created_surface"),
]

operations = [
migrations.AddField(
model_name="evaluation",
name="is_icpe",
field=models.BooleanField(default=False, verbose_name="Is ICPE?"),
),
]
12 changes: 12 additions & 0 deletions envergo/evaluations/migrations/0021_merge_20231129_0837.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 4.2 on 2023-11-29 08:37

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("evaluations", "0020_alter_evaluation_notice_log_cascade"),
("evaluations", "0020_evaluation_is_icpe_alter_evaluation_details_md_and_more"),
]

operations = []
45 changes: 28 additions & 17 deletions envergo/evaluations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class Evaluation(models.Model):
send_eval_to_sponsor = models.BooleanField(
_("Send evaluation to project sponsor"), default=True
)

is_icpe = models.BooleanField(_("Is ICPE?"), default=False)
created_at = models.DateTimeField(_("Date created"), default=timezone.now)

class Meta:
Expand Down Expand Up @@ -303,20 +303,30 @@ def get_email(self, request):
html_mail_template = f"evaluations/admin/eval_email_{result}.html"
to_be_transmitted = all(
(
not evaluation.is_icpe,
evaluation.user_type == USER_TYPES.instructor,
result != "non_soumis",
not evaluation.send_eval_to_sponsor,
)
)
icpe_not_transmitted = all(
(
evaluation.is_icpe,
evaluation.send_eval_to_sponsor,
evaluation.user_type == USER_TYPES.instructor,
)
)
context = {
"evaluation": evaluation,
"is_icpe": evaluation.is_icpe,
"rr_mention_md": evaluation.rr_mention_md,
"rr_mention_html": evaluation.rr_mention_html,
"moulinette": moulinette,
"evaluation_link": request.build_absolute_uri(
evaluation.get_absolute_url()
),
"to_be_transmitted": to_be_transmitted,
"icpe_not_transmitted": icpe_not_transmitted,
"required_actions_soumis": list(moulinette.all_required_actions_soumis()),
"required_actions_interdit": list(
moulinette.all_required_actions_interdit()
Expand Down Expand Up @@ -348,7 +358,7 @@ def get_recipients(self):
result = self.moulinette.result

if evaluation.user_type == USER_TYPES.instructor:
if evaluation.send_eval_to_sponsor:
if evaluation.send_eval_to_sponsor and not evaluation.is_icpe:
if result in ("interdit", "soumis", "action_requise"):
recipients = evaluation.project_sponsor_emails
else:
Expand All @@ -365,19 +375,17 @@ def get_cc_recipients(self):
evaluation = self.evaluation
result = self.moulinette.result

if evaluation.user_type == USER_TYPES.instructor:
if evaluation.send_eval_to_sponsor:
if result in ("interdit", "soumis"):
cc_recipients = evaluation.contact_emails
elif result == "action_requise":
cc_recipients = evaluation.contact_emails
else:
cc_recipients = []
else:
cc_recipients = []
cc_recipients = []

else:
cc_recipients = []
if all(
(
not evaluation.is_icpe,
evaluation.user_type == USER_TYPES.instructor,
evaluation.send_eval_to_sponsor,
result in ("interdit", "soumis", "action_requise"),
)
):
cc_recipients = evaluation.contact_emails

return cc_recipients

Expand All @@ -388,9 +396,12 @@ def get_bcc_recipients(self):

bcc_recipients = []

if (
evaluation.user_type == USER_TYPES.instructor
and evaluation.send_eval_to_sponsor
if all(
(
not evaluation.is_icpe,
evaluation.user_type == USER_TYPES.instructor,
evaluation.send_eval_to_sponsor,
)
):
if moulinette.loi_sur_leau and moulinette.loi_sur_leau.result == "soumis":
if config.ddtm_water_police_email:
Expand Down
119 changes: 119 additions & 0 deletions envergo/evaluations/tests/test_eval_emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,122 @@ def test_required_action_interdit(rf, moulinette_url):
)
assert "action attendue du porteur" not in body
assert "action requise interdit" in body


@pytest.mark.parametrize("footprint", [50])
def test_instructor_icpe_send_to_sponsor(rf, moulinette_url):
"""Test email when evalreq is:
- created by an instructor
- the "icpe" checkbox is checked
- send eval to sponsor is checked
"""
eval_kwargs = {
"user_type": USER_TYPES.instructor,
"moulinette_url": moulinette_url,
"send_eval_to_sponsor": True,
"is_icpe": True,
}
eval, moulinette = fake_moulinette(
moulinette_url,
"soumis",
"non_soumis",
"non_soumis",
"non_soumis",
**eval_kwargs,
)

req = rf.get("/")
eval_email = eval.get_evaluation_email()
email = eval_email.get_email(req)
assert email.to == ["[email protected]"]
assert email.cc == []
assert email.bcc == []

body = email.body
assert "À transmettre au porteur" not in body
assert (
"Le projet semble être une Installation Classée pour la Protection de l’Environnement (ICPE)"
in body
)
assert (
"nous n’avons pas envoyé cet avis directement au porteur, car EnvErgo ne se prononce pas encore"
in body
)


@pytest.mark.parametrize("footprint", [50])
def test_instructor_icpe_dont_send_to_sponsor(rf, moulinette_url):
"""Test email when evalreq is:
- created by an instructor
- the "icpe" checkbox is checked
- send eval to sponsor is not checked
"""
eval_kwargs = {
"user_type": USER_TYPES.instructor,
"moulinette_url": moulinette_url,
"send_eval_to_sponsor": False,
"is_icpe": True,
}
eval, moulinette = fake_moulinette(
moulinette_url,
"soumis",
"non_soumis",
"non_soumis",
"non_soumis",
**eval_kwargs,
)

req = rf.get("/")
eval_email = eval.get_evaluation_email()
email = eval_email.get_email(req)
assert email.to == ["[email protected]"]
assert email.cc == []
assert email.bcc == []

body = email.body
assert "À transmettre au porteur" not in body
assert (
"Le projet semble être une Installation Classée pour la Protection de l’Environnement (ICPE)"
in body
)
assert (
"nous n’avons pas envoyé cet avis directement au porteur, car EnvErgo ne se prononce pas encore"
not in body
)


@pytest.mark.parametrize("footprint", [1200])
def test_petitioner_icpe(rf, moulinette_url):
eval_kwargs = {
"user_type": USER_TYPES.petitioner,
"is_icpe": True,
"moulinette_url": moulinette_url,
"send_eval_to_sponsor": False,
}
eval, moulinette = fake_moulinette(
moulinette_url,
"soumis",
"non_soumis",
"non_soumis",
"non_soumis",
**eval_kwargs,
)

req = rf.get("/")
eval_email = eval.get_evaluation_email()
email = eval_email.get_email(req)

assert email.to == ["[email protected]", "[email protected]"]
assert email.cc == []
assert email.bcc == []

body = email.body
assert "À transmettre au porteur" not in body
assert (
"Le projet semble être une Installation Classée pour la Protection de l’Environnement (ICPE)"
in body
)
assert (
"nous n’avons pas envoyé cet avis directement au porteur, car EnvErgo ne se prononce pas encore"
not in body
)
6 changes: 6 additions & 0 deletions envergo/moulinette/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ def regulation_slug(self, obj):


class CriterionAdminForm(forms.ModelForm):
header = forms.CharField(
label=_("Header"),
required=False,
widget=admin.widgets.AdminTextareaWidget(attrs={"rows": 3}),
)

def get_initial_for_field(self, field, field_name):
"""Prevent Evaluator choice to be instanciated.
Expand Down
Loading

0 comments on commit 889c33a

Please sign in to comment.