Files
GTI_GERENCIADOR_FISCAL/scripts/analyze_inbound_observations.py
T

83 lines
3.6 KiB
Python

"""Read-only extraction of populated supplier-item fiscal observations."""
from __future__ import annotations
import hashlib
import json
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from central.app.evidence_aggregation import Observation, aggregate_observations # noqa: E402
def _hash(value: object) -> str:
return hashlib.sha256(str(value).encode("utf-8")).hexdigest()[:16]
def summarize_rows(rows: list[tuple[object, ...]]) -> dict:
observations = []
for product, supplier, observed_at, ncm, cfop, cst in rows:
identity = _hash(product)
supplier_id = _hash(supplier)
document = _hash(f"{supplier}:{product}:{observed_at}")
for attribute, value in (("ncm", ncm), ("cfop", cfop), ("cst", cst)):
if value not in (None, ""):
observations.append(Observation(identity, attribute, str(value).strip(), supplier_id, document, str(observed_at), "SUPPLIER_OBSERVATION"))
aggregate = aggregate_observations(observations)
return {
"observation_count": len(observations),
"aggregate_count": len(aggregate),
"sources": ["SUPPLIER_OBSERVATION"] if observations else [],
"strong_evidence_count": sum(1 for row in aggregate.values() if row["strong_evidence"]),
"conflict_count": sum(row["conflict_count"] for row in aggregate.values()),
}
def _env() -> None:
path = ROOT / ".env"
if path.exists():
for line in path.read_text(encoding="utf-8").splitlines():
if "=" in line and not line.lstrip().startswith("#"):
key, _, value = line.partition("=")
os.environ.setdefault(key.strip(), value.strip())
def analyze_database(path: Path) -> dict:
import fdb
conn = fdb.connect(database=str(path), user=os.environ["FB_USER"], password=os.environ["FB_PASSWORD"], fb_library_name=os.environ.get("FIREBIRD_CLIENT_LIBRARY"), isolation_level=fdb.ISOLATION_LEVEL_READ_COMMITED_RO)
try:
cur = conn.cursor()
cur.execute("SELECT TRIM(RDB$FIELD_NAME) FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'C000088'")
fields = {row[0] for row in cur.fetchall()}
required = {"CODPRODUTO", "CODFORNECEDOR", "DATA", "CLASSIFICACAO_FISCAL", "CFOP", "CST"}
if not required <= fields:
return {"database": path.name, "status": "NO_COMPLETE_INBOUND_ITEM_SHAPE", "fields_available": sorted(fields)}
cur.execute("SELECT CODPRODUTO, CODFORNECEDOR, DATA, CLASSIFICACAO_FISCAL, CFOP, CST FROM C000088")
rows = cur.fetchall()
summary = summarize_rows(rows)
return {"database": path.name, "status": "ANALYZED", "items_analyzed": len(rows), **summary, "origin_field_available": False, "origin_resolution": "ORIGIN_NEEDS_EVIDENCE"}
finally:
conn.close()
def main() -> None:
_env()
paths = [ROOT / "TESTESOFICIAIS.FDB"] + sorted((ROOT / "Banco").glob("*.FDB"))
result = {"artifact": "INBOUND_SUPPLIER_OBSERVATIONS_V1", "mode": "READ_ONLY", "firebird_writes": 0, "databases": []}
for path in paths:
try:
result["databases"].append(analyze_database(path))
except Exception as exc:
result["databases"].append({"database": path.name, "status": "UNAVAILABLE", "error_type": type(exc).__name__})
(ROOT / "docs/INBOUND_SUPPLIER_OBSERVATIONS_V1.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"artifact": result["artifact"], "databases": len(result["databases"]), "firebird_writes": 0}))
if __name__ == "__main__":
main()