# Análise Completa - NFE_API

## Visão Geral

A **NFE_API** é uma API RESTful stateless em **PHP 8.2+** para o ciclo de vida completo da **NF-e modelo 55**. Foi construída sobre as bibliotecas `nfephp-org/sped-nfe` e `nfephp-org/sped-da`.

### Características Principais

| Característica | Descrição |
|----------------|-----------|
| **Stateless** | Sem banco de dados, sem estado em disco |
| **Certificado por Requisição** | A1 em Base64 enviado no JSON |
| **Tratemento Centralizado de Erros** | Respostas JSON padronizadas |
| **Reforma Tributária** | Suporte a IBS/CBS/IS (PL_010) |
| **PHP Puro** | Sem frameworks, PSR-4 autoload |

---

## Arquitetura do Sistema

### Estrutura de Pastas

```
nfe_api/
├── public/
│   └── index.php                    # Front Controller
│
├── src/
│   ├── Bootstrap.php                # Composition Root - wiring de serviços
│   │
│   ├── Http/                        # Camada HTTP
│   │   ├── Request.php              # Representação da requisição
│   │   ├── Response.php             # Resposta HTTP imutável
│   │   └── Router.php              # Roteador com tratamento centralizado
│   │
│   ├── Controller/                   # Controllers (orquestração HTTP)
│   │   ├── AbstractController.php  # Base com helpers (extração config)
│   │   ├── EmissaoController.php   # POST /nfe/emitir
│   │   ├── PreviaController.php    # POST /nfe/previa
│   │   ├── CancelamentoController.php  # POST /nfe/cancelar
│   │   ├── CartaCorrecaoController.php # POST /nfe/cce
│   │   ├── DanfeController.php     # POST /nfe/danfe
│   │   └── DistDFeController.php   # POST /nfe/dfe
│   │
│   ├── Service/                      # Regras de negócio
│   │   ├── EmissaoService.php       # Fluxo completo de emissão
│   │   ├── PreviaService.php        # Pré-visualização (draft)
│   │   ├── EventService.php         # Cancelamento e CC-e
│   │   ├── DanfeService.php         # Geração de DANFE PDF
│   │   └── DistDFeService.php       # Distribuição DF-e + Manifestação
│   │
│   ├── Parser/
│   │   └── NfeParser.php           # Converte JSON → NFePHP\Make (XML)
│   │
│   ├── Support/
│   │   ├── ToolsFactory.php        # Fabrica de Tools NFePHP
│   │   ├── SefazComm.php           # Comunicação com SEFAZ (boundary)
│   │   └── DanfeRenderer.php       # Renderização de DANFE PDF
│   │
│   ├── Config/
│   │   └── CertificateConfig.php   # DTO do objeto "config"
│   │
│   └── Exception/
│       ├── ApiException.php         # Base abstract para exceções
│       ├── ValidationException.php  # 400 Bad Request
│       ├── SefazRejectionException.php  # 422 Unprocessable Entity
│       └── SefazUnavailableException.php # 502 Bad Gateway
│
├── tests/                            # Testes PHPUnit
├── composer.json                     # Dependências
└── docs/                            # Documentação completa
```

---

## Fluxo de Requisição

