Backend scores updates on products
This commit is contained in:
@@ -86,6 +86,18 @@ def _row_to_product_out(row: dict, fallback_brand: str) -> ProductOut:
|
||||
if fssai is not None:
|
||||
fssai = str(fssai).strip() or None
|
||||
|
||||
# NUMERIC arrives as decimal.Decimal, which Pydantic would coerce but JSON
|
||||
# would not. Converted here so 0.0 survives - `or None` would turn a real
|
||||
# score of zero into "not scored", and zero is a valid health score.
|
||||
def _score(key: str) -> Optional[float]:
|
||||
raw = row.get(key)
|
||||
if raw is None:
|
||||
return None
|
||||
try:
|
||||
return float(raw)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
return ProductOut(
|
||||
image_id=image_id,
|
||||
image_url=primary_url,
|
||||
@@ -108,6 +120,8 @@ def _row_to_product_out(row: dict, fallback_brand: str) -> ProductOut:
|
||||
selling_price=sp,
|
||||
barcode=bcd,
|
||||
barcode_type=bcd_type,
|
||||
nutrition_score=_score("nutrition_score"),
|
||||
health_score=_score("health_score"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -569,6 +569,8 @@ async def upload_nutrition_file(file: UploadFile = File(...)) -> Dict[str, Any]:
|
||||
skipped = 0
|
||||
skipped_non_consumable = 0
|
||||
status_counts = {"verified": 0, "partial": 0, "unavailable": 0}
|
||||
# Which brands to mirror onto the brand tables once the import commits.
|
||||
touched_brands: set = set()
|
||||
|
||||
try:
|
||||
with conn, conn.cursor() as cur:
|
||||
@@ -752,6 +754,7 @@ async def upload_nutrition_file(file: UploadFile = File(...)) -> Dict[str, Any]:
|
||||
)
|
||||
|
||||
imported_count += 1
|
||||
touched_brands.add(brand)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
@@ -761,6 +764,14 @@ async def upload_nutrition_file(file: UploadFile = File(...)) -> Dict[str, Any]:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
# Mirror onto the brand tables, so a consumer reading product rows directly
|
||||
# sees an uploaded score too. After the commit and outside the try, because
|
||||
# this must never turn a successful import into a 500 - sync_after_write
|
||||
# swallows its own failures for the same reason.
|
||||
if touched_brands:
|
||||
from app.services.nutrition_score_sync import sync_after_write
|
||||
sync_after_write(sorted(touched_brands))
|
||||
|
||||
return _finish(
|
||||
file.filename, len(df), imported_count, errors, skipped,
|
||||
"nutritional intelligence items",
|
||||
|
||||
Reference in New Issue
Block a user