Skip to content

Commit

Permalink
feat(brevo): small changes after review
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasAbrn committed Feb 13, 2025
1 parent 4ad29c8 commit 87d087b
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 151 deletions.
1 change: 1 addition & 0 deletions lemarche/api/tenders/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
}


@patch("lemarche.utils.apis.api_brevo.create_deal")
class TenderCreateApiTest(TestCase):
@classmethod
def setUpTestData(cls):
Expand Down
4 changes: 2 additions & 2 deletions lemarche/companies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@ def save(self, *args, **kwargs):
@receiver(post_save, sender=Company)
def create_company_in_brevo(sender, instance, created, **kwargs):
if created:
from lemarche.utils.apis.api_brevo import create_company
from lemarche.utils.apis.api_brevo import create_brevo_company_from_company

create_company(instance)
create_brevo_company_from_company(instance)
6 changes: 5 additions & 1 deletion lemarche/companies/tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.test import TestCase
from unittest.mock import patch

from lemarche.companies.factories import CompanyFactory
from lemarche.companies.models import Company
Expand All @@ -20,7 +21,10 @@ def test_str(self):

class CompanyQuerysetTest(TestCase):
@classmethod
def setUpTestData(cls):
@patch("lemarche.utils.apis.api_brevo.create_deal")
def setUpTestData(cls, mock_create_deal):
mock_create_deal.return_value = None

cls.user_1 = UserFactory()
cls.user_2 = UserFactory()
TenderFactory(author=cls.user_1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def handle(self, recently_updated: bool, **options):

# Step 2: loop on the siaes
for index, siae in enumerate(siaes_qs):
api_brevo.create_company(siae)
api_brevo.create_brevo_company_from_siae(siae)
if (index % 10) == 0: # avoid API rate-limiting
time.sleep(1)
if (index % 500) == 0:
Expand Down
61 changes: 20 additions & 41 deletions lemarche/crm/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@


@override_settings(BITOUBI_ENV="production", BREVO_API_KEY="fake-key")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.Configuration")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.ApiClient")
class CrmBrevoSyncCompaniesCommandTest(TestCase):
@classmethod
def setUpTestData(cls):
Expand Down Expand Up @@ -55,66 +58,39 @@ def setUpTestData(cls):
Siae.objects.with_tender_stats(since_days=90).filter(id=cls.siae_with_brevo_id.id).first()
)

@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.Configuration")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.ApiClient")
def test_new_siaes_are_synced_in_brevo(self, mock_api_client, mock_configuration, mock_companies_api):
"""Test new siaes are synced in brevo"""
mock_config = MagicMock()
mock_configuration.return_value = mock_config

mock_client = MagicMock()
mock_api_client.return_value = mock_client

mock_api = MagicMock()
mock_companies_api.return_value = mock_api
mock_configuration.return_value = MagicMock()
mock_api_client.return_value = MagicMock()
mock_companies_api.return_value = MagicMock()

mock_response = MagicMock()
mock_response.id = 12345
mock_api.companies_post.return_value = mock_response

mock_companies_api.companies_post.return_value = mock_response

expected_count = Siae.objects.filter(brevo_company_id__isnull=True).count()

# Run the command
call_command("crm_brevo_sync_companies")

actual_count = mock_api.companies_post.call_count
actual_count = mock_companies_api.companies_post.call_count

self.assertEqual(actual_count, expected_count, f"Expected {expected_count} API calls, got {actual_count}")

@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.Configuration")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.ApiClient")
def test_siae_has_tender_stats(self, mock_api_client, mock_configuration, mock_companies_api):
# Setup mock API chain similar to above
mock_config = MagicMock()
mock_configuration.return_value = mock_config
mock_client = MagicMock()
mock_api_client.return_value = mock_client
mock_api = MagicMock()
mock_companies_api.return_value = mock_api
mock_response = MagicMock()
mock_response.id = 12345
mock_api.companies_post.return_value = mock_response
mock_configuration.return_value = MagicMock()
mock_api_client.return_value = MagicMock()
mock_companies_api.return_value = MagicMock()

self.assertIsNotNone(self.siae_with_user_stats)
self.assertIsNotNone(self.siae_with_brevo_id_all_stats)

@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.Configuration")
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.ApiClient")
def test_siae_extra_data_is_preserved(self, mock_api_client, mock_configuration, mock_companies_api):
"""Test that creating a company in Brevo preserves existing extra_data"""
# Setup mock API chain
mock_config = MagicMock()
mock_configuration.return_value = mock_config
mock_client = MagicMock()
mock_api_client.return_value = mock_client
mock_api = MagicMock()
mock_companies_api.return_value = mock_api
mock_response = MagicMock()
mock_response.id = 12345
mock_api.companies_post.return_value = mock_response
mock_configuration.return_value = MagicMock()
mock_api_client.return_value = MagicMock()
mock_companies_api.return_value = MagicMock()

