# Treeunfe DFe 🪄

> Biblioteca Node.js open source para integração com webservices da SEFAZ, desenvolvida e mantida pela **Treeunfe**.

[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.pt-br.html)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-16%2B-green.svg)](https://nodejs.org/)

## 📖 Sobre

**Treeunfe DFe** é uma biblioteca open source desenvolvida e mantida pela empresa **Treeunfe**, projetada para simplificar a integração com os webservices da SEFAZ. A biblioteca oferece uma solução robusta e modular para automação de processos relacionados a documentos fiscais eletrônicos.

### ✨ Características

- 🚀 **Open Source**: Código aberto e gratuito para uso
- 🔄 **Atualizações Frequentes**: Mantida ativamente pela Treeunfe com atualizações regulares
- 📦 **Modular**: Instale apenas os módulos que você precisa
- 🛠️ **TypeScript**: Totalmente tipado para melhor experiência de desenvolvimento
- 📚 **Documentação Completa**: Documentação detalhada e exemplos práticos

## 🏢 Sobre a Treeunfe

A **Treeunfe** é uma empresa especializada em soluções fiscais e tributárias. Esta biblioteca é mantida ativamente pela equipe Treeunfe, garantindo atualizações frequentes, correções de bugs e suporte às últimas normas técnicas da SEFAZ.


## 💬 Comunidade

<div align="center">

### 🎯 Junte-se à nossa comunidade no Discord!

[![Discord](https://img.shields.io/badge/Discord-Entrar%20na%20Comunidade-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/HjAGPPrfCQ)

**Estamos aqui para apoiá-lo!**

✨ Tire suas dúvidas  
🤝 Colabore com a comunidade  
🚀 Contribua para o desenvolvimento open source

[**👉 Clique aqui para entrar no Discord**](https://discord.gg/HjAGPPrfCQ)

</div>






## 📦 Instalação

A biblioteca é modular, permitindo instalar apenas os módulos necessários:

```bash
# Instalar módulo NFe
npm install @treeunfe/nfe @treeunfe/types @treeunfe/shared

# Instalar módulo NFCe
npm install @treeunfe/nfce @treeunfe/types @treeunfe/shared

# Instalar módulo CTe
npm install @treeunfe/cte @treeunfe/types @treeunfe/shared

# Instalar módulo NFSe
npm install @treeunfe/nfse @treeunfe/types @treeunfe/shared

# Instalar módulo DANFE (geração de PDF)
npm install @treeunfe/danfe
```

## 🚀 Início Rápido

### Exemplo: NFe

```typescript
import { NFe, TreeunfeDFeService } from '@treeunfe/nfe';
import { TreeunfeDFeProps } from '@treeunfe/types';
import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);

// Inicializar serviço
const treeunfeDFeService = new TreeunfeDFeService();
const nfeHandler = new NFe(treeunfeDFeService);

// Configurar ambiente
await nfeHandler.LoadEnvironment({
  config: {
    dfe: {
      baixarXMLDistribuicao: true,
      pathXMLDistribuicao: "tmp/DistribuicaoDFe/NFe",
      armazenarXMLAutorizacao: true,
      pathXMLAutorizacao: "tmp/Autorizacao/NFe",
      armazenarXMLRetorno: true,
      pathXMLRetorno: "tmp/RequestLogs/NFe",
      armazenarXMLConsulta: true,
      pathXMLConsulta: "tmp/RequestLogs/NFe",
      
      pathCertificado: path.resolve(__dirname, "certificado.pfx"),
      senhaCertificado: "sua_senha_aqui",
      UF: "SP",
    },
    nfe: {
      ambiente: 2, // 1 = Produção, 2 = Homologação
      versaoDF: "4.00",
      tokenCSC: 'seu_token_csc',
      idCSRT: '01'
    },
    lib: {
      connection: {
        timeout: 30000,
      },
      log: {
        exibirLogNoConsole: true,
        armazenarLogs: true,
        pathLogs: 'tmp/Logs/NFe'
      },
      useOpenSSL: false,
      useForSchemaValidation: 'validateSchemaJsBased',
    }
  } as TreeunfeDFeProps
});

// Consultar status do serviço
await nfeHandler.ConsultaStatusServico();

// Consultar protocolo
await nfeHandler.ConsultaProtocolo('00000000000000000000000000000000000000000000');
```

### Geração de DANFe / DANFCE (NF-e / NFC-e)

A partir desta versão a `chave` **não é mais passada como parâmetro** — ela é
extraída automaticamente de `LayoutNFe.infNFe.Id` (removendo o prefixo `NFe`).

```typescript
// DANFe NF-e
await nfeHandler.GerarDanfe({
  data: { NFe: layoutNFe, protNFe },
  outputPath: 'tmp/DANFe/minha-nfe.pdf',
});

// DANFCE NFC-e
await nfceHandler.GerarDanfe({
  data: { NFe: layoutNFe, protNFe },
  outputPath: 'tmp/DANFCE/minha-nfce.pdf',
});
```

#### Migração (breaking change)

Versões anteriores recebiam `chave: string` separadamente. Remova o campo:

```typescript
// ❌ ANTES
await nfeHandler.GerarDanfe({
  data: { NFe: layoutNFe, protNFe },
  chave: '41152002223903417000160000000000000426010515637278',
  outputPath: '...',
});

// ✅ AGORA
await nfeHandler.GerarDanfe({
  data: { NFe: layoutNFe, protNFe },
  outputPath: '...',
});
```

### Exemplo: NFSe

```typescript
import { NFSe, decodeNFSeB64Gzip, parseNFSeXml } from '@treeunfe/nfse';
import { TreeunfeDFeService } from '@treeunfe/nfe';
import { TreeunfeDFeProps } from '@treeunfe/types';
import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);

// Inicializar serviço
const treeunfeDFeService = new TreeunfeDFeService();
const nfseHandler = new NFSe(treeunfeDFeService);

// Configurar ambiente
await nfseHandler.LoadEnvironment({
  config: {
    dfe: {
      baixarXMLDistribuicao: true,
      pathXMLDistribuicao: "tmp/DistribuicaoDFe/NFSe",
      armazenarXMLAutorizacao: true,
      pathXMLAutorizacao: "tmp/Autorizacao/NFSe",
      armazenarXMLRetorno: true,
      pathXMLRetorno: "tmp/RequestLogs/NFSe",
      
      pathCertificado: path.resolve(__dirname, "certificado.pfx"),
      senhaCertificado: "sua_senha_aqui",
      UF: "SP",
    },
    nfse: {
      ambiente: 2, // 1 = Produção, 2 = Homologação
      versao: "1.00"
    },
    lib: {
      connection: {
        timeout: 30000,
      },
      log: {
        exibirLogNoConsole: true,
        armazenarLogs: true,
        pathLogs: 'tmp/Logs/NFSe'
      },
      useOpenSSL: false,
      useForSchemaValidation: 'validateSchemaJsBased',
    }
  } as TreeunfeDFeProps
});

// Consultar NFSe por chave
await nfseHandler.Consulta({
  chaveAcesso: '00000000000000000000000000000000000000000000'
});
```

### Geração de DANFSe (NT-008 v1.0)

A geração da DANFSe (Documento Auxiliar da NFS-e Nacional) é feita **localmente**
a partir do XML autorizado, conforme NT-008 v1.0 (SE/CGNFS-e, 05/05/2026). A API
HTTP de DANFSe da SefIN será suspensa em **01/07/2026** — a partir dessa data,
apenas a geração local funcionará.

#### 1. Fluxo típico — direto após `Autorizacao`

```typescript
import { NFSe, decodeNFSeB64Gzip, parseNFSeXml } from '@treeunfe/nfse';

const respAutorizacao = await nfseHandler.Autorizacao(dpsPayload);

// O retorno traz `nfseXmlGZipB64` (base64 + gzip do XML autorizado).
const xml = decodeNFSeB64Gzip(respAutorizacao.response.nfseXmlGZipB64);
const NFSe = parseNFSeXml(xml);

await nfseHandler.GerarDanfse({
  data: { NFSe },
  outputPath: `tmp/DANFSe/${respAutorizacao.response.chNFSe}-DANFSe.pdf`,
  // forceTransmitida: true, // opcional: remove o aviso "SEM VALIDADE JURÍDICA" em homologação
});
```

#### 2. Fluxo de re-geração — a partir de um XML salvo em disco

Útil quando você precisa **regerar uma DANFSe** semanas/meses depois (por
exemplo, reimpressão sob demanda no portal do cliente). Basta ter o XML
autorizado persistido (`armazenarXMLAutorizacao: true` na config grava
automaticamente em `pathXMLAutorizacao`).

```typescript
import fs from 'fs';
import { parseNFSeXml } from '@treeunfe/nfse';

const xml = fs.readFileSync('tmp/Autorizacao/NFSe/<chave>-nfse.xml', 'utf-8');
const NFSe = parseNFSeXml(xml);

await nfseHandler.GerarDanfse({
  data: { NFSe },
  outputPath: 'tmp/DANFSe/reimpressao.pdf',
});
```

O `parseNFSeXml` aceita tanto o XML "puro" (`<NFSe>...</NFSe>`) quanto o
envelopado (`<nfseProc>...</nfseProc>`), e aplica coerção numérica nos campos
monetários/percentuais conhecidos da NT-008. Atributos `Id` de `<infNFSe>`
e `<infDPS>` também são preservados (a chave de 50 dígitos vive em `infNFSe.id`
com o prefixo `NFS`).

#### 3. Acessando a chave de acesso e a UF a partir do parse

```typescript
import { parseNFSeXml } from '@treeunfe/nfse';
import { extractChaveFromNFSeId, ufFromIBGE } from '@treeunfe/danfe';

const NFSe = parseNFSeXml(xml);

// Chave de 50 dígitos (sem o prefixo "NFS")
const chave = extractChaveFromNFSeId(NFSe.infNFSe.id);

// UF derivada do código IBGE de 7 dígitos (útil quando o XSD não traz UF separada)
const uf = ufFromIBGE(NFSe.infNFSe.IBSCBS?.cLocalidadeIncid); // ex.: "PR"
```

#### Cobertura da implementação

- **A4 retrato, 1 página**, mesmo no cenário mais denso (Destinatário e
  Intermediário identificados, todos os blocos preenchidos).
- **Grid de 4 colunas equalizadas** em todos os blocos de dados (sombreado 5%
  restrito à célula-título), com áreas largas reservadas para descrições
  extensas (Descrição do Serviço, Informações Complementares).
- **QR Code** com URL `https://www.nfse.gov.br/ConsultaPublica/?tpc=1&chave=...`
  e nota explicativa em 3 linhas.
- Renderização dos blocos: Cabeçalho, Dados da NFS-e, Prestador, Tomador (com
  supressão), Destinatário (com supressões nota 2 e nota 3), Intermediário (com
  supressão), Serviço Prestado, Tributação Municipal (ISSQN, com supressão por
  não-incidência), Tributação Federal (condicional ≤ 2026 — nota 6), Tributação
  IBS/CBS, Valor Total, Informações Complementares (formato com pipes — nota 10)
  e Canhoto.
- **Marcas d'água** diagonais — `CANCELADA`, `SUBSTITUÍDA` e `NFS-e SEM
  VALIDADE JURÍDICA` (item 2.5) — **excludentes entre si** (nunca há duas
  sobrepostas) e renderizadas como **path vetorial** (não selecionáveis com o
  cursor, não copiáveis, não pesquisáveis via Ctrl+F).
- **Canhoto** rente ao rodapé com divisórias verticais entre os 3 campos.
- **Assinatura no rodapé** "*NFS-e emitida pelo Treeunfe NFSe - Orgulho de ser
  brasileiro*" precedida por bandeira do Brasil em vetor.
- Fontes **Liberation Sans** (substitutos métricos de Arial) embarcadas no
  pacote.

#### Migração (breaking change)

O método HTTP legado `nfseHandler.GerarDanfe(...)` foi **removido** nesta versão.
Substitua por `nfseHandler.GerarDanfse(...)` conforme exemplo acima.

## 📚 Funcionalidades

### NFe (Nota Fiscal Eletrônica)
- ✅ Autorização de NFe
- ✅ Consulta de Protocolo
- ✅ Consulta de Status do Serviço
- ✅ Distribuição DFe (por NSU, Último NSU ou Chave)
- ✅ Inutilização de NFe
- ✅ Recepção de Eventos (Cancelamento, Carta de Correção, EPEC, etc.)
- ✅ Geração de DANFE

### NFCe (Nota Fiscal de Consumidor Eletrônica)
- ✅ Autorização de NFCe
- ✅ Consulta de Protocolo
- ✅ Geração de QR Code
- ✅ Geração de DANFE

### CTe (Conhecimento de Transporte Eletrônico)
- ✅ Distribuição DFe (por NSU, Último NSU ou Chave)
- ✅ Download automático de documentos CT-e

### NFSe (Nota Fiscal de Serviços Eletrônica)
- ✅ Autorização de NFSe
- ✅ Consulta de NFSe
- ✅ Consulta de Parâmetros Municipais
- ✅ Registro de Eventos (Cancelamento, etc.)
- ✅ Distribuição por NSU
- ✅ **Geração local de DANFSe (NT-008 v1.0)** — substituindo a API HTTP da SefIN
  (suspensa em 01/07/2026)
- ✅ Utilities `decodeNFSeB64Gzip` e `parseNFSeXml` para conversão de
  `nfseXmlGZipB64` em `LayoutNFSe` tipado

## 📖 Documentação

Para documentação completa, exemplos detalhados e referência da API, acesse:

**🔗 [Documentação Completa](https://nfewizard-org.github.io/)**

## ⚙️ Requisitos

- **Node.js**: Versão 16 ou superior
- **Certificado**: Certificado A1 (arquivo .pfx)
- **TypeScript**: Recomendado (mas não obrigatório)

### Validação de Schema

Por padrão, a biblioteca utiliza validação baseada em Java. Para ambientes sem suporte ao JDK (como Vercel, AWS Lambda sem layers), configure:

```typescript
lib: {
  useForSchemaValidation: 'validateSchemaJsBased'
}
```

## 🤝 Contribuindo

Contribuições são bem-vindas! Este é um projeto open source mantido pela Treeunfe, e sua colaboração é muito apreciada.

### Como Contribuir

1. **Reportar Bugs**: Abra uma issue descrevendo o problema
2. **Sugerir Funcionalidades**: Compartilhe suas ideias
3. **Enviar Pull Requests**: Contribua com código, documentação ou melhorias
4. **Espalhar a Palavra**: Compartilhe o projeto com outros desenvolvedores

### Ao Abrir uma Issue

Por favor, inclua as seguintes informações:

```markdown
## Parametrização
- UF: SP
- Certificado: A1
- Método: NFE_ConsultaStatusServico
- Status: ✅ Funcionando / ❌ Com erro
```

Inclua também os logs gerados no diretório configurado em `pathLogs` (arquivos `app.jsonl`, `error.jsonl` e `http.jsonl`).

## 📝 Licença

Este projeto é licenciado sob a [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.pt-br.html).

## 🏢 Mantido por Treeunfe

Desenvolvido e mantido com ❤️ pela equipe **Treeunfe**.

- 🌐 Website: [Treeunfe](https://treeunfe.com.br)
- 📧 Suporte: suporte@treeunfe.com.br
- 💬 Issues: [GitHub Issues](https://github.com/treeunfe/treeunfe-dfe/issues)

## ⭐ Agradecimentos

Agradecemos a todos os contribuidores e usuários que tornam este projeto possível!

---

**Treeunfe DFe** - Simplificando a integração com a SEFAZ 🚀
