diff --git a/config/settings/base.py b/config/settings/base.py index ff581789f..67b058f72 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -344,8 +344,6 @@ CRISP_CHATBOX_ENABLED = env("DJANGO_CRISP_CHATBOX_ENABLED", default=False) CRISP_WEBSITE_ID = env("DJANGO_CRISP_WEBSITE_ID", default=None) -MAKE_COM_WEBHOOK = env("DJANGO_MAKE_COM_WEBHOOK", default=None) - SELF_DECLARATION_FORM_ID = "mDzXgX" TRANSFER_EVAL_EMAIL_FORM_ID = "mDzXgX" @@ -356,3 +354,13 @@ "DJANGO_GEOMETRICIAN_WEBINAR_FORM_URL", default="https://app.livestorm.co/p/3e2db81a-a8eb-4684-83e9-9ba999f8bb37/form", ) + +# Make.com integration settings +MAKE_COM_WEBHOOK = env( + "DJANGO_MAKE_COM_WEBHOOK", default=None +) # webhook for new evaluation requests + +MAKE_COM_EVALUATION_EDITION_WEBHOOK = env( + "DJANGO_MAKE_COM_EVALUATION_EDITION_WEBHOOK", + default=None, # webhook for edited evaluations +) diff --git a/envergo/evaluations/models.py b/envergo/evaluations/models.py index 46825fc0a..22df2096e 100644 --- a/envergo/evaluations/models.py +++ b/envergo/evaluations/models.py @@ -11,6 +11,8 @@ from django.core.mail import EmailMultiAlternatives from django.core.validators import FileExtensionValidator from django.db import models +from django.db.models import QuerySet +from django.db.models.signals import post_save from django.http import QueryDict from django.template.loader import render_to_string from django.urls import reverse @@ -106,6 +108,22 @@ def params_from_url(url): ) +class EvaluationQuerySet(QuerySet): + def update(self, **kwargs): + res = super().update(**kwargs) + for instance in self: + # Signal that the save is complete + post_save.send( + sender=Evaluation, + instance=instance, + created=False, + update_fields=None, + raw=False, + using=self.db, + ) + return res + + class Evaluation(models.Model): """A single evaluation for a building permit application. @@ -114,6 +132,8 @@ class Evaluation(models.Model): """ + objects = EvaluationQuerySet.as_manager() + uid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) reference = models.CharField( _("Reference"), diff --git a/envergo/evaluations/signals.py b/envergo/evaluations/signals.py index 0088490f7..c7a86ff75 100644 --- a/envergo/evaluations/signals.py +++ b/envergo/evaluations/signals.py @@ -1,13 +1,18 @@ import logging from anymail.signals import tracking +from django.db import transaction from django.db.models import F +from django.db.models.signals import post_save from django.dispatch import receiver from django.urls import reverse from envergo.analytics.models import Event -from envergo.evaluations.models import RecipientStatus, RegulatoryNoticeLog -from envergo.evaluations.tasks import warn_admin_of_email_error +from envergo.evaluations.models import Evaluation, RecipientStatus, RegulatoryNoticeLog +from envergo.evaluations.tasks import ( + post_evaluation_to_automation, + warn_admin_of_email_error, +) logger = logging.getLogger(__name__) @@ -117,3 +122,9 @@ def handle_mail_event(sender, event, esp_name, **kwargs): session_key=message_id, metadata=metadata, ) + + +@receiver(post_save, sender=Evaluation) +def handle_evaluation_edition(sender, instance, **kwargs): + if not kwargs.get("created", False): + transaction.on_commit(lambda: post_evaluation_to_automation.delay(instance.uid)) diff --git a/envergo/evaluations/tasks.py b/envergo/evaluations/tasks.py index b930e86b9..48c825b7b 100644 --- a/envergo/evaluations/tasks.py +++ b/envergo/evaluations/tasks.py @@ -11,7 +11,7 @@ from config.celery_app import app from envergo.confs.utils import get_setting -from envergo.evaluations.models import RecipientStatus, Request +from envergo.evaluations.models import Evaluation, RecipientStatus, Request from envergo.utils.mattermost import notify from envergo.utils.tools import get_base_url @@ -92,22 +92,10 @@ def handle_field(self, obj, field): @app.task def post_evalreq_to_automation(request_id, host): """Send request data to Make.com.""" - webhook_url = settings.MAKE_COM_WEBHOOK - if not webhook_url: - logger.warning("No make.com webhook configured. Doing nothing.") - return - logger.info(f"Sending data to make.com {request_id} {host}") request = Request.objects.get(id=request_id) - serialized = BetterJsonSerializer().serialize([request]) - json_data = json.loads(serialized)[0] - payload = json_data["fields"] - payload["pk"] = json_data["pk"] - - res = requests.post(webhook_url, json=payload) - if res.status_code != 200: - logger.error(f"Error while posting data to make.com: {res.text}") + post_a_model_to_automation(request, webhook_url) @app.task @@ -141,3 +129,27 @@ def warn_admin_of_email_error(recipient_status_id): from_email=settings.DEFAULT_FROM_EMAIL, fail_silently=False, ) + + +@app.task +def post_evaluation_to_automation(evaluation_uid): + """Send the edited evaluation data to a webhook.""" + webhook_url = settings.MAKE_COM_EVALUATION_EDITION_WEBHOOK + evaluation = Evaluation.objects.get(uid=evaluation_uid) + logger.info(f"Sending Evaluation to make.com {evaluation.reference}") + post_a_model_to_automation(evaluation, webhook_url) + + +def post_a_model_to_automation(model, webhook_url): + if not webhook_url: + logger.warning("No make.com webhook configured. Doing nothing.") + return + + serialized = BetterJsonSerializer().serialize([model]) + json_data = json.loads(serialized)[0] + payload = json_data["fields"] + payload["pk"] = json_data["pk"] + + res = requests.post(webhook_url, json=payload) + if res.status_code != 200: + logger.error(f"Error while posting data to make.com: {res.text}") diff --git a/envergo/evaluations/tests/test_models.py b/envergo/evaluations/tests/test_models.py index 58b79617b..43234cd58 100644 --- a/envergo/evaluations/tests/test_models.py +++ b/envergo/evaluations/tests/test_models.py @@ -1,9 +1,9 @@ -from unittest.mock import Mock +from unittest.mock import Mock, call, patch from urllib.parse import urlencode import pytest -from envergo.evaluations.models import Request +from envergo.evaluations.models import Evaluation, Request from envergo.evaluations.tests.factories import EvaluationFactory from envergo.geodata.conftest import loire_atlantique_department # noqa from envergo.geodata.conftest import bizous_town_center, france_map # noqa @@ -108,3 +108,25 @@ def test_prevent_storing_project_owner_details_when_we_should_not_send_him_the_e request.refresh_from_db() assert request.project_owner_phone == "+33612345678" assert request.project_owner_emails == ["test@test.com"] + + +def test_evaluation_edition_triggers_an_automation(): + with patch("django.db.transaction.on_commit", new=lambda fn: fn()): + with patch( + "envergo.evaluations.tasks.post_evaluation_to_automation.delay" + ) as mock_post: + evaluation = EvaluationFactory() # no call from creation + evaluation.application_number = "PC05112321D0001" + evaluation.save() # call from edition + evaluation2 = EvaluationFactory() # no call from creation + Evaluation.objects.update( + application_number="PC05112321D0001" + ) # call from edition for all the evaluations + + mock_post.assert_has_calls( + [ + call(evaluation.uid), + call(evaluation.uid), + call(evaluation2.uid), + ] + ) diff --git a/scalingo.json b/scalingo.json index 7999e4fa5..c871b2e4b 100644 --- a/scalingo.json +++ b/scalingo.json @@ -53,6 +53,9 @@ "DJANGO_MAKE_COM_WEBHOOK": { "value": "" }, + "DJANGO_MAKE_COM_EVALUATION_EDITION_WEBHOOK": { + "value": "" + }, "DJANGO_ADMIN_OTP_REQUIRED": { "value": "False" }