Missão 5: Fase 1 (Reference Data Registry): migration 0034 adds licence_terms, valid_from/ valid_to, file_size_bytes, raw_file_path, parse_errors, submitted_by/approved_by/ approved_at to the existing `datasets` table (additive only - the 9 pre-existing dataset kinds keep their current auto-activate behavior in central/app/datasets/service.py, completely untouched, so this changes nothing about the currently-running engine). New central/app/reference_registry.py is a separate, NEW ingestion workflow: register_draft() always lands as DRAFT (never auto-activates), diff_against_vigente() summarizes a draft against the current VIGENTE of the same kind for admin review, approve_draft()/reject_draft() are the only way to promote a DRAFT (refuses non-DRAFT rows and refuses a draft with recorded parse_errors). New admin screen "Tabelas oficiais" (/admin/reference-datasets, ADMIN only, CSRF, every decision audited as REFERENCE_DATASET_APPROVE/REJECT) lists the registry with a diff view and approve/reject buttons. New CLI (scripts/ingest_reference_dataset.py) downloads an official source (currently: NCM/Siscomex, no login/captcha), validates (minimum row count, a known-sample spot check), and registers a DRAFT - --dry-run never writes anything. P1 (NCM) validated for real: downloaded the live official Siscomex NCM JSON (2026-09-28, sha256 8a3bf89a..., 15,156 entries) with an identifiable User-Agent, one request. Its hash is IDENTICAL to the NCM dataset already ACTIVE in the Hub - confirms the currently loaded table is already current against the official source today. Raw file kept out of git (.gitignore: sources/raw/reference_registry/); manifest (URL, date, hash, size) recorded in docs/REFERENCE_DATASET_MANIFEST_V1.md, including P2-P6 sources still pending URL confirmation. Fase 5 (feasibility studies, no code): docs/VIABILIDADE_CCG_DFE_V1.md - CCG/SEFAZ GTIN lookup and Distribuição DF-e both require the client's own ICP-Brasil certificate; recommendation is NOT to implement now (would require either the Hub holding a client certificate - breaks the project's core security model - or the Agent making new outbound internet calls, against this mission's fixed rules). Reading the already-authorized purchase-NFe XML from disk via the Agent (path already stored in XML_MES) is recommended as the next concrete step instead: no certificate, no new internet call, opt-in per installation, result always tagged DECLARADO (never auto-promoted - consensus across purchase invoices is not fiscal truth). Open Food Facts stays identity-only, unchanged. 21 new tests, all passing. Full suite: 1147 passed, 1 skipped. No write to any Firebird database anywhere. No Agent code touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
2.4 KiB
HTML
40 lines
2.4 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Tabelas oficiais | GTI Fiscal{% endblock %}
|
|
{% block content %}
|
|
<div class="page-heading">
|
|
<div><p class="eyebrow">CATÁLOGO DE REFERÊNCIA FISCAL</p><h1>Tabelas oficiais</h1><p class="muted">Nenhuma versão vira "vigente" sem aprovação de um administrador do diff.</p></div>
|
|
</div>
|
|
<section class="panel">
|
|
{% for r in rows %}
|
|
<article class="panel" style="margin-top:12px"><div class="panel-title"><h3>{{ r.kind }} · {{ r.version_label }}</h3><span class="badge {{ '' if r.status in ['VIGENTE','ACTIVE'] else ('critical' if r.status in ['REJECTED'] else '') }}">{{ r.status }}</span></div>
|
|
<dl class="facts">
|
|
<dt>Fonte</dt><dd>{{ r.provider }} — <a href="{{ r.source_url }}" target="_blank" rel="noopener">{{ r.source_url }}</a></dd>
|
|
<dt>Linhas</dt><dd>{{ r.record_count }}</dd>
|
|
<dt>Baixado em</dt><dd>{{ r.downloaded_at }}{% if r.submitted_by %} · por {{ r.submitted_by }}{% endif %}</dd>
|
|
{% if r.licence_terms %}<dt>Licença/termos</dt><dd>{{ r.licence_terms }}</dd>{% endif %}
|
|
{% if r.parse_errors %}<dt>Erros de parse</dt><dd class="coverage-status error">{{ r.parse_errors }}</dd>{% endif %}
|
|
{% if r.approved_by %}<dt>Decidido por</dt><dd>{{ r.approved_by }}</dd>{% endif %}
|
|
{% if r.diff %}
|
|
<dt>Diff vs. vigente atual</dt>
|
|
<dd>
|
|
{% if r.diff.is_first_version %}Primeira versão deste tipo de dataset — nada para comparar.
|
|
{% else %}Vigente atual: {{ r.diff.current_vigente.version_label }} ({{ r.diff.current_vigente.record_count }} linhas) →
|
|
proposto: {{ r.diff.draft.version_label }} ({{ r.diff.draft.record_count }} linhas, diferença de {{ r.diff.record_count_delta }})
|
|
{% if r.diff.sha256_unchanged %} · conteúdo idêntico (mesmo hash){% endif %}{% endif %}
|
|
</dd>
|
|
{% endif %}
|
|
</dl>
|
|
{% if r.status == "DRAFT" and is_admin %}
|
|
<form method="post" action="/admin/reference-datasets/{{ r.id }}/decide" class="filters compact-filters">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button class="secondary" type="submit" name="action" value="approve" {% if r.parse_errors %}disabled title="corrija os erros de parse antes de aprovar"{% endif %}>Aprovar (vira vigente)</button>
|
|
<button class="secondary" type="submit" name="action" value="reject" onclick="return confirm('Rejeitar esta versão?')">Rejeitar</button>
|
|
</form>
|
|
{% endif %}
|
|
</article>
|
|
{% else %}
|
|
<p class="muted">Nenhum dataset registrado no catálogo novo ainda.</p>
|
|
{% endfor %}
|
|
</section>
|
|
{% endblock %}
|