-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat: Ajout d'attributs dans Brevo pour les structures #1513
Merged
Merged
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
175bdbf
Ajout de siae.extra_data dans le dictionnaire d'attributs
chloend 050b86b
Ajout d'un filtre 'since_days' dans la méthode 'with_tender_stats'
chloend 27044f0
Mise à jour de siae.extra_data lors de la synchronisation
chloend c97c8ce
Tests de la commande 'crm_brevo_sync_companies'
chloend ae5db36
Amélioration de la mise à jour de siae.extra_data
chloend 0d9af3a
Fix update siae.extra_data
chloend File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
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) | ||
recent_date = now - timedelta(days=10) | ||
|
||
|
||
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_1 = TenderFactory(deadline_date=date_tomorrow) | ||
cls.tender_2 = TenderFactory(deadline_date=date_tomorrow) | ||
|
||
TenderSiae.objects.create( | ||
tender=cls.tender_1, | ||
siae=cls.siae_with_user, | ||
detail_contact_click_date=recent_date, | ||
) | ||
|
||
TenderSiae.objects.create( | ||
tender=cls.tender_1, | ||
siae=cls.siae_with_brevo_id, | ||
email_send_date=recent_date, | ||
detail_contact_click_date=old_date, | ||
) | ||
|
||
cls.siae_with_user_stats = Siae.objects.with_tender_stats().filter(id=cls.siae_with_user.id).first() | ||
cls.siae_with_brevo_id_all_stats = ( | ||
Siae.objects.with_tender_stats().filter(id=cls.siae_with_brevo_id.id).first() | ||
) | ||
cls.siae_with_brevo_id_recent_stats = ( | ||
Siae.objects.with_tender_stats(since_days=90).filter(id=cls.siae_with_brevo_id.id).first() | ||
) | ||
|
||
# siae_with_brevo_id.extra_data initialization | ||
cls.siae_with_brevo_id.extra_data = { | ||
"brevo_company_data": { | ||
"completion_rate": cls.siae_with_brevo_id.completion_rate | ||
if cls.siae_with_brevo_id.completion_rate is not None | ||
else 0, | ||
"tender_received": cls.siae_with_brevo_id_recent_stats.tender_email_send_count_annotated, | ||
"tender_interest": cls.siae_with_brevo_id_recent_stats.tender_detail_contact_click_count_annotated, | ||
} | ||
} | ||
cls.siae_with_brevo_id.save() | ||
cls.initial_extra_data = cls.siae_with_brevo_id.extra_data.copy() | ||
|
||
def test_annotated_fields_set_up(self): | ||
"""Test annotated fields are correctly set up""" | ||
self.assertEqual( | ||
self.siae_with_user_stats.tender_email_send_count_annotated, | ||
0, | ||
"Le nombre total de besoins reçus devrait être 0", | ||
) | ||
self.assertEqual( | ||
self.siae_with_user_stats.tender_detail_contact_click_count_annotated, | ||
1, | ||
"Le nombre total de besoins intéressés devrait être 1", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_all_stats.tender_email_send_count_annotated, | ||
1, | ||
"Le nombre total de besoins reçus devrait être 1", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_all_stats.tender_detail_contact_click_count_annotated, | ||
1, | ||
"Le nombre total de besoins intéressés devrait être 1", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_recent_stats.tender_email_send_count_annotated, | ||
1, | ||
"Le nombre de besoins reçus dans les 90 derniers jours devrait être 1", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_recent_stats.tender_detail_contact_click_count_annotated, | ||
0, | ||
"Le nombre de besoins intéressés dans les 90 derniers jours 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): | ||
self.assertIsNotNone( | ||
self.siae_with_user_stats, | ||
"Cette SIAE devrait avoir des statistiques sur les besoins.", | ||
) | ||
self.assertIsNotNone( | ||
self.siae_with_brevo_id_all_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. | ||
- Test siae.extra_data update does not erase existing data. | ||
""" | ||
initial_extra_data = self.siae_with_user.extra_data.copy() | ||
initial_extra_data["test_data"] = "test value" | ||
|
||
self.siae_with_user.extra_data = initial_extra_data | ||
self.siae_with_user.save(update_fields=["extra_data"]) | ||
|
||
call_command("crm_brevo_sync_companies", recently_updated=True) | ||
|
||
self.siae_with_user.refresh_from_db() | ||
|
||
expected_extra_data = { | ||
"brevo_company_data": { | ||
"completion_rate": self.siae_with_user.completion_rate | ||
if self.siae_with_user.completion_rate is not None | ||
else 0, | ||
"tender_received": self.siae_with_user_stats.tender_email_send_count_annotated, | ||
"tender_interest": self.siae_with_user_stats.tender_detail_contact_click_count_annotated, | ||
}, | ||
"test_data": "test value", | ||
} | ||
|
||
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.""" | ||
call_command("crm_brevo_sync_companies", recently_updated=True) | ||
|
||
self.siae_with_brevo_id.refresh_from_db() | ||
self.assertEqual( | ||
self.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.""" | ||
TenderSiae.objects.create( | ||
tender=self.tender_2, | ||
siae=self.siae_with_brevo_id, | ||
email_send_date=now, | ||
detail_contact_click_date=now, | ||
) | ||
|
||
call_command("crm_brevo_sync_companies", recently_updated=True) | ||
|
||
self.siae_with_brevo_id_all_stats = ( | ||
Siae.objects.with_tender_stats().filter(id=self.siae_with_brevo_id.id).first() | ||
) | ||
self.siae_with_brevo_id_recent_stats = ( | ||
Siae.objects.with_tender_stats(since_days=90).filter(id=self.siae_with_brevo_id.id).first() | ||
) | ||
|
||
# Tender stats without date limit | ||
self.assertEqual( | ||
self.siae_with_brevo_id_all_stats.tender_email_send_count_annotated, | ||
2, | ||
"Le nombre total des besoins reçus devrait être 2", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_all_stats.tender_detail_contact_click_count_annotated, | ||
2, | ||
"Le nombre de bsoins interessés devrait être 2", | ||
) | ||
|
||
# Tender stats with date limit | ||
self.assertEqual( | ||
self.siae_with_brevo_id_recent_stats.tender_email_send_count_annotated, | ||
2, | ||
"Le nombre de besoins reçus dans les 90 jours devraient être 2", | ||
) | ||
self.assertEqual( | ||
self.siae_with_brevo_id_recent_stats.tender_detail_contact_click_count_annotated, | ||
1, | ||
"Les nombre de bsoins interessés dans les 90 jours devraient être 1", | ||
) | ||
|
||
expected_extra_data = { | ||
"brevo_company_data": { | ||
"completion_rate": self.siae_with_brevo_id.completion_rate | ||
if self.siae_with_brevo_id.completion_rate is not None | ||
else 0, | ||
"tender_received": self.siae_with_brevo_id_recent_stats.tender_email_send_count_annotated, | ||
"tender_interest": self.siae_with_brevo_id_recent_stats.tender_detail_contact_click_count_annotated, | ||
} | ||
} | ||
|
||
self.assertNotEqual( | ||
self.initial_extra_data, | ||
expected_extra_data, | ||
"Les valeurs récentes dans extra_data devraient être mises à jour en fonction du filtre de 90 jours.", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from datetime import timedelta | ||
from uuid import uuid4 | ||
|
||
from django.conf import settings | ||
|
@@ -78,6 +79,24 @@ def get_city_filter(perimeter, with_country=False): | |
return filters | ||
|
||
|
||
def count_field(field_name, date_limit): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Jolie |
||
""" | ||
Helper method to construct a conditional count annotation. | ||
""" | ||
condition = ( | ||
Q(**{f"tendersiae__{field_name}__gte": date_limit}) | ||
if date_limit | ||
else Q(**{f"tendersiae__{field_name}__isnull": False}) | ||
) | ||
return Sum( | ||
Case( | ||
When(condition, then=1), | ||
default=0, | ||
output_field=IntegerField(), | ||
) | ||
) | ||
|
||
|
||
class SiaeGroupQuerySet(models.QuerySet): | ||
def with_siae_stats(self): | ||
return self.annotate(siae_count_annotated=Count("siaes", distinct=True)) | ||
|
@@ -425,41 +444,20 @@ def filter_with_tender_tendersiae_status(self, tender, tendersiae_status=None): | |
|
||
return qs.distinct() | ||
|
||
def with_tender_stats(self): | ||
def with_tender_stats(self, since_days=None): | ||
""" | ||
Enrich each Siae with stats on their linked Tender | ||
Enrich each Siae with stats on their linked Tender. | ||
Optionally, limit the stats to the last `since_days` days. | ||
""" | ||
date_limit = timezone.now() - timedelta(days=since_days) if since_days else None | ||
|
||
return self.annotate( | ||
tender_count_annotated=Count("tenders", distinct=True), | ||
tender_email_send_count_annotated=Sum( | ||
Case(When(tendersiae__email_send_date__isnull=False, then=1), default=0, output_field=IntegerField()) | ||
), | ||
tender_email_link_click_count_annotated=Sum( | ||
Case( | ||
When(tendersiae__email_link_click_date__isnull=False, then=1), | ||
default=0, | ||
output_field=IntegerField(), | ||
) | ||
), | ||
tender_detail_display_count_annotated=Sum( | ||
Case( | ||
When(tendersiae__detail_display_date__isnull=False, then=1), default=0, output_field=IntegerField() | ||
) | ||
), | ||
tender_detail_contact_click_count_annotated=Sum( | ||
Case( | ||
When(tendersiae__detail_contact_click_date__isnull=False, then=1), | ||
default=0, | ||
output_field=IntegerField(), | ||
) | ||
), | ||
tender_detail_not_interested_count_annotated=Sum( | ||
Case( | ||
When(tendersiae__detail_not_interested_click_date__isnull=False, then=1), | ||
default=0, | ||
output_field=IntegerField(), | ||
) | ||
), | ||
tender_email_send_count_annotated=count_field("email_send_date", date_limit), | ||
tender_email_link_click_count_annotated=count_field("email_link_click_date", date_limit), | ||
tender_detail_display_count_annotated=count_field("detail_display_date", date_limit), | ||
tender_detail_contact_click_count_annotated=count_field("detail_contact_click_date", date_limit), | ||
tender_detail_not_interested_count_annotated=count_field("detail_not_interested_click_date", date_limit), | ||
) | ||
|
||
def with_brand_or_name(self, with_order_by=False): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.