merge: feature/cfop-ippt-write into master (Missao 8) - resolucao de conflitos, Alembic 0035 e manifest 1.3.15

This commit is contained in:
gti
2026-09-28 22:07:31 -03:00
12 changed files with 512 additions and 15 deletions
+28 -1
View File
@@ -341,7 +341,7 @@ def router(session_factory):
event["occurred_display"] = format_ui_datetime(datetime.fromisoformat(event["occurred_at"]) if event["occurred_at"] else None)
agent_blockers = list_blockers(session, tenant_id=installation.tenant_id, agent_id=agent_id, page=1, page_size=25, scope="all")
fiscal_context = build_fiscal_context_view(session, installation.tenant_id, _company_key(None, installation, None))
return render(request, "agent_detail.html", {"detail": detail, "tab": tab, "blockers": agent_blockers, "blocker_breakdown": blocker_filter_summary(session, tenant_id=installation.tenant_id, agent_id=agent_id, status="OPEN", scope="all")["blocker_breakdown"], "jobs": list_jobs(session, agent_id=agent_id, page=1, page_size=25, scope="all"), "events": events, "event_page": max(1, event_page), "has_more": has_more, "severity": severity or "", "event_type": event_type or "", "job_id": job_id or "", "product_code": product_code or "", "since": since or "", "until": until or "", "event_query_base": query_base(tab=tab, severity=severity, event_type=event_type, job_id=job_id, product_code=product_code, since=since, until=until), "auth": auth_data, "csrf_token": request.cookies.get("gti_csrf", ""), "ops": _ops_view(session, installation, agent), "features": _features_view(session, installation, enrich_code), "enrich_code": enrich_code or "", "is_admin": _is_privileged(auth_data[1]), "fiscal_context": fiscal_context})
return render(request, "agent_detail.html", {"detail": detail, "tab": tab, "blockers": agent_blockers, "blocker_breakdown": blocker_filter_summary(session, tenant_id=installation.tenant_id, agent_id=agent_id, status="OPEN", scope="all")["blocker_breakdown"], "jobs": list_jobs(session, agent_id=agent_id, page=1, page_size=25, scope="all"), "events": events, "event_page": max(1, event_page), "has_more": has_more, "severity": severity or "", "event_type": event_type or "", "job_id": job_id or "", "product_code": product_code or "", "since": since or "", "until": until or "", "event_query_base": query_base(tab=tab, severity=severity, event_type=event_type, job_id=job_id, product_code=product_code, since=since, until=until), "auth": auth_data, "csrf_token": request.cookies.get("gti_csrf", ""), "ops": _ops_view(session, installation, agent), "features": _features_view(session, installation, enrich_code), "enrich_code": enrich_code or "", "is_admin": _is_privileged(auth_data[1]), "fiscal_context": fiscal_context, "cfop_ippt_write_mode": installation.cfop_ippt_write_mode})
finally: session.close()
def _features_view(session, installation, enrich_code=None):
@@ -420,6 +420,33 @@ def router(session_factory):
return RedirectResponse(f"/agents/{agent_id}#contexto-fiscal", status_code=303)
finally: session.close()
@routes.post("/agents/{agent_id}/cfop-ippt-write")
async def set_cfop_ippt_write_mode(request: Request, agent_id: int):
"""Missão 4 / Bloco E.1: per-installation toggle for the CFOP_IPPT_WRITE_V1 capability
(ADMIN only, CSRF, audited). DISABLED by default; the Agent has no local switch."""
from .cfop_ippt_audit import WRITE_MODES as CFOP_IPPT_MODES
session, auth_data, redirect = page_auth(request)
if redirect: return redirect
try:
values = await form_values(request); web_session, admin = auth_data
require_csrf(web_session, values.get("csrf_token"))
agent, installation = _rtc_target(session, agent_id)
if not agent or not installation: return HTMLResponse("Agent not found", status_code=404)
if not _is_privileged(admin):
return _deny(session, admin, installation.tenant_id, "cfop_ippt_write:set", installation.installation_id)
mode = (values.get("mode") or "").strip().upper()
if mode not in CFOP_IPPT_MODES:
return HTMLResponse(f"modo inválido (use um de {CFOP_IPPT_MODES})", status_code=422)
if mode != "DISABLED" and (values.get("confirm") or "").strip().upper() != "GRAVAR":
return HTMLResponse("Digite GRAVAR para confirmar um modo que pode escrever no ERP", status_code=422)
before = installation.cfop_ippt_write_mode
installation.cfop_ippt_write_mode = mode
record_audit(session, admin_user_id=admin.id, tenant_id=installation.tenant_id, action="CFOP_IPPT_WRITE_MODE", target_type="installation", target_id=installation.installation_id,
context={"from": before, "to": mode, "operator": admin.display_name or admin.username, "role": admin.external_role or admin.auth_source}, severity="WARNING")
session.commit()
return RedirectResponse(f"/agents/{agent_id}#contexto-fiscal", status_code=303)
finally: session.close()
@routes.post("/agents/{agent_id}/enrichment/reevaluate")
async def reevaluate_enrichment(request: Request, agent_id: int):
"""Explicit, idempotent 'evaluate again' for one product (code=...) or every tracked product that is not enriched yet. KB/cache first; providers only when really needed."""