```
┌─────────────────────────────────────────────────────────────────────┐
│                        CLIENTE (Frontend/App)                       │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │ POST /nfe/emitir
                                  │ Content-Type: application/json
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     public/index.php                                │
│  • Front Controller                                                  │
│  • Boundary global de exceções                                      │
│  • Decodifica JSON body                                             │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         Http\Router                                  │
│  • Match da rota (/nfe/emitir → EmissaoController)                  │
│  • Try/Catch centralizado                                           │
│  • Conversão de exceções em JSON padronizado                        │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Controller\EmissaoController                      │
│  • Extrai objeto "config" (certificado, CNPJ, UF, ambiente)        │
│  • Extrai "payload" (dados da NF-e)                               │
│  • Extrai "tributacao" (padrões de impostos)                      │
│  • Validações de schema                                             │
│  • Delega ao Service                                                │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      Service\EmissaoService                          │
│  1. NfeParser::build()      → Monta XML via NFePHP\Make           │
│  2. ToolsFactory::make()    → Cria Tools com certificado          │
│  3. signNFe()              → Assina XML com certificado A1       │
│  4. sefazEnviaLote()       → Envia lote à SEFAZ                  │
│  5. sefazConsultaRecibo()  → Consulta protocolo (se async)       │
│  6. Complements::toAuthorize() → Monta nfeProc com protocolo    │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        Support\SefazComm                            │
│  • Boundary de comunicação SOAP                                     │
│  • Catch ValidatorException → ValidationException (400)             │
│  • Catch Throwable → SefazUnavailableException (502)              │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        Resposta JSON                                │
│  {                                                                 │
│    "success": true,                                                │
│    "data": {                                                      │
│      "status": "autorizado",                                       │
│      "chave": "3524...",                                           │
│      "protocolo": "135250...",                                      │
│      "cStat": "100",                                              │
│      "xMotivo": "Autorizado o uso da NF-e",                        │
│      "xml": "PD94bWwgdmVyc2lvbj0i..."  (nfeProc Base64)         │
│    }                                                               │
│  }                                                                 │
└─────────────────────────────────────────────────────────────────────┘
```

---

## Endpoints da API

### 1. GET /health
**Descrição**: Health check da API

```bash
curl -X GET http://localhost:8080/health
```

**Response**:
```json
{
  "success": true,
  "status": "ok",
  "service": "nfe-api"
}
```

---

### 2. POST /nfe/previa
**Descrição**: Monta e assina localmente, gera DANFE de pré-visualização (sem enviar à SEFAZ)

**Payload**:
```json
{
  "config": {
    "certificado": "BASE64_DO_PFX_A1",
    "senha": "senha",
    "cnpj": "99999999000191",
    "ambiente": 2,
    "uf": "SP"
  },
  "payload": {
    "ide": { "natOp": "VENDA", "serie": 1, "nNF": 1, "dhEmi": "2024-01-15T10:00:00-03:00" },
    "emit": { "xNome": "EMPRESA TESTE", "IE": "123456789" },
    "enderEmit": { "xLgr": "RUA", "nro": "123", "xMun": "SAO PAULO", "UF": "SP" },
    "dest": { "xNome": "CLIENTE", "CPF": "12345678909" },
    "det": [
      { "prod": { "cProd": "001", "xProd": "PRODUTO", "qCom": 1, "vUnCom": 100, "vProd": 100 }, "imposto": {} }
    ],
    "total": { "ICMSTot": { "vProd": 100, "vNF": 100 } }
  }
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "chave": "35240199999999000191550010000000011234567890",
    "xml": "PD94bWwgdmVyc2lvbj0i...",
    "danfe": "JVBERi0xLjQK...",
    "ambiente": 2
  }
}
```

---

### 3. POST /nfe/emitir
**Descrição**: Fluxo completo de emissão com autorização SEFAZ

**Payload**:
```json
{
  "config": { "certificado": "...", "senha": "...", "cnpj": "...", "ambiente": 1, "uf": "SP" },
  "payload": { /* dados da NF-e */ },
  "tributacao": { "icms": { "orig": 0, "CST": "00", "vBC": 100, "pICMS": 18, "vICMS": 18 } },
  "sincrono": true,
  "lote": "000000000000001"
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "status": "autorizado",
    "chave": "35240199999999000191550010000000011234567890",
    "protocolo": "135250000000001",
    "cStat": "100",
    "xMotivo": "Autorizado o uso da NF-e",
    "recibo": null,
    "xml": "PD94bWwgdmVyc2lvbj0i...",
    "ambiente": 1
  }
}
```

---

### 4. POST /nfe/cancelar
**Descrição**: Cancela uma NF-e autorizada

**Payload**:
```json
{
  "config": { "certificado": "...", "senha": "...", "cnpj": "...", "ambiente": 1, "uf": "SP" },
  "chave": "35240199999999000191550010000000011234567890",
  "protocolo": "135250000000001",
  "justificativa": "Cancelamento solicitado pelo cliente - pedido indevido"
}
```