# Set initial extra_data and ensure other Siaes have brevo_company_id
initial_extra_data = {"test_data": "test value"}
Expand All @@ -123,13 +99,16 @@ def test_siae_extra_data_is_preserved(self, mock_api_client, mock_configuration,
self.siae_with_name.brevo_company_id = "999999"
self.siae_with_name.save()

mock_api.companies_post.reset_mock()
mock_companies_api.return_value = MagicMock()
mock_response = MagicMock()
mock_response.id = 12345
mock_companies_api.companies_post.return_value = mock_response

call_command("crm_brevo_sync_companies", recently_updated=True)

self.siae_with_user.refresh_from_db()

mock_api.companies_post.assert_called_once()
mock_companies_api.companies_post.assert_called_once()

self.assertEqual(self.siae_with_user.brevo_company_id, "12345")

Expand Down
4 changes: 2 additions & 2 deletions lemarche/siaes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,9 +1283,9 @@ def siae_post_save(sender, instance, created, **kwargs):

# Handle Brevo company creation
if created:
from lemarche.utils.apis.api_brevo import create_company
from lemarche.utils.apis.api_brevo import create_brevo_company_from_siae

create_company(instance)
create_brevo_company_from_siae(instance)


@receiver(m2m_changed, sender=Siae.users.through)
Expand Down
54 changes: 13 additions & 41 deletions lemarche/siaes/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,48 +681,20 @@ def test_last_activity_is_updated_at(self):


class SiaeSignalTest(TestCase):
@patch("lemarche.utils.apis.api_brevo.create_company")
def test_create_siae_in_brevo_signal(self, mock_create_company):
"""Test that creating a new SIAE triggers the Brevo sync"""
# Mock the environment check to always return True
with patch("lemarche.utils.apis.api_brevo.settings.BITOUBI_ENV", "production"):
# Create a new SIAE
siae = SiaeFactory()

# Verify create_company was called once with the SIAE instance
mock_create_company.assert_called_once_with(siae)
@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
def test_siae_creation_with_brevo_integration(self, mock_companies_api):
mock_response = MagicMock()
mock_response.id = 12345
mock_companies_api_instance = mock_companies_api.return_value
mock_companies_api_instance.companies_post.return_value = mock_response

# Create another SIAE
siae2 = SiaeFactory()
self.assertEqual(mock_create_company.call_count, 2)
mock_create_company.assert_called_with(siae2)
siae = SiaeFactory(name="Test SIAE", website="https://example.com")

# Update existing SIAE
siae.name = "Updated Name"
siae.save()
self.assertTrue(mock_companies_api_instance.companies_post.called)
args, kwargs = mock_companies_api_instance.companies_post.call_args
body_obj = args[0]

# Call count should still be 2 since we only sync on creation
self.assertEqual(mock_create_company.call_count, 2)
self.assertEqual(body_obj.name, "Test SIAE")
self.assertEqual(body_obj.attributes, {"domain": "https://example.com", "app_id": siae.id, "siae": True})

@patch("lemarche.utils.apis.api_brevo.sib_api_v3_sdk.CompaniesApi")
def test_siae_attributes_sent_to_brevo(self, mock_companies_api):
"""Test the attributes sent to Brevo when creating a SIAE"""
# Mock the environment check to always return True
with patch("lemarche.utils.apis.api_brevo.settings.BITOUBI_ENV", "production"):
# Setup the mock response
mock_response = MagicMock()
mock_response.id = 12345
mock_instance = mock_companies_api.return_value
mock_instance.companies_post.return_value = mock_response

# Create a SIAE
siae = SiaeFactory(name="Test SIAE", website="https://example.com")

# Get the Body instance that was passed to companies_post
args, kwargs = mock_instance.companies_post.call_args
body_obj = args[0]

self.assertEqual(body_obj.name, "Test SIAE")
self.assertEqual(body_obj.attributes, {"domain": "https://example.com", "app_id": siae.id, "siae": True})

self.assertEqual(siae.brevo_company_id, 12345)
self.assertEqual(siae.brevo_company_id, 12345)
6 changes: 1 addition & 5 deletions lemarche/tenders/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1289,8 +1289,4 @@ def tender_post_save(sender, instance, created, **kwargs):
if created:
from lemarche.utils.apis.api_brevo import create_deal

try:
create_deal(tender=instance)
except Exception as e:
# Log the error but don't prevent tender creation
logger.error(f"Error creating Brevo deal for tender {instance.id}: {e}")
create_deal(tender=instance)
49 changes: 23 additions & 26 deletions lemarche/tenders/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1184,36 +1184,33 @@ def test_set_validated_handles_brevo_error(self, mock_create_deal):
self.assertEqual(tender.logs[0]["action"], "validate")


@patch("lemarche.utils.apis.api_brevo.create_deal")
def test_set_validated_only_works_on_draft(self, mock_create_deal):
"""Test that set_validated only works on draft tenders"""
tender = TenderFactory(status=tender_constants.STATUS_VALIDATED)

tender.set_validated()
class BrevoTestCase(TestCase):
@patch("lemarche.utils.apis.api_brevo.create_deal")
def test_create_deal_on_tender_creation(self, mock_create_deal):
"""Test that creating a new tender creates a Brevo deal"""
tender = TenderFactory()

# Verify no API call was made
mock_create_deal.assert_not_called()
# Verify create_deal was called once with the tender instance
mock_create_deal.assert_called_once_with(tender=tender)

# Verify no changes were made
self.assertEqual(tender.status, tender_constants.STATUS_VALIDATED)
# Create another tender
tender2 = TenderFactory()
self.assertEqual(mock_create_deal.call_count, 2)
mock_create_deal.assert_called_with(tender=tender2)

# Update existing tender
tender.title = "Updated Title"
tender.save()

@patch("lemarche.utils.apis.api_brevo.create_deal")
def test_create_deal_on_tender_creation(self, mock_create_deal):
"""Test that creating a new tender creates a Brevo deal"""
tender = TenderFactory()

# Verify create_deal was called once with the tender instance
mock_create_deal.assert_called_once_with(tender=tender)
# Call count should still be 2 since we only sync on creation
self.assertEqual(mock_create_deal.call_count, 2)

# Create another tender
tender2 = TenderFactory()
self.assertEqual(mock_create_deal.call_count, 2)
mock_create_deal.assert_called_with(tender=tender2)
@patch("lemarche.utils.apis.api_brevo.create_deal")
def test_set_validated_only_works_on_draft(self, mock_create_deal):
"""Test that set_validated only works on draft tenders"""
tender = TenderFactory(status=tender_constants.STATUS_VALIDATED)

# Update existing tender
tender.title = "Updated Title"
tender.save()
tender.set_validated()

# Call count should still be 2 since we only sync on creation
self.assertEqual(mock_create_deal.call_count, 2)
# Verify no changes were made
self.assertEqual(tender.status, tender_constants.STATUS_VALIDATED)
24 changes: 14 additions & 10 deletions lemarche/users/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,70 +57,74 @@ def test_kind_detail_display(self):
)


