From 9a3db2bb9709b6749294d72f1b4ff2f1459ab273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Thu, 16 Jan 2025 06:10:37 +0100 Subject: [PATCH] final commit --- lemarche/api/tenders/tests.py | 21 ---- lemarche/api/tenders/views.py | 1 - ...modification_request_and_reject_message.py | 4 +- .../templates/tenders/admin_change_form.html | 5 +- lemarche/tenders/admin.py | 66 +++++-------- .../update_tender_status_to_rejected.py | 6 +- ...r_email_sent_for_modification_and_more.py} | 11 +-- lemarche/tenders/models.py | 35 +++---- lemarche/tenders/tests/test_commands.py | 4 +- lemarche/tenders/tests/test_models.py | 63 ++---------- lemarche/utils/test_urls.py | 18 ---- lemarche/utils/urls.py | 6 +- lemarche/www/pages/views.py | 3 - lemarche/www/tenders/tasks.py | 98 +++++++++---------- lemarche/www/tenders/tests.py | 20 +--- lemarche/www/tenders/views.py | 1 - 16 files changed, 108 insertions(+), 254 deletions(-) rename lemarche/tenders/migrations/{0095_tender_changes_information_and_more.py => 0096_tender_email_sent_for_modification_and_more.py} (71%) delete mode 100644 lemarche/utils/test_urls.py diff --git a/lemarche/api/tenders/tests.py b/lemarche/api/tenders/tests.py index 4468e047f..acb5ec3ef 100644 --- a/lemarche/api/tenders/tests.py +++ b/lemarche/api/tenders/tests.py @@ -197,26 +197,6 @@ def test_create_contact_call_has_user_buyer_attributes(self, mock_create_contact if sectors.exists(): attributes["TYPE_VERTICALE_ACHETEUR"] = sectors.first().name - def test_add_log_entry_method(self): - """Test 'add_log_entry' method to check tender logs""" - extra_data = {"source": "TALLY"} - _, tender, _ = self.setup_mock_user_and_tender_creation( - title="Test tally", user=self.user_buyer, extra_data=extra_data - ) - tender.add_log_entry("PUBLISHED") - tender.save() - - self.assertEqual(tender.status, tender_constants.STATUS_PUBLISHED) - self.assertEqual(len(tender.logs), 1) - - tender.status = tender_constants.STATUS_DRAFT - tender.save() - tender.status = tender_constants.STATUS_PUBLISHED - tender.add_log_entry("PUBLISHED") - tender.save() - - self.assertEqual(len(tender.logs), 2) - def test_reset_modification_request(self): """Test 'reset_modification_request' method to check tender fields updates""" extra_data = {"source": "TALLY"} @@ -228,7 +208,6 @@ def test_reset_modification_request(self): self.assertEqual(tender.status, tender_constants.STATUS_PUBLISHED) self.assertEqual(tender.email_sent_for_modification, False) - self.assertEqual(tender.changes_information, "") def test_create_tender_with_different_contact_data(self): tender_data = TENDER_JSON.copy() diff --git a/lemarche/api/tenders/views.py b/lemarche/api/tenders/views.py index cbecb4a1d..9469def6f 100644 --- a/lemarche/api/tenders/views.py +++ b/lemarche/api/tenders/views.py @@ -83,7 +83,6 @@ def perform_create(self, serializer: TenderSerializer): ) # Check before adding logs or resetting modification request if tender.status == tender_constants.STATUS_PUBLISHED: - tender.add_log_entry("PUBLISHED") tender.reset_modification_request() add_to_contact_list(user=user, type="signup", source=user_source, tender=tender) diff --git a/lemarche/conversations/migrations/0019_add_templatetransactional_tender_author_modification_request_and_reject_message.py b/lemarche/conversations/migrations/0019_add_templatetransactional_tender_author_modification_request_and_reject_message.py index d2784f86d..7382f9476 100644 --- a/lemarche/conversations/migrations/0019_add_templatetransactional_tender_author_modification_request_and_reject_message.py +++ b/lemarche/conversations/migrations/0019_add_templatetransactional_tender_author_modification_request_and_reject_message.py @@ -17,8 +17,8 @@ def create_template(apps, schema_editor): def delete_template(apps, schema_editor): TemplateTransactional = apps.get_model("conversations", "TemplateTransactional") - TemplateTransactional.objects.get(code="TENDERS_AUTHOR_MODIFICATION_REQUEST").delete() - TemplateTransactional.objects.get(code="TENDERS_AUTHOR_REJECT_MESSAGE").delete() + TemplateTransactional.objects.filter(code="TENDERS_AUTHOR_MODIFICATION_REQUEST").delete() + TemplateTransactional.objects.filter(code="TENDERS_AUTHOR_REJECT_MESSAGE").delete() class Migration(migrations.Migration): diff --git a/lemarche/templates/tenders/admin_change_form.html b/lemarche/templates/tenders/admin_change_form.html index 0823e794c..3cc6c321c 100644 --- a/lemarche/templates/tenders/admin_change_form.html +++ b/lemarche/templates/tenders/admin_change_form.html @@ -36,9 +36,10 @@ {% block after_related_objects %} {{ block.super }} {% if original %} - {% if not original.validated_at %} + {% if not original.validated_at and original.status == "PUBLISHED"%}
+
{% endif %}
@@ -54,7 +55,7 @@

