Skip to content

Commit

Permalink
refactor(Price tags): fix stats. move constants. cleanup (#653)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphodn authored Dec 23, 2024
1 parent 4643706 commit 08d148f
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 44 deletions.
24 changes: 16 additions & 8 deletions open_prices/api/proofs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from django.urls import reverse
from PIL import Image

from open_prices.common.constants import PriceTagStatus
from open_prices.locations import constants as location_constants
from open_prices.locations.factories import LocationFactory
from open_prices.prices.factories import PriceFactory
Expand Down Expand Up @@ -406,11 +405,11 @@ def setUpTestData(cls):
cls.price_tag_1 = PriceTagFactory(
proof=cls.proof,
price=cls.price,
status=PriceTagStatus.linked_to_price.value,
status=proof_constants.PriceTagStatus.linked_to_price.value,
)
cls.price_tag_2 = PriceTagFactory(proof=cls.proof)
cls.price_tag_3 = PriceTagFactory(
proof=cls.proof_2, status=PriceTagStatus.deleted
proof=cls.proof_2, status=proof_constants.PriceTagStatus.deleted
)

def test_price_tag_list(self):
Expand Down Expand Up @@ -556,7 +555,10 @@ def test_price_tag_create_with_price(self):
self.assertEqual(response.data["created_by"], self.user_session.user.user_id)
self.assertEqual(response.data["updated_by"], self.user_session.user.user_id)
self.assertEqual(response.data["price_id"], self.price.id)
self.assertEqual(response.data["status"], PriceTagStatus.linked_to_price.value)
self.assertEqual(
response.data["status"],
proof_constants.PriceTagStatus.linked_to_price.value,
)


class PriceTagUpdateApiTest(TestCase):
Expand Down Expand Up @@ -616,7 +618,10 @@ def test_price_tag_set_price_id(self):
# Price ID was set to the new value
self.assertEqual(response.data["price_id"], self.price.id)
# Status was automatically set to linked_to_price
self.assertEqual(response.data["status"], PriceTagStatus.linked_to_price.value)
self.assertEqual(
response.data["status"],
proof_constants.PriceTagStatus.linked_to_price.value,
)

def test_price_tag_set_invalid_price_id(self):
self.assertEqual(self.price_tag.price_id, None)
Expand All @@ -638,11 +643,13 @@ def test_price_tag_set_status(self):
self.url,
content_type="application/json",
# Price associated with another proof
data={"status": PriceTagStatus.not_readable.value},
data={"status": proof_constants.PriceTagStatus.not_readable.value},
headers={"Authorization": f"Bearer {self.user_session.token}"},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["status"], PriceTagStatus.not_readable.value)
self.assertEqual(
response.data["status"], proof_constants.PriceTagStatus.not_readable.value
)

def test_price_tag_invalid_status(self):
self.assertEqual(self.price_tag.status, None)
Expand Down Expand Up @@ -721,5 +728,6 @@ def test_price_tag_delete(self):
self.assertEqual(response.data, None)
self.assertEqual(PriceTag.objects.filter(id=self.price_tag.id).count(), 1)
self.assertEqual(
PriceTag.objects.get(id=self.price_tag.id).status, PriceTagStatus.deleted
PriceTag.objects.get(id=self.price_tag.id).status,
proof_constants.PriceTagStatus.deleted,
)
4 changes: 2 additions & 2 deletions open_prices/api/proofs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
)
from open_prices.api.utils import get_source_from_request
from open_prices.common.authentication import CustomAuthentication
from open_prices.common.constants import PriceTagStatus
from open_prices.proofs import constants as proof_constants
from open_prices.proofs.ml import extract_from_price_tag
from open_prices.proofs.models import PriceTag, Proof
from open_prices.proofs.utils import store_file
Expand Down Expand Up @@ -175,7 +175,7 @@ def destroy(self, request: Request, *args, **kwargs) -> Response:
{"detail": "Cannot delete price tag with associated prices."},
status=status.HTTP_403_FORBIDDEN,
)
price_tag.status = PriceTagStatus.deleted
price_tag.status = proof_constants.PriceTagStatus.deleted
price_tag.save()
return Response(status=status.HTTP_204_NO_CONTENT)

