Skip to content

Commit

Permalink
Siae & Tender: update annotated count
Browse files Browse the repository at this point in the history
  • Loading branch information
raphodn committed Oct 25, 2023
1 parent da6939e commit 16f42f6
Show file tree
Hide file tree
Showing 21 changed files with 263 additions and 246 deletions.
16 changes: 4 additions & 12 deletions lemarche/favorites/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,9 @@ def test_with_siae_stats(self):
self.assertEqual(favorite_list_queryset.get(id=favorite_list.id).siae_count_annotated, 0)
self.assertEqual(favorite_list_queryset.get(id=favorite_list_with_siaes.id).siae_count_annotated, 2)

def test_siae_annotate_with_user_favorite_list_count(self):
def test_siae_with_in_user_favorite_list_stats(self):
FavoriteListFactory(user=self.user, siaes=[self.siae_1])
FavoriteListFactory(user=self.user, siaes=[self.siae_1])
siae_queryset = Siae.objects.annotate_with_user_favorite_list_count(self.user)
self.assertEqual(siae_queryset.get(id=self.siae_1.id).in_user_favorite_list_count, 2)
self.assertEqual(siae_queryset.get(id=self.siae_2.id).in_user_favorite_list_count, 0)

def test_siae_annotate_with_user_favorite_list_ids(self):
favorite_list_1 = FavoriteListFactory(user=self.user, siaes=[self.siae_1])
FavoriteListFactory(user=self.user, siaes=[self.siae_1])
siae_queryset = Siae.objects.annotate_with_user_favorite_list_ids(self.user)
self.assertEqual(len(siae_queryset.get(id=self.siae_1.id).in_user_favorite_list_ids), 2)
self.assertEqual(len(siae_queryset.get(id=self.siae_2.id).in_user_favorite_list_ids), 0)
self.assertEqual(siae_queryset.get(id=self.siae_1.id).in_user_favorite_list_ids[0], favorite_list_1.id)
siae_queryset = Siae.objects.with_in_user_favorite_list_stats(self.user)
self.assertEqual(siae_queryset.get(id=self.siae_1.id).in_user_favorite_list_count_annotated, 2)
self.assertEqual(siae_queryset.get(id=self.siae_2.id).in_user_favorite_list_count_annotated, 0)
68 changes: 35 additions & 33 deletions lemarche/siaes/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin):
"label_count_with_link",
"client_reference_count_with_link",
"image_count_with_link",
"tender_email_send_count_with_link",
"tender_detail_display_count_with_link",
"tender_detail_contact_click_count_with_link",
"tender_email_send_count_annotated_with_link",
"tender_detail_display_count_annotated_with_link",
"tender_detail_contact_click_count_annotated_with_link",
"created_at",
]
list_filter = [
Expand Down Expand Up @@ -175,11 +175,11 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin):
"coords_display",
"logo_url",
"logo_url_display",
"tender_count_with_link",
"tender_email_send_count_with_link",
"tender_email_link_click_count_with_link",
"tender_detail_display_count_with_link",
"tender_detail_contact_click_count_with_link",
"tender_count_annotated_with_link",
"tender_email_send_count_annotated_with_link",
"tender_email_link_click_count_annotated_with_link",
"tender_detail_display_count_annotated_with_link",
"tender_detail_contact_click_count_annotated_with_link",
"logs_display",
# "import_raw_object",
"import_raw_object_display",
Expand Down Expand Up @@ -295,11 +295,11 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin):
"Besoins des acheteurs",
{
"fields": (
"tender_count_with_link",
"tender_email_send_count_with_link",
"tender_email_link_click_count_with_link",
"tender_detail_display_count_with_link",
"tender_detail_contact_click_count_with_link",
"tender_count_annotated_with_link",
"tender_email_send_count_annotated_with_link",
"tender_email_link_click_count_annotated_with_link",
"tender_detail_display_count_annotated_with_link",
"tender_detail_contact_click_count_annotated_with_link",
)
},
),
Expand Down Expand Up @@ -531,52 +531,54 @@ def import_raw_object_display(self, instance: Siae = None):

import_raw_object_display.short_description = Siae._meta.get_field("import_raw_object").verbose_name

def tender_count_with_link(self, siae):
def tender_count_annotated_with_link(self, siae):
url = reverse("admin:tenders_tender_changelist") + f"?siaes__in={siae.id}"
return format_html(f'<a href="{url}">{getattr(siae, "tender_count", 0)}</a>')
return format_html(f'<a href="{url}">{getattr(siae, "tender_count_annotated", 0)}</a>')

