Initial commit.

This commit is contained in:
Edward Betts 2026-09-19 11:32:53 +01:00
commit 628e5c3823
26 changed files with 3478 additions and 0 deletions

45
ocado_grocy/pantry.py Normal file
View file

@ -0,0 +1,45 @@
"""Select shelf-stable stock using Ocado metadata, without a product-name list."""
from dataclasses import dataclass
@dataclass(frozen=True)
class Decision:
include: bool
reason: str
uncertain: bool = False
PERISHABLE_CATEGORIES = {"fresh & chilled food", "frozen food", "bakery"}
SHELF_STABLE_CATEGORIES = {
"food cupboard", "treats & snacks", "soft drinks, tea & coffee", "beer, wine & spirits",
"household & cleaning", "home care & cleaning", "health, beauty & personal care",
"beauty & toiletries", "pets", "health, medicines & wellbeing", "home & garden",
"m&s food cupboard", "m&s snacks & treats",
}
def classify(item, overrides=None):
overrides = overrides or {}
key = item.product_id or item.name
if key in overrides:
value = overrides[key]
if not isinstance(value, bool):
raise ValueError(f"pantry override {key!r} must be true or false")
return Decision(value, "explicit product override")
storage_type = item.metadata.get("storage_type")
if storage_type in {"FRIDGE", "FREEZER"}:
return Decision(False, "requires cold storage")
product = item.metadata.get("ocado", {})
storage = str(product.get("storage", "")).casefold()
if "keep refrigerated" in storage or "keep frozen" in storage:
return Decision(False, "requires cold storage")
categories = product.get("categoryPath", [])
if isinstance(categories, str):
categories = [categories]
categories = {str(category).strip().casefold() for category in categories}
if categories & PERISHABLE_CATEGORIES:
return Decision(False, "fresh, chilled, frozen or bakery category")
if categories & SHELF_STABLE_CATEGORIES:
return Decision(True, "shelf-stable product category")
# CUPBOARD alone also describes bananas, onions and potatoes.
return Decision(False, "missing or ambiguous product category", uncertain=True)