Files
GTI_GERENCIADOR_FISCAL/fiscal/central/app/ai/questionnaire.py
T
gti d21a9d1140 Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'
git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
2026-09-29 14:43:23 -03:00

102 lines
4.7 KiB
Python

"""Pure, review-first questionnaire helpers for local fiscal context."""
import csv
import io
import json
from central.app.context_keys import validate_entry
def _options(row):
value = row.get("VALID_OPTIONS", [])
if isinstance(value, str):
try:
value = json.loads(value)
except json.JSONDecodeError:
value = [x.strip() for x in value.split("|") if x.strip()]
return list(value) if isinstance(value, (list, tuple, set)) else [value]
def build_questionnaire(rows):
result = []
for row in rows:
scope = str(row.get("SCOPE", row.get("scope", ""))).strip().upper()
key = str(row.get("KEY", row.get("key", ""))).strip()
scope_key = str(row.get("GROUP") or row.get("NCM") or row.get("scope_key") or "").strip()
result.append({
"question_id": str(row.get("QUESTION_ID", row.get("question_id", ""))).strip(),
"database": str(row.get("DATABASE", row.get("database", ""))).strip(),
"scope": scope,
"scope_key": scope_key if scope != "COMPANY" else "",
"group": str(row.get("GROUP") or "").strip(),
"key": key,
"question": row.get("QUESTION", row.get("question", "")),
"options": _options(row),
"affected": {"products": int(row.get("PRODUCTS_AFFECTED") or row.get("products_affected") or 0), "cells": int(row.get("CELLS") or row.get("cells") or 0)},
"examples": row.get("EXAMPLES", row.get("examples", "")),
"consequence": row.get("WHAT_IT_WILL_RESOLVE", row.get("consequence", "")),
})
return sorted(result, key=lambda q: (q["database"], q["scope"], q["scope_key"], q["key"], q["question_id"]))
def group_questions(questions):
"""Group equivalent human decisions while retaining every affected question ID."""
groups = {}
for question in questions:
key = (question["database"], question["group"], question["scope_key"], question["key"], question["question"], tuple(question["options"]))
group = groups.setdefault(key, {
"group_id": "GROUP-" + str(len(groups) + 1),
"database": question["database"],
"group": question["group"],
"scope": question["scope"],
"scope_key": question["scope_key"],
"key": question["key"],
"question": question["question"],
"options": question["options"],
"question_ids": [],
"affected": {"products": 0, "cells": 0},
"examples": [],
"consequence": question["consequence"],
})
group["question_ids"].append(question["question_id"])
group["affected"]["products"] += question["affected"]["products"]
group["affected"]["cells"] += question["affected"]["cells"]
if question["examples"] and len(group["examples"]) < 5:
group["examples"].append(str(question["examples"]))
return list(groups.values())
def validate_answers(questions, answers):
entries, effects, rollback_plan = [], [], []
by_id = {q["question_id"]: q for q in questions}
for question_id, value in answers.items():
if question_id not in by_id:
raise ValueError(f"unknown question {question_id!r}; nothing was persisted")
q = by_id[question_id]
value = str(value).strip()
if q["options"] and value not in q["options"]:
raise ValueError(f"{question_id}: value must be one of {q['options']}; nothing was persisted")
entry, error = validate_entry({"scope": q["scope"], "scope_key": q["scope_key"], "key": q["key"], "value": value})
if error:
raise ValueError(f"{question_id}: {error}; nothing was persisted")
entry["company_key"] = q["database"]
entries.append(entry)
effect = {"question_id": question_id, "database": q["database"], "key": q["key"], "affected": q["affected"], "behavior": "context_entry"}
if q["key"] == "entry_scope" and value == "MIXED_OR_DYNAMIC":
effect["behavior"] = "no_static_cfop_entrada"
effects.append(effect)
if q["key"] == "store_ipi_profile" and value == "LEAVE_NOT_APPLICABLE":
rollback_plan.append({"database": q["database"], "field": "IPI", "affected_cells": q["affected"]["cells"]})
return {"entries": entries, "effects": effects, "rollback_plan": rollback_plan}
def render_json(result):
return json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
def render_csv(result):
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=["company_key", "scope", "scope_key", "key", "value", "reason"])
writer.writeheader()
writer.writerows({k: entry.get(k, "") for k in writer.fieldnames} for entry in result["entries"])
return output.getvalue()