diff --git a/DFe.Testes/Gerais/DanfePdfClownChaveAlfanumericaTestes.cs b/DFe.Testes/Gerais/DanfePdfClownChaveAlfanumericaTestes.cs
index 1599753fa..10107b6be 100644
--- a/DFe.Testes/Gerais/DanfePdfClownChaveAlfanumericaTestes.cs
+++ b/DFe.Testes/Gerais/DanfePdfClownChaveAlfanumericaTestes.cs
@@ -72,5 +72,37 @@ public void Gerar_DanfeComChave_ProduzPdf(string chaveAcesso)
}
}
}
+
+ [TestMethod]
+ public void Gerar_DanfeComTributosRtc_ProduzPdf()
+ {
+ var model = CriarViewModelMinimo("23190811820016000167650010000000221100000227");
+ model.Emitente.CRT = "3";
+ model.ExibirTributosRtc = true;
+ model.CalculoImposto.ValorIbsUf = 0.01m;
+ model.CalculoImposto.ValorIbsMunicipio = 0.02m;
+ model.CalculoImposto.ValorCbs = 0.09m;
+ model.CalculoImposto.ValorImpostoSeletivo = 0.20m;
+ model.Produtos.Add(new ProdutoViewModel
+ {
+ Codigo = "1", Descricao = "PRODUTO DE TESTE", Ncm = "12345678",
+ ClassificacaoTributariaIbsCbs = "000001", Cfop = 5102,
+ Unidade = "UN", Quantidade = 1, ValorUnitario = 10, ValorTotal = 10,
+ BaseIbsCbs = 10m, AliquotaIbsUf = 0.10m, AliquotaIbsMunicipio = 0.05m,
+ AliquotaCbs = 0.90m, ValorIbsUf = 0.01m, ValorIbsMunicipio = 0.02m,
+ ValorCbs = 0.09m, BaseImpostoSeletivo = 10m,
+ AliquotaImpostoSeletivo = 2m, ValorImpostoSeletivo = 0.20m
+ });
+
+ using (var danfe = new DanfeDoc(model))
+ using (var stream = new MemoryStream())
+ {
+ danfe.Gerar();
+ danfe.Salvar(stream);
+ var bytes = stream.ToArray();
+ Assert.IsTrue(bytes.Length > 1000);
+ Assert.AreEqual("%PDF", System.Text.Encoding.ASCII.GetString(bytes, 0, 4));
+ }
+ }
}
}
diff --git a/DFe.Testes/Gerais/DanfeRtcLeituraTestes.cs b/DFe.Testes/Gerais/DanfeRtcLeituraTestes.cs
new file mode 100644
index 000000000..7868414d7
--- /dev/null
+++ b/DFe.Testes/Gerais/DanfeRtcLeituraTestes.cs
@@ -0,0 +1,52 @@
+// Copyright (c) colaboradores do DFe.NET. Licença LGPL-2.1-or-later; consulte LICENSE.
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NFe.Danfe.PdfClown.Modelo;
+
+namespace DFe.Testes.Gerais
+{
+ /// Verifica leitura de grupos opcionais e preservação dos valores do XML da RTC.
+ [TestClass]
+ public class DanfeRtcLeituraTestes
+ {
+ private static string Xml(string imposto, string total) => @"
+
+55111121
+11222333000181TESTE1
+11222333000181TESTE
+1TESTE51021100100
+0102" + imposto + @"
+100100" + total + @"9
+21000000000000000002026-11-02T12:00:00-03:00";
+
+ /// Ausência de RTC não deve gerar valores ou ativar o novo layout.
+ [TestMethod]
+ public void DadoXmlSemRtc_QuandoLer_EntaoPreservaAusencia()
+ {
+ var modelo = DanfeViewModel.CreateFromXmlString(Xml("", ""));
+ Assert.IsFalse(modelo.ExibirTributosRtc);
+ Assert.IsNull(modelo.Produtos[0].BaseIbsCbs);
+ Assert.IsNull(modelo.CalculoImposto.ValorCbs);
+ Assert.IsTrue(modelo.Produtos[0].PossuiCsosn);
+ }
+
+ /// Alíquota efetiva zero deve prevalecer sobre a nominal.
+ [TestMethod]
+ public void DadoReducaoIntegral_QuandoLer_EntaoPreservaAliquotaEfetivaZero()
+ {
+ var modelo = DanfeViewModel.CreateFromXmlString(Xml(@"200200001100
+0.100
+0.90.360.36
+10022", @"20.3612.345.67.899.87"));
+ Assert.IsTrue(modelo.ExibirTributosRtc);
+ Assert.AreEqual(0m, modelo.Produtos[0].AliquotaIbsUf);
+ Assert.AreEqual(0.36m, modelo.Produtos[0].AliquotaCbs);
+ Assert.IsNull(modelo.Produtos[0].AliquotaIbsMunicipio);
+ Assert.AreEqual(2m, modelo.Produtos[0].ValorImpostoSeletivo);
+ Assert.AreEqual(2m, modelo.CalculoImposto.ValorImpostoSeletivo);
+ Assert.AreEqual(12.3m, modelo.CalculoImposto.ValorIbsMono);
+ Assert.AreEqual(45.6m, modelo.CalculoImposto.ValorCbsMono);
+ Assert.AreEqual(7.89m, modelo.CalculoImposto.ValorIbsMonoReten);
+ Assert.AreEqual(9.87m, modelo.CalculoImposto.ValorCbsMonoReten);
+ }
+ }
+}
diff --git a/NFe.Danfe.PdfClown/Blocos/BlocoCalculoImposto.cs b/NFe.Danfe.PdfClown/Blocos/BlocoCalculoImposto.cs
index 9875512fc..c428f7aed 100644
--- a/NFe.Danfe.PdfClown/Blocos/BlocoCalculoImposto.cs
+++ b/NFe.Danfe.PdfClown/Blocos/BlocoCalculoImposto.cs
@@ -9,6 +9,22 @@ class BlocoCalculoImposto : BlocoBase
public BlocoCalculoImposto(DanfeViewModel viewModel, Estilo estilo) : base(viewModel, estilo)
{
var m = ViewModel.CalculoImposto;
+ if (ViewModel.ExibirTributosRtc)
+ {
+ AdicionarLinhaCampos()
+ .ComCampoNumerico("BASE DE CÁLCULO DO ICMS", m.BaseCalculoIcms)
+ .ComCampoNumerico("VALOR DO ICMS", m.ValorIcms)
+ .ComCampoNumerico("BASE DE CÁLCULO DO ICMS ST", m.BaseCalculoIcmsSt)
+ .ComCampoNumerico("VALOR DO ICMS ST", m.ValorIcmsSt)
+ .ComCampoNumerico("VALOR DO IPI", m.ValorIpi)
+ .ComLargurasIguais();
+ if (ViewModel.ExibirIcmsInterestadual && (m.vICMSUFDest.HasValue || m.vFCPUFDest.HasValue))
+ AdicionarLinhaCampos()
+ .ComCampoNumerico("VALOR DO DIFAL NA UF DE DESTINO", m.vICMSUFDest)
+ .ComCampoNumerico("VALOR DO FCP NA UF DE DESTINO", m.vFCPUFDest)
+ .ComLargurasIguais();
+ return;
+ }
var l = AdicionarLinhaCampos()
.ComCampoNumerico("BASE DE CÁLC. DO ICMS", m.BaseCalculoIcms)
@@ -54,6 +70,6 @@ public BlocoCalculoImposto(DanfeViewModel viewModel, Estilo estilo) : base(viewM
}
public override PosicaoBloco Posicao => PosicaoBloco.Topo;
- public override string Cabecalho => "Cálculo do Imposto";
+ public override string Cabecalho => ViewModel.ExibirTributosRtc ? "TOTAL DO ICMS / IPI" : "Cálculo do Imposto";
}
}
diff --git a/NFe.Danfe.PdfClown/Blocos/BlocoCalculoIssqn.cs b/NFe.Danfe.PdfClown/Blocos/BlocoCalculoIssqn.cs
index 04d05df55..f47c54396 100644
--- a/NFe.Danfe.PdfClown/Blocos/BlocoCalculoIssqn.cs
+++ b/NFe.Danfe.PdfClown/Blocos/BlocoCalculoIssqn.cs
@@ -18,7 +18,7 @@ public BlocoCalculoIssqn(DanfeViewModel viewModel, Estilo estilo) : base(viewMod
.ComLargurasIguais();
}
- public override PosicaoBloco Posicao => PosicaoBloco.Base;
+ public override PosicaoBloco Posicao => ViewModel.ExibirTributosRtc ? PosicaoBloco.Topo : PosicaoBloco.Base;
public override string Cabecalho => "CÁLCULO DO ISSQN";
}
}
diff --git a/NFe.Danfe.PdfClown/Blocos/BlocoIdentificacaoEmitente.cs b/NFe.Danfe.PdfClown/Blocos/BlocoIdentificacaoEmitente.cs
index 5e55e9546..e74e12bc4 100644
--- a/NFe.Danfe.PdfClown/Blocos/BlocoIdentificacaoEmitente.cs
+++ b/NFe.Danfe.PdfClown/Blocos/BlocoIdentificacaoEmitente.cs
@@ -54,6 +54,12 @@ public BlocoIdentificacaoEmitente(DanfeViewModel viewModel, Estilo estilo) : bas
.ComCampo("Cnpj", Formatador.FormatarCnpj(ViewModel.Emitente.CnpjCpf), AlinhamentoHorizontal.Centro)
.ComLargurasIguais();
+ if (ViewModel.ExibirTributosRtc)
+ AdicionarLinhaCampos()
+ .ComCampo("Código do Regime Tributário", ViewModel.Emitente.CRT)
+ .ComCampo("Tipo de Regime de Apuração do IBS e da CBS", "")
+ .ComLargurasIguais();
+
}
public XObject Logo
diff --git a/NFe.Danfe.PdfClown/Blocos/BlocoTotalIbsCbsIs.cs b/NFe.Danfe.PdfClown/Blocos/BlocoTotalIbsCbsIs.cs
new file mode 100644
index 000000000..a2f2e3933
--- /dev/null
+++ b/NFe.Danfe.PdfClown/Blocos/BlocoTotalIbsCbsIs.cs
@@ -0,0 +1,36 @@
+// Copyright (c) colaboradores do DFe.NET. Licença LGPL-2.1-or-later; consulte LICENSE.
+using NFe.Danfe.PdfClown.Elementos;
+using NFe.Danfe.PdfClown.Enumeracoes;
+using NFe.Danfe.PdfClown.Modelo;
+
+namespace NFe.Danfe.PdfClown.Blocos
+{
+ /// Bloco de totais do DANFE conforme a NT 2026.010.
+ internal class BlocoTotalIbsCbsIs : BlocoBase
+ {
+ public BlocoTotalIbsCbsIs(DanfeViewModel viewModel, Estilo estilo) : base(viewModel, estilo)
+ {
+ var m = viewModel.CalculoImposto;
+ var linha = AdicionarLinhaCampos()
+ .ComCampoNumerico("VALOR DA CBS", (double?)m.ValorCbs)
+ .ComCampoNumerico("VALOR DO IBS UF", (double?)m.ValorIbsUf)
+ .ComCampoNumerico("VALOR DO IBS MUNICÍPIO", (double?)m.ValorIbsMunicipio)
+ .ComCampoNumerico("VALOR DO IMPOSTO SELETIVO", (double?)m.ValorImpostoSeletivo)
+ .ComLargurasIguais();
+
+ if (m.ValorIbsMono.HasValue || m.ValorCbsMono.HasValue ||
+ m.ValorIbsMonoReten.HasValue || m.ValorCbsMonoReten.HasValue)
+ {
+ AdicionarLinhaCampos()
+ .ComCampoNumerico("VALOR DO IBS MONOFÁSICO", (double?)m.ValorIbsMono)
+ .ComCampoNumerico("VALOR DA CBS MONOFÁSICA", (double?)m.ValorCbsMono)
+ .ComCampoNumerico("IBS MONOFÁSICO POR RETENÇÃO", (double?)m.ValorIbsMonoReten)
+ .ComCampoNumerico("CBS MONOFÁSICA POR RETENÇÃO", (double?)m.ValorCbsMonoReten)
+ .ComLargurasIguais();
+ }
+ }
+
+ public override PosicaoBloco Posicao => PosicaoBloco.Topo;
+ public override string Cabecalho => "Total do IBS/CBS/IS";
+ }
+}
diff --git a/NFe.Danfe.PdfClown/Blocos/BlocoTotalProdutosNota.cs b/NFe.Danfe.PdfClown/Blocos/BlocoTotalProdutosNota.cs
new file mode 100644
index 000000000..3e9f5f4b7
--- /dev/null
+++ b/NFe.Danfe.PdfClown/Blocos/BlocoTotalProdutosNota.cs
@@ -0,0 +1,27 @@
+// Copyright (c) colaboradores do DFe.NET. Licença LGPL-2.1-or-later; consulte LICENSE.
+using NFe.Danfe.PdfClown.Elementos;
+using NFe.Danfe.PdfClown.Enumeracoes;
+using NFe.Danfe.PdfClown.Modelo;
+
+namespace NFe.Danfe.PdfClown.Blocos
+{
+ /// Bloco de totais do DANFE conforme a NT 2026.010.
+ internal class BlocoTotalProdutosNota : BlocoBase
+ {
+ public BlocoTotalProdutosNota(DanfeViewModel model, Estilo estilo) : base(model, estilo)
+ {
+ var m = model.CalculoImposto;
+ AdicionarLinhaCampos()
+ .ComCampoNumerico("VALOR TOTAL DOS PRODUTOS", m.ValorTotalProdutos)
+ .ComCampoNumerico("VALOR DO FRETE", m.ValorFrete)
+ .ComCampoNumerico("VALOR DO SEGURO", m.ValorSeguro)
+ .ComCampoNumerico("DESCONTO", m.Desconto)
+ .ComCampoNumerico("OUTRAS DESPESAS", m.OutrasDespesas)
+ .ComLargurasIguais();
+ AdicionarLinhaCampos().ComCampoNumerico("VALOR TOTAL DA NOTA", m.ValorTotalNota).ComLargurasIguais();
+ }
+
+ public override PosicaoBloco Posicao => PosicaoBloco.Topo;
+ public override string Cabecalho => "TOTAL DOS PRODUTOS E TOTAL DA NOTA";
+ }
+}
diff --git a/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs b/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs
index 67557c0d7..0464d25c0 100644
--- a/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs
+++ b/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs
@@ -25,7 +25,19 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es
Tabela = new Tabela(Estilo);
var cabecalho4 = ViewModel.Emitente.CRT == "3" ? "O/CST" : "O/CSOSN";
- if (ViewModel.Orientacao == Orientacao.Retrato)
+ if (ViewModel.ExibirTributosRtc)
+ {
+ Tabela
+ .ComColuna(0, ae, "DESCRIÇÃO / NCM / CLASS. TRIB.")
+ .ComColuna(7F, ac, "ORIG. / CST", "CSOSN / CFOP")
+ .ComColuna(7F, ad, "QTD / UN")
+ .ComColunaDeValor(8F, ad, "VLR UNIT.")
+ .ComColunaDeValor(8F, ad, "VLR TOTAL")
+ .ComColunaTributos(14F, "BASES DE CÁLCULO")
+ .ComColunaTributos(17F, "ALÍQUOTAS")
+ .ComColunaTributos(21F, "VALOR DOS TRIBUTOS");
+ }
+ else if (ViewModel.Orientacao == Orientacao.Retrato)
{
Tabela
.ComColuna(8.5f, ac, "CÓDIGO", "PRODUTO")
@@ -43,7 +55,7 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es
.ComColunaDeValor(3.5F, ad, "ALIQ.", "ICMS")
.ComColunaDeValor(3.5F, ad, "ALIQ.", "IPI");
}
- if (ViewModel.Orientacao == Orientacao.Paisagem)
+ else if (ViewModel.Orientacao == Orientacao.Paisagem)
{
Tabela
.ComColuna(8.1f, ac, "CÓDIGO PRODUTO")
@@ -66,6 +78,27 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es
foreach (var p in ViewModel.Produtos)
{
+ if (ViewModel.ExibirTributosRtc)
+ {
+ Tabela.AdicionarLinha(new List
+ {
+ p.DescricaoCompleta + "\nNCM " + p.Ncm +
+ (string.IsNullOrEmpty(p.ClassificacaoTributariaIbsCbs) ? "" : " / cClassTrib " + p.ClassificacaoTributariaIbsCbs),
+ (p.PossuiCsosn ? "O/CSOSN " : "O/CST ") + p.OCst + "\nCFOP " + p.Cfop.ToString(),
+ p.Quantidade.Formatar() + "\n[" + p.Unidade + "]",
+ p.ValorUnitario.Formatar(),
+ p.ValorTotal.Formatar(),
+ "ICMS\t" + Numero(p.BaseIcms) + "\nIBS/CBS\t" + Numero(p.BaseIbsCbs) +
+ "\nIS\t" + Numero(p.BaseImpostoSeletivo) + "\nIPI\t" + Numero(p.BaseIpi),
+ "ICMS\t" + Percentual(p.AliquotaIcms) + "\tCBS\t" + Percentual(p.AliquotaCbs) +
+ "\nIBS UF\t" + Percentual(p.AliquotaIbsUf) + "\tIPI\t" + Percentual(p.AliquotaIpi) +
+ "\nIBS MUN\t" + Percentual(p.AliquotaIbsMunicipio) + "\tIS\t" + Percentual(p.AliquotaImpostoSeletivo),
+ "ICMS\t" + Numero(p.ValorIcms) + "\tCBS\t" + Numero(p.ValorCbs) +
+ "\nIBS UF\t" + Numero(p.ValorIbsUf) + "\tIPI\t" + Numero(p.ValorIpi) +
+ "\nIBS MUN\t" + Numero(p.ValorIbsMunicipio) + "\tIS\t" + Numero(p.ValorImpostoSeletivo)
+ });
+ continue;
+ }
var linha = new List
{
p.Codigo,
@@ -88,6 +121,11 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es
}
}
+ private static string Numero(decimal? valor) => valor?.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("pt-BR")) ?? "";
+ private static string Numero(double? valor) => valor?.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("pt-BR")) ?? "";
+ private static string Percentual(decimal? valor) => valor.HasValue ? Numero(valor) + "%" : "";
+ private static string Percentual(double? valor) => valor.HasValue ? Numero(valor) + "%" : "";
+
public override void Draw(Gfx gfx)
{
base.Draw(gfx);
diff --git a/NFe.Danfe.PdfClown/DanfeDoc.cs b/NFe.Danfe.PdfClown/DanfeDoc.cs
index 354b1c03a..1480b1978 100644
--- a/NFe.Danfe.PdfClown/DanfeDoc.cs
+++ b/NFe.Danfe.PdfClown/DanfeDoc.cs
@@ -62,11 +62,17 @@ public DanfeDoc(DanfeViewModel viewModel)
if (ViewModel.Duplicatas.Count > 0)
AdicionarBloco();
- AdicionarBloco(ViewModel.Orientacao == Orientacao.Paisagem ? EstiloPadrao : CriarEstilo(4.75F));
+ if (ViewModel.ExibirTributosRtc)
+ AdicionarBloco(CriarEstilo(6F, 8F));
+ AdicionarBloco(ViewModel.ExibirTributosRtc ? CriarEstilo(6F, 8F) : ViewModel.Orientacao == Orientacao.Paisagem ? EstiloPadrao : CriarEstilo(4.75F));
+ if (ViewModel.ExibirTributosRtc)
+ AdicionarBloco(CriarEstilo(6F, 8F));
+ if (ViewModel.ExibirTributosRtc && ViewModel.CalculoIssqn.Mostrar)
+ AdicionarBloco();
AdicionarBloco();
AdicionarBloco(CriarEstilo(tFonteCampoConteudo: 8));
- if (ViewModel.CalculoIssqn.Mostrar)
+ if (ViewModel.CalculoIssqn.Mostrar && !ViewModel.ExibirTributosRtc)
AdicionarBloco();
AdicionarMetadata();
diff --git a/NFe.Danfe.PdfClown/Elementos/Tabela.cs b/NFe.Danfe.PdfClown/Elementos/Tabela.cs
index f847c3aae..6a318a78f 100644
--- a/NFe.Danfe.PdfClown/Elementos/Tabela.cs
+++ b/NFe.Danfe.PdfClown/Elementos/Tabela.cs
@@ -70,6 +70,13 @@ public void AdicionarLinha(List linha)
Linhas.Add(linha);
}
+ /// Adiciona coluna com pares rótulo/valor separados por tabulação em cada linha.
+ public Tabela ComColunaTributos(float largura, params string[] cabecalho)
+ {
+ Colunas.Add(new TabelaColuna(cabecalho, largura) { RotulosEValores = true });
+ return this;
+ }
+
public void AjustarLarguraColunas()
{
var sw = Colunas.Sum(x => x.PorcentagemLargura);
@@ -120,6 +127,8 @@ private Boolean DesenharLinha(Gfx gfx)
_DY1 = _DY;
TextBlock[] tb = new TextBlock[Colunas.Count];
+ var camposTributos = new List();
+ float alturaTributos = 0;
for (int i = 0; i < Colunas.Count; i++)
{
@@ -128,6 +137,47 @@ private Boolean DesenharLinha(Gfx gfx)
float w = (Width * c.PorcentagemLargura) / 100F;
+ if (c.RotulosEValores)
+ {
+ float y = _DY + PaddingSuperior;
+ foreach (var linha in v.Split('\n'))
+ {
+ var campos = linha.Split('\t');
+ int pares = campos.Length / 2;
+ float larguraCelula = w - 2 * PaddingHorizontal;
+ float alturaLinha = FonteCorpo.AlturaLinha;
+ for (int par = 0; par < pares; par++)
+ {
+ float larguraPar = pares == 2 ? larguraCelula * (par == 0 ? 0.56F : 0.44F) : larguraCelula;
+ string rotulo = campos[par * 2];
+ string valor = campos[par * 2 + 1];
+ float inicio = x + PaddingHorizontal + (par == 0 ? 0 : larguraCelula * 0.56F);
+ float larguraRotulo = FonteCorpo.MedirLarguraTexto(rotulo) + 0.7F;
+ float larguraValor = FonteCorpo.MedirLarguraTexto(valor);
+ bool empilhar = larguraRotulo + larguraValor > larguraPar - 1.2F;
+ var titulo = new TextBlock(rotulo, FonteCorpo)
+ {
+ X = inicio, Y = y, Width = larguraPar - 1.2F,
+ AlinhamentoHorizontal = AlinhamentoHorizontal.Esquerda
+ };
+ var numero = new TextBlock(valor, FonteCorpo)
+ {
+ X = inicio + (empilhar ? 0 : larguraRotulo),
+ Y = y + (empilhar ? titulo.Height : 0),
+ Width = larguraPar - 1.2F - (empilhar ? 0 : larguraRotulo),
+ AlinhamentoHorizontal = AlinhamentoHorizontal.Direita
+ };
+ camposTributos.Add(titulo);
+ if (!string.IsNullOrEmpty(valor)) camposTributos.Add(numero);
+ alturaLinha = Math.Max(alturaLinha, numero.Y - y + numero.Height);
+ }
+ y += alturaLinha + 0.5F;
+ }
+ alturaTributos = Math.Max(alturaTributos, y - (_DY + PaddingSuperior));
+ x += w;
+ continue;
+ }
+
if (!string.IsNullOrWhiteSpace(v))
{
float larguraUtil = w - 2F * Estilo.PaddingHorizontal;
@@ -145,7 +195,7 @@ private Boolean DesenharLinha(Gfx gfx)
}
- var tbm = tb.Where(t => t != null).Max(t => t.Height);
+ var tbm = Math.Max(alturaTributos, tb.Where(t => t != null).Select(t => t.Height).DefaultIfEmpty(0).Max());
if (tbm + _DY + PaddingInferior + PaddingSuperior > BoundingBox.Bottom) return false;
for (int i = 0; i < Colunas.Count; i++)
@@ -153,6 +203,8 @@ private Boolean DesenharLinha(Gfx gfx)
if (tb[i] != null)
tb[i].Draw(gfx);
}
+ foreach (var campo in camposTributos)
+ campo.Draw(gfx);
_DY += Math.Max(tbm, FonteCorpo.AlturaLinha) + PaddingSuperior + PaddingInferior;
diff --git a/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs b/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs
index 9a1c5c981..efcaf80c5 100644
--- a/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs
+++ b/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs
@@ -14,6 +14,8 @@ internal class TabelaColuna
/// em vez de ser quebrado no meio dos caracteres.
///
public bool AjustarFonteParaCaber { get; private set; }
+ /// Desenha pares de rótulos e valores em posições independentes na célula.
+ public bool RotulosEValores { get; set; }
public TabelaColuna(string[] cabecalho, float porcentagemLargura, AlinhamentoHorizontal alinhamentoHorizontal = AlinhamentoHorizontal.Esquerda, bool ajustarFonteParaCaber = false)
{
diff --git a/NFe.Danfe.PdfClown/Esquemas/ProcNFe.cs b/NFe.Danfe.PdfClown/Esquemas/ProcNFe.cs
index 5621cfeb0..05733f080 100644
--- a/NFe.Danfe.PdfClown/Esquemas/ProcNFe.cs
+++ b/NFe.Danfe.PdfClown/Esquemas/ProcNFe.cs
@@ -326,6 +326,90 @@ public partial class ProdutoImposto
public string vTotTrib { get; set; }
public ProdutoICMS ICMS { get; set; }
public ProdutoIPI IPI { get; set; }
+ public ImpostoSeletivo IS { get; set; }
+ public ImpostoIbsCbs IBSCBS { get; set; }
+ }
+
+ /// Dados de ImpostoSeletivo para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class ImpostoSeletivo
+ {
+ /// Conteúdo da tag vBCIS informado no XML; ausente permanece sem valor.
+ public decimal? vBCIS { get; set; }
+ /// Conteúdo da tag pIS informado no XML; ausente permanece sem valor.
+ public decimal? pIS { get; set; }
+ /// Conteúdo da tag vIS informado no XML; ausente permanece sem valor.
+ public decimal? vIS { get; set; }
+ }
+
+ /// Dados de ImpostoIbsCbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class ImpostoIbsCbs
+ {
+ /// Conteúdo da tag CST informado no XML; ausente permanece sem valor.
+ public string CST { get; set; }
+ /// Conteúdo da tag cClassTrib informado no XML; ausente permanece sem valor.
+ public string cClassTrib { get; set; }
+ /// Conteúdo da tag gIBSCBS informado no XML; ausente permanece sem valor.
+ public GrupoIbsCbs gIBSCBS { get; set; }
+ }
+
+ /// Dados de GrupoIbsCbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class GrupoIbsCbs
+ {
+ /// Conteúdo da tag vBC informado no XML; ausente permanece sem valor.
+ public decimal? vBC { get; set; }
+ /// Conteúdo da tag gIBSUF informado no XML; ausente permanece sem valor.
+ public GrupoIbsUf gIBSUF { get; set; }
+ /// Conteúdo da tag gIBSMun informado no XML; ausente permanece sem valor.
+ public GrupoIbsMunicipio gIBSMun { get; set; }
+ /// Conteúdo da tag gCBS informado no XML; ausente permanece sem valor.
+ public GrupoCbs gCBS { get; set; }
+ }
+
+ /// Dados de ReducaoAliquota para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class ReducaoAliquota
+ {
+ /// Conteúdo da tag pAliqEfet informado no XML; ausente permanece sem valor.
+ public decimal? pAliqEfet { get; set; }
+ }
+
+ /// Dados de GrupoIbsUf para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class GrupoIbsUf
+ {
+ /// Conteúdo da tag pIBSUF informado no XML; ausente permanece sem valor.
+ public decimal? pIBSUF { get; set; }
+ /// Conteúdo da tag gRed informado no XML; ausente permanece sem valor.
+ public ReducaoAliquota gRed { get; set; }
+ /// Conteúdo da tag vIBSUF informado no XML; ausente permanece sem valor.
+ public decimal? vIBSUF { get; set; }
+ }
+
+ /// Dados de GrupoIbsMunicipio para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class GrupoIbsMunicipio
+ {
+ /// Conteúdo da tag pIBSMun informado no XML; ausente permanece sem valor.
+ public decimal? pIBSMun { get; set; }
+ /// Conteúdo da tag gRed informado no XML; ausente permanece sem valor.
+ public ReducaoAliquota gRed { get; set; }
+ /// Conteúdo da tag vIBSMun informado no XML; ausente permanece sem valor.
+ public decimal? vIBSMun { get; set; }
+ }
+
+ /// Dados de GrupoCbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class GrupoCbs
+ {
+ /// Conteúdo da tag pCBS informado no XML; ausente permanece sem valor.
+ public decimal? pCBS { get; set; }
+ /// Conteúdo da tag gRed informado no XML; ausente permanece sem valor.
+ public ReducaoAliquota gRed { get; set; }
+ /// Conteúdo da tag vCBS informado no XML; ausente permanece sem valor.
+ public decimal? vCBS { get; set; }
}
///
@@ -547,6 +631,78 @@ public partial class Total
{
public ICMSTotal ICMSTot { get; set; }
public ISSQNTotal ISSQNtot { get; set; }
+ public TotalImpostoSeletivo ISTot { get; set; }
+ public TotalIbsCbs IBSCBSTot { get; set; }
+ }
+
+ /// Dados de TotalImpostoSeletivo para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalImpostoSeletivo
+ {
+ /// Conteúdo da tag vIS informado no XML; ausente permanece sem valor.
+ public decimal? vIS { get; set; }
+ }
+
+ /// Dados de TotalIbsCbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalIbsCbs
+ {
+ /// Conteúdo da tag gIBS informado no XML; ausente permanece sem valor.
+ public TotalIbs gIBS { get; set; }
+ /// Conteúdo da tag gCBS informado no XML; ausente permanece sem valor.
+ public TotalCbs gCBS { get; set; }
+ /// Conteúdo da tag gMono informado no XML; ausente permanece sem valor.
+ public TotalMonofasico gMono { get; set; }
+ }
+
+ /// Dados de TotalIbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalIbs
+ {
+ /// Conteúdo da tag vIBS informado no XML; ausente permanece sem valor.
+ public decimal? vIBS { get; set; }
+ /// Conteúdo da tag gIBSUF informado no XML; ausente permanece sem valor.
+ public TotalIbsUf gIBSUF { get; set; }
+ /// Conteúdo da tag gIBSMun informado no XML; ausente permanece sem valor.
+ public TotalIbsMunicipio gIBSMun { get; set; }
+ }
+
+ /// Dados de TotalIbsUf para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalIbsUf
+ {
+ /// Valor informado na tag vIBSUF do total da NF-e.
+ /// Conteúdo da tag vIBSUF informado no XML; ausente permanece sem valor.
+ public decimal? vIBSUF { get; set; }
+ }
+ /// Dados de TotalIbsMunicipio para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalIbsMunicipio
+ {
+ /// Valor informado na tag vIBSMun do total da NF-e.
+ /// Conteúdo da tag vIBSMun informado no XML; ausente permanece sem valor.
+ public decimal? vIBSMun { get; set; }
+ }
+ /// Dados de TotalCbs para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalCbs
+ {
+ /// Valor informado na tag vCBS do total da NF-e.
+ /// Conteúdo da tag vCBS informado no XML; ausente permanece sem valor.
+ public decimal? vCBS { get; set; }
+ }
+ /// Dados de TotalMonofasico para leitura e impressão do XML da NF-e.
+ [XmlType(Namespace = Namespaces.NFe)]
+ public class TotalMonofasico
+ {
+ /// Conteúdo da tag vIBSMono informado no XML; ausente permanece sem valor.
+ public decimal? vIBSMono { get; set; }
+ /// Conteúdo da tag vCBSMono informado no XML; ausente permanece sem valor.
+ public decimal? vCBSMono { get; set; }
+ /// Conteúdo da tag vIBSMonoReten informado no XML; ausente permanece sem valor.
+ public decimal? vIBSMonoReten { get; set; }
+ /// Conteúdo da tag vCBSMonoReten informado no XML; ausente permanece sem valor.
+ public decimal? vCBSMonoReten { get; set; }
}
diff --git a/NFe.Danfe.PdfClown/Modelo/CalculoImpostoViewModel.cs b/NFe.Danfe.PdfClown/Modelo/CalculoImpostoViewModel.cs
index 1dcf698a0..026bbeb9e 100644
--- a/NFe.Danfe.PdfClown/Modelo/CalculoImpostoViewModel.cs
+++ b/NFe.Danfe.PdfClown/Modelo/CalculoImpostoViewModel.cs
@@ -2,6 +2,23 @@
{
public class CalculoImpostoViewModel
{
+ /// Valor total da CBS informado em gCBS/vCBS.
+ public decimal? ValorCbs { get; set; }
+ /// Valor total do IBS da UF informado em gIBSUF/vIBSUF.
+ public decimal? ValorIbsUf { get; set; }
+ /// Valor total do IBS municipal informado em gIBSMun/vIBSMun.
+ public decimal? ValorIbsMunicipio { get; set; }
+ /// Valor total do Imposto Seletivo informado em ISTot/vIS.
+ public decimal? ValorImpostoSeletivo { get; set; }
+ /// Valor total do IBS monofásico informado em gMono/vIBSMono.
+ public decimal? ValorIbsMono { get; set; }
+ /// Valor total da CBS monofásica informado em gMono/vCBSMono.
+ public decimal? ValorCbsMono { get; set; }
+ /// Valor total do IBS monofásico por retenção.
+ public decimal? ValorIbsMonoReten { get; set; }
+ /// Valor total da CBS monofásica por retenção.
+ public decimal? ValorCbsMonoReten { get; set; }
+
///
/// Base de Cálculo do ICMS
/// Tag vBC
diff --git a/NFe.Danfe.PdfClown/Modelo/DanfeViewModel.cs b/NFe.Danfe.PdfClown/Modelo/DanfeViewModel.cs
index fa19aa3c2..ef7659759 100644
--- a/NFe.Danfe.PdfClown/Modelo/DanfeViewModel.cs
+++ b/NFe.Danfe.PdfClown/Modelo/DanfeViewModel.cs
@@ -142,6 +142,9 @@ public float Margem
///
public CalculoImpostoViewModel CalculoImposto { get; set; }
+ /// Indica que o XML contém grupos IBS/CBS ou IS a imprimir no DANFE.
+ public bool ExibirTributosRtc { get; set; }
+
///
/// Produtos da Nota Fiscal
///
diff --git a/NFe.Danfe.PdfClown/Modelo/DanfeViewModelCreator.cs b/NFe.Danfe.PdfClown/Modelo/DanfeViewModelCreator.cs
index 5de61dfee..88a7bfee3 100644
--- a/NFe.Danfe.PdfClown/Modelo/DanfeViewModelCreator.cs
+++ b/NFe.Danfe.PdfClown/Modelo/DanfeViewModelCreator.cs
@@ -244,6 +244,20 @@ public static DanfeViewModel CreateFromXml(ProcNFe procNfe)
if (imposto != null)
{
+ var ibsCbs = imposto.IBSCBS?.gIBSCBS;
+ produto.ClassificacaoTributariaIbsCbs = imposto.IBSCBS?.cClassTrib;
+ produto.BaseIbsCbs = ibsCbs?.vBC;
+ produto.AliquotaIbsUf = ibsCbs?.gIBSUF?.gRed?.pAliqEfet ?? ibsCbs?.gIBSUF?.pIBSUF;
+ produto.AliquotaIbsMunicipio = ibsCbs?.gIBSMun?.gRed?.pAliqEfet ?? ibsCbs?.gIBSMun?.pIBSMun;
+ produto.AliquotaCbs = ibsCbs?.gCBS?.gRed?.pAliqEfet ?? ibsCbs?.gCBS?.pCBS;
+ produto.ValorIbsUf = ibsCbs?.gIBSUF?.vIBSUF;
+ produto.ValorIbsMunicipio = ibsCbs?.gIBSMun?.vIBSMun;
+ produto.ValorCbs = ibsCbs?.gCBS?.vCBS;
+ produto.BaseImpostoSeletivo = imposto.IS?.vBCIS;
+ produto.AliquotaImpostoSeletivo = imposto.IS?.pIS;
+ produto.ValorImpostoSeletivo = imposto.IS?.vIS;
+ model.ExibirTributosRtc |= imposto.IBSCBS != null || imposto.IS != null;
+
if (imposto.ICMS != null)
{
var icms = imposto.ICMS.ICMS;
@@ -254,6 +268,7 @@ public static DanfeViewModel CreateFromXml(ProcNFe procNfe)
produto.BaseIcms = icms.vBC;
produto.AliquotaIcms = icms.pICMS;
produto.OCst = icms.orig + icms.CST + icms.CSOSN;
+ produto.PossuiCsosn = !string.IsNullOrEmpty(icms.CSOSN);
}
}
@@ -264,6 +279,7 @@ public static DanfeViewModel CreateFromXml(ProcNFe procNfe)
if (ipi != null)
{
produto.ValorIpi = ipi.vIPI;
+ produto.BaseIpi = ipi.vBC;
produto.AliquotaIpi = ipi.pIPI;
}
}
@@ -284,6 +300,16 @@ public static DanfeViewModel CreateFromXml(ProcNFe procNfe)
}
model.CalculoImposto = CriarCalculoImpostoViewModel(infNfe.total.ICMSTot);
+ var totalIbsCbs = infNfe.total.IBSCBSTot;
+ model.CalculoImposto.ValorCbs = totalIbsCbs?.gCBS?.vCBS;
+ model.CalculoImposto.ValorIbsUf = totalIbsCbs?.gIBS?.gIBSUF?.vIBSUF;
+ model.CalculoImposto.ValorIbsMunicipio = totalIbsCbs?.gIBS?.gIBSMun?.vIBSMun;
+ model.CalculoImposto.ValorImpostoSeletivo = infNfe.total.ISTot?.vIS;
+ model.CalculoImposto.ValorIbsMono = totalIbsCbs?.gMono?.vIBSMono;
+ model.CalculoImposto.ValorCbsMono = totalIbsCbs?.gMono?.vCBSMono;
+ model.CalculoImposto.ValorIbsMonoReten = totalIbsCbs?.gMono?.vIBSMonoReten;
+ model.CalculoImposto.ValorCbsMonoReten = totalIbsCbs?.gMono?.vCBSMonoReten;
+ model.ExibirTributosRtc |= totalIbsCbs != null || infNfe.total.ISTot != null;
var issqnTotal = infNfe.total.ISSQNtot;
diff --git a/NFe.Danfe.PdfClown/Modelo/ProdutoViewModel.cs b/NFe.Danfe.PdfClown/Modelo/ProdutoViewModel.cs
index f0f187024..6a632f58d 100644
--- a/NFe.Danfe.PdfClown/Modelo/ProdutoViewModel.cs
+++ b/NFe.Danfe.PdfClown/Modelo/ProdutoViewModel.cs
@@ -2,6 +2,29 @@
{
public class ProdutoViewModel
{
+ /// Classificação tributária IBS/CBS informada no item.
+ public string ClassificacaoTributariaIbsCbs { get; set; }
+ /// Base de cálculo do IBS e CBS.
+ public decimal? BaseIbsCbs { get; set; }
+ /// Alíquota do IBS da UF, efetiva quando houver redução.
+ public decimal? AliquotaIbsUf { get; set; }
+ /// Alíquota do IBS municipal, efetiva quando houver redução.
+ public decimal? AliquotaIbsMunicipio { get; set; }
+ /// Alíquota da CBS, efetiva quando houver redução.
+ public decimal? AliquotaCbs { get; set; }
+ /// Valor do IBS da UF.
+ public decimal? ValorIbsUf { get; set; }
+ /// Valor do IBS municipal.
+ public decimal? ValorIbsMunicipio { get; set; }
+ /// Valor da CBS.
+ public decimal? ValorCbs { get; set; }
+ /// Base de cálculo do Imposto Seletivo.
+ public decimal? BaseImpostoSeletivo { get; set; }
+ /// Alíquota do Imposto Seletivo.
+ public decimal? AliquotaImpostoSeletivo { get; set; }
+ /// Valor do Imposto Seletivo.
+ public decimal? ValorImpostoSeletivo { get; set; }
+
///
/// Código do produto ou serviço
/// Tag cProd
@@ -33,6 +56,9 @@ public class ProdutoViewModel
///
public string OCst { get; set; }
+ /// Identifica CSOSN quando informado no grupo ICMS do item.
+ public bool PossuiCsosn { get; set; }
+
///
/// Código Fiscal de Operações e Prestações
/// Tag CFOP
@@ -87,6 +113,9 @@ public class ProdutoViewModel
///
public double? ValorIpi { get; set; }
+ /// Base de cálculo do IPI informada no XML.
+ public double? BaseIpi { get; set; }
+
///
/// Alíquota do IPI
/// Tag pIPI