@sinete/nfe 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  /** Versão de `@sinete/nfe`, para o padrão de `verProc`/`verAplic` (`formatarVerProc` do @sinete/core). */
2
- export declare const VERSAO_PACOTE = "0.5.0";
2
+ export declare const VERSAO_PACOTE = "0.6.0";
3
3
  //# sourceMappingURL=versao-gerada.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinete/nfe",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "NF-e modelo 55: modelo de entrada tipado, montagem com totais em decimal exato, validação antes de assinar, autorização, consultas, eventos, inutilização, contingência SVC e Distribuição DF-e",
5
5
  "keywords": [
6
6
  "nfe",
@@ -47,13 +47,13 @@
47
47
  "@sinete/core": "^0.3.0",
48
48
  "@sinete/ibs-cbs": "^0.2.2",
49
49
  "@sinete/ibs-cbs-dados": ">=2026.9.3",
50
- "@sinete/rejeicoes": "^0.4.0",
50
+ "@sinete/rejeicoes": "^0.4.1",
51
51
  "@sinete/schemas": "^0.3.0",
52
52
  "@sinete/transport": "^0.3.0",
53
53
  "@sinete/validators": "^0.3.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@sinete/sefaz-sim": "^0.3.0"
56
+ "@sinete/sefaz-sim": "^0.4.0"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public"
@@ -631,7 +631,10 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
631
631
  const nfce = mod === '65';
632
632
  // Padrões da identificação resolvidos uma vez: o mesmo valor vai para o ide e para a calculadora de IBS/CBS. A NFC-e
633
633
  // é presencial e para consumidor final (MOC 7.0 Anexo I, B25a-10 e B25b-20).
634
- const indPres = entrada.indPres ?? (nfce ? '1' : finNFeIn === '2' || finNFeIn === '3' ? '0' : '9');
634
+ // NF-e com DANFE Simplificado Tipo 2 (tpImp 6): parte das regras da NFC-e vale para ela (NT 2026.002 v1.11).
635
+ const tipo2 = !nfce && entrada.tpImp === '6';
636
+ // Na NFC-e e na Tipo 2 a operação é presencial ou entrega a domicílio (B25b-20, rejeição 717): o padrão é 1.
637
+ const indPres = entrada.indPres ?? (nfce || tipo2 ? '1' : finNFeIn === '2' || finNFeIn === '3' ? '0' : '9');
635
638
  const indFinal = entrada.indFinal ?? (nfce || entrada.destinatario?.indIEDest === '9' ? '1' : '0');
636
639
  const ctx = new Ctx(issues, { ...MODES, ...opcoes.arredondamento }, finNFeIn !== '2' && finNFeIn !== '3');
637
640
  const pRedutorGov = entrada.gCompraGov && ctx.req(entrada.gCompraGov.pRedutor, 'gCompraGov.pRedutor', D0302A04);
@@ -768,9 +771,11 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
768
771
  }
769
772
 
770
773
  // Identificação que as regras do modelo conferem antes de montar.
771
- // Na NFC-e a operação é sempre interna (B11a-10, rejeição 707): o endereço do consumidor não a torna interestadual.
774
+ // Na NFC-e e na Tipo 2 a operação é sempre interna (B11a-10, rejeição 707): o endereço do consumidor não a torna
775
+ // interestadual.
772
776
  const idDest =
773
- entrada.idDest ?? (nfce ? '1' : destUf === 'EX' ? '3' : destUf !== undefined && destUf !== emitUf ? '2' : '1');
777
+ entrada.idDest ??
778
+ (nfce || tipo2 ? '1' : destUf === 'EX' ? '3' : destUf !== undefined && destUf !== emitUf ? '2' : '1');
774
779
  const tpImp = entrada.tpImp ?? (nfce ? '4' : '1');
775
780
  conferirDestinatario(
776
781
  entrada,
@@ -784,10 +789,11 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
784
789
  },
785
790
  issues,
