Ir para conteúdo
Fórum Script Brasil
  • 0

Importação de Notas - PDF


Irroration

Pergunta

Pessoal,  

Preciso de algum método ou ferramenta que seja capaz de fazer uma importação parametrizada de  notas em PDF.

O Objetivo é importadas dados de notas ficais para Excel, Access, SQL, PHP

As notas tem um padrão e estou a procura de uma forma de importar isso.

Alguém conhece ou poderia me direcionar?

Grande Abraço.

Link para o comentário
Compartilhar em outros sites

2 respostass a esta questão

Posts Recomendados

  • 0

Todas as notas fiscais são feitas no formato XML. O Excel é um excelente aplicativo que consegue importar o XML no formato CSV e assim você consegue montar a memória de cálculo para diferença de alíquota de ICMS ou ICMS Substituição Tributária no caso das compras fora do estado de São Paulo.

Eu já uso o PHP que tem uma boa ferramenta para importar o XML para a memória do computador (eu já uso uma tabela provisória do MySQL), comparo o novo custo do produto com o velho e atualizo, e em seguida uso todas as informações para dar entrada no estoque.

Nem sempre o fornecedor manda o arquivo XML, nesse caso eu peço para o meu irmão tirar uma foto da chave do DANFE, e com essa chave eu vou no portal da Nota Fiscal Eletrônica e peço para fazer o download do arquivo (o portal só autoriza a consulta plena ou o download com o certificado digital da empresa que consta na Nota Fiscal Eletrônica).

Estamos em 2025, esse é um mundo totalmente diferente. No meu tempo, a gente ajuntava todas as notas para encaminhar para a contabilidade para fazer a escrituração, apuração e imprimir os livros fiscais. Hoje não. A Contabilidade tem um esquema que consegue puxar todos os xml com o CNJP do cliente. Não sei que mágica é essa, tudo o que sei é que existe uma empresa por trás disso, como eles conseguem fazer esse serviço, isso é um mistério para mim.

O que eu mando para a contabilidade são os xml que eu criei para vender.

Se você tem PHP, aqui está um código parcial que eu fiz (eu criei um query builder baseado no PDO->query()) e roteador bem simples que passa pelo arquivo index com a sintaxe ?classe.método.argumento):

 

arquivo nf.php
<?php

class NF {

    function atualiza() {
        $previa=(new Conn)->select("* from tbnf");
        extract($_SESSION['vetor']);
        return view('nfView',['previa'=>$previa,'nNF' => $nNF,'xNome' => $xNome,
            'codp' => $codp,'vNF' => $vNF,'difAliqICMS' => $difAliqICMS, 'soma'=>$soma,'st'=>$st]);
    }

    function CFOP() { return view('nfArquivo',['action'=>'?NF.CFOPselecionado']); }

    function CFOPatualizar() {
        $cfop = $_POST['cfop'];
        $codprod = $_POST['codprod'];
        (new Conn)->update("tbprod set cfop='$cfop' where codprod = $codprod");
    }

