Skip to content

Commit

Permalink
feat: Ajout d'un attribut pour filtrer l'envoi des besoins d'achat (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
chloend authored Oct 7, 2024
1 parent ba0b379 commit d074709
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 4 deletions.
45 changes: 45 additions & 0 deletions lemarche/static/itou_marche/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
55 changes: 55 additions & 0 deletions lemarche/static/js/admin_tender_confirmation.js
Original file line number Diff line number Diff line change
@@ -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') {
const message = `Le besoin « ${title} » sera envoyé uniquement aux partenaires commerciaux.`;
messageElement.textContent = message;
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.dataset.recipient;
const title = button.dataset.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();
}
});
});
15 changes: 14 additions & 1 deletion lemarche/templates/tenders/admin_change_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,21 @@
{% endif %}
{% else %}
<p><i>L'envoi des besoins 'validés' se fait toutes les 5 minutes, du Lundi au Vendredi, entre 9h et 17h</i></p>
<input type="submit" name="_validate_tender" value="Valider (sauvegarder) et envoyer aux structures 🚀" />
<input type="submit" value="Valider (sauvegarder) et envoyer aux structures 🚀" data-recipient="siaes" data-title="{{ original.title }}" style="margin-right: 5px"/>
<input type="submit" value="Valider (sauvegarder) et envoyer aux partenaires 🚀" data-recipient="partners" data-title="{{ original.title }}"/>
{% endif %}
</div>
{% endif %}

<!-- Modale de confirmation pour l'envoi d'un besoin d'achat -->
<div id="tender-send-confirmation-modal" class="tender-send-modal-container" style="display:none">
<div id="tender-send-modal-content" class="tender-send-modal-content">
<h1>Êtes-vous sûr ?</h1>
<p id="tender-send-message"></p>
<div id="submit-tender" class="submit-row">
<input type="submit" id="submit-button" class="submit-button" value="Confirmer"/>
<a id="cancel-button" class="button" href="#">Annuler</a>
</div>
</div>
</div>
{% endblock %}
15 changes: 14 additions & 1 deletion lemarche/tenders/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -783,7 +786,17 @@ 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)
# 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 :)")
return HttpResponseRedirect(".")
if request.POST.get("_validate_send_to_commercial_partners"):
obj.send_to_commercial_partners_only = True
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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"),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.15 on 2024-10-03 16:05

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("tenders", "0092_tender_send_to_commercial_partners_only"),
]

operations = [
migrations.AlterField(
model_name="tender",
name="send_to_commercial_partners_only",
field=models.BooleanField(default=False, verbose_name="Envoyer uniquement aux partenaires commerciaux"),
),
]
4 changes: 4 additions & 0 deletions lemarche/tenders/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
)

Expand Down Expand Up @@ -632,6 +633,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 commerciaux", default=False
)

# partner data
partner_approch_id = models.IntegerField("Partenaire APProch : ID", blank=True, null=True)
Expand Down
29 changes: 27 additions & 2 deletions lemarche/tenders/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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],
Expand All @@ -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],
Expand All @@ -365,16 +368,19 @@ 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,
status=tender_constants.STATUS_SENT,
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)
Expand Down Expand Up @@ -1085,17 +1091,36 @@ 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,
)
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())

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
Expand Down

0 comments on commit d074709

Please sign in to comment.