**Response**:
```json
{
  "success": true,
  "data": {
    "evento": "110111",
    "chave": "35240199999999000191550010000000011234567890",
    "cStat": "135",
    "xMotivo": "Evento registrado e vinculado a NF-e",
    "protocolo": "234567890123456",
    "nSeqEvento": 1,
    "xml": "PD94bWwgdmVyc2lvbj0i..."
  }
}
```

---

### 5. POST /nfe/cce
**Descrição**: Carta de Correção Eletrônica

**Payload**:
```json
{
  "config": { "certificado": "...", "senha": "...", "cnpj": "...", "ambiente": 1, "uf": "SP" },
  "chave": "35240199999999000191550010000000011234567890",
  "correcao": "Correção do endereço de entrega: alterar rua para Av. Brasil",
  "sequencia": 1
}
```

---

### 6. POST /nfe/danfe
**Descrição**: Gera DANFE (PDF) de uma NF-e

**Payload**:
```json
{
  "xml": "PD94bWwgdmVyc2lvbj0i...",
  "ambiente": 2,
  "stream": false
}
```

**Response** (stream: false):
```json
{
  "success": true,
  "data": {
    "ambiente": 2,
    "danfe": "JVBERi0xLjQK..."
  }
}
```

**Response** (stream: true): PDF binário diretamente

---

### 7. POST /nfe/dfe
**Descrição**: Distribuição de DF-e e Manifestação de Destinatário

**Consulta por NSU**:
```json
{
  "config": { "certificado": "...", "senha": "...", "cnpj": "...", "ambiente": 2, "uf": "SP" },
  "acao": "consulta",
  "ultNSU": 0
}
```

**Response**:
```json
{
  "success": true,
  "acao": "consulta",
  "data": {
    "cStat": "138",
    "xMotivo": "Documento(s) localizado(s)(s)(s) na base de dados da SEFAZ",
    "ultNSU": "000000000000100",
    "maxNSU": "000000000000200",
    "documentos": [
      { "chave": "...", "NSU": "...", "schema": "resNFe", "xml": "..." }
    ]
  }
}
```

**Manifestação**:
```json
{
  "config": { "certificado": "...", "senha": "...", "cnpj": "...", "ambiente": 2, "uf": "SP" },
  "acao": "manifestacao",
  "tipo": "confirmacao",
  "chave": "35240199999999000191550010000000011234567890"
}
```

**Tipos de Manifestação**:
| tipo | Descrição |
|------|-----------|
| `ciencia` | Ciência da Operação (210210) |
| `confirmacao` | Confirmação da Operação (210220) |
| `desconhecimento` | Desconhecimento (210220) |
| `nao_realizada` | Operação Não Realizada (210220) |

---

## Objeto `config`

O objeto `config` é obrigatório em todas as requisições que envolvem certificado ou comunicação SEFAZ:

```json
{
  "config": {
    "certificado": "BASE64_DO_ARQUIVO_PFX_A1",
    "senha": "senha-do-certificado",
    "cnpj": "99999999000191",
    "ambiente": 2,
    "uf": "SP",
    "schemes": "PL_009_V4",
    "versao": "4.00",
    "CSC": "",
    "CSCid": ""
  }
}
```

| Campo | Obrigatório | Descrição |
|-------|-------------|-----------|
| `certificado` | ✅ | Certificado A1 em Base64 (.pfx) |
| `senha` | ✅ | Senha do certificado |
| `cnpj` | ✅ | CNPJ do emitente (14 dígitos) |
| `ambiente` | ✅ | 1=Produção, 2=Homologação |
| `uf` | ✅ | UF do emitente |
| `schemes` | ❌ | Layout (use `PL_010_*` para Reforma Tributária) |
| `versao` | ❌ | Versão XML (padrão: "4.00") |

---

## Estrutura do Payload NF-e

O payload segue o layout oficial da NF-e:

```json
{
  "payload": {
    "infNFe": { "versao": "4.00" },
    "ide": { "natOp": "...", "serie": 1, "nNF": 1, "dhEmi": "...", "tpNF": 1 },
    "emit": { "xNome": "...", "IE": "...", "CNPJ": "..." },
    "enderEmit": { "xLgr": "...", "nro": "...", "xMun": "...", "UF": "..." },
    "dest": { "xNome": "...", "CNPJ/CPF": "..." },
    "det": [
      {
        "prod": { "cProd": "...", "xProd": "...", "qCom": 1, "vUnCom": 100, "vProd": 100 },
        "imposto": { "vTotTrib": 0 },
        "icms": { "orig": 0, "CST": "00", "vBC": 100, "pICMS": 18, "vICMS": 18 },
        "pis": { "CST": "01", "vBC": 100, "pPIS": 1.65, "vPIS": 1.65 },
        "cofins": { "CST": "01", "vBC": 100, "pCOFINS": 7.6, "vCOFINS": 7.6 }
      }
    ],
    "total": { "ICMSTot": { "vProd": 100, "vNF": 100 } },
    "transp": { "modFrete": 9 },
    "pag": { "detPag": [{ "indPag": 0, "tPag": "01", "vPag": 100 }] }
  }
}
```

### Blocos de Impostos Suportados

| Bloco | Método NFePHP | Descrição |
|-------|--------------|-----------|
| `icms` | `tagICMS` | ICMS Regime Normal (CST) |
| `icmssn` | `tagICMSSN` | ICMS Simples Nacional (CSOSN) |
| `icmsst` | `tagICMSST` | ICMS-ST |
| `icmsufdest` | `tagICMSUFDest` | DIFAL |
| `ipi` | `tagIPI` | IPI |
| `pis` | `tagPIS` | PIS |
| `cofins` | `tagCOFINS` | COFINS |
| `ibscbs` | `tagIBSCBS` | **IBS/CBS** (Reforma Tributária) |
| `is` | `tagIS` | Imposto Seletivo |

---

## Tratamento de Erros

### Mapeamento de Exceções → HTTP

| Exceção | HTTP | Código | Descrição |
|---------|------|--------|-----------|
| `ValidationException` | 400 | `validation_error` | Payload inválido |
| `SefazRejectionException` | 422 | `sefaz_rejection` | Rejeição SEFAZ |
| `SefazUnavailableException` | 502 | `sefaz_unavailable` | SEFAZ fora do ar |
| (não tratada) | 500 | `internal_error` | Erro interno |

### Formato de Resposta de Erro

```json
{
  "success": false,
  "error": {
    "code": "validation_error",
    "message": "config.cnpj deve conter 14 digitos.",
    "details": {
      "cStat": "539",
      "xMotivo": "Rejeicao: Duplicidade de NF-e"
    }
  }
}
```

### Principais cStats de Rejeição

| cStat | Descrição |
|-------|-----------|
| 100 | Autorizado |
| 101 | Cancelamento homologado |
| 135 | Evento registrado |
| 539 | Duplicidade de NF-e |
| 204 | Duplicidade de evento |
| 215 | Falha schema XML |
| 225 | Falha noハsh |
| 302 | Uso indevido (intermitência) |

---

## Componentes Principais

### 1. Bootstrap (Composition Root)

```php
final class Bootstrap
{
    public static function router(): Router
    {
        // Instancia todos os serviços
        $toolsFactory = new ToolsFactory();
        $parser = new NfeParser();
        $danfeRenderer = new DanfeRenderer();
        
        $previaService = new PreviaService($parser, $toolsFactory, $danfeRenderer);
        $emissaoService = new EmissaoService($parser, $toolsFactory);
        $eventService = new EventService($toolsFactory);
        $danfeService = new DanfeService($danfeRenderer);
        $distService = new DistDFeService($toolsFactory);
        
        // Registra rotas
        $router->post('/nfe/previa', new PreviaController($previaService));
        $router->post('/nfe/emitir', new EmissaoController($emissaoService));
        // ...
        
        return $router;
    }
}
```

### 2. Router (Tratamento Centralizado)

```php
final class Router
{
    public function dispatch(Request $request): Response
    {
        try {
            $handler = $this->routes[$request->method][$request->path] ?? null;
            // ...
            return $handler($request);
        } catch (ApiException $e) {
            return $this->renderApiException($e);  // 400/422
        } catch (Throwable $e) {
            return $this->renderUnexpected($e);     // 500
        }
    }
}
```

