Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Changement de conditions de synchronisation des DDB vers le crm brevo #1622

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions lemarche/tenders/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from ckeditor.widgets import CKEditorWidget
from django import forms
from django.conf import settings
from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline
from django.core.exceptions import ValidationError
Expand Down Expand Up @@ -256,6 +255,23 @@ class Meta:
model = Tender
fields = "__all__"

is_followed_by_us = forms.BooleanField(
widget=forms.CheckboxInput(),
required=False,
label=Tender._meta.get_field("is_followed_by_us").verbose_name,
)
proj_resulted_in_reserved_tender = forms.BooleanField(
widget=forms.CheckboxInput(),
required=False,
label=Tender._meta.get_field("proj_resulted_in_reserved_tender").verbose_name,
)

is_reserved_tender = forms.BooleanField(
widget=forms.CheckboxInput(),
required=False,
label=Tender._meta.get_field("is_reserved_tender").verbose_name,
)

Comment on lines +263 to +274
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ça sort un peu du cadre de la PR mais c'est un petit quick win pour faciliter la saisie pour les bizdev

def clean(self):
"""
Add validation on form rules:
Expand Down Expand Up @@ -501,8 +517,8 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
"admins",
"is_followed_by_us",
"proj_resulted_in_reserved_tender",
"proj_link_to_tender",
"is_reserved_tender",
"proj_link_to_tender",
)
},
),
Expand Down Expand Up @@ -789,7 +805,7 @@ def response_change(self, request, obj: Tender):
return HttpResponseRedirect("./#structures") # redirect to structures sections
if request.POST.get("_validate_send_to_siaes"):
obj.set_validated()
if obj.amount_int > settings.BREVO_TENDERS_MIN_AMOUNT_TO_SEND:
if obj.is_followed_by_us:
madjid-asa marked this conversation as resolved.
Show resolved Hide resolved
try:
api_brevo.create_deal(tender=obj, owner_email=request.user.email)
# we link deal(tender) with author contact
Expand Down
33 changes: 12 additions & 21 deletions lemarche/tenders/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import random
from datetime import datetime, timedelta
from uuid import uuid4

Expand Down Expand Up @@ -754,27 +753,19 @@ def save(self, *args, **kwargs):
- update the object content_fill_dates
- generate the slug field
"""
self.set_last_updated_fields()
try:
self.set_slug()
# generate random status for is_followed_by_us
if (
not self.pk
and self.kind == tender_constants.KIND_PROJECT
and self.is_followed_by_us is None
and self.amount_int > settings.BREVO_TENDERS_MIN_AMOUNT_TO_SEND
):
self.is_followed_by_us = random.random() < 0.5 # 50% True, 50% False
with transaction.atomic():
super().save(*args, **kwargs)
except IntegrityError as e:
# check that it's a slug conflict
# Full message expected: duplicate key value violates unique constraint "tenders_tender_slug_0f0b821f_uniq" DETAIL: Key (slug)=(...) already exists. # noqa
if "tenders_tender_slug" in str(e):
self.set_slug(with_uuid=True)
with transaction.atomic():
self.set_last_updated_fields()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je ne vois pas à quoi sert la transaction; s'il y a une erreur de contrainte d'intégrité, il n'y aura pas de commit du SQL ?

try:
self.set_slug()
super().save(*args, **kwargs)
else:
raise e
except IntegrityError as e:
# check that it's a slug conflict
# Full message expected: duplicate key value violates unique constraint "tenders_tender_slug_0f0b821f_uniq" DETAIL: Key (slug)=(...) already exists. # noqa
if "tenders_tender_slug" in str(e):
self.set_slug(with_uuid=True)
super().save(*args, **kwargs)
else:
raise e

@cached_property
def contact_full_name(self) -> str:
Expand Down
91 changes: 91 additions & 0 deletions lemarche/tenders/tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from unittest.mock import patch

from django.contrib.admin.sites import AdminSite
from django.contrib.messages.storage.fallback import FallbackStorage
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpResponse
from django.test import RequestFactory, TestCase