Date idéale de début des prestations dépassée ({{ original.start_working_date }})

{% endif %} {% endif %} - {% else %} + {% elif original.status == "PUBLISHED" %}

L'envoi des besoins 'validés' se fait toutes les 5 minutes, du Lundi au Vendredi, entre 9h et 17h

diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py index 274bfdbcd..63759c19c 100644 --- a/lemarche/tenders/admin.py +++ b/lemarche/tenders/admin.py @@ -1,3 +1,5 @@ +import logging + from ckeditor.widgets import CKEditorWidget from django import forms from django.contrib import admin @@ -31,6 +33,9 @@ ) +logger = logging.getLogger(__name__) + + class KindFilter(MultiChoice): FILTER_LABEL = Tender._meta.get_field("kind").verbose_name BUTTON_LABEL = "Appliquer" @@ -282,8 +287,6 @@ def clean(self): """ cleaned_data = super().clean() distance_location = cleaned_data.get("distance_location") - email_sent_for_modification = cleaned_data.get("email_sent_for_modification") - changes_information = cleaned_data.get("changes_information") if distance_location: location = cleaned_data.get("location") @@ -296,11 +299,6 @@ def clean(self): {"location": "Le champ 'Distance en km' est spécifié, ce champ doit être une ville"} ) - if not email_sent_for_modification and changes_information: - raise forms.ValidationError( - {"changes_information": "Vous devez cocher la case 'Modifications requises' pour remplir ce champ"} - ) - @admin.register(Tender, site=admin_site) class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): @@ -314,7 +312,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): "start_working_date_in_list", "siae_count_annotated_with_link_in_list", "siae_detail_contact_click_count_annotated_with_link_in_list", - "email_sent_for_modification", + "status", "is_validated_or_sent", "is_followed_by_us", ] @@ -525,8 +523,6 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): { "fields": ( "admins", - "email_sent_for_modification", - "changes_information", "is_followed_by_us", "proj_resulted_in_reserved_tender", "is_reserved_tender", @@ -560,28 +556,22 @@ class Media: def handle_email_sent_for_modification(self, request, obj): """ - Send an email to the author of the tender to request a modification, if it hasn't already been done. - Update the status of the tender to STATUS_DRAFT and the email_sent_for_modification field. - Redirect to the page for modifying the tender. + Send an email to the author and set some fields with 'set_modification_request' + Display an error message if the email can't be sent """ - if obj.email_sent_for_modification: - try: - send_tender_author_modification_request(tender=obj) - self.message_user(request, "Une demande de modification a été envoyée à l'auteur du besoin") - obj.email_sent_for_modification = True - obj.status = tender_constants.STATUS_DRAFT - obj.add_log_entry("SEND_TENDER_AUTHOR_MODIFICATION_REQUEST") - obj.save(update_fields=["email_sent_for_modification", "status", "logs"]) - except Exception as e: - # Force the email_sent_for_modification field to False - obj.email_sent_for_modification = False - obj.save(update_fields=["email_sent_for_modification"]) - self.message_user( - request, - f"Erreur lors de l'envoi de la demande de modification : {str(e)}", - level="error", - ) - return HttpResponseRedirect(".") + try: + send_tender_author_modification_request(tender=obj) + obj.set_modification_request() + self.message_user(request, "Une demande de modification a été envoyée à l'auteur du besoin") + except Exception as e: + self.message_user( + request, + "Erreur lors de l'envoi de la demande de modification : veuillez contacter le support.", + level="error", + ) + logger.error(f"Exception when sending mail {e}") + finally: + return HttpResponseRedirect(".") def handle_rejected_status(self, request, obj): """ @@ -624,27 +614,15 @@ def get_readonly_fields(self, request, obj=None): # slug cannot be changed once the tender is validated if obj.status == tender_constants.STATUS_VALIDATED: readonly_fields.append("slug") - # cannot edit 'email_sent_for_modification' while tender is not published - if obj and obj.email_sent_for_modification and obj.status != Tender.STATUS_PUBLISHED: - readonly_fields.append("email_sent_for_modification") return readonly_fields def save_model(self, request, obj: Tender, form, change): """ Set Tender author on create - Set 'email_sent_for_modification' and 'changes_information' on update """ if not obj.id and not obj.author_id: obj.author = request.user - if change and obj.email_sent_for_modification: - fields_to_update = ["email_sent_for_modification"] - if obj.changes_information: - fields_to_update.append("changes_information") - obj.save(update_fields=fields_to_update) - - obj.save() - def save_formset(self, request, form, formset, change): """ Set Note author on create @@ -862,7 +840,7 @@ def response_change(self, request, obj: Tender): # we don't need to send it in the crm, parteners manage them self.message_user(request, "Ce dépôt de besoin a été validé. Il sera envoyé aux partenaires :)") return HttpResponseRedirect(".") - if obj.email_sent_for_modification and obj.status == tender_constants.STATUS_PUBLISHED: + if request.POST.get("_send_modification_request"): return self.handle_email_sent_for_modification(request, obj) if obj.status == tender_constants.STATUS_REJECTED: return self.handle_rejected_status(request, obj) diff --git a/lemarche/tenders/management/commands/update_tender_status_to_rejected.py b/lemarche/tenders/management/commands/update_tender_status_to_rejected.py index fc369e48f..dfd512f23 100644 --- a/lemarche/tenders/management/commands/update_tender_status_to_rejected.py +++ b/lemarche/tenders/management/commands/update_tender_status_to_rejected.py @@ -22,12 +22,12 @@ def handle(self, *args, **options): for tender in tenders_draft: email_sent_at = None for log_entry in tender.logs: - if log_entry.get("action") == "send_tender_author_modification_request": - email_sent_at = log_entry.get("email_sent_at") + if log_entry.get("action") == "send tender author modification request": + email_sent_at = log_entry.get("date") break if email_sent_at: - email_sent_at_date = timezone.now().strptime(email_sent_at, "%Y-%m-%dT%H:%M:%S.%f%z") + email_sent_at_date = timezone.datetime.fromisoformat(email_sent_at) if email_sent_at_date <= threshold_date: tenders_to_update.append(tender) diff --git a/lemarche/tenders/migrations/0095_tender_changes_information_and_more.py b/lemarche/tenders/migrations/0096_tender_email_sent_for_modification_and_more.py similarity index 71% rename from lemarche/tenders/migrations/0095_tender_changes_information_and_more.py rename to lemarche/tenders/migrations/0096_tender_email_sent_for_modification_and_more.py index ba8b31c4e..477d6f2d0 100644 --- a/lemarche/tenders/migrations/0095_tender_changes_information_and_more.py +++ b/lemarche/tenders/migrations/0096_tender_email_sent_for_modification_and_more.py @@ -1,21 +1,14 @@ -# Generated by Django 4.2.15 on 2024-12-26 18:02 +# Generated by Django 4.2.15 on 2025-01-16 04:01 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("tenders", "0094_add_templatetransactional_tender_author_commercial_partners"), + ("tenders", "0095_remove_tender_accept_cocontracting_and_more"), ] operations = [ - migrations.AddField( - model_name="tender", - name="changes_information", - field=models.TextField( - blank=True, verbose_name="Informations complémentaires sur les modifications requises" - ), - ), migrations.AddField( model_name="tender", name="email_sent_for_modification", diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py index 11dd03e0e..bc0803b3a 100644 --- a/lemarche/tenders/models.py +++ b/lemarche/tenders/models.py @@ -616,7 +616,6 @@ class Tender(models.Model): email_sent_for_modification = models.BooleanField( "Modifications requises", help_text="Envoyer un e-mail pour demander des modifications", default=False ) - changes_information = models.TextField("Informations complémentaires sur les modifications requises", blank=True) # Admin specific for proj proj_resulted_in_reserved_tender = models.BooleanField( "Abouti à un appel d’offre (uniquement sourcing)", null=True @@ -712,35 +711,29 @@ def __init__(self, *args, **kwargs): for field_name in self.TRACK_UPDATE_FIELDS: setattr(self, f"__previous_{field_name}", getattr(self, field_name)) - def add_log_entry(self, action, details=None): - """ - Add an entry to the log list. - - Args: - action (str): The action that was performed (e.g. status change, email sent, etc.) - details (dict, optional): Additional details about the action - """ - log_entry = { - "action": action, - "timestamp": timezone.now().isoformat(), - } - if details: - log_entry["details"] = details - - self.logs.append(log_entry) - def reset_modification_request(self): """ Reset modification request when republishing a tender. This method can only be called on Tender updates if status is changed to published """ if self.status == self.STATUS_PUBLISHED and self.email_sent_for_modification: - if self.changes_information: - self.changes_information = "" - self.save(update_fields=["changes_information"]) self.email_sent_for_modification = False self.save(update_fields=["email_sent_for_modification"]) + def set_modification_request(self): + """ + Set modification request when republishing a tender. + This method can only be called on Tender updates if status is changed to published + """ + self.email_sent_for_modification = True + self.status = tender_constants.STATUS_DRAFT + log_item = { + "action": "send tender author modification request", + "date": timezone.now().isoformat(), + } + self.logs.append(log_item) + self.save(update_fields=["email_sent_for_modification", "status", "logs"]) + def set_slug(self, with_uuid=False): """ The slug field should be unique. diff --git a/lemarche/tenders/tests/test_commands.py b/lemarche/tenders/tests/test_commands.py index 1aac37e13..d2dbfded6 100644 --- a/lemarche/tenders/tests/test_commands.py +++ b/lemarche/tenders/tests/test_commands.py @@ -197,14 +197,14 @@ def test_update_tender_status_to_rejected(self): tender_recent = TenderFactory( status=tender_constants.STATUS_DRAFT, logs=[ - {"action": "send_tender_author_modification_request", "email_sent_at": recent_date.isoformat()}, + {"action": "send tender author modification request", "date": recent_date.isoformat()}, ], ) tender_expired = TenderFactory( status=tender_constants.STATUS_DRAFT, logs=[ - {"action": "send_tender_author_modification_request", "email_sent_at": threshold_date.isoformat()}, + {"action": "send tender author modification request", "date": threshold_date.isoformat()}, ], ) diff --git a/lemarche/tenders/tests/test_models.py b/lemarche/tenders/tests/test_models.py index 13cf1552d..05ce91555 100644 --- a/lemarche/tenders/tests/test_models.py +++ b/lemarche/tenders/tests/test_models.py @@ -1092,41 +1092,17 @@ def test_email_sent_for_published_status(self, mock_send_email): self.form_data | { "title": "New title", - "email_sent_for_modification": "True", + "_send_modification_request": "Envoyer une demande de modification", }, follow=True, ) tender_response = response.context_data["adminform"].form.instance + actions = [log["action"] for log in tender_response.logs] mock_send_email.assert_called_once_with(tender=tender_response) + self.assertTrue(tender_response.email_sent_for_modification) self.assertEqual(tender_response.status, tender_constants.STATUS_DRAFT) - - @patch("lemarche.tenders.admin.send_tender_author_modification_request") - def test_email_not_sent_for_non_published_status(self, mock_send_email): - """ - Test that when the tender status is not PUBLISHED, - the modification email is not sent. - """ - self.client.force_login(self.user) - - self.tender.status = tender_constants.STATUS_DRAFT - self.tender.save() - - tender_update_post_url = get_admin_change_view_url(self.tender) - - response = self.client.post( - tender_update_post_url, - self.form_data - | { - "title": "New title", - "email_sent_for_modification": "True", - }, - follow=True, - ) - tender_response = response.context_data["adminform"].form.instance - - mock_send_email.assert_not_called() - self.assertEqual(tender_response.status, tender_constants.STATUS_DRAFT) + self.assertIn("send tender author modification request", actions) def test_email_sent_for_modification_updates_status_and_logs(self): """Test 'email_sent_for_modification' updates tender status and logs""" @@ -1138,7 +1114,7 @@ def test_email_sent_for_modification_updates_status_and_logs(self): self.form_data | { "title": "New title", - "email_sent_for_modification": True, + "_send_modification_request": "Envoyer une demande de modification", }, follow=True, ) @@ -1149,27 +1125,8 @@ def test_email_sent_for_modification_updates_status_and_logs(self): # Tasks 'send_tender_autor_modification_request' logs email sent date log_entry = tender_response.logs[0] - self.assertEqual(log_entry["action"], "SEND_TENDER_AUTHOR_MODIFICATION_REQUEST") - self.assertIn("timestamp", log_entry) - - def test_changes_information_cannot_be_edited_if_email_not_sent(self): - """Test changes_information cannot be edited if email not sent.""" - self.client.force_login(self.user) - tender_update_post_url = get_admin_change_view_url(self.tender) - - response = self.client.post( - tender_update_post_url, - self.form_data - | { - "title": "New title", - "changes_information": "test", - }, - follow=True, - ) - form = response.context_data["adminform"].form - tender_response = response.context_data["adminform"].form.instance - self.assertFalse(form.is_valid()) - self.assertEqual(tender_response.changes_information, "") + self.assertEqual(log_entry["action"], "send tender author modification request") + self.assertIn("date", log_entry) @patch("lemarche.tenders.admin.send_tender_author_modification_request") def test_handle_email_sent_for_modification_failure(self, mock_send_email): @@ -1187,7 +1144,7 @@ def test_handle_email_sent_for_modification_failure(self, mock_send_email): self.form_data | { "title": "New title", - "email_sent_for_modification": True, + "_send_modification_request": "Envoyer une demande de modification", }, follow=True, ) @@ -1199,9 +1156,9 @@ def test_handle_email_sent_for_modification_failure(self, mock_send_email): self.assertEqual(tender_response.status, tender_constants.STATUS_PUBLISHED) self.assertFalse(tender_response.email_sent_for_modification) - self.assertNotIn("SEND_TENDER_AUTHOR_MODIFICATION_REQUEST", actions) + self.assertNotIn("send tender author modification request", actions) self.assertIn( - "Erreur lors de l'envoi de la demande de modification : Simulated email sending failure", message_texts + "Erreur lors de l'envoi de la demande de modification : veuillez contacter le support.", message_texts ) mock_send_email.assert_called_once_with(tender=tender_response) diff --git a/lemarche/utils/test_urls.py b/lemarche/utils/test_urls.py deleted file mode 100644 index c3a41400c..000000000 --- a/lemarche/utils/test_urls.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.test import TestCase -from django.urls import reverse - -from lemarche.tenders.models import Tender -from lemarche.utils.urls import get_object_update_url - - -class GetObjectUrlTest(TestCase): - def test_get_object_update_url(self): - """ - Check the function returns the correct update object URL. - """ - obj = Tender(slug="test-slug") - - update_url = get_object_update_url(obj, "tenders") # any app should work - expected_url = reverse("tenders:update", kwargs={"slug": "test-slug"}) - - self.assertEqual(update_url, expected_url) diff --git a/lemarche/utils/urls.py b/lemarche/utils/urls.py index b167a81c2..e7bf0340c 100644 --- a/lemarche/utils/urls.py +++ b/lemarche/utils/urls.py @@ -5,7 +5,7 @@ from django.conf import settings from django.contrib.sites.models import Site from django.db.models import Model -from django.urls import reverse, reverse_lazy +from django.urls import reverse_lazy from django.utils.http import url_has_allowed_host_and_scheme @@ -57,10 +57,6 @@ def get_object_share_url(obj: Model): return f"https://{get_domain_url()}{obj.get_absolute_url()}" -def get_object_update_url(obj: Model, app: str): - return reverse(f"{app}:update", kwargs={"slug": obj.slug}) - - def get_object_admin_url(obj: Model): admin_url = reverse_lazy(f"admin:{obj._meta.app_label}_{obj._meta.model_name}_change", args=[obj.id]) return f"https://{get_domain_url()}{admin_url}" diff --git a/lemarche/www/pages/views.py b/lemarche/www/pages/views.py index ec168d30f..b0093c94c 100644 --- a/lemarche/www/pages/views.py +++ b/lemarche/www/pages/views.py @@ -286,8 +286,6 @@ def csrf_failure(request, reason=""): # noqa C901 # create tender if is_adding: tender: Tender = create_tender_from_dict(tender_dict) - if tender.status == tender_constants.STATUS_PUBLISHED: - tender.add_log_entry("PUBLISHED") tender.save() add_to_contact_list(user=user, type="signup", source=user_constants.SOURCE_TENDER_FORM, tender=tender) elif is_update: @@ -305,7 +303,6 @@ def csrf_failure(request, reason=""): # noqa C901 setattr(tender, attribute, tender_dict.get(attribute)) # Check before adding logs or resetting modification request if tender.status == tender_constants.STATUS_PUBLISHED: - tender.add_log_entry("PUBLISHED") tender.reset_modification_request() tender.save() diff --git a/lemarche/www/tenders/tasks.py b/lemarche/www/tenders/tasks.py index ccfedce9b..ed0c7e9bf 100644 --- a/lemarche/www/tenders/tasks.py +++ b/lemarche/www/tenders/tasks.py @@ -16,7 +16,7 @@ from lemarche.utils.apis import api_mailjet, api_slack from lemarche.utils.data import date_to_string from lemarche.utils.emails import send_mail_async, whitelist_recipient_list -from lemarche.utils.urls import get_domain_url, get_object_admin_url, get_object_share_url, get_object_update_url +from lemarche.utils.urls import get_domain_url, get_object_admin_url, get_object_share_url logger = logging.getLogger(__name__) @@ -542,46 +542,34 @@ def send_tender_author_modification_request(tender: Tender): Send an email to the author of a Tender notifying them that their submission is invalid and requires modification. """ recipient_list = whitelist_recipient_list([tender.author.email]) - if len(recipient_list): - recipient_email = recipient_list[0] - recipient_name = tender.author.full_name + if not recipient_list: + return - # Custom message if tender.changes_information is not empty - if tender.changes_information: - changes_information = f"Message complémentaire de l'administration : {tender.changes_information}" - else: - changes_information = "" + recipient_email = tender.author.email + recipient_name = tender.author.full_name - tender_update_url = f"{get_object_update_url(tender, 'tenders')}" - variables = { - "TENDER_ID": tender.id, - "TENDER_TITLE": tender.title, - "TENDER_CREATED_AT": tender.created_at.strftime("%d %B %Y"), - "TENDER_AUTHOR_ID": tender.author.id, - "TENDER_AUTHOR_FIRST_NAME": tender.author.first_name, - "TENDER_CHANGES_INFORMATION": changes_information, - "TENDER_UPDATE_URL": tender_update_url, - } + tender_update_url = reverse("tenders:update", kwargs={"slug": tender.slug}) + logger.debug(f"Tender Update URL: {tender_update_url}") - email_template = TemplateTransactional.objects.get(code="TENDERS_AUTHOR_MODIFICATION_REQUEST") + variables = { + "TENDER_ID": tender.id, + "TENDER_TITLE": tender.title, + "TENDER_CREATED_AT": tender.created_at.strftime("%d %B %Y"), + "TENDER_AUTHOR_ID": tender.author.id, + "TENDER_AUTHOR_FIRST_NAME": tender.author.first_name, + "TENDER_UPDATE_URL": tender_update_url, + } - if not tender.contact_notifications_disabled: - email_template.send_transactional_email( - recipient_email=recipient_email, - recipient_name=recipient_name, - variables=variables, - recipient_content_object=tender.author, - parent_content_object=tender, - ) + email_template = TemplateTransactional.objects.get(code="TENDERS_AUTHOR_MODIFICATION_REQUEST") - # Log email sent date - tender.logs.append( - { - "action": "send_tender_author_modification_request", - "email_sent_at": timezone.now().isoformat(), - } + if not tender.contact_notifications_disabled: + email_template.send_transactional_email( + recipient_email=recipient_email, + recipient_name=recipient_name, + variables=variables, + recipient_content_object=tender.author, + parent_content_object=tender, ) - tender.save(update_fields=["logs"]) def send_tender_author_reject_message(tender: Tender): @@ -589,28 +577,30 @@ def send_tender_author_reject_message(tender: Tender): Send an email to the author of a Tender notifying them that their submission is rejected. """ recipient_list = whitelist_recipient_list([tender.author.email]) - if len(recipient_list): - recipient_email = recipient_list[0] - recipient_name = tender.author.full_name + if not recipient_list: + return - variables = { - "TENDER_ID": tender.id, - "TENDER_TITLE": tender.title, - "TENDER_CREATED_AT": tender.created_at.strftime("%d %B %Y"), - "TENDER_AUTHOR_ID": tender.author.id, - "TENDER_AUTHOR_FIRST_NAME": tender.author.first_name, - } + recipient_email = tender.author.email + recipient_name = tender.author.full_name + + variables = { + "TENDER_ID": tender.id, + "TENDER_TITLE": tender.title, + "TENDER_CREATED_AT": tender.created_at.strftime("%d %B %Y"), + "TENDER_AUTHOR_ID": tender.author.id, + "TENDER_AUTHOR_FIRST_NAME": tender.author.first_name, + } - email_template = TemplateTransactional.objects.get(code="TENDERS_AUTHOR_REJECT_MESSAGE") + email_template = TemplateTransactional.objects.get(code="TENDERS_AUTHOR_REJECT_MESSAGE") - if not tender.contact_notifications_disabled: - email_template.send_transactional_email( - recipient_email=recipient_email, - recipient_name=recipient_name, - variables=variables, - recipient_content_object=tender.author, - parent_content_object=tender, - ) + if not tender.contact_notifications_disabled: + email_template.send_transactional_email( + recipient_email=recipient_email, + recipient_name=recipient_name, + variables=variables, + recipient_content_object=tender.author, + parent_content_object=tender, + ) def send_tenders_siaes_survey(tender: Tender, kind="transactioned_question_7d"): diff --git a/lemarche/www/tenders/tests.py b/lemarche/www/tenders/tests.py index 344e6344c..44bd5545c 100644 --- a/lemarche/www/tenders/tests.py +++ b/lemarche/www/tenders/tests.py @@ -297,22 +297,13 @@ def test_create_contact_call_has_user_buyer_attributes(self, mock_create_contact attributes["TYPE_VERTICALE_ACHETEUR"], "Expected TYPE_VERTICALE_ACHETEUR to be None for non-TALLY sources" ) - def test_add_log_entry_method(self): - """Test 'add_log_entry' method to check tender logs""" + def test_send_tender_author_modification_request(self): + """Test the tender updae url in 'send_tender_author_modification_request' function""" tender, _ = self.setup_mock_user_and_tender_creation(user=self.user_buyer) - tender.add_log_entry("PUBLISHED") - tender.save() - - self.assertEqual(tender.status, tender_constants.STATUS_PUBLISHED) - self.assertEqual(len(tender.logs), 1) - - tender.status = tender_constants.STATUS_DRAFT - tender.save() - tender.status = tender_constants.STATUS_PUBLISHED - tender.add_log_entry("PUBLISHED") - tender.save() + tender_update_url = reverse("tenders:update", kwargs={"slug": tender.slug}) + expected_url = f"/besoins/modifier/{tender.slug}" - self.assertEqual(len(tender.logs), 2) + self.assertEqual(tender_update_url, expected_url) def test_reset_modification_request(self): """Test 'reset_modification_request' method to check tender fields updates""" @@ -322,7 +313,6 @@ def test_reset_modification_request(self): self.assertEqual(tender.status, tender_constants.STATUS_PUBLISHED) self.assertEqual(tender.email_sent_for_modification, False) - self.assertEqual(tender.changes_information, "") class TenderListViewTest(TestCase): diff --git a/lemarche/www/tenders/views.py b/lemarche/www/tenders/views.py index 05e5d73da..1ed106ce1 100644 --- a/lemarche/www/tenders/views.py +++ b/lemarche/www/tenders/views.py @@ -216,7 +216,6 @@ def save_instance_tender(self, tender_dict: dict, form_dict: dict, is_draft: boo setattr(self.instance, attribute, tender_dict.get(attribute)) # Check before adding logs or resetting modification request if tender_status == tender_constants.STATUS_PUBLISHED: - self.instance.add_log_entry("PUBLISHED") self.instance.reset_modification_request() self.instance.save() else: