Skip to content

Commit

Permalink
feat: fetch product data from OpenFoodFacts (#49)
Browse files Browse the repository at this point in the history
* Product get_or_create: get info if created

* Fetch data from OFF

* Update product

* Fixes
  • Loading branch information
raphodn committed Nov 22, 2023
1 parent e5fee84 commit cc5a778
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
12 changes: 11 additions & 1 deletion app/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,20 @@ def create_product(db: Session, product: ProductCreate):


def get_or_create_product(db: Session, product: ProductCreate):
created = False
db_product = get_product_by_code(db, code=product.code)
if not db_product:
db_product = create_product(db, product=product)
return db_product
created = True
return db_product, created


def update_product(db: Session, product: ProductBase, update_dict: dict):
for key, value in update_dict.items():
setattr(product, key, value)
db.commit()
db.refresh(product)
return product


# Prices
Expand Down
16 changes: 14 additions & 2 deletions app/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@

from app import crud
from app.schemas import LocationCreate, PriceBase, ProductCreate
from app.utils import fetch_location_openstreetmap_details
from app.utils import (
fetch_location_openstreetmap_details,
fetch_product_openfoodfacts_details,
)


def create_price_product(db: Session, price: PriceBase):
if price.product_code:
# get or create the corresponding product
product = ProductCreate(code=price.product_code)
db_product = crud.get_or_create_product(db, product=product)
db_product, created = crud.get_or_create_product(db, product=product)
# link the product to the price
crud.set_price_product(db, price=price, product=db_product)
# fetch data from OpenFoodFacts if created
if created:
product_openfoodfacts_details = fetch_product_openfoodfacts_details(
product=db_product
)
if product_openfoodfacts_details:
crud.update_product(
db, product=db_product, update_dict=product_openfoodfacts_details
)


def create_price_location(db: Session, price: PriceBase):
Expand Down
40 changes: 38 additions & 2 deletions app/utils.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import logging

import sentry_sdk
from openfoodfacts import API, APIVersion, Country, Environment, Flavor
from openfoodfacts.utils import get_logger
from OSMPythonTools.nominatim import Nominatim
from sentry_sdk.integrations import Integration
from sentry_sdk.integrations.logging import LoggingIntegration

from app.schemas import LocationBase
from app.schemas import LocationBase, ProductBase

logger = get_logger(__name__)


# Sentry
# ------------------------------------------------------------------------------
def init_sentry(sentry_dsn: str | None, integrations: list[Integration] | None = None):
if sentry_dsn:
integrations = integrations or []
Expand All @@ -26,6 +29,39 @@ def init_sentry(sentry_dsn: str | None, integrations: list[Integration] | None =
)


# OpenFoodFacts
# ------------------------------------------------------------------------------
def openfoodfacts_product_search(code: str):
client = API(
username=None,
password=None,
country=Country.world,
flavor=Flavor.off,
version=APIVersion.v2,
environment=Environment.org,
)
return client.product.get(code)


def fetch_product_openfoodfacts_details(product: ProductBase):
product_openfoodfacts_details = dict()
try:
response = openfoodfacts_product_search(code=product.code)
if response["status"]:
product_openfoodfacts_details["source"] = Flavor.off
for off_field in ["product_name", "product_quantity", "image_url"]:
if off_field in response["product"]:
product_openfoodfacts_details[off_field] = response["product"][
off_field
]
return product_openfoodfacts_details
except Exception:
logger.exception("Error returned from OpenFoodFacts")
return


# OpenStreetMap
# ------------------------------------------------------------------------------
def openstreetmap_nominatim_search(osm_id: int, osm_type: str):
client = Nominatim()
search_query = f"{osm_type}/{osm_id}"
Expand Down Expand Up @@ -53,5 +89,5 @@ def fetch_location_openstreetmap_details(location: LocationBase):

return location_openstreetmap_details
except Exception:
logger.exception("error returned from OpenStreetMap")
logger.exception("Error returned from OpenStreetMap")
return

0 comments on commit cc5a778

Please sign in to comment.