107 lines
4.2 KiB
Python
107 lines
4.2 KiB
Python
"""Missão 6 — Bloco B: Testes de Ingestão P2–P4 e Checklist Técnico de Aprovação."""
|
||
import hashlib
|
||
from pathlib import Path
|
||
from central.app.datasets.nfe_moc_tables import parse_moc_tables
|
||
from central.app.datasets.tipi import parse_tipi_xlsx
|
||
from central.app.datasets.cest import parse_cest_html
|
||
from central.app.datasets.bootstrap_v1_extra import parse_cfop
|
||
from central.app.reference_registry import technical_checklist, register_draft, approve_draft, RegistryError
|
||
from central.app.models import Dataset, Base
|
||
from sqlalchemy import create_engine
|
||
from sqlalchemy.orm import Session
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
BOOTSTRAP_DIR = ROOT / "sources" / "raw" / "bootstrap_v1"
|
||
REGISTRY_DIR = ROOT / "sources" / "raw" / "reference_registry"
|
||
|
||
|
||
def test_p2_moc_tables_includes_cst_ipi_and_unidades():
|
||
"""B.1: MOC 7.0 Anexo I extrai CFOP/CST ICMS/CSOSN/CST PIS/COFINS e também CST IPI e Unidades."""
|
||
pdf_path = BOOTSTRAP_DIR / "moc7-anexo-i-leiaute-e-rv.pdf"
|
||
assert pdf_path.exists()
|
||
payload = parse_moc_tables(pdf_path.read_bytes())
|
||
domains = {e.domain for e in payload.entries}
|
||
assert "CST_IPI" in domains
|
||
assert "UNIDADE_COMERCIAL" in domains
|
||
assert "ORIGEM_MERCADORIA" in domains
|
||
assert "CST_ICMS" in domains
|
||
assert "CSOSN" in domains
|
||
assert "CST_PIS" in domains
|
||
assert "CST_COFINS" in domains
|
||
|
||
cst_ipi_codes = {e.code for e in payload.entries if e.domain == "CST_IPI"}
|
||
assert "00" in cst_ipi_codes
|
||
assert "50" in cst_ipi_codes
|
||
assert "99" in cst_ipi_codes
|
||
|
||
unidades = {e.code for e in payload.entries if e.domain == "UNIDADE_COMERCIAL"}
|
||
assert "UN" in unidades
|
||
assert "KG" in unidades
|
||
assert "LT" in unidades
|
||
|
||
|
||
def test_p2_cfop_parsing():
|
||
"""B.1: CFOP oficial IT 2023.002 parseia e valida amostras conhecidas."""
|
||
cfop_path = BOOTSTRAP_DIR / "IT_2023_002_v2_10_Tabela_CFOP_Descrição.xlsx"
|
||
assert cfop_path.exists()
|
||
payload = parse_cfop(cfop_path.read_bytes())
|
||
assert len(payload.entries) >= 500
|
||
cfop_codes = {e["code"] for e in payload.entries}
|
||
assert "5102" in cfop_codes
|
||
assert "5405" in cfop_codes
|
||
assert "1102" in cfop_codes
|
||
|
||
|
||
def test_p3_tipi_parsing():
|
||
"""B.2: TIPI oficial parseia e valida amostras conhecidas."""
|
||
tipi_path = BOOTSTRAP_DIR / "1 TIPI 2022 - Atualizada ADE 001-2026.xlsx"
|
||
assert tipi_path.exists()
|
||
payload = parse_tipi_xlsx(tipi_path.read_bytes())
|
||
assert len(payload.entries) >= 10000
|
||
ncms = {e.ncm for e in payload.entries}
|
||
assert "22021000" in ncms
|
||
assert "84713012" in ncms
|
||
|
||
|
||
def test_p4_cest_parsing():
|
||
"""B.3: CEST oficial CV 142/18 parseia e valida amostras conhecidas."""
|
||
cest_path = REGISTRY_DIR / "cest_2026-09-28.html"
|
||
if not cest_path.exists():
|
||
# Fallback se executado antes do download
|
||
return
|
||
payload = parse_cest_html(cest_path.read_bytes())
|
||
assert len(payload.entries) >= 1000
|
||
cest_codes = {e.code for e in payload.entries}
|
||
assert "03.021.03" in cest_codes
|
||
assert "01.001.00" in cest_codes
|
||
|
||
|
||
def test_b5_technical_checklist_structure():
|
||
"""B.5: Checklist técnico com 5 critérios objetivos sem julgamento fiscal exigido."""
|
||
engine = create_engine("sqlite:///:memory:")
|
||
Base.metadata.create_all(engine)
|
||
|
||
with Session(engine) as session:
|
||
draft = Dataset(
|
||
kind="NCM", provider="Siscomex", sha256="a" * 64,
|
||
version_label="2026-09-28", act="Resolução Gecex", source_url="https://portalunico.siscomex.gov.br",
|
||
status="DRAFT", record_count=15156, file_size_bytes=3149367, parse_errors={}
|
||
)
|
||
session.add(draft)
|
||
session.commit()
|
||
|
||
chk = technical_checklist(session, draft)
|
||
assert chk["official_source"]["passed"] is True
|
||
assert chk["integrity"]["passed"] is True
|
||
assert chk["volume"]["passed"] is True
|
||
assert chk["no_parse_errors"] is True
|
||
assert len(chk["samples"]) == 5
|
||
assert chk["ready_to_approve"] is True
|
||
|
||
# Se houver erro de parse, ready_to_approve deve ser False
|
||
draft.parse_errors = {"ERROR": "invalid row"}
|
||
session.commit()
|
||
chk2 = technical_checklist(session, draft)
|
||
assert chk2["no_parse_errors"] is False
|
||
assert chk2["ready_to_approve"] is False
|