from datetime import date from typing import Protocol import httpx from sqlalchemy.orm import Session from app.models.entities import Home, Product def expiry_status(product: Product, home: Home) -> str: if not product.expires_at: return "ok" today = date.today() if product.expires_at <= today: return "expired" if (product.expires_at - today).days <= home.expiry_warning_days: return "soon" return "ok" class ProductLookup(Protocol): async def by_barcode(self, barcode: str) -> dict | None: ... class OpenFoodFactsLookup(ProductLookup): async def by_barcode(self, barcode: str) -> dict | None: url = f"https://world.openfoodfacts.org/api/v2/product/{barcode}.json" async with httpx.AsyncClient(timeout=8) as client: response = await client.get(url) if response.status_code != 200: return None data = response.json() product = data.get("product") if not product: return None return { "name": product.get("product_name") or product.get("generic_name") or "", "brand": product.get("brands"), "category": (product.get("categories_tags") or ["Other"])[0].replace("en:", ""), "image_url": product.get("image_front_small_url") or product.get("image_url"), "barcode": barcode, } def low_stock_products(db: Session, home_id: str) -> list[Product]: return [ product for product in db.query(Product).filter(Product.home_id == home_id).all() if product.quantity <= product.min_quantity ]