git-subtree-dir: fiscal git-subtree-mainline:d95165fc8fgit-subtree-split:102ba84500
83 lines
3.6 KiB
Python
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()
|