    function CFOPselecionado() {
        (new Conn)->delete("tbnf");
        (new Conn)->exec("alter table tbnf auto_increment = 1");
        $nfe=simplexml_load_file($_FILES['arquivo']['tmp_name']);
        $itens=$nfe->NFe->infNFe->det;
        $nNF = (float)$nfe->NFe->infNFe->ide->nNF;
        $xNome = (string)$nfe->NFe->infNFe->emit->xNome;
        $nome = explode(" ", $xNome)[0];        
        $codp = (new Conn)->select("codp from tbpessoa where pessoa like '%$nome%'")[0]->codp;
        foreach ($itens as $item){
            // no campo codforn uso a primeira letra para identificar o fornecedor
            $codforn = (string)$item->prod->cProd;
            $criterio= strtolower($nome[0].$codforn);
            $consulta = (new Conn)->select("* from tbprod where codforn like '%$criterio%' ");
            $codprod = 'null';
            if (count($consulta) == 1) {
                $codprod = $consulta[0]->codprod;
            } 
            if (count($consulta) > 1) {
                $consulta2 = (new Conn)->select("* from tbprod where codforn like '%$criterio' ");
                if(count($consulta2) == 1){
                    $codprod = $consulta2[0]->codprod;
                    $consulta = $consulta2;
                } else {
                    echo "existem vários produtos com codforn com o critério $criterio";
                    foreach($consulta as $c) {
                        echo "<br>".$c->codprod." ".$c->prod;
                    }
                    exit;
                }
            }
            if (count($consulta)==0) {
                echo "nenhum produto encontrado com o critério $criterio";
                exit;
            }
            $produto = substr((string)$item->prod->xProd,0,79);
            $cfop = (string)$item->prod->CFOP;
            if($cfop==6101 || $cfop==6102 || $cfop==5101) {
                $cfop=5102;
            }
            if($cfop==6401 || $cfop==6402 || $cfop==6403 || $cfop==5401) {
                $cfop=5405;
            } 
            $class=($cfop == $consulta[0]->cfop) ? "w-[50px] text-right" : 
                "w-[50px] text-red-500 text-right";
            $ncm = (string)$item->prod->NCM;
            $class2=($ncm == $consulta[0]->cf) ? "w-[100px] text-right" : 
                "w-[100px] text-red-500 text-right";
            (new Conn)->insert("tbnf (codforn,codprod,prod,cfop,codp,ncm,class,class2) 
                values ($codforn,$codprod,'$produto','$cfop',$codp,'$ncm','$class','$class2')");
        }
        $previa=(new Conn)->select("* from tbnf");
        return view('nfCFOPview',['previa'=>$previa,'nNF' => $nNF,'xNome' => $xNome,
            'codp' => $codp]);
    }

    function custo() {
        $custoAtual = $_POST['custoAtual'];
        $codprod = $_POST['codprod'];
        $margem=(new Conn)->select("marg from tbprod where codprod=$codprod")[0]->marg;
        $venda=pvenda($custoAtual,$margem);
        $class="class=text-end";
        (new Conn)->update("tbnf set custoanterior=$custoAtual, class='$class' where codprod=$codprod");
        (new Conn)->update("tbprod set custo=$custoAtual, 
            venda=$venda where codprod = $codprod");
    }
    

    function incluir() {
        $lcto=$_POST['lcto'];
        $verifica=count((new Conn)->select("* from tbhistprod where lcto=$lcto"));
        if($verifica){
            $mensagem="<h1>Nota já lançada. <a href=?NF.atualiza>Voltar</a></h1>";
            return view('mensagemView',['mensagem'=>$mensagem]);
        }
        $dia=(new Conn)->select("dia from tbdiario where lcto=$lcto")[0]->dia;
        $matriz=(new Conn)->select("* from tbnf");
        foreach($matriz as $vetor) {
            (new Conn)->insert("tbhistprod (codprod,dia,qt,custototal,codp,lcto)
                values ('$vetor->codprod','$dia',$vetor->qt,$vetor->custototal,$vetor->codp,$lcto)");
        }
        return header("location:?Diario.inicio.$dia");
    }

    function inicio() { return view('nfArquivo',['action'=>'?NF.selecionada']); }

    function qt() {
        $qt=$_POST['qt'];
        $id=$_POST['id'];
        $previa=(new Conn)->select("* from tbnf where id=$id")[0];
        $novoClass=$previa->class;
        $custoAtual=intval($previa->custototal/$qt*100)/100;
        if($custoAtual!==$previa->custoanterior) {
            $novoClass="class=\"text-danger text-end\"";
        }
        (new Conn)->update("tbnf set class='$novoClass', custoatual=$custoAtual,
            qt=$qt where id=$id");
        return $this->atualiza();
    }

    function selecionada() {
        (new Conn)->delete("tbnf");
        (new Conn)->exec("alter table tbnf auto_increment = 1");
        $nfe=simplexml_load_file($_FILES['arquivo']['tmp_name']);
        $itens=$nfe->NFe->infNFe->det;
        $difAliqICMS=0;
        $st=0;
        $aliquotaInterna=0.18;
        foreach ($itens as $item) {
            if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP ==6101) {
                $vBC = (float)$item->imposto->ICMS->ICMS10->vBC;
                $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC;
                $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS;
                $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS;
                if((float)$item->prod->NCM == 40169300) {
                    $st += round($vBC*(1.4)*$aliquotaInterna-$vICMS+0.00001,2); // anel de vedação
                } else {
                    $difAliqICMS += round(($vBC * $aliquotaInterna - $vICMS+0.00001),2);
                }
            }
        }
        $vNF = (float)$nfe->NFe->infNFe->total->ICMSTot->vNF;
        $nNF = (float)$nfe->NFe->infNFe->ide->nNF;
        $xNome = (string)$nfe->NFe->infNFe->emit->xNome;
        $nome = explode(" ", $xNome)[0];        
        $codp = (new Conn)->select("codp from tbpessoa where pessoa like '%$nome%'")[0]->codp;
        $soma=0;
        foreach ($itens as $item){
            // no campo codforn uso a primeira letra para identificar o fornecedor
            $codforn = (string)$item->prod->cProd;
            $criterio= strtolower($nome[0].$codforn);
            $consulta = (new Conn)->select("* from tbprod where codforn like '%$criterio%' ");
            $codprod = 'null';
            if (count($consulta) == 1) {
                $codprod = $consulta[0]->codprod;
            } 
            if (count($consulta) > 1) {
                echo "existem vários produtos com codforn com o critério $criterio";
                foreach($consulta as $c) {
                    echo "<br>".$c->codprod." ".$c->prod;
                }
                exit;
            }
            if (count($consulta)==0) {
                echo "nenhum produto encontrado com o critério $criterio";
                exit;
            }
            $produto = substr((string)$item->prod->xProd,0,79);
            $quantidade = (string)$item->prod->qCom;
            if (is_numeric($codprod)) {
                $produtoDobrado = [506, 507, 508, 509, 510, 519, 1768, 1770, 1772];
                if (in_array($codprod, $produtoDobrado)) {
                    $quantidade = 2 * $quantidade;
                }
                $produtox5=[1798];
                if (in_array($codprod,$produtox5 )) {
                    $quantidade = 5 * $quantidade;
                }
                $produtoX10 = [2192, 2190,1782,2456];
                if (in_array($codprod, $produtoX10)) {
                    $quantidade = 10 * $quantidade;
                }
                $produtox12 = [2403,2406,2496,2497,2498,2499];
                if (in_array($codprod, $produtox12)) {
                    $quantidade = 12 * $quantidade;
                }
                $produtox24 = [2493,2405,2494,2495,2409];
                if (in_array($codprod, $produtox24)) {
                    $quantidade = 24 * $quantidade;
                }
            }
            $vICMSST1 = ((float)$item->imposto->ICMS->ICMS10->vICMSST) ?
                (float)$item->imposto->ICMS->ICMS10->vICMSST : null;
            $vICMSST2 = ((float)$item->imposto->ICMS->ICMSSN202->vICMSST) ?
                (float)$item->imposto->ICMS->ICMSSN202->vICMSST : null;
            $vICMSST = $vICMSST1 ? $vICMSST1 : $vICMSST2;
            $difAliq = 0;
            if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP == 6101){
                $vBC = (float)$item->imposto->ICMS->ICMS10->vBC;
                $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC;
                $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS;
                $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS;
                if((float)$item->prod->NCM == 40169300) {
                    $difAliq = round($vBC * 1.4 * $aliquotaInterna -$vICMS+0.00001,2); // usando variável $difAliq como st
                } else {
                    $difAliq = round(($vBC * $aliquotaInterna - $vICMS+0.00001),2);
                }
            }
            $vIPI = (float)$item->imposto->IPI->IPITrib->vIPI ? 
                (float)$item->imposto->IPI->IPITrib->vIPI : 0;
            $vProd = (string)$item->prod->vProd;
            $valorTotal = $vProd + $vICMSST + $difAliq + $vIPI;
            $soma += $valorTotal;
            $class = "class=text-end";
            $custoAtual=0;
            $custoAnterior=0;
            if (is_numeric($codprod)) {
                $custoAtual = intval($valorTotal / $quantidade * 100) / 100;
                $consulta = (new Conn)->select("custo from tbprod where codprod=$codprod");
                $custoAnterior = $consulta[0]->custo;
                if (abs($custoAnterior - $custoAtual) > 0.02) {
                    $class = "class=\"text-end text-danger\"";
                }
            }
            $produto=str_replace("'","''",$produto);
            (new Conn)->insert("tbnf (codforn,codprod,prod,qt,custoatual,
                custoanterior,class,custototal,codp,cfop,class2) 
                values ('$codforn',$codprod,'$produto',$quantidade,$custoAtual,
                $custoAnterior,'$class',$valorTotal,$codp,'5405','text-right')");
        }
        $previa=(new Conn)->select("* from tbnf");
        $_SESSION['vetor']=['nNF' => $nNF,'xNome' => $xNome,
            'codp' => $codp,'vNF' => $vNF,'difAliqICMS' => $difAliqICMS, 'soma'=>$soma,'st'=>$st];
        return view('nfView',['previa'=>$previa,'nNF' => $nNF,'xNome' => $xNome,
            'codp' => $codp,'vNF' => $vNF,'difAliqICMS' => $difAliqICMS, 'soma'=>$soma,'st'=>$st]);
    }

    function verXML(){
        return view('nfArquivo',['action'=>'?NF.xml']);
    }

    function xml(){
        $nfe=simplexml_load_file($_FILES['arquivo']['tmp_name']);
        return imprime($nfe);
    }
}

arquivo nfArquivo.php
<?php require 'menuView.php' ?>
<script>btmenu.innerHTML="Nota do Fornecedor";document.title="Nota do Fornecedor"</script>
<div class=mb-3>
<form method=post enctype="multipart/form-data" action="<?=$action?>">
    <label for=arquivo class=form-label>Escolha o arquivo XML</label>
    <input type=file name=arquivo class=form-control id=formfile required onchange=submit()>
</form>
</div>

arquivo nfCFOPview.php
<?php include('menuView.php'); ?>
<script>
    btMenu.innerHTML='NF Fornecedor CFOP';document.title="NF Fornecedor CFOP"
    function getCsrfToken() { 
        return document.querySelector('meta[name="csrf-token"]').getAttribute('content'); 
    }
    function atualizar(cfop, codprod) {
        var xmlhttp = new XMLHttpRequest();
        var url = "nfCFOPatualizar";
        var formData = new FormData();
        formData.append('cfop', cfop);
        formData.append('codprod', codprod);
        formData.append('_token', getCsrfToken());
        xmlhttp.open("POST", url, true);
        
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {
                console.log("Estado da requisição: " + xmlhttp.readyState);
                if (xmlhttp.status == 200) {
                    location.reload();
                } else {
                    alert("Erro na requisição: " + xmlhttp.status);
                }
            }
        }; 
        xmlhttp.send(formData);
    }
</script>
<div class="flex">
    <div class="w-[50px] text-right">Cforn</div>
    <div class="w-[50px] text-right">Cod</div>
    <div class="w-[448px] ml-2">Produto</div>
    <div class="w-[50px] text-right">CFOP</div>
    <div class="w-[100px] text-right">NCM</div>
</div>
<?php foreach($previa as $p): ?>
    <div class="flex odd:bg-gray-200">
        <div class="w-[50px] text-right"><?=$p->codforn?></div>
        <div class="w-[50px] text-right"><?=$p->codprod?></div>
        <div class="w-[448px] ml-2 truncate"><?=$p->prod?></div>
        <div class="<?=$p->class?>" onclick="atualizar(<?=$p->cfop?>,<?=$p->codprod?>)">
            <?=$p->cfop?>
        </div>
        <div class="<?=$p->class2?>"><?=$p->ncm?></div>
    </div>
<?php endforeach; ?>

arquivo nfView.php
<?php include('menuView.php'); ?>
<script>
    btMenu.innerHTML='NF Fornecedor';document.title="NF Fornecedor"
    function atualizar(custoAtual, custoAnterior, codprod) {
    var confirma = confirm("Atualizar?\ncusto atual: " + custoAtual + "\ncusto anterior: " + custoAnterior);
    if (confirma) {
        var xmlhttp = new XMLHttpRequest();
        var url = "?NF.custo";
        var formData = new FormData();
        formData.append('custoAtual', custoAtual);
        formData.append('codprod', codprod);

        xmlhttp.open("POST", url, true);
        
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {
                console.log("Estado da requisição: " + xmlhttp.readyState);
                if (xmlhttp.status == 200) {
                    // console.log("Status da resposta: " + xmlhttp.status);
                    // alert("Resposta do servidor: " + xmlhttp.responseText);
                    location.replace("?NF.atualiza");
                } else {
                    alert("Erro na requisição: " + xmlhttp.status);
                }
            }
        }; 
        xmlhttp.send(formData);
      	
    }
}


