From 987db15d1c893d7ecb1dc7fcdb04586d009896b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 14:54:47 +0200 Subject: [PATCH 01/12] =?UTF-8?q?Test=20:=20l'attribut=20'send=5Fto=5Fcomm?= =?UTF-8?q?ercial=5Fpartners=5Fonly'=20doit=20=C3=AAtre=20=C3=A0=20False?= =?UTF-8?q?=20par=20d=C3=A9faut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/tests/test_models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lemarche/tenders/tests/test_models.py b/lemarche/tenders/tests/test_models.py index 73b62511b..eb0f9f1eb 100644 --- a/lemarche/tenders/tests/test_models.py +++ b/lemarche/tenders/tests/test_models.py @@ -1092,6 +1092,7 @@ def test_edit_form_no_matching_on_validate_submission(self): tender_response = response.context_data["adminform"].form.instance self.assertEqual(tender_response.id, self.tender.id) self.assertContains(response, "Validé le ") + self.assertFalse(tender_response.send_to_commercial_partners_only) self.assertTrue(hasattr(tender_response, "siae_count_annotated")) self.assertEqual(tender_response.siae_count_annotated, 1) self.assertEqual(tender_response.siae_count_annotated, self.tender.tendersiae_set.count()) From 4154b8a4d05ae705577ac6936d90076bf19b7455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 14:55:34 +0200 Subject: [PATCH 02/12] Ajout de l'attribut 'send_to_commercial_partners_only' au model Tender --- ...2_tender_send_to_commercial_partners_only.py | 17 +++++++++++++++++ lemarche/tenders/models.py | 3 +++ 2 files changed, 20 insertions(+) create mode 100644 lemarche/tenders/migrations/0092_tender_send_to_commercial_partners_only.py diff --git a/lemarche/tenders/migrations/0092_tender_send_to_commercial_partners_only.py b/lemarche/tenders/migrations/0092_tender_send_to_commercial_partners_only.py new file mode 100644 index 000000000..66803fccc --- /dev/null +++ b/lemarche/tenders/migrations/0092_tender_send_to_commercial_partners_only.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.15 on 2024-09-27 12:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("tenders", "0091_tender_is_followed_by_us_tender_is_reserved_tender_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="tender", + name="send_to_commercial_partners_only", + field=models.BooleanField(default=False, verbose_name="Envoyer uniquement aux partenaires externes"), + ), + ] diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py index 3960b74f3..65de80ee1 100644 --- a/lemarche/tenders/models.py +++ b/lemarche/tenders/models.py @@ -632,6 +632,9 @@ class Tender(models.Model): ) # could become foreign key # Admin specific for tenders is_reserved_tender = models.BooleanField("Appel d'offre reservé", null=True) + send_to_commercial_partners_only = models.BooleanField( + "Envoyer uniquement aux partenaires externes", default=False + ) # partner data partner_approch_id = models.IntegerField("Partenaire APProch : ID", blank=True, null=True) From 33532e8a53576ad667d628ba754eae4780b3962d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 16:10:19 +0200 Subject: [PATCH 03/12] =?UTF-8?q?Test=20:=20-=20Assurer=20que=20'send=5Fto?= =?UTF-8?q?=5Fcommercial=5Fpartners=5Fonly'=20est=20True=20lors=20de=20l'e?= =?UTF-8?q?nvoi=20aux=20partenaires=20-=20D=C3=A9placer=20les=20tests=20d'?= =?UTF-8?q?envoi=20aux=20partenaires=20dans=20une=20m=C3=A9thode=20distinc?= =?UTF-8?q?te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/tests/test_models.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lemarche/tenders/tests/test_models.py b/lemarche/tenders/tests/test_models.py index eb0f9f1eb..4da7ee59f 100644 --- a/lemarche/tenders/tests/test_models.py +++ b/lemarche/tenders/tests/test_models.py @@ -1097,6 +1097,24 @@ def test_edit_form_no_matching_on_validate_submission(self): self.assertEqual(tender_response.siae_count_annotated, 1) self.assertEqual(tender_response.siae_count_annotated, self.tender.tendersiae_set.count()) + def test_edit_form_validate_submission_to_commercial_partners(self): + 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", + "_validate_send_to_commercial_partners": "Valider (sauvegarder) et envoyer aux partenaires.", + }, + follow=True, + ) + tender_response = response.context_data["adminform"].form.instance + self.assertEqual(tender_response.id, self.tender.id) + self.assertContains(response, "Validé le ") + self.assertTrue(tender_response.send_to_commercial_partners_only) + class TenderUtilsTest(TestCase): @classmethod From 9f7ab8b675133b2a432ef823170263d9b3285128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 16:19:05 +0200 Subject: [PATCH 04/12] =?UTF-8?q?Met=20l'attribut=20'send=5Fto=5Fcommercia?= =?UTF-8?q?l=5Fpartners=5Fonly'=20=C3=A0=20True=20lors=20de=20l'envoi=20au?= =?UTF-8?q?x=20partenaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/admin.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py index c5c06b594..940e52aec 100644 --- a/lemarche/tenders/admin.py +++ b/lemarche/tenders/admin.py @@ -792,6 +792,17 @@ def response_change(self, request, obj: Tender): self.message_user(request, "Ce dépôt de besoin a été synchronisé avec Brevo") self.message_user(request, "Ce dépôt de besoin a été validé. Il sera envoyé en temps voulu :)") return HttpResponseRedirect(".") + if request.POST.get("_validate_send_to_commercial_partners"): + obj.set_validated() + obj.send_to_commercial_partners_only = True + if obj.amount_int > settings.BREVO_TENDERS_MIN_AMOUNT_TO_SEND: + api_brevo.create_deal(tender=obj, owner_email=request.user.email) + # we link deal(tender) with author contact + api_brevo.link_deal_with_contact_list(tender=obj) + self.message_user(request, "Ce dépôt de besoin a été synchronisé avec Brevo") + self.message_user(request, "Ce dépôt de besoin a été validé. Il sera envoyé en temps voulu :)") + obj.save() + return HttpResponseRedirect(".") elif request.POST.get("_restart_tender"): restart_send_tender_task(tender=obj) self.message_user(request, "Ce dépôt de besoin a été renvoyé aux structures") From 34af7ac64dbd095a8de31f91fe404bdd14a47b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 16:19:32 +0200 Subject: [PATCH 05/12] Ajout du bouton 'Valider et envoyer aux partenaires' --- lemarche/templates/tenders/admin_change_form.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lemarche/templates/tenders/admin_change_form.html b/lemarche/templates/tenders/admin_change_form.html index a9e8a778e..a3affd811 100644 --- a/lemarche/templates/tenders/admin_change_form.html +++ b/lemarche/templates/tenders/admin_change_form.html @@ -57,6 +57,8 @@ {% else %}

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

+ + {% endif %} {% endif %} From dc15ed99fdf00df2201bee9e5a81b1cb47e37d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 17:08:38 +0200 Subject: [PATCH 06/12] =?UTF-8?q?Test=20:=20le=20besoin=20n'est=20pas=20en?= =?UTF-8?q?voy=C3=A9=20aux=20structures=20si=20'send=5Fto=5Fcommercial=5Fp?= =?UTF-8?q?artners=5Fonly=20est=20True?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/tests/test_models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lemarche/tenders/tests/test_models.py b/lemarche/tenders/tests/test_models.py index 4da7ee59f..247ed3555 100644 --- a/lemarche/tenders/tests/test_models.py +++ b/lemarche/tenders/tests/test_models.py @@ -341,6 +341,7 @@ def test_validated_sent_batch(self): validated_at=None, first_sent_at=None, last_sent_at=None, + send_to_commercial_partners_only=False, ) TenderFactory( siaes=[siae], @@ -349,6 +350,7 @@ def test_validated_sent_batch(self): validated_at=timezone.now(), first_sent_at=None, last_sent_at=None, + send_to_commercial_partners_only=False, ) TenderFactory( siaes=[siae], @@ -357,6 +359,7 @@ def test_validated_sent_batch(self): validated_at=timezone.now(), first_sent_at=timezone.now(), last_sent_at=timezone.now(), + send_to_commercial_partners_only=False, ) TenderFactory( siaes=[siae], @@ -365,7 +368,9 @@ def test_validated_sent_batch(self): validated_at=one_hour_ago, first_sent_at=one_hour_ago, last_sent_at=one_hour_ago, + send_to_commercial_partners_only=False, ) + # This tender would be sent if send_to_commercial_partners_only was False TenderFactory( siaes=[siae], version=1, @@ -373,8 +378,9 @@ def test_validated_sent_batch(self): validated_at=two_days_ago, first_sent_at=two_days_ago, last_sent_at=two_days_ago, + send_to_commercial_partners_only=True, ) - self.assertEqual(Tender.objects.validated_sent_batch().count(), 1) + self.assertEqual(Tender.objects.validated_sent_batch().count(), 0) def test_is_not_outdated(self): TenderFactory(deadline_date=None) From 8d666756b4f8389d605422ce53997e6d55a690f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Fri, 27 Sep 2024 17:10:13 +0200 Subject: [PATCH 07/12] =?UTF-8?q?Ajout=20du=20filtre=20'send=5Fto=5Fcommer?= =?UTF-8?q?cial=5Fpartners=5Fonly'=20dans=20la=20m=C3=A9thode=20'validated?= =?UTF-8?q?=5Fsent=5Fbatch'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py index 65de80ee1..89a563494 100644 --- a/lemarche/tenders/models.py +++ b/lemarche/tenders/models.py @@ -87,6 +87,7 @@ def validated_sent_batch(self): & Q(siae_detail_contact_click_count_annotated__lte=F("limit_nb_siae_interested")) & ~Q(siae_count_annotated=F("siae_email_send_count_annotated")) & Q(last_sent_at__lt=yesterday) + & Q(send_to_commercial_partners_only=False) ) ) From fd6cdee2681583601492dfab147b60675fdda710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Mon, 30 Sep 2024 22:14:46 +0200 Subject: [PATCH 08/12] =?UTF-8?q?Renomme=20le=20champ=20du=20formulaire=20?= =?UTF-8?q?d'envoi=20aux=20structures=20pour=20am=C3=A9liorer=20la=20clart?= =?UTF-8?q?=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lemarche/tenders/tests/test_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemarche/tenders/tests/test_models.py b/lemarche/tenders/tests/test_models.py index 247ed3555..97ee5d791 100644 --- a/lemarche/tenders/tests/test_models.py +++ b/lemarche/tenders/tests/test_models.py @@ -1091,7 +1091,7 @@ def test_edit_form_no_matching_on_validate_submission(self): self.form_data | { "title": "New title", - "_validate_tender": "Valider (sauvegarder) et envoyer aux structures", + "_validate_send_to_siaes": "Valider (sauvegarder) et envoyer aux structures", }, follow=True, ) From 4d6a3a6c74f4751378ad13d0050fa72d5876109f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Mon, 30 Sep 2024 22:17:30 +0200 Subject: [PATCH 09/12] Ajout de la classe Media dans TenderAdmin pour du js custom --- lemarche/tenders/admin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py index 940e52aec..81790de5e 100644 --- a/lemarche/tenders/admin.py +++ b/lemarche/tenders/admin.py @@ -526,6 +526,9 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): change_form_template = "tenders/admin_change_form.html" + class Media: + js = ["/static/js/admin_tender_confirmation.js"] + def get_queryset(self, request): qs = super().get_queryset(request) qs = qs.select_related("author") @@ -783,7 +786,7 @@ def response_change(self, request, obj: Tender): obj.set_siae_found_list() self.message_user(request, "Les structures concernées ont été mises à jour.") return HttpResponseRedirect("./#structures") # redirect to structures sections - if request.POST.get("_validate_tender"): + if request.POST.get("_validate_send_to_siaes"): obj.set_validated() if obj.amount_int > settings.BREVO_TENDERS_MIN_AMOUNT_TO_SEND: api_brevo.create_deal(tender=obj, owner_email=request.user.email) From 1553afea8072ae2e5c799a06163fe69bd11d11c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Mon, 30 Sep 2024 22:18:34 +0200 Subject: [PATCH 10/12] Ajout de la modale de confirmation et retrait des attributs 'name' des boutons --- .../templates/tenders/admin_change_form.html | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lemarche/templates/tenders/admin_change_form.html b/lemarche/templates/tenders/admin_change_form.html index a3affd811..0823e794c 100644 --- a/lemarche/templates/tenders/admin_change_form.html +++ b/lemarche/templates/tenders/admin_change_form.html @@ -56,10 +56,21 @@ {% endif %} {% else %}

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

