Ir para conteúdo
  • Cadastre-se

Recommended Posts

Postado

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

  • Curtir 2
  • Consultores
Postado

Tarefa ACBR-8725. topico vinculado.

Obrigado pela contribuição

image.png

Alexandre de Paula
Gerente de Projetos
Ajude o Projeto ACBr crescer - Assine o Clube PRO                    

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  ícone Discórdia Discord   

Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil

 

 

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 conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.

The popup will be closed in 10 segundos...