From 16e0e59556b3fa7bd5c40de8b1b16736c93a5424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Odini?= Date: Sun, 2 Mar 2025 16:43:35 +0100 Subject: [PATCH] feat(Stats): new price_year_count field (#738) --- open_prices/prices/models.py | 5 +++-- open_prices/prices/tests.py | 6 +++++- .../0013_totalstats_price_year_count.py | 17 +++++++++++++++++ open_prices/stats/models.py | 8 ++++++++ open_prices/stats/tests.py | 5 +++++ 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 open_prices/stats/migrations/0013_totalstats_price_year_count.py diff --git a/open_prices/prices/models.py b/open_prices/prices/models.py index 4d52ece4..c37e4949 100644 --- a/open_prices/prices/models.py +++ b/open_prices/prices/models.py @@ -15,7 +15,7 @@ When, signals, ) -from django.db.models.functions import Cast +from django.db.models.functions import Cast, ExtractYear from django.dispatch import receiver from django.utils import timezone from openfoodfacts.taxonomy import ( @@ -58,6 +58,7 @@ def has_type_group_consumption(self): def with_extra_fields(self): return self.annotate( + date_year_annotated=ExtractYear("date"), source_annotated=Case( When( source__contains="Open Prices Web App", @@ -70,7 +71,7 @@ def with_extra_fields(self): When(source__contains="API", then=Value(constants.SOURCE_API)), default=Value(constants.SOURCE_OTHER), output_field=CharField(), - ) + ), ) def calculate_min(self): diff --git a/open_prices/prices/tests.py b/open_prices/prices/tests.py index 52166add..c03e59ed 100644 --- a/open_prices/prices/tests.py +++ b/open_prices/prices/tests.py @@ -24,7 +24,7 @@ class PriceQuerySetTest(TestCase): def setUpTestData(cls): PriceFactory(price=5, price_is_discounted=True, price_without_discount=10) PriceFactory(price=8, source="Open Prices Web App") - PriceFactory(price=10) + PriceFactory(price=10, date="2024-01-01") def test_has_discount(self): self.assertEqual(Price.objects.count(), 3) @@ -36,6 +36,10 @@ def test_exclude_discounted(self): def with_extra_fields(self): self.assertEqual(Price.objects.count(), 3) + self.assertEqual( + Price.objects.with_extra_fields().filter(date_year_annotated=2024).count(), + 1, + ) self.assertEqual( Price.objects.with_extra_fields() .filter(source_annotated=constants.SOURCE_WEB) diff --git a/open_prices/stats/migrations/0013_totalstats_price_year_count.py b/open_prices/stats/migrations/0013_totalstats_price_year_count.py new file mode 100644 index 00000000..2893158f --- /dev/null +++ b/open_prices/stats/migrations/0013_totalstats_price_year_count.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.4 on 2025-03-02 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("stats", "0012_totalstats_proof_count_per_source"), + ] + + operations = [ + migrations.AddField( + model_name="totalstats", + name="price_year_count", + field=models.PositiveIntegerField(default=0), + ), + ] diff --git a/open_prices/stats/models.py b/open_prices/stats/models.py index 5f84619a..d2515bb3 100644 --- a/open_prices/stats/models.py +++ b/open_prices/stats/models.py @@ -12,6 +12,7 @@ class TotalStats(SingletonModel): "price_type_category_tag_count", "price_with_discount_count", "price_currency_count", + "price_year_count", "price_type_group_community_count", "price_type_group_consumption_count", "price_source_web_count", @@ -72,6 +73,7 @@ class TotalStats(SingletonModel): price_type_category_tag_count = models.PositiveIntegerField(default=0) price_with_discount_count = models.PositiveIntegerField(default=0) price_currency_count = models.PositiveIntegerField(default=0) + price_year_count = models.PositiveIntegerField(default=0) price_type_group_community_count = models.PositiveIntegerField(default=0) price_type_group_consumption_count = models.PositiveIntegerField(default=0) price_source_web_count = models.PositiveIntegerField(default=0) @@ -135,6 +137,12 @@ def update_price_stats(self): self.price_currency_count = ( Price.objects.values_list("currency", flat=True).distinct().count() ) + self.price_year_count = ( + Price.objects.with_extra_fields() + .values_list("date_year_annotated", flat=True) + .distinct() + .count() + ) self.price_type_group_community_count = ( Price.objects.has_type_group_community().count() ) diff --git a/open_prices/stats/tests.py b/open_prices/stats/tests.py index 0abb4931..b2a3860c 100644 --- a/open_prices/stats/tests.py +++ b/open_prices/stats/tests.py @@ -47,6 +47,7 @@ def setUpTestData(cls): location_osm_id=cls.location.osm_id, location_osm_type=cls.location.osm_type, currency="EUR", + date="2024-06-30", owner=cls.user.user_id, source="Open Prices Web App", ) @@ -70,6 +71,7 @@ def setUpTestData(cls): proof_id=cls.proof_price_tag.id, price=1.0, currency=cls.proof_price_tag.currency, + date=cls.proof_price_tag.date, owner=cls.user.user_id, source="Open Prices Web App", ) @@ -92,6 +94,7 @@ def setUpTestData(cls): proof_id=cls.proof_gdpr_request.id, price=2.0, currency=cls.proof_gdpr_request.currency, + date="2025-01-01", owner=cls.user_2.user_id, source="API", ) @@ -108,6 +111,7 @@ def test_update_price_stats(self): self.assertEqual(self.total_stats.price_type_category_tag_count, 0) self.assertEqual(self.total_stats.price_with_discount_count, 0) self.assertEqual(self.total_stats.price_currency_count, 0) + self.assertEqual(self.total_stats.price_year_count, 0) self.assertEqual(self.total_stats.price_type_group_community_count, 0) self.assertEqual(self.total_stats.price_type_group_consumption_count, 0) self.assertEqual(self.total_stats.price_source_web_count, 0) @@ -121,6 +125,7 @@ def test_update_price_stats(self): self.assertEqual(self.total_stats.price_type_category_tag_count, 1) self.assertEqual(self.total_stats.price_with_discount_count, 0) self.assertEqual(self.total_stats.price_currency_count, 1) + self.assertEqual(self.total_stats.price_year_count, 3) # None included self.assertEqual(self.total_stats.price_type_group_community_count, 1) self.assertEqual(self.total_stats.price_type_group_consumption_count, 1) self.assertEqual(self.total_stats.price_source_web_count, 1)