### 3. SefazComm (Boundary SEFAZ)

```php
final class SefazComm
{
    public static function send(callable $call): string
    {
        try {
            return $call();  // Executa método NFePHP
        } catch (ValidatorException $e) {
            throw new ValidationException('Schema invalido', [...]);
        } catch (Throwable $e) {
            throw new SefazUnavailableException('SEFAZ indisponivel', [...]);
        }
    }
}
```

### 4. NfeParser (JSON → XML)

```php
final class NfeParser
{
    public function build(array $payload, array $tributacao, ?string $schema): Make
    {
        $make = new Make($schema);
        
        $make->taginfNFe($payload['infNFe']);
        $make->tagide($payload['ide']);
        $make->tagemit($payload['emit']);
        
        foreach ($payload['det'] as $item) {
            $make->tagprod($item['prod']);
            // Itera sobre todos os blocos de imposto
            foreach (self::ITEM_TAX_MAP as $key => $method) {
                if (isset($item[$key])) {
                    $make->{$method}($item[$key]);
                }
            }
        }
        
        return $make;
    }
}
```

---

## Integração com NFePHP

A API utiliza duas bibliotecas principais:

### sped-nfe (Comunicação SEFAZ)
```php
$tools = new Tools($configJson, $certificate);
$tools->model(55);  // NF-e modelo 55

// Métodos utilizados:
$tools->signNFe($xml);           // Assinar
$tools->sefazEnviaLote($xmls, $lote, $indSinc);  // Enviar
$tools->sefazConsultaRecibo($recibo);             // Consultar
$tools->sefazCancela($chave, $justificativa, $protocolo);  // Cancelar
$tools->sefazManifesta($chave, $tpEvento, $just, $seq);    // Manifestar
$tools->sefazDistDFe($ultNSU, $numNSU);                   // Distribuição
```

### sped-da (DANFE PDF)
```php
$danfe = new Danfe($xml);
$danfe->debugMode(false);
$danfe->creditsIntegratorFooter('NFE_API');
$pdf = $danfe->render();
```

---

## Requisitos de Sistema

```json
{
  "php": ">=8.2",
  "extensoes": [
    "soap",      // Comunicação SOAP com SEFAZ
    "openssl",   // Assinatura digital
    "curl",      // HTTP requests
    "dom",       // Manipulação XML
    "libxml",    // Parser XML
    "simplexml", // Conversão XML
    "mbstring",  // Strings UTF-8
    "zlib",      // Compressão gzip
    "gd"         // Geração PDF
  ]
}
```

### Dependências Composer
```json
{
  "nfephp-org/sped-nfe": "^5.2",
  "nfephp-org/sped-da": "^1.1"
}
```

---

## Comandos Disponíveis

```bash
# Instalação
composer install

# Executar servidor dev
composer start  # PHP built-in server em http://0.0.0.0:8080

# Qualidade de código
composer cs      # PHP_CodeSniffer (PSR-12)
composer cs:fix  # Auto-fix PSR-12
composer stan    # PHPStan (análise estática)
composer test    # PHPUnit (testes)
```

---

## Comparação: NFE_API vs NFeWizard (planagro-server)

| Aspecto | NFE_API (PHP) | NFeWizard (Node.js) |
|---------|---------------|---------------------|
| **Linguagem** | PHP 8.2+ | Node.js |
| **Stateless** | ✅ 100% | ❌ Persiste estado |
| **Certificado** | Por requisição (Base64) | Configuração fixa |
| **Biblioteca SEFAZ** | nfephp-org/sped-nfe | nfewizard-io |
| **Emissão NF-e** | ✅ Completo | ✅ Completo |
| **Cancelamento** | ✅ | ❌ (em desenvolvimento) |
| **CC-e** | ✅ | ❌ |
| **DANFE** | ✅ | ✅ |
| **Manifesto DF-e** | ✅ | ✅ |
| **Distribuição NSU** | ✅ | ✅ |
| **Reforma Tributária** | ✅ (PL_010) | ❌ |