</script>
<table class='table table-striped table-sm'>
<tr class=fw-semibold><td colspan=3>NF <?=$nNF." ".substr($xNome,0,10)." codp ".$codp?><td><td><td class=text-end><?=dec($vNF)?>
<?php if($difAliqICMS!==0 || $st!==0): ?>
    <tr class=fw-semibold><td><td><td>Diferença de Alíquota de ICMS<td><td><td class=text-end><?=dec($difAliqICMS)?>
    <tr class=fw-semibold><td><td><td>Substituição Tributária<td><td><td class=text-end><?=dec($st)?>
    <tr class=fw-semibold><td><td><td>Total a conferir<td><td><td class=text-end><?=dec($difAliqICMS+$vNF+$st)?>
<?php endif; ?>
</table>
<table class="table table-striped table-sm">
    <th style="max-width:50px">Cforn
    <th style="width:50px text-end">Cod
    <th style="width:330px">Produto
    <th class=text-end>Qt
    <th class=text-end>Custo
    <th class=text-end>Total
<?php foreach($previa as $p): ?>
    <tr><td style="max-width:80px" class=text-end><?=$p->codforn?>
        <td style="max-width:50px" class=text-end><?=$p->codprod?>
        <td style="max-width:330px" class="overflow-hidden" ><?=$p->prod?>
        <td>
            <form method=post action=?NF.qt>
                <input name=qt value='<?=$p->qt?>' class="inv text-end" size='1' onchange=submit()>
                <input type=hidden name=id value='<?=$p->id?>'>
            </form>
        <td <?=$p->class?> onclick="atualizar(<?=$p->custoatual?>,<?=$p->custoanterior?>,<?=$p->codprod?>)"><?=dec($p->custoatual)?>
        <td class=text-end><?=dec($p->custototal)?>