from lemarche.tenders.admin import TenderAdmin
from lemarche.tenders.factories import TenderFactory
from lemarche.tenders.models import Tender
from lemarche.users.factories import UserFactory


# Create a dummy response function for the middleware
def get_response(request):
return HttpResponse("OK")


class TenderAdminTestCase(TestCase):
def setUp(self):
# Initialize required objects for testing
self.factory = RequestFactory()
self.admin_site = AdminSite()
self.user_admin = UserFactory(is_superuser=True) # Admin user
self.admin = TenderAdmin(Tender, self.admin_site)

def setUpRequest(self, tender, is_followed_by_us):
tender.is_followed_by_us = is_followed_by_us
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est ce que c'est utile ? Si j'ai bien compris c'est déjà set par la factory, pourquoi le reset et refaire un save()?
Normalement tu pourrais définir ta request dans le setup, et l'appeler avec un self.request, pas besoin des args tender et is_followed_by_us

tender.save()
request = self.factory.post("/", data={"_validate_send_to_siaes": "1"})
Guilouf marked this conversation as resolved.
Show resolved Hide resolved
request.user = self.user_admin

# Initialize and apply SessionMiddleware
middleware = SessionMiddleware(get_response)
middleware.process_request(request)
request.session.save() # Save the session to avoid any issues
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ca marche sans, je dirais que le moins c'est le mieux ;)


# Attach a message storage system to the request
setattr(request, "_messages", FallbackStorage(request))

return request

@patch("lemarche.tenders.admin.api_brevo.create_deal") # Mock the create_deal API call
@patch("lemarche.tenders.admin.api_brevo.link_deal_with_contact_list") # Mock the link_deal API call
def test_validate_send_to_siaes_not_synch_brevo(self, mock_link_deal, mock_create_deal):
tender = TenderFactory(is_followed_by_us=False) # Tender object
request = self.setUpRequest(tender, is_followed_by_us=False)

# Call the response_change method without the validation action enabled
response = self.admin.response_change(request, tender)

# Check that the create_deal and link_deal functions were not called
mock_create_deal.assert_not_called()
mock_link_deal.assert_not_called()

# Verify the response
self.assertEqual(response.status_code, 302)
self.assertIn(".", response.url)

# Verify the flash messages
messages = request._messages._queued_messages
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ca marche, mais ce sont des attributs privés, la voie "officielle" c'est celle là j'ai l'impression https://docs.djangoproject.com/en/5.1/ref/contrib/messages/#django.contrib.messages.get_messages

self.assertEqual(len(messages), 1) # Expecting only one message
self.assertEqual(str(messages[0]), "Ce dépôt de besoin a été validé. Il sera envoyé en temps voulu :)")

@patch("lemarche.tenders.admin.api_brevo.create_deal") # Mock the create_deal API call
@patch("lemarche.tenders.admin.api_brevo.link_deal_with_contact_list") # Mock the link_deal API call
def test_validate_send_to_siaes_with_sync_brevo(self, mock_link_deal, mock_create_deal):
tender = TenderFactory(is_followed_by_us=True) # Tender object
request = self.setUpRequest(tender, is_followed_by_us=True)

# Call the response_change method
response = self.admin.response_change(request, tender)

# Verify that the tender is marked as validated
tender.refresh_from_db()
self.assertTrue(tender.is_validated)

# Check if the create_deal and link_deal API methods were called
mock_create_deal.assert_called_once_with(tender=tender, owner_email=self.user_admin.email)
mock_link_deal.assert_called_once_with(tender=tender)

# Ensure the response redirects correctly
self.assertEqual(response.status_code, 302)
self.assertIn(".", response.url)

# Verify flash messages
messages = request._messages._queued_messages
self.assertEqual(len(messages), 2) # Expecting two messages
self.assertEqual(str(messages[0]), "Ce dépôt de besoin a été synchronisé avec Brevo")
self.assertEqual(str(messages[1]), "Ce dépôt de besoin a été validé. Il sera envoyé en temps voulu :)")
Loading