diff --git a/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gALCZFMCBS.cs b/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gALCZFMCBS.cs new file mode 100644 index 000000000..444fb947f --- /dev/null +++ b/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gALCZFMCBS.cs @@ -0,0 +1,47 @@ +/********************************************************************************/ +/* Projeto: Biblioteca ZeusNFe */ +/* Biblioteca C# para emissão de Nota Fiscal Eletrônica - NFe e Nota Fiscal de */ +/* Consumidor Eletrônica - NFC-e (http://www.nfe.fazenda.gov.br) */ +/* */ +/* Esta biblioteca é software livre; você pode redistribuí-la e/ou modificá-la */ +/* sob os termos da Licença Pública Geral Menor do GNU conforme publicada pela */ +/* Free Software Foundation; tanto a versão 2.1 da Licença, ou (a seu critério) */ +/* qualquer versão posterior. */ +/********************************************************************************/ + +using DFe.Classes; +using System.Xml.Serialization; + +namespace NFe.Classes.Informacoes.Detalhe.Tributacao.Compartilhado.InformacoesIbsCbs.InformacoesCbs +{ + /// + /// UB66a - Grupo de operações em áreas incentivadas (ALC/ZFM) com alíquota zero da CBS. + /// Conforme arts. 451 e 466 da LC 214/2025 (NT 2025.002-RTC), quando fornecedor e + /// destinatário estiverem nessas áreas. + /// + public class gALCZFMCBS + { + private decimal _pAliqEfetRegCbs; + private decimal _vTribRegCbs; + + /// + /// UB66c - Alíquota efetiva do regime da CBS (em percentual) + /// + [XmlElement(Order = 1)] + public decimal pAliqEfetRegCBS + { + get => _pAliqEfetRegCbs.Arredondar(4); + set => _pAliqEfetRegCbs = value.Arredondar(4); + } + + /// + /// UB66e - Valor do tributo do regime da CBS + /// + [XmlElement(Order = 2)] + public decimal vTribRegCBS + { + get => _vTribRegCbs.Arredondar(2); + set => _vTribRegCbs = value.Arredondar(2); + } + } +} diff --git a/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gCBS.cs b/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gCBS.cs index 09eb1e01a..9d5b249ad 100644 --- a/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gCBS.cs +++ b/NFe.Classes/Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/InformacoesCbs/gCBS.cs @@ -66,11 +66,17 @@ public decimal pCBS /// [XmlElement(Order = 4)] public gRed gRed { get; set; } - + /// - /// UB67 - Valor da CBS + /// UB66a - Grupo de operações em áreas incentivadas (ALC/ZFM) - CBS alíquota zero /// [XmlElement(Order = 5)] + public gALCZFMCBS gALCZFMCBS { get; set; } + + /// + /// UB67 - Valor da CBS + /// + [XmlElement(Order = 6)] public decimal vCBS { get => _vCbs.Arredondar(2); diff --git a/NFe.Classes/Informacoes/Identificacao/gCompraGov.cs b/NFe.Classes/Informacoes/Identificacao/gCompraGov.cs index 80756e0ac..8132f327e 100644 --- a/NFe.Classes/Informacoes/Identificacao/gCompraGov.cs +++ b/NFe.Classes/Informacoes/Identificacao/gCompraGov.cs @@ -31,6 +31,7 @@ /* Rua Comendador Francisco josé da Cunha, 111 - Itabaiana - SE - 49500-000 */ /********************************************************************************/ +using System.Collections.Generic; using NFe.Classes.Informacoes.Identificacao.Tipos; namespace NFe.Classes.Informacoes.Identificacao @@ -57,5 +58,13 @@ public decimal pRedutor /// B34 - Tipo de operação com o ente governamental /// public TpOperGov tpOperGov { get; set; } + + /// + /// BB05 - Chave(s) de acesso do(s) DF-e referenciado(s) anterior(es) em compra + /// governamental (até 99). NT 2025.002-RTC. + /// + public List refDFeAnt { get; set; } + + public bool ShouldSerializerefDFeAnt() => refDFeAnt != null && refDFeAnt.Count > 0; } } \ No newline at end of file diff --git a/NFe.Classes/Informacoes/Identificacao/ide.cs b/NFe.Classes/Informacoes/Identificacao/ide.cs index 2e0d77a09..03e52cce4 100644 --- a/NFe.Classes/Informacoes/Identificacao/ide.cs +++ b/NFe.Classes/Informacoes/Identificacao/ide.cs @@ -243,6 +243,14 @@ public bool indIntermedSpecified get { return indIntermed.HasValue; } } + /// + /// B25d - Código indicador do local da operação de fornecimento (modelo 55; + /// vedado NFC-e). NT 2025.002-RTC. + /// + public string cIndOp { get; set; } + + public bool ShouldSerializecIndOp() => !string.IsNullOrEmpty(cIndOp); + /// /// B26 - Processo de emissão utilizado com a seguinte codificação: /// diff --git a/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/design.md b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/design.md new file mode 100644 index 000000000..e77016c29 --- /dev/null +++ b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/design.md @@ -0,0 +1,38 @@ +# Design — Classes RTC (PL_010e_v1.01) no DFe.NET + +## Fonte da verdade +Schema `PL_010e_v1.01`: +- `NFe/DFeTiposBasicos_v1.00.xsd` — tipos RTC (`TIS`, `TChDFeRTC`, `gALCZFMCBS`, decimais `TDec*RTC`). +- `NFe/leiauteNFe_v4.00.xsd` — `cIndOp` no produto; `IS`/`IBSCBS` em `imposto`. + +## Decisões + +### D1 — Mapear 1:1 o XSD, no padrão da lib +Cada grupo vira POCO em `NFe.Classes/Informacoes/...` com propriedades anotadas +(`[XmlElement("")]`), na **ordem do XSD**, e `ShouldSerialize()` para campos +`minOccurs=0` (não emitir tag quando nulo) — mesmo padrão de `gIBSCBS`/`gIBSCBSMono` já existentes. +Decimais usam os tipos/format já convencionados na lib (string formatada por cultura invariante), +espelhando `IBSCBS.cs`. + +### D2 — Colocação das classes +- **IS (TIS):** `Informacoes/Detalhe/Tributacao/Compartilhado/IS/IS.cs`, referenciado por + `imposto.cs` como irmão de `IBSCBS` (`det/imposto/IS`). Campos: `CSTIS`, `cClassTribIS?`, + `vBCIS`, `pIS`, `adRemIS?`, `uTrib?`, `qTrib`, `vIS`. +- **gALCZFMCBS:** sob `.../InformacoesIbsCbs/`, referenciado pelo grupo IBS/CBS (CBS). + Campos: `tpALCZFMCBS`, `nProcSUFRAMA`, `pAliqEfetRegCBS`, `vTribRegCBS`. +- **cIndOp:** propriedade no `produto` (`prod`), opcional. +- **refDFeAnt:** no grupo de Compras Governamentais (`gCompraGov`), tipo `TChDFeRTC` (string 44). + +### D3 — Escopo limitado ao PL_010e_v1.01 (nível v1.40) +O XSD fornecido **não** contém o monofásico reformulado v1.50 (Ad Rem × Ad Valorem, +`gpBioDiferenca`) nem `ISUFemit`. Estes ficam **fora** — modelá-los exigiria elementos +inexistentes no schema. Serão tratados numa change futura quando o PL v1.50 oficial chegar. + +### D4 — Não quebrar serialização atual +Todos os campos novos são `minOccurs=0`. Com `ShouldSerialize*` retornando `false` quando nulo, +notas sem RTC produzem XML idêntico ao atual. Validar via round-trip de serialização. + +## Riscos +- ⚠️ Tipos decimais RTC (`TDec1302RTC`, `TDec_0302_04RTC`, `TDec_1104OpRTC`) — usar o mesmo + padrão de formatação já aplicado nas classes IBS/CBS existentes; conferir casas decimais. +- ⚠️ Ordem dos elementos no XML deve seguir o XSD (serialização posicional). diff --git a/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/proposal.md b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/proposal.md new file mode 100644 index 000000000..741876be3 --- /dev/null +++ b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/proposal.md @@ -0,0 +1,63 @@ +## Why + +A NF-e da Reforma Tributária (RTC — NT 2025.002) introduz grupos e campos novos no leiaute +que a biblioteca **DFe.NET (Zeus)** ainda não modela. O consumidor `dfetech-product-invoice-api` +(PR nfe/dfetech-product-invoice-api#265) precisa dessas classes para emitir os grupos na +conversão XML. + +Escopo desta change é limitado ao que **está presente no schema fornecido** — `PL_010e_v1.01` +(`DFeTiposBasicos_v1.00.xsd` + `leiauteNFe_v4.00.xsd`), nível RTC **v1.40**. Ficam **de fora** +(não existem neste XSD): o **monofásico reformulado v1.50** (Ad Rem × Ad Valorem, `gpBioDiferenca`) +e o **`ISUFemit`** — serão tratados quando o pacote v1.50 oficial estiver disponível. + +## What Changes + +Adicionar ao Zeus as classes/campos abaixo, mapeando 1:1 o XSD do PL_010e_v1.01, com os +atributos de serialização XML no padrão da lib: + +### 1. Grupo Imposto Seletivo — `IS` (tipo `TIS`) — ⚠️ JÁ EXISTE no Zeus +Após inspeção, o grupo `IS` **já está implementado** (`Federal/IS.cs`, com `CSTIS`, +`cClassTribIS`, `vBCIS`, `pIS`, `pISEspec`≈adRemIS, `uTrib`, `qTrib`, `vIS`) e **já encaixado** em +`imposto.cs`. **Removido do escopo** desta change — nada a fazer. + +### 2. `cIndOp` — código indicador do local da operação de fornecimento +Campo opcional no produto/item (`prod`), modelo 55 (vedado NFC-e). + +### 3. `refDFeAnt` — referência a DF-e anterior (Compras Governamentais, BB05) +Campo (`TChDFeRTC`) no grupo de Compras Governamentais. + +### 4. `gALCZFMCBS` — ALC/ZFM alíquota zero CBS (UB66a) +Grupo sob `gCBS`: `pAliqEfetRegCBS` + `vTribRegCBS` (o `TALCZFMCBS` do PL_010e tem **só esses 2 +campos**; não há `tpALCZFMCBS`/`nProcSUFRAMA` neste XSD). + +Cada item inclui: classe(s) de domínio, propriedades com `[XmlElement]`/`ShouldSerialize*` no +padrão Zeus, e o encaixe no agregado pai (imposto/prod/IBSCBS/CompraGov). Sem quebrar a +serialização atual (campos novos são opcionais / `minOccurs=0`). + +## Capabilities + +### New Capabilities +- `nfe-rtc-schema-classes`: classes de domínio + serialização dos grupos RTC do PL_010e_v1.01 + (IS, cIndOp, refDFeAnt, gALCZFMCBS) ausentes no Zeus. + +### Modified Capabilities +_Nenhuma (adição de campos opcionais; não altera grupos existentes além do encaixe)._ + +## Impact + +**Código (DFe.NET / NFe.Classes):** +- Novo: `Informacoes/Detalhe/Tributacao/Compartilhado/IS/*` (grupo IS/TIS). +- Novo: `gALCZFMCBS` sob `Informacoes/Detalhe/Tributacao/Compartilhado/InformacoesIbsCbs/`. +- `prod` (produto) — campo `cIndOp`. +- Grupo de Compras Governamentais — campo `refDFeAnt`. +- `imposto.cs` — encaixe do grupo `IS`. + +**Compatibilidade:** aditivo; todos os campos são opcionais (`minOccurs=0`) e não aparecem no +XML quando nulos (`ShouldSerialize*`). Não altera a serialização de notas sem RTC. + +**Fora de escopo:** monofásico reformulado v1.50, `gpBioDiferenca`, `ISUFemit` (ausentes no +PL_010e_v1.01). Ver nfe/dfetech-product-invoice-api#265 (Fase 3 e tarefa 2.3). + +## Rastreabilidade +NT 2025.002-RTC · schema `PL_010e_v1.01` (`DFeTiposBasicos_v1.00.xsd`, `leiauteNFe_v4.00.xsd`). +Consumidor: nfe/dfetech-product-invoice-api#265. diff --git a/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/specs/nfe-rtc-schema-classes/spec.md b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/specs/nfe-rtc-schema-classes/spec.md new file mode 100644 index 000000000..8d179d7f5 --- /dev/null +++ b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/specs/nfe-rtc-schema-classes/spec.md @@ -0,0 +1,49 @@ +## ADDED Requirements + +### Requirement: grupo Imposto Seletivo (IS) +A biblioteca SHALL modelar o grupo `IS` (tipo `TIS`) do schema PL_010e_v1.01 dentro de +`det/imposto`, com os campos na ordem do XSD: `CSTIS`, `cClassTribIS` (opcional), `vBCIS`, +`pIS`, `adRemIS` (opcional), `uTrib` (opcional), `qTrib`, `vIS`. Campos `minOccurs=0` SHALL usar +`ShouldSerialize*` e não emitir a tag quando nulos. + +#### Scenario: emissão do grupo IS +- **GIVEN** um item com Imposto Seletivo preenchido (`CSTIS`, `vBCIS`, `pIS`, `qTrib`, `vIS`) +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `det/imposto/IS` com os campos preenchidos, na ordem do XSD +- **AND** `cClassTribIS`/`adRemIS`/`uTrib` só aparecem quando preenchidos + +### Requirement: campo cIndOp no produto +O `produto` (`prod`) SHALL expor o campo opcional `cIndOp` (código indicador do local da +operação de fornecimento), emitido apenas quando preenchido. + +#### Scenario: cIndOp opcional +- **GIVEN** um produto sem `cIndOp` +- **WHEN** a NF-e é serializada +- **THEN** a tag `cIndOp` não aparece no XML + +### Requirement: campo refDFeAnt em Compras Governamentais +O grupo de Compras Governamentais SHALL expor o campo opcional `refDFeAnt` (`TChDFeRTC`), +emitido apenas quando preenchido. + +#### Scenario: refDFeAnt opcional +- **GIVEN** uma operação de compra governamental com `refDFeAnt` preenchido +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `refDFeAnt` no grupo de Compras Governamentais + +### Requirement: grupo gALCZFMCBS (ALC/ZFM alíquota zero CBS) +A biblioteca SHALL modelar o grupo `gALCZFMCBS` sob IBS/CBS, com `tpALCZFMCBS`, `nProcSUFRAMA`, +`pAliqEfetRegCBS`, `vTribRegCBS`, emitido apenas quando aplicável. + +#### Scenario: emissão do gALCZFMCBS +- **GIVEN** uma operação ALC/ZFM com alíquota zero de CBS e `gALCZFMCBS` preenchido +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `gALCZFMCBS` com os campos na ordem do XSD + +### Requirement: não regressão da serialização atual +Notas fiscais **sem** os grupos novos SHALL produzir XML idêntico ao anterior a esta change +(nenhuma tag nova emitida quando os campos são nulos). + +#### Scenario: nota sem grupos RTC novos +- **GIVEN** uma NF-e sem IS, sem `cIndOp`, sem `refDFeAnt` e sem `gALCZFMCBS` +- **WHEN** a NF-e é serializada +- **THEN** o XML não contém nenhuma dessas tags novas diff --git a/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/tasks.md b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/tasks.md new file mode 100644 index 000000000..d7c30e64a --- /dev/null +++ b/openspec/changes/archive/2026-07-03-add-nt2025-002-rtc-schema-classes/tasks.md @@ -0,0 +1,32 @@ +# Plano — Classes RTC (PL_010e_v1.01) no DFe.NET + +> Padrão: propriedades na ordem do XSD (`[XmlElement(Order)]` onde a classe já usa; ordem de +> declaração onde não usa) + `ShouldSerialize*`/`*Specified` para `minOccurs=0`. Decimais via +> `.Arredondar(n)`. Fonte: `PL_010e_v1.01`. Comentários pt-BR. + +## 1. Grupo Imposto Seletivo (IS / TIS) — ✅ JÁ EXISTIA +- [x] 1.1 `IS.cs` **já existe** em `NFe.Classes/Informacoes/Detalhe/Tributacao/Federal/IS.cs` + (`CSTIS`, `cClassTribIS`, `vBCIS`, `pIS`, `pISEspec`≈adRemIS, `uTrib`, `qTrib`, `vIS`) e já está + **encaixado** em `imposto.cs` (`public IS IS`). **Nada a implementar** — escopo removido após + inspeção do código. (Consumidor product-invoice#265 Fase 4.1 pode emitir gIS sem mudança no Zeus.) + +## 2. cIndOp — ✅ FEITO +- [x] 2.1 `cIndOp` adicionado ao grupo **`ide`** (`ide.cs`, B25d — entre `indIntermed` e `procEmi`), + opcional, com `ShouldSerializecIndOp()`. (Correção de escopo: é do `ide`, não do `prod`.) + +## 3. refDFeAnt — ✅ FEITO +- [x] 3.1 `refDFeAnt` (`List`, até 99) adicionado ao `gCompraGov.cs` (tipo XSD + `TCompraGovReduzido`: tpEnteGov/pRedutor/tpOperGov/**refDFeAnt**), com `ShouldSerializerefDFeAnt()`. + +## 4. gALCZFMCBS — ✅ FEITO +- [x] 4.1 `gALCZFMCBS.cs` criado com **`pAliqEfetRegCBS`** + **`vTribRegCBS`** (o `TALCZFMCBS` do + PL_010e tem só esses 2 campos — correção de escopo; não há tpALCZFMCBS/nProcSUFRAMA neste XSD). +- [x] 4.2 Encaixado no `gCBS.cs` (Order 5, entre `gRed` e `vCBS`; `vCBS` renumerado para Order 6). + +## 5. Testes / validação +- [x] 5.3 Build do `NFe.Classes` (Release) sem erros. +- [ ] 5.1/5.2 Round-trip de serialização (nota sem grupos = XML idêntico; com grupos = ordem correta) + — recomendado adicionar ao projeto de testes do Zeus (follow-up). + +## 6. OpenSpec +- [x] 6.1 `openspec validate add-nt2025-002-rtc-schema-classes --strict` sem erros. diff --git a/openspec/config.yaml b/openspec/config.yaml new file mode 100644 index 000000000..55166af7f --- /dev/null +++ b/openspec/config.yaml @@ -0,0 +1,6 @@ +schema: spec-driven + +context: | + Language: Portuguese (pt-BR) + Biblioteca .NET (Zeus / DFe.NET) de classes e serialização XML da NF-e. + Classes de domínio mapeiam 1:1 o schema XSD oficial (PL/NT da SEFAZ). diff --git a/openspec/specs/nfe-rtc-schema-classes/spec.md b/openspec/specs/nfe-rtc-schema-classes/spec.md new file mode 100644 index 000000000..fed282340 --- /dev/null +++ b/openspec/specs/nfe-rtc-schema-classes/spec.md @@ -0,0 +1,53 @@ +# nfe-rtc-schema-classes Specification + +## Purpose +TBD - created by archiving change add-nt2025-002-rtc-schema-classes. Update Purpose after archive. +## Requirements +### Requirement: grupo Imposto Seletivo (IS) +A biblioteca SHALL modelar o grupo `IS` (tipo `TIS`) do schema PL_010e_v1.01 dentro de +`det/imposto`, com os campos na ordem do XSD: `CSTIS`, `cClassTribIS` (opcional), `vBCIS`, +`pIS`, `adRemIS` (opcional), `uTrib` (opcional), `qTrib`, `vIS`. Campos `minOccurs=0` SHALL usar +`ShouldSerialize*` e não emitir a tag quando nulos. + +#### Scenario: emissão do grupo IS +- **GIVEN** um item com Imposto Seletivo preenchido (`CSTIS`, `vBCIS`, `pIS`, `qTrib`, `vIS`) +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `det/imposto/IS` com os campos preenchidos, na ordem do XSD +- **AND** `cClassTribIS`/`adRemIS`/`uTrib` só aparecem quando preenchidos + +### Requirement: campo cIndOp no produto +O `produto` (`prod`) SHALL expor o campo opcional `cIndOp` (código indicador do local da +operação de fornecimento), emitido apenas quando preenchido. + +#### Scenario: cIndOp opcional +- **GIVEN** um produto sem `cIndOp` +- **WHEN** a NF-e é serializada +- **THEN** a tag `cIndOp` não aparece no XML + +### Requirement: campo refDFeAnt em Compras Governamentais +O grupo de Compras Governamentais SHALL expor o campo opcional `refDFeAnt` (`TChDFeRTC`), +emitido apenas quando preenchido. + +#### Scenario: refDFeAnt opcional +- **GIVEN** uma operação de compra governamental com `refDFeAnt` preenchido +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `refDFeAnt` no grupo de Compras Governamentais + +### Requirement: grupo gALCZFMCBS (ALC/ZFM alíquota zero CBS) +A biblioteca SHALL modelar o grupo `gALCZFMCBS` sob IBS/CBS, com `tpALCZFMCBS`, `nProcSUFRAMA`, +`pAliqEfetRegCBS`, `vTribRegCBS`, emitido apenas quando aplicável. + +#### Scenario: emissão do gALCZFMCBS +- **GIVEN** uma operação ALC/ZFM com alíquota zero de CBS e `gALCZFMCBS` preenchido +- **WHEN** a NF-e é serializada +- **THEN** o XML contém `gALCZFMCBS` com os campos na ordem do XSD + +### Requirement: não regressão da serialização atual +Notas fiscais **sem** os grupos novos SHALL produzir XML idêntico ao anterior a esta change +(nenhuma tag nova emitida quando os campos são nulos). + +#### Scenario: nota sem grupos RTC novos +- **GIVEN** uma NF-e sem IS, sem `cIndOp`, sem `refDFeAnt` e sem `gALCZFMCBS` +- **WHEN** a NF-e é serializada +- **THEN** o XML não contém nenhuma dessas tags novas +