Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from app.core.exceptions import DomainError
|
||||
from app.modules.sync.engine import SyncEngine
|
||||
from app.modules.sync.schemas import ChangeEventIn
|
||||
from app.modules.zootech.catalog_apply import load_catalog_row
|
||||
from app.modules.zootech.sync_content_hash import compute_content_hash
|
||||
|
||||
|
||||
class ZootechServiceError(DomainError):
|
||||
pass
|
||||
|
||||
|
||||
def _emit_change(enterprise_id: str, table: str, record_id: str, payload: dict, version: int, content_hash: str) -> None:
|
||||
event = ChangeEventIn(
|
||||
event_id=str(uuid4()),
|
||||
seq=None,
|
||||
domain="global",
|
||||
table=table,
|
||||
record_id=record_id,
|
||||
action="upsert",
|
||||
version=version,
|
||||
content_hash=content_hash,
|
||||
payload=payload,
|
||||
emitted_at=datetime.now(UTC),
|
||||
origin_site_id=SyncEngine.ORCHESTRATOR_SITE_ID,
|
||||
)
|
||||
SyncEngine(enterprise_id, SyncEngine.ORCHESTRATOR_SITE_ID).process_push([event], origin="orchestrator")
|
||||
|
||||
|
||||
def upsert_component(enterprise_id: str, record_id: str | None, body: dict) -> dict:
|
||||
rid = record_id or str(uuid4())
|
||||
existing = load_catalog_row(enterprise_id, "component", rid)
|
||||
version = int(body.get("version") or (existing or {}).get("version") or 0) + 1 if existing else 1
|
||||
payload = {
|
||||
"id": rid,
|
||||
"name": body.get("name", (existing or {}).get("name", "")),
|
||||
"type": body.get("type", (existing or {}).get("type", "")),
|
||||
"is_active": body.get("is_active", (existing or {}).get("is_active", True)),
|
||||
"dry_matter": float(body.get("dry_matter", (existing or {}).get("dry_matter", 0.0))),
|
||||
"protein": float(body.get("protein", (existing or {}).get("protein", 0.0))),
|
||||
"energy": float(body.get("energy", (existing or {}).get("energy", 0.0))),
|
||||
"price": float(body.get("price", (existing or {}).get("price", 0.0))),
|
||||
"external_no": body.get("external_no", (existing or {}).get("external_no")),
|
||||
"version": version,
|
||||
}
|
||||
content_hash = compute_content_hash(payload)
|
||||
payload["content_hash"] = content_hash
|
||||
_emit_change(enterprise_id, "component", rid, payload, version, content_hash)
|
||||
return load_catalog_row(enterprise_id, "component", rid) or payload
|
||||
|
||||
|
||||
def patch_component(enterprise_id: str, record_id: str, body: dict) -> dict:
|
||||
existing = load_catalog_row(enterprise_id, "component", record_id)
|
||||
if not existing:
|
||||
raise ZootechServiceError("NOT_FOUND")
|
||||
merged = {**existing, **body}
|
||||
return upsert_component(enterprise_id, record_id, merged)
|
||||
|
||||
|
||||
def upsert_recipe(enterprise_id: str, record_id: str | None, body: dict) -> dict:
|
||||
rid = record_id or str(uuid4())
|
||||
existing = load_catalog_row(enterprise_id, "recipe", rid)
|
||||
version = int(body.get("version") or (existing or {}).get("version") or 0) + 1 if existing else 1
|
||||
payload = {
|
||||
"id": rid,
|
||||
"name": body.get("name", (existing or {}).get("name", "")),
|
||||
"heads_per_trip": int(body.get("heads_per_trip", (existing or {}).get("heads_per_trip", 1))),
|
||||
"mixing_time": int(body.get("mixing_time", (existing or {}).get("mixing_time", 0))),
|
||||
"trip_percent": float(body.get("trip_percent", (existing or {}).get("trip_percent", 100.0))),
|
||||
"dry_matter_locked": body.get("dry_matter_locked", (existing or {}).get("dry_matter_locked", False)),
|
||||
"version": version,
|
||||
}
|
||||
if "ingredients" in body:
|
||||
payload["ingredients"] = body["ingredients"]
|
||||
elif existing and "ingredients" in existing:
|
||||
payload["ingredients"] = existing["ingredients"]
|
||||
content_hash = compute_content_hash(payload)
|
||||
payload["content_hash"] = content_hash
|
||||
_emit_change(enterprise_id, "recipe", rid, payload, version, content_hash)
|
||||
return load_catalog_row(enterprise_id, "recipe", rid) or payload
|
||||
Reference in New Issue
Block a user