"""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()