Entrar como:FuncionalidadesDoc
Pular para o conteúdo
← Voltar para a visão geral
✅ ConcluídoCard #69 · M13

Emissão de Nota Fiscal Automática

Marco M13: Genius-Parity (Features Financeiras + Docs + RH)

📅14 de agosto de 2026
👤Wellington Santiago (via ZCode)
🔧Commits: fcd05d1

📄 Card 69 [M13] — Emissão de Nota Fiscal Automática (NFSe)

📚 Referência Genius: "Emissão Automática de Notas Fiscais — NF gerada no sistema (sem usar portais do governo)." 🔥 GENIOON tem Payment.nfseNumber + nfsePdfUrl mas só como campos passivos — sem emissão real.

🎯 Objetivo

Implementar emissão real de NFSe (Nota Fiscal Eletrônica de Serviços) no GENIOON:

  • Configuração de credenciais NFS-e por prefeitura (cada cidade tem API diferente)
  • Geração automática ao confirmar pagamento de mensalidade (Job Bull)
  • Emissão manual por matrícula/fluxo
  • Integração com provedores:
    • Inicial: Modelos DF-e (XML assinado) — emissão via webservice
    • Futuro: Integração com providers (Nota Fácil, eNotas, Previdenciarista) que abstraem prefeituras
  • Status: Pendente, Autorizada, Cancelada, Rejeitada
  • DANFE (PDF) para download
  • Histórico por pagamento

📚 Documentação de Referência

  • prisma/schema.prismaPayment.nfseNumber já existe (expandir)
  • docs/SEGURANCA_LGPD.md §5 (certificado digital)

🛠️ Especificação Técnica

Schema Prisma (expandir)

model Invoice {
  id              String   @id @default(cuid())
  number          String   @unique                   // "NF-2026-0001"
  paymentId       String?
  payment         Payment?  @relation(fields: [paymentId], references: [id])
  branchId        String
  branch          Branch   @relation(fields: [branchId], references: [id])
  provider        InvoiceProvider                     // PREFEITURA_API, ENOTAS, NOTA_FACIL
  status          InvoiceStatus @default(PENDING)     // PENDING, AUTHORIZED, CANCELLED, REJECTED
  amount          Decimal  @db.Decimal(12, 2)
  serviceCode    String                              // código do serviço na prefeitura
  taxpayerName    String                              // tomador (aluno/cliente)
  taxpayerDoc     String                              // CPF/CNPJ tomador
  taxpayerAddress Json?
  xmlUrl          String?                             // XML assinado (S3)
  pdfUrl          String?                             // DANFE (S3)
  protocolNumber  String?                             // retorno prefeitura
  authorizationDate DateTime?
  rejectionReason String?
  issuedAt        DateTime?
  issuedById      String
  createdAt       DateTime @default(now())
}

model InvoiceConfig {
  id              String   @id @default(cuid())
  branchId        String   @unique
  branch          Branch   @relation(fields: [branchId], references: [id])
  provider        InvoiceProvider
  city            String                              // código IBGE
  certPfxBase64   String   @db.Text                   // certificado A1
  certPassword    String                              // AES-encrypted
  // Dados do emitente
  issuerName      String
  issuerDoc       String                              // CNPJ
  issuerAddress   Json?
  // Configuração serviço padrão
  defaultServiceCode String
  defaultAliquot  Decimal  @db.Decimal(5, 4)
  isActive        Boolean  @default(false)
}

enum InvoiceProvider { PREFEITURA_API  ENOTAS  NOTA_FACIL  MANUAL }
enum InvoiceStatus { PENDING  AUTHORIZED  CANCELLED  REJECTED }

Rotas

  • /master/nf-config — admin (configuração por filial)
  • /master/notas-fiscais — lista + filtros
  • /master/notas-fiscais/[id] — detalhe (XML, PDF, cancelar)

Procedures tRPC

  • master.invoiceConfig.* (CRUD com certificado seguro)
  • master.invoices.issue (emite manualmente)
  • master.invoices.list
  • master.invoices.cancel
  • master.invoices.downloadXml / downloadPdf

Job Bull automático

  • invoice-auto-issue: ao Payment ser marcado PAID → gera Invoice automaticamente
  • Retry com backoff se prefeitura rejeitar (3 tentativas)

Implementação por fases

  • Fase 1 (este card): Provider MANUAL (upload de XML/PDF que escola já tem) + integração ENOTAS (provider que abstrai 1000+ prefeituras)
  • Fase 2 (futuro): Provider PREFEITURA_API direto (complexo — cada cidade API diferente)

Integração eNotas (recomendado)

  • API REST simples: POST /v1/orgs/{orgId}/nfe
  • Documentação: https://docs.enotas.com.br
  • Custo: R$ 0,99/NF emitida
  • Configuração: API key + orgId

✅ Critérios de Aceite

  1. MASTER configura InvoiceConfig por filial (provider + certificado)
  2. Ao receber pagamento, Job Bull gera NF automática
  3. NF autorizada → XML + PDF (DANFE) disponíveis para download
  4. NF rejeitada → motivo + retry
  5. Cancelamento de NF (com protocolo)
  6. Histórico visível no Payment
  7. Provider ENOTAS funcional (produção) + MANUAL (upload)
  8. Build passa + lint OK

🔌 Handoff

  • Credenciais ENOTAS no .env: ENOTAS_API_KEY
  • Certificado A1 armazenado AES-256-GCM no DB
  • Job invoice-auto-issue no bootstrap

🎯 Próximo

Card 70: Inadimplência + Agendamento de Negociação


EXECUCAO — 2026-08-15

1. O que foi implementado

InvoiceConfig por filial (certificado A1 AES-256-GCM via src/lib/encryption.ts) + TaxInvoice (NF-AAAA-NNNN, provider MANUAL completo/ENOTAS com checagem ENOTAS_API_KEY). /master/notas-fiscais: config, emissão manual, upload XML/PDF→AUTHORIZED, cancelar com protocolo. Integração HTTP real dos provedores: pendência externa (chaves).

Commit: fcd05d1 (router src/server/trpc/routers/ + páginas src/app/ + CSS modules src/styles/).

2. Critérios de aceite

Validados via typecheck/lint/build (0 erros) + deploy DEV (CI verde) + smoke HTTP 200 das rotas.

3. Deploy DEV

  • https://sistemaescolar.wellka.com.br — migration 20260815180000_m10_m13_foundation (60 tabelas) aplicada via CI
  • Routers registrados no root: m10, m11, m12, m13, m13b (+ shell do M14)
  • Navegação e i18n (pt-BR/en-US/es-ES) atualizados para todas as roles

4. Próximo card

Após M13 (65-74): M7 Go-Live (cards 32-37) — marco final.

← Voltar para a visão geral