Files
GTI_GERENCIADOR_FISCAL/central/app/evidence_aggregation.py
T

48 lines
1.8 KiB
Python

"""Conservative aggregation of supplier/document observations."""
from dataclasses import dataclass
from collections import defaultdict
from typing import Any, Iterable
@dataclass(frozen=True)
class Observation:
product_id: str
attribute: str
value: str
supplier_id: str
document_id: str
observed_at: str
provenance: str = "SUPPLIER_OBSERVATION"
def aggregate_observations(observations: Iterable[Observation]) -> dict[tuple[str, str], dict[str, Any]]:
grouped: dict[tuple[str, str], list[Observation]] = defaultdict(list)
seen: set[tuple[str, str, str, str]] = set()
for observation in observations:
key = (observation.product_id, observation.attribute)
dedupe = (observation.product_id, observation.attribute, observation.supplier_id, observation.document_id)
if dedupe not in seen and observation.value not in (None, ""):
grouped[key].append(observation)
seen.add(dedupe)
output = {}
for key, rows in grouped.items():
values = {row.value for row in rows}
counts = {value: sum(row.value == value for row in rows) for value in values}
supplier_count = len({row.supplier_id for row in rows})
agreement_rate = max(counts.values()) / len(rows) if rows else 0.0
conflict_count = max(0, len(values) - 1)
strong = len(rows) >= 2 and supplier_count >= 2 and len(values) == 1
output[key] = {
"value": next(iter(values)) if strong else None,
"observation_count": len(rows),
"supplier_count": supplier_count,
"agreement_rate": agreement_rate,
"latest_observation": max(row.observed_at for row in rows),
"conflict_count": conflict_count,
"strong_evidence": strong,
"provenance": sorted({row.provenance for row in rows}),
}
return output