Expand Down
12 changes: 0 additions & 12 deletions open_prices/common/constants.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
import enum

from babel.numbers import list_currencies

CURRENCY_LIST = sorted(list_currencies())
CURRENCY_CHOICES = [(key, key) for key in CURRENCY_LIST]


class PriceTagStatus(enum.IntEnum):
deleted = 0
linked_to_price = 1
not_readable = 2
not_price_tag = 3


PRICE_TAG_STATUS_CHOICES = [(item.value, item.name) for item in PriceTagStatus]
12 changes: 12 additions & 0 deletions open_prices/proofs/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import enum

TYPE_PRICE_TAG = "PRICE_TAG"
TYPE_RECEIPT = "RECEIPT"
TYPE_GDPR_REQUEST = "GDPR_REQUEST"
Expand Down Expand Up @@ -31,3 +33,13 @@
PRICE_TAG_PREDICTION_TYPE_CHOICES = [
(PRICE_TAG_EXTRACTION_TYPE, PRICE_TAG_EXTRACTION_TYPE)
]


class PriceTagStatus(enum.IntEnum):
deleted = 0
linked_to_price = 1
not_readable = 2
not_price_tag = 3


PRICE_TAG_STATUS_CHOICES = [(item.value, item.name) for item in PriceTagStatus]
16 changes: 13 additions & 3 deletions open_prices/proofs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,14 @@ def proof_post_save_run_ml_models(sender, instance, created, **kwargs):
)


class PriceTagQuerySet(models.QuerySet):
def status_unknown(self):
return self.filter(status=None)

def status_linked_to_price(self):
return self.filter(status=proof_constants.PriceTagStatus.linked_to_price.value)


class PriceTag(models.Model):
"""A single price tag in a proof."""

Expand All @@ -429,7 +437,7 @@ class PriceTag(models.Model):
help_text="Coordinates of the bounding box, in the format [y_min, x_min, y_max, x_max]",
)
status = models.IntegerField(
choices=constants.PRICE_TAG_STATUS_CHOICES,
choices=proof_constants.PRICE_TAG_STATUS_CHOICES,
null=True,
blank=True,
help_text="The annotation status",
Expand Down Expand Up @@ -463,6 +471,8 @@ class PriceTag(models.Model):
auto_now=True, help_text="When the tag was last updated"
)

objects = models.Manager.from_queryset(PriceTagQuerySet)()

class Meta:
db_table = "price_tags"
verbose_name = "Price Tag"
Expand Down Expand Up @@ -523,8 +533,8 @@ def clean(self, *args, **kwargs):
)

if self.status is None:
self.status = constants.PriceTagStatus.linked_to_price.value
elif self.status != constants.PriceTagStatus.linked_to_price.value:
self.status = proof_constants.PriceTagStatus.linked_to_price.value
elif self.status != proof_constants.PriceTagStatus.linked_to_price.value:
utils.add_validation_error(
validation_errors,
"status",
Expand Down
2 changes: 1 addition & 1 deletion open_prices/proofs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ def test_select_proof_image_dir_existing_dir_create_new_dir(self):
self.assertEqual(selected_dir, images_dir / "0002")


class TestPriceTagCreation(TestCase):
class PriceTagCreationTest(TestCase):
def test_create_price_tag_invalid_bounding_box_length(self):
with self.assertRaises(ValidationError) as cm:
PriceTagFactory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ class Migration(migrations.Migration):
),
migrations.AddField(
model_name="totalstats",
name="price_tag_linked_to_price_count",
name="price_tag_status_linked_to_price_count",
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name="totalstats",
name="price_tag_unknown_count",
name="price_tag_status_unknown_count",
field=models.PositiveIntegerField(default=0),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.1.4 on 2024-12-23 10:49

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("stats", "0004_totalstats_price_tag_count_and_more"),
]

operations = [
migrations.RenameField(
model_name="totalstats",
old_name="price_tag_status_linked_to_price_count",
new_name="price_tag_status_linked_to_price_count",
),
migrations.RenameField(
model_name="totalstats",
old_name="price_tag_status_unknown_count",
new_name="price_tag_status_unknown_count",
),
]
19 changes: 9 additions & 10 deletions open_prices/stats/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from django.utils import timezone
from solo.models import SingletonModel