tender_count_with_link.short_description = "Besoins concernés"
tender_count_with_link.admin_order_field = "tender_count"
tender_count_annotated_with_link.short_description = "Besoins concernés"
tender_count_annotated_with_link.admin_order_field = "tender_count_annotated"

def tender_email_send_count_with_link(self, siae):
def tender_email_send_count_annotated_with_link(self, siae):
url = (
reverse("admin:tenders_tender_changelist")
+ f"?siaes__in={siae.id}&tendersiae__email_send_date__isnull=False"
)
return format_html(f'<a href="{url}">{getattr(siae, "tender_email_send_count", 0)}</a>')
return format_html(f'<a href="{url}">{getattr(siae, "tender_email_send_count_annotated", 0)}</a>')

tender_email_send_count_with_link.short_description = "Besoins reçus"
tender_email_send_count_with_link.admin_order_field = "tender_email_send_count"
tender_email_send_count_annotated_with_link.short_description = "Besoins reçus"
tender_email_send_count_annotated_with_link.admin_order_field = "tender_email_send_count_annotated"

def tender_email_link_click_count_with_link(self, siae):
def tender_email_link_click_count_annotated_with_link(self, siae):
url = (
reverse("admin:tenders_tender_changelist")
+ f"?siaes__in={siae.id}&tendersiae__email_link_click_date__isnull=False"
)
return format_html(f'<a href="{url}">{getattr(siae, "tender_email_link_click_count", 0)}</a>')
return format_html(f'<a href="{url}">{getattr(siae, "tender_email_link_click_count_annotated", 0)}</a>')

tender_email_link_click_count_with_link.short_description = "Besoins cliqués"
tender_email_link_click_count_with_link.admin_order_field = "tender_email_link_click_count"
tender_email_link_click_count_annotated_with_link.short_description = "Besoins cliqués"
tender_email_link_click_count_annotated_with_link.admin_order_field = "tender_email_link_click_count_annotated"

def tender_detail_display_count_with_link(self, siae):
def tender_detail_display_count_annotated_with_link(self, siae):
url = (
reverse("admin:tenders_tender_changelist")
+ f"?siaes__in={siae.id}&tendersiae__detail_display_date__isnull=False"
)
return format_html(f'<a href="{url}">{getattr(siae, "tender_detail_display_count", 0)}</a>')
return format_html(f'<a href="{url}">{getattr(siae, "tender_detail_display_count_annotated", 0)}</a>')

tender_detail_display_count_with_link.short_description = "Besoins vues"
tender_detail_display_count_with_link.admin_order_field = "tender_detail_display_count"
tender_detail_display_count_annotated_with_link.short_description = "Besoins vues"
tender_detail_display_count_annotated_with_link.admin_order_field = "tender_detail_display_count_annotated"

def tender_detail_contact_click_count_with_link(self, siae):
def tender_detail_contact_click_count_annotated_with_link(self, siae):
url = (
reverse("admin:tenders_tender_changelist")
+ f"?siaes__in={siae.id}&tendersiae__detail_contact_click_date__isnull=False"
)
return format_html(f'<a href="{url}">{getattr(siae, "tender_detail_contact_click_count", 0)}</a>')
return format_html(f'<a href="{url}">{getattr(siae, "tender_detail_contact_click_count_annotated", 0)}</a>')

tender_detail_contact_click_count_with_link.short_description = "Besoins intéressés"
tender_detail_contact_click_count_with_link.admin_order_field = "tender_detail_contact_click_count"
tender_detail_contact_click_count_annotated_with_link.short_description = "Besoins intéressés"
tender_detail_contact_click_count_annotated_with_link.admin_order_field = (
"tender_detail_contact_click_count_annotated"
)

def logs_display(self, siae=None):
if siae:
Expand Down
9 changes: 8 additions & 1 deletion lemarche/siaes/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from factory.django import DjangoModelFactory

from lemarche.siaes import constants as siae_constants
from lemarche.siaes.models import Siae, SiaeClientReference, SiaeGroup, SiaeLabelOld, SiaeOffer
from lemarche.siaes.models import Siae, SiaeClientReference, SiaeGroup, SiaeImage, SiaeLabelOld, SiaeOffer


class SiaeGroupFactory(DjangoModelFactory):
Expand Down Expand Up @@ -75,3 +75,10 @@ class Meta:
model = SiaeLabelOld

name = factory.Faker("name", locale="fr_FR")


class SiaeImageFactory(DjangoModelFactory):
class Meta:
model = SiaeImage