786
791
  );
787
- if (nfce) {
792
+ if (nfce || tipo2) {
788
793
  conferirNfce(
789
794
  entrada,
790
795
  {
796
+ mod: nfce ? '65' : '55',
791
797
  tpNF: entrada.tpNF,
792
798
  idDest,
793
799
  tpImp,
@@ -859,10 +865,10 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
859
865
  }
860
866
  const semIe = !nfce && entrada.emitente.IE === undefined;
861
867
  const itens = entrada.itens.map((it, n) => montarItem(ctx, it, n, finNFeIn === '1', semIe));
862
- // Na NFC-e em homologação, a descrição do primeiro item é a literal da RV I04-10, como o nome do destinatário da
863
- // E04-20: o builder a põe, e a descrição informada fica fora do XML de teste.
868
+ // Na NFC-e e na Tipo 2 (NT 2026.002) em homologação, a descrição do primeiro item é a literal da RV I04-10, como o
869
+ // nome do destinatário da E04-20: o builder a põe, e a descrição informada fica fora do XML de teste.
864
870
  const primeiro = itens[0];
865
- if (nfce && opcoes.ambiente === 'homologacao' && primeiro !== undefined) {
871
+ if ((nfce || tipo2) && opcoes.ambiente === 'homologacao' && primeiro !== undefined) {
866
872
  (primeiro.det.prod as unknown as Record<string, unknown>).xProd = XPROD_HOMOLOGACAO_NFCE;
867
873
  }
868
874
 
@@ -986,10 +992,12 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
986
992
  });
987
993
  // Texto e tamanho dos campos de texto pelo tipo do PL, com o caminho da entrada (ADR 0011); o campo que outra
988
994
  // conferência já recusou fica só com a ocorrência dela.
989
- // Em homologação, o nome do destinatário e, na NFC-e, a descrição do primeiro item são as literais da E04-20 e da I04-10:
990
- // o texto informado não vai ao XML.
995
+ // Em homologação, o nome do destinatário e, na NFC-e e na Tipo 2, a descrição do primeiro item são as literais da E04-20
996
+ // e da I04-10: o texto informado não vai ao XML.
991
997
  const substituidos =
992
- opcoes.ambiente === 'homologacao' ? ['destinatario.xNome', ...(nfce ? ['itens[0].produto.xProd'] : [])] : [];
998
+ opcoes.ambiente === 'homologacao'
999
+ ? ['destinatario.xNome', ...(nfce || tipo2 ? ['itens[0].produto.xProd'] : [])]
1000
+ : [];
993
1001
  conferirTextosDaEntrada(entrada, pl.infNFe as ComplexType, issues, new Set(substituidos));
994
1002
  // Nota sem IE do emitente (NT 2026.007, ADR 0012): conferida antes de parar nas ocorrências dos itens, para todas as
995
1003
  // violações voltarem juntas.
@@ -1289,6 +1297,7 @@ export async function montarNfe(entrada: DadosNfe, opcoes: MontarNfeOpcoes): Pro
1289
1297
  pagamentoNfce(pag, vNF, issues);
1290
1298
  }
1291
1299
  // W16-40 (rejeição 750): acima do limite, a NFC-e identifica o destinatário por CNPJ, CPF ou idEstrangeiro.
1300
+ // Na Tipo 2 a W16-40 não tem o que conferir: a NF-e sempre identifica o destinatário (E01-10, rejeição 719).
1292
1301
  if (nfce && vNF.gt(Decimal.of(NFCE_LIMITE_SEM_DESTINATARIO)) && dest === undefined) {
1293
1302
  issues.add(
1294
1303
  'destinatario',
package/src/build/nfce.ts CHANGED
@@ -180,6 +180,8 @@ const TPAG_VEDADOS: Readonly<Record<string, string>> = {
180
180
 
181
181
  /** Identificação já resolvida pelo montador (com os padrões aplicados). */
182
182
  export interface IdeNfce {
183
+ /** 65 é a NFC-e; 55, a NF-e com DANFE Simplificado Tipo 2 (tpImp 6), que a NT 2026.002 põe sob parte destas regras. */
184
+ readonly mod: '55' | '65';
183
185
  readonly tpNF: string;
184
186
  readonly idDest: string;
185
187
  readonly tpImp: string;
@@ -191,21 +193,29 @@ export interface IdeNfce {
191
193
  /**
192
194
  * Regras da NFC-e sobre a entrada (origem `entrada`, ADR 0011), todas de aplicação obrigatória. Grupos que a NFC-e
193
195
  * não tem saem como `grupo_vedado` no caminho da entrada.
196
+ *
197
+ * A NT 2026.002 v1.11 (homologação em 01/07/2026, produção em 03/08/2026) estende parte delas à NF-e com DANFE
198
+ * Simplificado Tipo 2 (`mod` 55, `tpImp` 6): as que a NT escreve "Se NFC-e ou NF-e com DANFE Simplificado Tipo 2". As
199
+ * que ela não cita (data de previsão de entrega, tpImp 4 e 5, cMunFGIBS, compra governamental, o destinatário fora da
200
+ * E01-20, ISSQN, transportador, pagamento e exportação) seguem só da NFC-e (`soNfce`). A G01-10 (local de entrega,
201
+ * 670) fica de fora: a NT a marca como implementação futura.
194
202
  */
195
203
  export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): void {
196
- const vedado = (path: string, msg: string): void => issues.add(path, 'grupo_vedado', `NFC-e ${msg}`);
197
- const invalido = (path: string, msg: string): void => issues.add(path, 'campo_invalido', `NFC-e ${msg}`);
204
+ const soNfce = ide.mod === '65';
205
+ const doc = soNfce ? 'NFC-e' : 'NF-e com DANFE Simplificado Tipo 2';
206
+ const vedado = (path: string, msg: string): void => issues.add(path, 'grupo_vedado', `${doc} ${msg}`);
207
+ const invalido = (path: string, msg: string): void => issues.add(path, 'campo_invalido', `${doc} ${msg}`);
198
208
 
199
209
  // B. Identificação
200
210
  if (input.dhSaiEnt !== undefined) vedado('dhSaiEnt', 'sem data de entrada ou saída (B10-10, rejeição 705)');
201
- if (input.dPrevEntrega !== undefined) {
211
+ if (soNfce && input.dPrevEntrega !== undefined) {
202
212
  vedado('dPrevEntrega', 'sem data de previsão de entrega (NT 2025.002, B10a-10, rejeição 1153)');
203
213
  }
204
214
  if (ide.tpNF !== '1') invalido('tpNF', 'só de saída, tpNF 1 (B11-10, rejeição 706)');
205
215
  if (ide.idDest !== '1') {
206
216
  invalido('idDest', 'só em operação interna, idDest 1 (B11a-10, rejeição 707)');
207
217
  }
208
- if (ide.tpImp !== '4' && ide.tpImp !== '5') {
218
+ if (soNfce && ide.tpImp !== '4' && ide.tpImp !== '5') {
209
219
  invalido('tpImp', 'com DANFC-e: tpImp 4 (impresso) ou 5 (mensagem eletrônica) (B21-10, rejeição 709)');
210
220
  }
211
221
  if (ide.finNFe !== '1') invalido('finNFe', 'só com finalidade normal, finNFe 1 (B25-20, rejeição 715)');
@@ -213,13 +223,13 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
213
223
  if (!['1', '4', '5'].includes(ide.indPres)) {
214
224
  invalido('indPres', 'só presencial: indPres 1, 4 (entrega a domicílio) ou 5 (NT 2025.002, B25b-20, rejeição 717)');
215
225
  }
216
- if (input.cMunFGIBS !== undefined && ide.indPres !== '5') {
226
+ if (soNfce && input.cMunFGIBS !== undefined && ide.indPres !== '5') {
217
227
  invalido(
218
228
  'cMunFGIBS',
219
229
  'com cMunFGIBS só em operação presencial fora do estabelecimento, indPres 5 (NT 2025.002, B25b-60, rejeição 1000)',
220
230
  );
221
231
  }
222
- if (input.cMunFGIBS === undefined && ide.indPres === '5') {
232
+ if (soNfce && input.cMunFGIBS === undefined && ide.indPres === '5') {
223
233
  issues.add(
224
234
  'cMunFGIBS',
225
235
  'campo_obrigatorio',
@@ -229,7 +239,7 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
229
239
  if (input.referenciadas !== undefined && input.referenciadas.length > 0) {
230
240
  vedado('referenciadas', 'não referencia documento fiscal (BA01-10, rejeição 708)');
231
241
  }
232
- if (input.gCompraGov !== undefined)
242
+ if (soNfce && input.gCompraGov !== undefined)
233
243
  vedado('gCompraGov', 'sem compra governamental (NT 2025.002, BB01-10, rejeição 1006)');
234
244
 
235
245
  // C. Emitente
@@ -242,17 +252,19 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
242
252
  issues.add(
243
253
  'destinatario',
244
254
  'campo_obrigatorio',
245
- 'NFC-e com entrega a domicílio identifica o destinatário (E01-20, rejeição 787)',
255
+ `${doc} com entrega a domicílio identifica o destinatário (E01-20, rejeição 787)`,
246
256
  );
247
257
  }
248
- if (ide.indPres === '4' && d !== undefined && d.endereco === undefined) {
258
+ // F01-10 (669): sem local de retirada.
259
+ if (input.retirada !== undefined) vedado('retirada', 'sem local de retirada (F01-10, rejeição 669)');
260
+ if (soNfce && ide.indPres === '4' && d !== undefined && d.endereco === undefined) {
249
261
  issues.add(
250
262
  'destinatario.endereco',
251
263
  'campo_obrigatorio',
252
264
  'NFC-e com entrega a domicílio informa o endereço do destinatário (E05-20, rejeição 788)',
253
265
  );
254
266
  }
255
- if (d !== undefined) {
267
+ if (soNfce && d !== undefined) {
256
268
  if (d.CNPJ !== undefined && input.emitente.CNPJ !== undefined && digitos(d.CNPJ) === digitos(input.emitente.CNPJ)) {
257
269
  invalido('destinatario.CNPJ', 'com destinatário igual ao emitente (E02-20, rejeição 220)');
258
270
  }
@@ -271,7 +283,10 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
271
283
  if (esp.arma !== undefined) vedado(`${p}.produto.especifico.arma`, 'sem armamento (L01-10, rejeição 738)');
272
284
  if (esp.nRECOPI !== undefined)
273
285
  vedado(`${p}.produto.especifico.nRECOPI`, 'sem papel imune RECOPI (LB01-10, rejeição 348)');
274
- if (it.produto.tpCredPresIBSZFM !== undefined) {
286
+ if (it.produto.indTot === '0') {
287
+ invalido(`${p}.produto.indTot`, 'sem item fora do total, indTot 1 (I17b-10, rejeição 774)');
288
+ }
289
+ if (soNfce && it.produto.tpCredPresIBSZFM !== undefined) {
275
290
  vedado(
276
291
  `${p}.produto.tpCredPresIBSZFM`,
277
292
  'sem classificação para subapuração do IBS na ZFM (NT 2025.002, I05k-10, rejeição 1165)',
@@ -279,14 +294,14 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
279
294
  }
280
295
  const cfop = it.produto.CFOP.replace(/\D/g, '');
281
296
  const imp = it.impostos;
282
- if (cfop === CFOP_ISSQN && imp.issqn === undefined) {
297
+ if (soNfce && cfop === CFOP_ISSQN && imp.issqn === undefined) {
283
298
  issues.add(
284
299
  `${p}.impostos.issqn`,
285
300
  'combinacao_invalida',
286
301
  'NFC-e com CFOP 5.933 tem o grupo do ISSQN (I08-160, rejeição 374)',
287
302
  );
288
303
  }
289
- if (cfop !== CFOP_ISSQN && imp.issqn !== undefined) {
304
+ if (soNfce && cfop !== CFOP_ISSQN && imp.issqn !== undefined) {
290
305
  issues.add(
291
306
  `${p}.produto.CFOP`,
292
307
  'combinacao_invalida',
@@ -314,10 +329,10 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
314
329
  if (tr !== undefined && tr.modFrete !== '9' && !entrega) {
315
330
  invalido('transporte.modFrete', 'sem frete fora da entrega a domicílio: modFrete 9 (X02-10, rejeição 753)');
316
331
  }
317
- if (tr?.transportador !== undefined && !entrega) {
332
+ if (soNfce && tr?.transportador !== undefined && !entrega) {
318
333
  vedado('transporte.transportador', 'só tem transportador na entrega a domicílio (X03-10, rejeição 754)');
319
334
  }
320
- if (entrega && tr?.transportador === undefined) {
335
+ if (soNfce && entrega && tr?.transportador === undefined) {
321
336
  issues.add(
322
337
  'transporte.transportador',
323
338
  'campo_obrigatorio',
@@ -331,6 +346,17 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
331
346
 
332
347
  // Y e YA. Cobrança e pagamento
333
348
  if (input.cobranca !== undefined) vedado('cobranca', 'sem fatura nem duplicata (Y01-10, rejeição 760)');
349
+ // O pagamento é só da NFC-e: a NT 2026.002 não estende as regras do grupo YA à Tipo 2.
350
+ if (soNfce) conferirPagamentoNfce(input, issues);
351
+
352
+ // Z. Grupos que a NFC-e não tem
353
+ if (soNfce && input.exporta !== undefined) vedado('exporta', 'sem comércio exterior (ZA01-30, rejeição 814)');
354
+ if (input.compra !== undefined) vedado('compra', 'sem dados de compra (ZB01-10, rejeição 762)');
355
+ if (input.cana !== undefined) vedado('cana', 'sem aquisição de cana (ZC01-10, rejeição 763)');
356
+ }
357
+
358
+ /** Pagamento informado na NFC-e: obrigatório, sem os meios vedados e com o grupo do cartão quando pede. */
359
+ function conferirPagamentoNfce(input: DadosNfe, issues: Issues): void {
334
360
  if (input.pagamento === undefined || input.pagamento.detPag.length === 0) {
335
361
  issues.add(
336
362
  'pagamento',
@@ -351,11 +377,6 @@ export function conferirNfce(input: DadosNfe, ide: IdeNfce, issues: Issues): voi
351
377
  }
352
378
  });
353
379
  }
354
-
355
- // Z. Grupos que a NFC-e não tem
356
- if (input.exporta !== undefined) vedado('exporta', 'sem comércio exterior (ZA01-30, rejeição 814)');
357
- if (input.compra !== undefined) vedado('compra', 'sem dados de compra (ZB01-10, rejeição 762)');
358
- if (input.cana !== undefined) vedado('cana', 'sem aquisição de cana (ZC01-10, rejeição 763)');
359
380
  }
360
381
 
361
382
  /** O `pag` montado, na forma que as regras de pagamento leem e completam. */
@@ -1,3 +1,3 @@
1
1
  // GERADO por scripts/versao-gerada.ts a partir do package.json. Não edite: rode `bun scripts/versao-gerada.ts`.
2
2
  /** Versão de `@sinete/nfe`, para o padrão de `verProc`/`verAplic` (`formatarVerProc` do @sinete/core). */
3
- export const VERSAO_PACOTE = '0.5.0';
3
+ export const VERSAO_PACOTE = '0.6.0';