### Quando usar cada um?

**NFE_API (PHP)**:
- Quando precisa de API stateless (microserviços)
- Quando certificado varia por requisição
- Quando precisa de CC-e (Carta de Correção)
- Quando quer integração com linguagem PHP

**NFeWizard (Node.js)**:
- Quando já tem infraestrutura Node.js
- Quando certificado é fixo por configuração
- Quando precisa de persistência de estado (NSU, configurações)
- Quando está integrado ao planagro-server

---

## Integração com planagro-server

O `planagro-server` atualmente usa `nfewizard-io` para comunicação SEFAZ. A **NFE_API** pode ser uma alternativa ou complemento para:

1. **Emissão de NF-e** (quando o emitente é diferente do destinatário)
2. **Cancelamento e CC-e** (não disponíveis em nfewizard-io)
3. **Reforma Tributária** (IBS/CBS/IS via PL_010)

### Possível Arquitetura Integrada

```
┌─────────────────────┐     ┌─────────────────────┐
│   planagro-server   │     │      NFE_API        │
│     (Node.js)       │     │       (PHP)         │
│                     │     │                     │
│ • Manifesto         │────▶│ • Emissão NF-e      │
│ • Distribuição DF-e │     │ • Cancelamento      │
│ • Armazenamento     │     │ • CC-e              │
│ • Lógica de negocio │     │ • DANFE             │
└─────────────────────┘     └─────────────────────┘
        │                              │
        │         ┌────────────┐       │
        └────────▶│  Firebird  │◀──────┘
                  │  Database  │
                  └────────────┘
```

---

## Scripts e Exemplos

### 1. Emissão Completa

```bash
curl -X POST http://localhost:8080/nfe/emitir \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "certificado": "'$(base64 -i certificado.pfx)'",
      "senha": "123456",
      "cnpj": "99999999000191",
      "ambiente": 2,
      "uf": "SP"
    },
    "payload": { /* ... */ }
  }'
```

### 2. Pré-visualização

```bash
curl -X POST http://localhost:8080/nfe/previa \
  -H "Content-Type: application/json" \
  -d '{
    "config": { /* ... */ },
    "payload": { /* ... */ }
  }' | jq -r '.data.danfe' | base64 -d > danfe_preview.pdf
```

### 3. Cancelamento

```bash
curl -X POST http://localhost:8080/nfe/cancelar \
  -H "Content-Type: application/json" \
  -d '{
    "config": { /* ... */ },
    "chave": "352401...",
    "protocolo": "135250...",
    "justificativa": "Cancelamento por erro de digitacao"
  }'
```

### 4. Consulta DF-e

```bash
curl -X POST http://localhost:8080/nfe/dfe \
  -H "Content-Type: application/json" \
  -d '{
    "config": { /* ... */ },
    "acao": "consulta",
    "ultNSU": 0
  }'
```

---

## Boas Práticas

1. **Segurança do Certificado**
   - Nunca exponha o certificado em logs
   - Use HTTPS em produção
   - Considere criptografia adicional do Base64

2. **Tratamento de Erros**
   - Sempre verifique `success` na resposta
   - Implemente retry com backoff para `SefazUnavailableException`
   - Salve cStats rejeitados para análise

3. **Performance**
   - Mantenha o certificado em memória (se múltiplas requisições)
   - Use conexão persistente com SEFAZ
   - Cacheie configurações de UF/webservices

4. **Validação Local**
   - Valide schema antes de enviar à SEFAZ
   - Calcule-chave antes da emissão
   - Verifique CSC para NFC-e (não usado em NF-e)

---

## Conclusão

A **NFE_API** é uma API robusta e bem arquitetada para o ciclo de vida completo da NF-e. Sua natureza stateless e uso de PHP puro a tornam ideal para:

- Microserviços
- Integrações externas
- Alternativa ao nfewizard-io para funcionalidades específicas
- Suporte à Reforma Tributária

A documentação existente em `docs/` é completa e detalhada, cobrindo desde Quick Start até exemplos avançados de payloads.
