Leonardo Gregianin Postado Quinta as 04:50 Postado Quinta as 04:50 Suporte a DANFSe v2.0 (NT 008 SE/CGNFS-e) no motor FPDF Contexto / Motivação O leiaute do DANFSe para o Sistema Nacional NFS-e (Ambiente de Dados Nacional) mudou com a NT 008/SE-CGNFS-e — a versão anterior do ACBr.DANFSeX.FPDFA4Retrato (leiaute municipal/ABRASF) não é compatível com o layout exigido para proPadraoNacional. Este PR adiciona um renderer dedicado, no mesmo motor de relatórios (ACBr_fpdf_report/ACBr_fpdf_ext), sem introduzir dependência de bibliotecas de terceiros. Escopo Arquivo novo: Componentes/ACBr/Fontes/ACBrDFe/ACBrNFSeX/DANFSE/FPDF/ACBr.DANFSeX.FPDFPadraoNacional.pas Nova classe TACBrDANFSeFPDFPadraoNacional = class(TFPDFReport), ~1600 linhas. Segue a mesma convenção arquitetural de TACBrDANFSeFPDFA4Retrato (construtor Create(ANFSe: TNFSe), SalvarPDF overloads), mas com um pipeline de bandas (AddBand) próprio, mapeado 1:1 ao Anexo I da NT 008. Arquivos alterados: ACBrNFSeXDANFSeFPDFClass.pas — ExecutaImpressaoPDFUmaNFSe passa a bifurcar por Configuracoes.Geral.Provedor = proPadraoNacional, delegando para o novo renderer; demais provedores continuam no TACBrDANFSeFPDFA4Retrato (comportamento preservado, zero mudança de rota para quem já usa o leiaute municipal). Pacotes/Delphi/ACBrDFe/ACBrNFSeX/DANFSE/FPDF/ACBr_NFSeXDanfseFPDF.dpk — adicionada a unit nova ao contains. Decisões de design relevantes para revisão 1. Grade de campos sem bordas verticais (fidelidade ao gerador oficial) O PDF gerado pelo Sefin Nacional não desenha grade por célula — só linhas horizontais nos limites de bloco (btPageHeader a btPageHeader) e preenchimento cinza claro (5% K) na célula-título, sem traço vertical algum entre colunas (validado extraindo os page.get_drawings() de um PDF de referência real via PyMuPDF: 22 operações vetoriais na página inteira). A implementação original deste PR desenhava uma TFPDF.Rect completa por campo (~800 operações/página). Foi refeita para reproduzir o padrão oficial: DesenharCampo não desenha borda nenhuma (só preenchimento quando Sombreado=True); um único DesenharLinhaSeparadora (uma PDF.Line horizontal) fecha cada bloco. Cuidado de ordem de desenho: a linha separadora é emitida depois do preenchimento cinza do título de bloco (não antes) — como ambos ocupam Y=0 do banda, desenhar a linha primeiro faz o fill cinza pintar por cima e apagá-la. Resultado final: 24 operações/página (a diferença de 2 vs. o oficial é só o modo de desenho do próprio QR Code, ver item 4). 2. Motor de bandas (TFPDFReport/AddBand) Confirmado por leitura de ACBr_fpdf_report.pas: a altura passada a AddBand é a declarada, não a real desenhada — usada pelo motor para posicionar a próxima banda (DrawBand). Cada CalcAltura* precisa bater exatamente com o que o Banda* correspondente desenha, senão sobra/falta espaço entre blocos. btPageFooter ancora sempre no rodapé da página independente do conteúdo acima (DrawLastBands) — por isso todos os blocos fluem em btPageHeader (sequencial) exceto Informações Complementares (btData, altura dinâmica = espaço livre) e Canhoto (btPageFooter, fixo no rodapé), replicando o comportamento observado no gerador oficial (Informações Complementares estica até o Canhoto). 3. Logomarca — sem asset embutido, seguindo convenção já usada no ACBr LogoNFSe: string (caminho de arquivo ou conteúdo binário bruto) — mesmo nome/tipo já declarado em TACBrNFSeXDANFSeClass.LogoNFSe e mesma semântica de TDFeReportFortes.CarregarLogo (usado por NFe/CTe/MDFe/NF3e/NFCom). Sem valor padrão embutido: se vazio, o espaço do cabeçalho fica em branco. 4. QR Code Conteúdo montado a partir de cURLConsultaPublica + ChaveDeAcesso — TNFSe.Link não é preenchido pelo parser do Padrão Nacional (PadraoNacional.LerXml.pas), então o gate de exibição usa infNFSe.ID/ChaveAcesso, não Link. Desenhado via PDF.QRCode (módulo a módulo, retângulos vetoriais pretos) — diferente do PDF oficial, que parece embutir o QR como imagem rasterizada única. Funcionalmente equivalente (QR válido, testado com leitor), mas gera ~700 operações vetoriais extras por página; não normalizado neste PR — encaminhar como possível otimização futura se ACBr_fpdf_ext ganhar suporte a inserir QR como imagem. 5. Mapeamento de fontes NT 008 item 2.4 exige Arial (labels) e Microsoft Sans Serif (conteúdo) — nenhuma é fonte core do FPDF. Mapeadas para 'Arial' (alias interno resolvido para Helvetica core) até que TTFs sejam embarcadas via AddFont. Sinalizar para revisão: isso é uma aproximação visual, não 100% NT-008-literal; embarcar as TTFs certas teria implicação de licenciamento a avaliar antes. 6. Campos dinâmicos por bloco (Tomador/Destinatário/Intermediário/Tributação Municipal) Cada bloco tem duas formas de renderização: grade completa (quando há dado) ou uma única linha "vazia" central (DesenharLinhaVazia, sem grade, mensagem fixa conforme NT 008 itens 2.3/2.5 — ex. TOMADOR/ADQUIRENTE DA OPERACAO NAO IDENTIFICADO NA NFS-e), replicando o padrão do gerador oficial para blocos suprimidos. Exemplo de uso: program ExemploDANFSeComLogo; {$APPTYPE CONSOLE} uses SysUtils, Classes, ACBrNFSeX, ACBrNFSeXConversao, ACBrNFSeXDANFSeFPDFClass, ACBrNFSeXClass; var iNFSe: TACBrNFSeX; DANFSeFPDF: TACBrNFSeXDANFSeFPDF; begin iNFSe := TACBrNFSeX.Create(nil); DANFSeFPDF := TACBrNFSeXDANFSeFPDF.Create(nil); try iNFSe.DANFSE := DANFSeFPDF; iNFSe.SetProvedor(proPadraoNacional); // LogoNFSe e' herdada de TACBrNFSeXDANFSeClass (mesma propriedade usada // por NFe/CTe/MDFe/etc via TDFeReportFortes.CarregarLogo) - aceita // caminho de arquivo... DANFSeFPDF.LogoNFSe := 'C:\CargoPro\Recursos\logo-nfse-horizontal.png'; // ...ou, se preferir nao depender de um arquivo solto no disco, o // conteudo binario da imagem direto na string (ver CarregarLogoNFSeBytes // em ACBr.DANFSeX.FPDFPadraoNacional.pas: se FileExists falhar, o valor // e' tratado como o proprio conteudo do arquivo, nao um caminho): // // var // LogoBytes: TBytes; // begin // TFile.ReadAllBytes(...) ou carregar de um resource (RCDATA) do exe; // DANFSeFPDF.LogoNFSe := TEncoding.ANSI.GetString(LogoBytes); // cuidado com encoding, ver nota abaixo iNFSe.NotasFiscais.Clear; iNFSe.NotasFiscais.LoadFromFile('C:\CargoPro\exemplos\nfse\minha-nota.xml'); DANFSeFPDF.PathPDF := 'C:\CargoPro\Saida'; DANFSeFPDF.Sistema := 'CargoPro'; DANFSeFPDF.ImprimirDANFSe; WriteLn('OK -> ', DANFSeFPDF.ArquivoPDF); finally DANFSeFPDF.Free; iNFSe.Free; end; end. ACBrNFSeXDANFSeFPDFClass.pas ACBr.DANFSeX.FPDFPadraoNacional.pas ACBr_NFSeXDanfseFPDF.dpk 2 [email protected] | https://leonardogregianin.com | https://www.robonfse.com.br
Fundadores Daniel Simoes Postado Quinta as 14:21 Fundadores Postado Quinta as 14:21 Muito obrigado pela contribuição @Leonardo Gregianin @Alexandre de Paula, creio que já temos uma tarefa para essa finalidade... Essa contribuição irá nos ajudar muito 1 Daniel Simões de Almeida O melhor TEF, é com o Projeto ACBr - Clique e Conheça Ajude o Projeto ACBr crescer - Assine o SAC (15) 2105-0750 (15)99790-2976.
Consultores Alexandre.Paula Postado Quinta as 14:25 Consultores Postado Quinta as 14:25 Tarefa ACBR-8725. topico vinculado. Obrigado pela contribuição Alexandre de Paula Gerente de Projetos Ajude o Projeto ACBr crescer - Assine o Clube PRO (15) 2105-0750 (15)99790-2976. Discord Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil
Recommended Posts
Crie uma conta ou entre para comentar
Você precisar ser um membro para fazer um comentário
Criar uma conta
Crie uma nova conta em nossa comunidade. É fácil!
Crie uma nova contaEntrar
Já tem uma conta? Faça o login.
Entrar Agora