From 90f756c08f7112eba7ea248e75334c378e8eeaa0 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Wed, 31 Jul 2024 18:01:02 +0200 Subject: [PATCH] On Product create, fetch data from OFF. Update tests --- open_prices/api/prices/tests.py | 15 +++++++++++++++ open_prices/common/openfoodfacts.py | 22 +++++++++++----------- open_prices/common/openstreetmap.py | 16 ++++++++-------- open_prices/prices/tests.py | 7 +++++++ open_prices/products/factories.py | 2 ++ open_prices/products/models.py | 16 ++++++++++++++++ 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/open_prices/api/prices/tests.py b/open_prices/api/prices/tests.py index 5260f071..be900e86 100644 --- a/open_prices/api/prices/tests.py +++ b/open_prices/api/prices/tests.py @@ -1,8 +1,17 @@ +from django.db.models import signals from django.test import TestCase from django.urls import reverse +from open_prices.locations.models import ( + Location, + location_post_create_fetch_data_from_openstreetmap, +) from open_prices.prices.factories import PriceFactory from open_prices.prices.models import Price +from open_prices.products.models import ( + Product, + product_post_create_fetch_data_from_openfoodfacts, +) from open_prices.proofs.factories import ProofFactory from open_prices.users.factories import SessionFactory @@ -172,6 +181,12 @@ def test_price_delete(self): class PriceCreateApiTest(TestCase): @classmethod def setUpTestData(cls): + signals.post_save.disconnect( + product_post_create_fetch_data_from_openfoodfacts, sender=Product + ) + signals.post_save.disconnect( + location_post_create_fetch_data_from_openstreetmap, sender=Location + ) cls.url = reverse("api:prices-list") cls.user_session = SessionFactory() cls.user_proof = ProofFactory(owner=cls.user_session.user.user_id) diff --git a/open_prices/common/openfoodfacts.py b/open_prices/common/openfoodfacts.py index 4a51ad16..721241a5 100644 --- a/open_prices/common/openfoodfacts.py +++ b/open_prices/common/openfoodfacts.py @@ -1,6 +1,6 @@ import requests from django.conf import settings -from openfoodfacts import API, APIVersion, Country, Flavor +from openfoodfacts import API, APIVersion, Country, Environment, Flavor from openfoodfacts.images import generate_image_url from openfoodfacts.types import JSONType @@ -8,10 +8,10 @@ "product_name", "product_quantity", "product_quantity_unit", - "categories_tags", + # "categories_tags", "brands", - "brands_tags", - "labels_tags", + # "brands_tags", + # "labels_tags", "image_url", "nutriscore_grade", "ecoscore_grade", @@ -74,13 +74,13 @@ def generate_main_image_url( image_rev = images[image_key]["rev"] image_id = f"{image_key}.{image_rev}.400" return generate_image_url( - code, image_id=image_id, flavor=flavor, environment=settings.environment + code, image_id=image_id, flavor=flavor, environment=Environment.org ) return None -def get_product(product_code: str, flavor: Flavor = Flavor.off) -> JSONType | None: +def get_product(code: str, flavor: Flavor = Flavor.off) -> JSONType | None: client = API( user_agent=settings.OFF_USER_AGENT, username=None, @@ -88,20 +88,20 @@ def get_product(product_code: str, flavor: Flavor = Flavor.off) -> JSONType | No country=Country.world, flavor=flavor, version=APIVersion.v2, - environment=settings.environment, + environment=Environment.org, ) - return client.product.get(product_code) + return client.product.get(code) def get_product_dict(product, flavor=Flavor.off) -> JSONType | None: product_dict = dict() try: response = get_product(code=product.code, flavor=flavor) - if response and response["status"]: + if response: product_dict["source"] = flavor for off_field in OFF_FIELDS: - if off_field in response["product"]: - product_dict[off_field] = response["product"][off_field] + if off_field in response: + product_dict[off_field] = response[off_field] product_dict = normalize_product_fields(product_dict) return product_dict except Exception: diff --git a/open_prices/common/openstreetmap.py b/open_prices/common/openstreetmap.py index 6c77d695..334ba1e4 100644 --- a/open_prices/common/openstreetmap.py +++ b/open_prices/common/openstreetmap.py @@ -18,7 +18,7 @@ def get_location(osm_id: int, osm_type: str) -> list: def get_location_dict(location): - location_openstreetmap_details = dict() + location_dict = dict() try: response = get_location( osm_id=location.osm_id, osm_type=location.osm_type.lower() @@ -28,12 +28,12 @@ def get_location_dict(location): if osm_field in response[0]: key = f"osm_{osm_field}" value = response[0][osm_field] - location_openstreetmap_details[key] = value + location_dict[key] = value for osm_field in list(OSM_TAG_FIELDS_MAPPING.keys()): if osm_field in response[0]: key = f"osm_{OSM_TAG_FIELDS_MAPPING[osm_field]}" value = response[0][osm_field] - location_openstreetmap_details[key] = value + location_dict[key] = value if "address" in response[0]: for osm_address_field in OSM_ADDRESS_FIELDS: if osm_address_field in response[0]["address"]: @@ -41,17 +41,17 @@ def get_location_dict(location): value = response[0]["address"][osm_address_field] if osm_address_field == "country_code": # "fr" -> "FR" value = value.upper() - location_openstreetmap_details[key] = value + location_dict[key] = value # manage city - location_openstreetmap_details["osm_address_city"] = None + location_dict["osm_address_city"] = None for osm_address_place_field in OSM_ADDRESS_PLACE_FIELDS: if osm_address_place_field in response[0]["address"]: - if not location_openstreetmap_details["osm_address_city"]: + if not location_dict["osm_address_city"]: key = "osm_address_city" value = response[0]["address"][osm_address_place_field] - location_openstreetmap_details[key] = value + location_dict[key] = value - return location_openstreetmap_details + return location_dict except Exception: # logger.exception("Error returned from OpenStreetMap") return None diff --git a/open_prices/prices/tests.py b/open_prices/prices/tests.py index 4e4101b7..70084465 100644 --- a/open_prices/prices/tests.py +++ b/open_prices/prices/tests.py @@ -9,6 +9,10 @@ ) from open_prices.prices import constants as price_constants from open_prices.prices.factories import PriceFactory +from open_prices.products.models import ( + Product, + product_post_create_fetch_data_from_openfoodfacts, +) from open_prices.proofs.factories import ProofFactory from open_prices.users.factories import SessionFactory @@ -16,6 +20,9 @@ class PriceModelSaveTest(TestCase): @classmethod def setUpTestData(cls): + signals.post_save.disconnect( + product_post_create_fetch_data_from_openfoodfacts, sender=Product + ) signals.post_save.disconnect( location_post_create_fetch_data_from_openstreetmap, sender=Location ) diff --git a/open_prices/products/factories.py b/open_prices/products/factories.py index 03f646d7..e2d71577 100644 --- a/open_prices/products/factories.py +++ b/open_prices/products/factories.py @@ -2,11 +2,13 @@ import factory import factory.fuzzy +from django.db.models.signals import post_save from factory.django import DjangoModelFactory from open_prices.products.models import Product +@factory.django.mute_signals(post_save) class ProductFactory(DjangoModelFactory): class Meta: model = Product diff --git a/open_prices/products/models.py b/open_prices/products/models.py index 56615e2c..2aee2e9a 100644 --- a/open_prices/products/models.py +++ b/open_prices/products/models.py @@ -1,4 +1,6 @@ from django.db import models +from django.db.models import signals +from django.dispatch import receiver from django.utils import timezone from open_prices.products import constants as product_constants @@ -40,3 +42,17 @@ class Meta: def save(self, *args, **kwargs): self.full_clean() super().save(*args, **kwargs) + + +@receiver(signals.post_save, sender=Product) +def product_post_create_fetch_data_from_openfoodfacts( + sender, instance, created, **kwargs +): + if created: + from open_prices.common import openfoodfacts as common_openfoodfacts + + product_openfoodfacts_details = common_openfoodfacts.get_product_dict(instance) + if product_openfoodfacts_details: + for key, value in product_openfoodfacts_details.items(): + setattr(instance, key, value) + instance.save()