@patch("lemarche.utils.apis.api_brevo.create_deal")
@patch("lemarche.utils.apis.api_brevo.create_contact")
@patch("lemarche.utils.apis.api_brevo.create_company")
@patch("lemarche.utils.apis.api_brevo.send_transactional_email_with_template")
class UserModelQuerysetTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = UserFactory()

def test_is_admin_bizdev(self):
def test_is_admin_bizdev(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
UserFactory(kind=user_constants.KIND_ADMIN, is_staff=True)
UserFactory(kind=user_constants.KIND_ADMIN, is_staff=True, position="BizDev")
UserFactory(kind=user_constants.KIND_ADMIN, is_staff=True, position="Bizdev")
self.assertEqual(User.objects.count(), 1 + 3)
self.assertEqual(User.objects.is_admin_bizdev().count(), 2)

def test_has_company(self):
def test_has_company(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
CompanyFactory(users=[user_2])
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.has_company().count(), 1)

def test_has_siae(self):
def test_has_siae(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
SiaeFactory(users=[user_2])
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.has_siae().count(), 1)

def test_has_tender(self):
def test_has_tender(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
TenderFactory(author=user_2)
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.has_tender().count(), 1)

def test_has_favorite_list(self):
def test_has_favorite_list(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
FavoriteListFactory(user=user_2)
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.has_favorite_list().count(), 1)

def test_has_api_key(self):
def test_has_api_key(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
UserFactory(api_key="coucou")
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.has_api_key().count(), 1)

def test_has_email_domain(self):
def test_has_email_domain(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
UserFactory(email="[email protected]")
UserFactory(email="[email protected]")
self.assertEqual(User.objects.count(), 1 + 2)
for EMAIL_DOMAIN in ["ain.fr", "@ain.fr"]:
with self.subTest(email_domain=EMAIL_DOMAIN):
self.assertEqual(User.objects.has_email_domain(email_domain=EMAIL_DOMAIN).count(), 1)

def test_with_siae_stats(self):
def test_with_siae_stats(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
SiaeFactory(users=[user_2])
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.with_siae_stats().filter(id=self.user.id).first().siae_count_annotated, 0)
self.assertEqual(User.objects.with_siae_stats().filter(id=user_2.id).first().siae_count_annotated, 1)

def test_with_tender_stats(self):
def test_with_tender_stats(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory()
TenderFactory(author=user_2)
self.assertEqual(User.objects.count(), 1 + 1)
self.assertEqual(User.objects.with_tender_stats().filter(id=self.user.id).first().tender_count_annotated, 0)
self.assertEqual(User.objects.with_tender_stats().filter(id=user_2.id).first().tender_count_annotated, 1)

def test_chain_querysets(self):
def test_chain_querysets(self, mock_send_email, mock_create_company, mock_create_contact, mock_create_deal):
user_2 = UserFactory(api_key="chain")
siae = SiaeFactory()
siae.users.add(user_2)
Expand Down
Loading

0 comments on commit 87d087b

Please sign in to comment.