diff --git a/lemarche/crm/tests.py b/lemarche/crm/tests.py new file mode 100644 index 000000000..c8db2187c --- /dev/null +++ b/lemarche/crm/tests.py @@ -0,0 +1,208 @@ +from datetime import timedelta +from unittest.mock import patch + +from django.core.management import call_command +from django.test import TestCase +from django.utils import timezone + +from lemarche.siaes.factories import SiaeFactory +from lemarche.siaes.models import Siae +from lemarche.tenders.factories import TenderFactory +from lemarche.tenders.models import TenderSiae +from lemarche.users.factories import UserFactory +from lemarche.users.models import User + + +now = timezone.now() +date_tomorrow = now + timedelta(days=1) +old_date = timezone.now() - timedelta(days=91) + + +class CrmBrevoSyncCompaniesCommandTest(TestCase): + @classmethod + def setUpTestData(cls): + """Siae instances initialization""" + cls.user_siae = UserFactory(kind=User.KIND_SIAE) + cls.siae_with_name = SiaeFactory(name="Test Company 1") + cls.siae_with_user = SiaeFactory(users=[cls.user_siae]) + cls.siae_with_brevo_id = SiaeFactory( + brevo_company_id="123456789", + completion_rate=50, + ) + + cls.tender = TenderFactory(deadline_date=date_tomorrow) + + TenderSiae.objects.create( + tender=cls.tender, + siae=cls.siae_with_user, + detail_contact_click_date=now, + ) + TenderSiae.objects.create( + tender=cls.tender, + siae=cls.siae_with_brevo_id, + email_send_date=now, + detail_contact_click_date=old_date, + ) + + def test_annotated_fields_set_up(self): + """Test annotated fields are correctly set up""" + siae_with_user_stats = Siae.objects.with_tender_stats().filter(id=self.siae_with_user.id).first() + + self.assertEqual( + siae_with_user_stats.tender_email_send_count_annotated, + 0, + "Le nombre total de besoins reçus devrait être 0", + ) + self.assertEqual( + siae_with_user_stats.tender_detail_contact_click_count_annotated, + 1, + "Le nombre total de besoins intéressés devrait être 1", + ) + + siae_with_brevo_id_stats = Siae.objects.with_tender_stats().filter(id=self.siae_with_brevo_id.id).first() + self.assertEqual( + siae_with_brevo_id_stats.tender_email_send_count_annotated, + 1, + "Le nombre total de besoins reçus devrait être 1", + ) + self.assertEqual( + siae_with_brevo_id_stats.tender_detail_contact_click_count_annotated, + 1, + "Le nombre total de besoins intéressés devrait être 1", + ) + + siae_with_brevo_id_recent_stats = ( + Siae.objects.with_tender_stats(since_days=90).filter(id=self.siae_with_brevo_id.id).first() + ) + self.assertEqual( + siae_with_brevo_id_recent_stats.tender_email_send_count_annotated, + 1, + "Le nombre total de besoins reçus devrait être 1", + ) + self.assertEqual( + siae_with_brevo_id_recent_stats.tender_detail_contact_click_count_annotated, + 0, + "Le nombre total de besoins intéressés devrait être 0", + ) + + @patch("lemarche.utils.apis.api_brevo.create_or_update_company") + def test_new_siaes_are_synced_in_brevo(self, mock_create_or_update_company): + """Test new siaes are synced in brevo""" + call_command("crm_brevo_sync_companies") + + self.assertEqual(mock_create_or_update_company.call_count, 3) + + def test_siae_has_tender_stats(self): + siae_with_user_tender_stats = Siae.objects.with_tender_stats().filter(id=self.siae_with_brevo_id.id).first() + siae_with_brevo_id_tender_stats = ( + Siae.objects.with_tender_stats().filter(id=self.siae_with_brevo_id.id).first() + ) + self.assertIsNotNone( + siae_with_user_tender_stats, + "Cette SIAE devrait avoir des statistiques sur les besoins.", + ) + self.assertIsNotNone( + siae_with_brevo_id_tender_stats, + "Cette SIAE devrait avoir des statistiques sur les besoins.", + ) + + def test_siae_extra_data_is_set_on_first_sync(self): + """Test siae is updated if extra_data is changed.""" + initial_extra_data = self.siae_with_user.extra_data.copy() + call_command("crm_brevo_sync_companies", recently_updated=True) + + siae_with_user_stats = Siae.objects.with_tender_stats(since_days=90).filter(id=self.siae_with_user.id).first() + self.siae_with_user.refresh_from_db() + + expected_extra_data = { + "TAUX DE COMPLÉTION": self.siae_with_tender.completion_rate, + "BESOINS REÇUS": siae_with_user_stats.tender_email_send_count_annotated, + "BESOINS INTERESSÉS": siae_with_user_stats.tender_detail_contact_click_count_annotated, + } + + self.assertNotEqual(initial_extra_data, expected_extra_data, "siae.extra_data aurait dû être mis à jour.") + self.assertEqual( + self.siae_with_user.extra_data, expected_extra_data, "siae.extra_data n'est pas conforme aux attentes." + ) + + def test_siae_extra_data_is_not_updated_if_no_changes(self): + """Test siae.extra_data is not updated if no changes.""" + siae_with_brevo_id_stats = ( + Siae.objects.with_tender_stats(since_days=90).filter(id=self.siae_with_brevo_id.id).first() + ) + # siae.extra_data should already be set for updates + self.siae_with_brevo_id.extra_data = { + "TAUX DE COMPLÉTION": self.siae_with_brevo_id.completion_rate, # not annotated field + "BESOINS REÇUS": siae_with_brevo_id_stats.tender_email_send_count_annotated, + "BESOINS INTERESSÉS": siae_with_brevo_id_stats.tender_detail_contact_click_count_annotated, + } + self.siae_with_brevo_id.save() + initial_extra_data = self.siae_with_brevo_id.extra_data.copy() + + call_command("crm_brevo_sync_companies", recently_updated=True) + + self.siae_with_brevo_id.refresh_from_db() + self.assertEqual( + initial_extra_data, + self.siae_with_brevo_id.extra_data, + "siae.extra_data a été mis à jour alors qu'il n'y avait pas de changement.", + ) + + def test_fields_update_within_90_days_and_ignore_older_changes(self): + """Test fields update within 90 days and ignore older changes.""" + # Update annotated fields of a TenderSiae + TenderSiae.objects.filter( + tender=self.tender, + siae=self.siae_with_brevo_id, + ).update( + email_send_date=now, + detail_contact_click_date=now, + ) + + call_command("crm_brevo_sync_companies", recently_updated=True) + + siae_with_all_stats = Siae.objects.with_tender_stats().filter(id=self.siae_with_brevo_id.id).first() + siae_with_recent_stats = ( + Siae.objects.with_tender_stats(since_days=90).filter(id=self.siae_with_brevo_id.id).first() + ) + + expected_extra_data = { + "completion_rate": self.siae_with_brevo_id.completion_rate, + "recent_tender_email_send_count": siae_with_recent_stats.tender_email_send_count_annotated, + "recent_tender_detail_click_count": siae_with_recent_stats.tender_detail_contact_click_count_annotated, + } + + self.assertEqual( + siae_with_all_stats.tender_email_send_count_annotated, 1, "Le compte total d'envois d'email devrait être 1" + ) + + self.assertEqual( + siae_with_recent_stats.tender_email_send_count_annotated, + 2, + "Le nombre de besoins reçus dans les 90 jours devraient être 2", + ) + self.assertEqual( + siae_with_all_stats.tender_detail_contact_click_count_annotated, + 2, + "Le nombre de bsoins interessés devrait être 2", + ) + + self.assertEqual( + siae_with_recent_stats.tender_detail_contact_click_count_annotated, + 1, + "Les nombre de bsoins interessés dans les 90 jours devraient être 1", + ) + + self.siae_with_brevo_id.refresh_from_db() + + expected_extra_data = { + "TAUX DE COMPLÉTION": self.siae_with_brevo_id.completion_rate, + "BESOINS REÇUS": siae_with_recent_stats.tender_email_send_count_annotated, + "BESOINS INTERESSÉS": siae_with_recent_stats.tender_detail_contact_click_count_annotated, + } + + self.assertEqual( + self.siae_with_brevo_id.extra_data, + expected_extra_data, + "Les valeurs récentes dans extra_data devraient être mises à jour en fonction du filtre de 90 jours.", + )