<?php endforeach; ?>
<tr class=fw-semibold><td><td><td>Total dos itens<td><td></td><td class=text-end><?=dec($soma)?>
</table>
<div>
Enviar tudo para o banco de dados
<form action=?NF.incluir method=post>
    <input name=lcto placeholder="Número do Lançamento" required>
    <input type=submit>
</form>
</div>

 

Link para o comentário
Compartilhar em outros sites

  • 0

Olá, @Irroration!

Se as notas fiscais que você deseja importar seguem um padrão fixo, existem algumas formas de extrair os dados para planilhas ou bancos de dados. Aqui estão algumas opções que podem te ajudar:

1. Conversão Manual para XML e Importação

  • Se o PDF contém um layout de NF-e, você pode tentar recuperar o XML da nota fiscal no site da SEFAZ e importar diretamente os dados.
  • Caso tenha apenas o PDF, ferramentas como Convertio ou iLovePDF podem ajudar na conversão para CSV/Excel.

2. Ferramentas para Extração Automática de Dados

📌 Tabula (Gratuito e Open Source) – Se as notas fiscais possuem tabelas bem estruturadas, o Tabula consegue extrair os dados diretamente do PDF para Excel.
📌 PDFTables – Serviço online que converte PDFs estruturados em planilhas editáveis.
📌 PyPDF2 (Python) – Se precisar de um método programático, bibliotecas como PyPDF2 ou PDFPlumber conseguem extrair textos de PDFs para manipulação em Python.

3. Integração com Sistemas de Gestão

Se você precisa importar essas notas frequentemente para SQL, PHP ou Access, uma solução mais eficiente seria usar um sistema que automatize a importação e elimine o trabalho manual. Algumas empresas utilizam essa solução de gestão para automação de notas fiscais, que facilita a extração e o processamento de dados.

Se puder detalhar mais o formato das notas e a estrutura de dados que precisa extrair, posso sugerir soluções mais específicas! 🚀

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,4k
    • Posts
      652,2k
×
×
  • Criar Novo...