name = factory.Faker("name", locale="fr_FR")
50 changes: 20 additions & 30 deletions lemarche/siaes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django.contrib.gis.db import models as gis_models
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.measure import D
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.search import TrigramSimilarity # SearchVector
from django.db import IntegrityError, models, transaction
from django.db.models import BooleanField, Case, CharField, Count, F, IntegerField, PositiveIntegerField, Q, Sum, When
Expand Down Expand Up @@ -312,20 +311,12 @@ def with_country_geo_range(self):
def exclude_country_geo_range(self):
return self.exclude(Q(geo_range=siae_constants.GEO_RANGE_COUNTRY))

def annotate_with_user_favorite_list_count(self, user):
def with_in_user_favorite_list_stats(self, user):
"""
Enrich each Siae with the number of occurences in the user's favorite lists
"""
return self.prefetch_related("favorite_lists").annotate(
in_user_favorite_list_count=Count("favorite_lists", filter=Q(favorite_lists__user=user))
)

def annotate_with_user_favorite_list_ids(self, user):
"""
Enrich each Siae with the list of occurences in the user's favorite lists
"""
return self.prefetch_related("favorite_lists").annotate(
in_user_favorite_list_ids=ArrayAgg("favorite_lists__pk", filter=Q(favorite_lists__user=user))
in_user_favorite_list_count_annotated=Count("favorite_lists", filter=Q(favorite_lists__user=user))
)

def has_contact_email(self):
Expand Down Expand Up @@ -371,23 +362,23 @@ def with_tender_stats(self):
Enrich each Siae with stats on their linked Tender
"""
return self.annotate(
tender_count=Count("tenders", distinct=True),
tender_email_send_count=Sum(
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=Sum(
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=Sum(
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=Sum(
tender_detail_contact_click_count_annotated=Sum(
Case(
When(tendersiae__detail_contact_click_date__isnull=False, then=1),
default=0,
Expand All @@ -396,16 +387,16 @@ def with_tender_stats(self):
),
)

def annotate_with_brand_or_name(self, with_order_by=False):
def with_brand_or_name(self, with_order_by=False):
"""
We usually want to display the brand by default
See Siae.name_display()
"""
qs = self.annotate(
brand_or_name=Case(When(brand="", then=F("name")), default=F("brand"), output_field=CharField())
brand_or_name_annotated=Case(When(brand="", then=F("name")), default=F("brand"), output_field=CharField())
)
if with_order_by:
qs = qs.order_by("brand_or_name")
qs = qs.order_by("brand_or_name_annotated")
return qs

def with_content_filled_stats(self):
Expand All @@ -417,12 +408,12 @@ def with_content_filled_stats(self):
- Level 4 (full): user_count + sector_count + description + logo + client_reference_count + image_count + label_count # noqa
"""
return self.annotate(
content_filled_basic=Case(
content_filled_basic_annotated=Case(
When(Q(user_count__gte=1) & Q(sector_count__gte=1) & ~Q(description=""), then=True),
default=False,
output_field=BooleanField(),
),
content_filled_full=Case(
content_filled_full_annotated=Case(
When(
Q(user_count__gte=1)
& Q(sector_count__gte=1)
Expand All @@ -441,24 +432,23 @@ def with_content_filled_stats(self):
def content_not_filled(self):
return self.filter(Q(sector_count=0) | Q(contact_email=""))

def with_employees_count(self):
def with_employees_stats(self):
"""
Enrich each Siae with count of employees
Annotate first to use the field "c2_etp_count" if employees_insertion_count is null
Next, the sum of an integer and a null value is null, so we check if fields are not null before make sum
"""
return self.annotate(
employees_insertion_count_with_c2_etp=Case(
employees_insertion_count_with_c2_etp_annotated=Case(
When(employees_insertion_count=None, then=Round(F("c2_etp_count"))),
default=F("employees_insertion_count"),
output_field=PositiveIntegerField(),
)
).annotate(
employees_count=Case(
When(employees_insertion_count_with_c2_etp=None, then=F("employees_permanent_count")),
When(employees_permanent_count=None, then=F("employees_insertion_count_with_c2_etp")),
default=F("employees_insertion_count_with_c2_etp") + F("employees_permanent_count"),
)
),
employees_count_annotated=Case(
When(employees_insertion_count_with_c2_etp_annotated=None, then=F("employees_permanent_count")),
When(employees_permanent_count=None, then=F("employees_insertion_count_with_c2_etp_annotated")),
default=F("employees_insertion_count_with_c2_etp_annotated") + F("employees_permanent_count"),
),
)


Expand Down
Loading

0 comments on commit 16f42f6

Please sign in to comment.