from open_prices.common.constants import PriceTagStatus


class TotalStats(SingletonModel):
PRICE_COUNT_FIELDS = [
Expand All @@ -28,15 +26,16 @@ class TotalStats(SingletonModel):
]
PRICE_TAG_COUNT_FIELDS = [
"price_tag_count",
"price_tag_unknown_count",
"price_tag_linked_to_price_count",
"price_tag_status_unknown_count",
"price_tag_status_linked_to_price_count",
]
USER_COUNT_FIELDS = ["user_count", "user_with_price_count"]
COUNT_FIELDS = (
PRICE_COUNT_FIELDS
+ PRODUCT_COUNT_FIELDS
+ LOCATION_COUNT_FIELDS
+ PROOF_COUNT_FIELDS
+ PRICE_TAG_COUNT_FIELDS
+ USER_COUNT_FIELDS
)

Expand All @@ -56,8 +55,8 @@ class TotalStats(SingletonModel):
proof_type_gdpr_request_count = models.PositiveIntegerField(default=0)
proof_type_shop_import_count = models.PositiveIntegerField(default=0)
price_tag_count = models.PositiveIntegerField(default=0)
price_tag_unknown_count = models.PositiveIntegerField(default=0)
price_tag_linked_to_price_count = models.PositiveIntegerField(default=0)
price_tag_status_unknown_count = models.PositiveIntegerField(default=0)
price_tag_status_linked_to_price_count = models.PositiveIntegerField(default=0)
user_count = models.PositiveIntegerField(default=0)
user_with_price_count = models.PositiveIntegerField(default=0)

Expand Down Expand Up @@ -115,10 +114,10 @@ def update_price_tag_stats(self):
from open_prices.proofs.models import PriceTag

self.price_tag_count = PriceTag.objects.count()
self.price_tag_unknown_count = PriceTag.objects.filter(status=None).count()
self.price_tag_linked_to_price_count = PriceTag.objects.filter(
status=PriceTagStatus.linked_to_price.value
).count()
self.price_tag_status_unknown_count = PriceTag.objects.status_unknown().count()
self.price_tag_status_linked_to_price_count = (
PriceTag.objects.status_linked_to_price().count()
)
self.save(update_fields=self.PRICE_TAG_COUNT_FIELDS + ["updated"])

def update_user_stats(self):
Expand Down
11 changes: 5 additions & 6 deletions open_prices/stats/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.db import IntegrityError
from django.test import TestCase

from open_prices.common.constants import PriceTagStatus
from open_prices.locations.factories import LocationFactory
from open_prices.prices import constants as price_constants
from open_prices.prices.factories import PriceFactory
Expand Down Expand Up @@ -77,7 +76,7 @@ def setUpTestData(cls):
PriceTagFactory(
proof=cls.proof_price_tag,
price=cls.price,
status=PriceTagStatus.linked_to_price.value,
status=proof_constants.PriceTagStatus.linked_to_price.value,
)

def test_update_price_stats(self):
Expand Down Expand Up @@ -124,13 +123,13 @@ def test_update_proof_stats(self):

def test_update_price_tag_stats(self):
self.assertEqual(self.total_stats.price_tag_count, 0)
self.assertEqual(self.total_stats.price_tag_unknown_count, 0)
self.assertEqual(self.total_stats.price_tag_linked_to_price_count, 0)
self.assertEqual(self.total_stats.price_tag_status_unknown_count, 0)
self.assertEqual(self.total_stats.price_tag_status_linked_to_price_count, 0)
# update_price_tag_stats() will update price_tag_counts
self.total_stats.update_price_tag_stats()
self.assertEqual(self.total_stats.price_tag_count, 2)
self.assertEqual(self.total_stats.price_tag_unknown_count, 1)
self.assertEqual(self.total_stats.price_tag_linked_to_price_count, 1)
self.assertEqual(self.total_stats.price_tag_status_unknown_count, 1)
self.assertEqual(self.total_stats.price_tag_status_linked_to_price_count, 1)

def test_update_user_stats(self):
self.assertEqual(self.total_stats.user_count, 0)
Expand Down

0 comments on commit 08d148f

Please sign in to comment.