from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy import select from app.core.database import session_scope from app.modules.sync.tenant import TenantContext, get_tenant_context, require_enterprise_zootech from app.modules.zootech.catalog_apply import load_catalog_row from app.modules.zootech import service as zootech_service from app.modules.zootech.service import ZootechServiceError from app.modules.zootech.models import ZootechComponent, ZootechRecipe router = APIRouter() def _list_components(enterprise_id: str) -> list[dict]: with session_scope() as db: rows = list( db.scalars( select(ZootechComponent).where( ZootechComponent.enterprise_id == enterprise_id, ZootechComponent.is_deleted.is_(False), ) ) ) return [ { "id": row.id, "name": row.name, "type": row.type, "is_active": row.is_active, "dry_matter": row.dry_matter, "protein": row.protein, "energy": row.energy, "price": row.price, "external_no": row.external_no, "version": row.version, "content_hash": row.content_hash, } for row in rows ] def _list_recipes(enterprise_id: str) -> list[dict]: with session_scope() as db: rows = list( db.scalars( select(ZootechRecipe).where( ZootechRecipe.enterprise_id == enterprise_id, ZootechRecipe.is_deleted.is_(False), ) ) ) return [ { "id": row.id, "name": row.name, "heads_per_trip": row.heads_per_trip, "mixing_time": row.mixing_time, "trip_percent": row.trip_percent, "dry_matter_locked": row.dry_matter_locked, "version": row.version, "content_hash": row.content_hash, } for row in rows ] @router.get("/components") def list_components( enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") return {"components": _list_components(enterprise_id)} @router.get("/components/{component_id}") def get_component( component_id: str, enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") row = load_catalog_row(enterprise_id, "component", component_id) if not row: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="NOT_FOUND") return row @router.post("/components") def create_component( body: dict, enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") return zootech_service.upsert_component(enterprise_id, None, body) @router.patch("/components/{component_id}") def update_component( component_id: str, body: dict, enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") try: return zootech_service.patch_component(enterprise_id, component_id, body) except ZootechServiceError: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="NOT_FOUND") from None @router.post("/recipes") def create_recipe( body: dict, enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") return zootech_service.upsert_recipe(enterprise_id, None, body) @router.get("/recipes") def list_recipes( enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") return {"recipes": _list_recipes(enterprise_id)} @router.get("/recipes/{recipe_id}") def get_recipe( recipe_id: str, enterprise_id: str = Query(...), tenant: TenantContext = Depends(require_enterprise_zootech), ): if tenant.enterprise_id != enterprise_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") row = load_catalog_row(enterprise_id, "recipe", recipe_id) if not row: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="NOT_FOUND") return row