Automação · Comércio exterior

Validador de documentos de importação

Antes de liberar um embarque, alguém precisa conferir se invoice, packing list, shipping list e certificados de análise contam a mesma história. Escrevi um script em Python que faz essa conferência e entrega um relatório pronto. Aqui a mesma conferência roda no seu navegador.

JavaScript · SheetJS · pdf.jsPython · pandasTesseract OCRDados fictícios

Teste agora

Montei um embarque fictício com os cinco documentos que chegam do fornecedor. Tem alguns erros escondidos neles. Clique em conferir e veja o que o validador encontra.

Baixar o kit (.zip)

Regras desta demo: validade mínima de 18 meses na chegada (ETA da invoice), fabricação até 6 meses antes da invoice e uma anuência fictícia para o SKU-2214, válida desde 01/06/2025.

Por que isso importa

Comércio exterior é uma cadeia de prazos. Uma quantidade que não bate, um lote repetido ou uma validade curta descoberta tarde vira carga parada no terminal, custo de armazenagem e risco de faltar produto na ponta.

A conferência manual cruza quatro ou cinco documentos linha a linha. É lenta, cansativa e depende de quem está conferindo naquele dia.

Como funciona

Fluxo do validador Os documentos do embarque entram, são lidos como texto ou por OCR, passam por 12 checagens e geram um relatório em Excel com falhas, pontos de atenção e um rascunho de e-mail. Documentos Invoice (Excel) Packing list (Excel) Shipping list (Excel) Certificados de análise (PDF) Invoice e packing assinados (PDF) Leitura Excel: pandas PDF digital: texto direto (PyMuPDF) PDF escaneado: OpenCV limpa a imagem e o Tesseract lê Cache por página 12 checagens Cabeçalho e CNPJ Quantidades Valores e pesos Caixas Lotes e séries Validade Certificados Anuência Relatório Excel com Falha, Atenção e OK Abas de apoio Rascunho de e-mail para o fornecedor
Do documento ao relatório. Um certificado ilegível não derruba a execução: a página com problema vira um ponto de atenção.

A versão desta página faz o mesmo caminho em JavaScript. O SheetJS lê o Excel, o pdf.js lê o texto dos PDFs e as 12 checagens rodam no seu navegador. Só o OCR de PDF escaneado ficou de fora, porque pesaria demais para uma página.

Três níveis de resultado

As 12 checagens

CódigoO que confere
ACabeçalho coerente entre os documentos: exportador, número da invoice e do pedido, faturado para, entregar para, contato.
A2CNPJ do importador presente, com dígito verificador válido e igual em todos os documentos.
BQuantidade por SKU: invoice x shipping list.
CQuantidade por família: shipping list x packing list, e total geral da invoice x packing list.
DValores da invoice: quantidade x preço unitário = valor da linha.
EPesos do packing list: soma das linhas x totais declarados.
FCaixas: shipping list x packing list, inclusive por tamanho de caixa.
GLotes: quantidade igual ao número de séries, sem série duplicada, sem o mesmo lote em dois códigos.
HValidade mínima na chegada (padrão de 18 meses) e fabricação recente.
ICertificado de análise lote a lote: lote presente, código, séries e validade iguais ao shipping list.
JDocumentos finais assinados (PDF) x planilhas: número da invoice, quantidades, caixas e pesos.
KAnuência regulatória: lote fabricado antes da data da anuência do produto é bloqueado.

Trechos da lógica

Versões simplificadas, escritas para esta página, de duas partes do script.

Ler a página: texto direto ou OCR

def texto_da_pagina(pagina):
    texto = pagina.get_text()
    if len(texto.strip()) > 50:          # PDF digital: o texto já está lá
        return texto
    pix = pagina.get_pixmap(dpi=300)      # PDF escaneado: vira imagem
    img = np.frombuffer(pix.samples, np.uint8).reshape(pix.h, pix.w, pix.n)
    cinza = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    _, pb = cv2.threshold(cinza, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return pytesseract.image_to_string(pb)

Validade mínima e fabricação recente

def checar_validade(lote, data_chegada, meses_min=18, meses_fab_max=6):
    restantes = meses_entre(data_chegada, lote.validade)
    if restantes < meses_min:
        return "FALHA", f"Lote {lote.numero} chega com {restantes} meses (mínimo {meses_min})"
    if meses_entre(lote.fabricacao, data_chegada) > meses_fab_max:
        return "ATENCAO", f"Lote {lote.numero} fabricado há mais de {meses_fab_max} meses"
    return "OK", f"Lote {lote.numero} dentro do prazo"

O que aprendi

Sobre o código: o script original trabalha com documentos reais de fornecedores e não é público. A versão desta página foi reescrita em JavaScript e o kit de exemplo foi montado do zero: empresas, produtos, lotes e números são inventados.