- - - + + {% endif %} {% endif %} + + + {% endblock %} From 6680db096e8bfc25ee1f278a525db0851b51fd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Mon, 30 Sep 2024 22:20:49 +0200 Subject: [PATCH 11/12] Modale de confirmation pour l'envoi des besoins --- .../static/js/admin_tender_confirmation.js | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 lemarche/static/js/admin_tender_confirmation.js diff --git a/lemarche/static/js/admin_tender_confirmation.js b/lemarche/static/js/admin_tender_confirmation.js new file mode 100644 index 000000000..b12f5c673 --- /dev/null +++ b/lemarche/static/js/admin_tender_confirmation.js @@ -0,0 +1,55 @@ +document.addEventListener('DOMContentLoaded', function () { + const modal = document.getElementById('tender-send-confirmation-modal'); + const confirmBtn = document.getElementById('submit-button'); + const cancelBtn = document.getElementById('cancel-button'); + + function openModal(recipient, title) { + const messageElement = document.getElementById('tender-send-message'); + + // Set an attribute 'name' depending on the recipient + if (recipient === 'siaes') { + messageElement.textContent = "Le besoin « " + title + " » sera envoyé aux structures."; + confirmBtn.setAttribute('name', '_validate_send_to_siaes'); + } else if (recipient === 'partners') { + messageElement.textContent = "Le besoin « " + title + " » sera envoyé aux partenaires."; + confirmBtn.setAttribute('name', '_validate_send_to_commercial_partners'); + } + modal.style.display = 'block'; + } + + // data-recipent attribute determines the recipient of the tender + const buttons = document.querySelectorAll('input[data-recipient]'); + buttons.forEach(function(button) { + button.addEventListener('click', function(e) { + e.preventDefault(); // Prevent instant form submission + const recipient = button.getAttribute('data-recipient'); + const title = button.getAttribute('data-title'); + openModal(recipient, title); + }); + }); + + function closeModal() { + modal.style.display = 'none'; + } + + // Two different ways to close the modal: + // click on the cancel button + cancelBtn.addEventListener('click', function(e) { + e.preventDefault(); // Prevent page from scrolling up + closeModal(); + }); + + // click outside the modal + window.addEventListener('click', function (e) { + if (e.target === modal) { + closeModal(); + } + }); + + // Action confirmation + confirmBtn.addEventListener('click', function () { + if (formToSubmit) { + formToSubmit.submit(); + } + }); +}); From 193200f68bff5d61b553a99167db046ee79040cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9?= Date: Mon, 30 Sep 2024 22:21:22 +0200 Subject: [PATCH 12/12] Ajout de CSS custom pour la modale de confirmation --- lemarche/static/itou_marche/admin.css | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lemarche/static/itou_marche/admin.css b/lemarche/static/itou_marche/admin.css index 93d06ba66..488e2255d 100644 --- a/lemarche/static/itou_marche/admin.css +++ b/lemarche/static/itou_marche/admin.css @@ -23,3 +23,48 @@ div.custom-checkbox-select-multiple > div > label { width: 100%; /* 160px default ; to avoid line breaks */ } + +/* Modal style for tender change admin */ +.tender-send-modal-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1000; +} + +.tender-send-modal-content { + position: absolute; + top: 45%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #212121; + margin: auto; + max-width: 500px; + width: 90%; + padding: 20px; + border-radius: 4px; +} + +#submit-tender { + margin-bottom: 0; +} + +#submit-button.submit-button { + background-color: #ba2121; +} + +#submit-button.submit-button:hover { + background-color: #a41515; +} + +#cancel-button { + margin-left: auto; + padding: 10px 15px; +} + +#cancel-button:hover { + padding: 10px 15px; +}