BuyingAgent/backend/app/discovery/criteria.py

78 lines
3.0 KiB
Python
Raw Normal View History

from __future__ import annotations
from typing import Any
from uuid import UUID
from app.domain.validation import DomainValidationError, canonical_json, sha256_text
def parse_project_criteria(definition: dict[str, Any]) -> dict[str, Any]:
items = definition.get("items")
if not isinstance(items, list) or not items:
raise DomainValidationError("criteria.items must be a non-empty list")
seen: set[str] = set()
canonical_items: list[dict[str, Any]] = []
for raw in items:
criterion_id = raw.get("criterion_definition_id")
key = raw.get("criterion")
item_id = str(raw.get("id") or criterion_id or key or "")
if not item_id:
raise DomainValidationError("each criterion needs id, criterion_definition_id or criterion")
if item_id in seen:
raise DomainValidationError("duplicate criterion id", {"id": item_id})
seen.add(item_id)
if not criterion_id and not key:
raise DomainValidationError("criterion_definition_id or criterion is required", {"id": item_id})
if not raw.get("operator"):
raise DomainValidationError("operator is required", {"id": item_id})
enabled = raw.get("enabled_for_discovery")
if enabled is None:
enabled = raw.get("mandatory", True)
canonical_items.append(
{
"id": item_id,
"criterion_definition_id": None if criterion_id is None else UUID(str(criterion_id)),
"criterion": None if key is None else str(key),
"operator": str(raw["operator"]),
"value": raw.get("value"),
"enabled_for_discovery": bool(enabled),
"mandatory": bool(enabled),
"value_type": raw.get("value_type"),
"unit": raw.get("unit"),
"semantic": raw.get("semantic"),
"category": raw.get("category"),
}
)
canonical = {
"items": [
{
"id": item["id"],
"criterion_definition_id": None
if item["criterion_definition_id"] is None
else str(item["criterion_definition_id"]),
"criterion": item["criterion"],
"operator": item["operator"],
"value": item["value"],
"enabled_for_discovery": item["enabled_for_discovery"],
}
for item in canonical_items
]
}
return {
"items": canonical_items,
"definition": canonical,
"definition_hash": sha256_text(canonical_json(canonical)),
}
def criterion_payload(row) -> dict[str, Any]:
return {
"id": row.item_id,
"criterion_definition_id": row.criterion_definition_id,
"criterion": row.criterion_key,
"operator": row.operator,
"value": row.value,
"enabled_for_discovery": row.enabled_for_discovery,
"mandatory": row.enabled_for_discovery,
}