📄 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+nfsePdfUrlmas 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.prisma—Payment.nfseNumberjá 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.listmaster.invoices.cancelmaster.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
- MASTER configura InvoiceConfig por filial (provider + certificado)
- Ao receber pagamento, Job Bull gera NF automática
- NF autorizada → XML + PDF (DANFE) disponíveis para download
- NF rejeitada → motivo + retry
- Cancelamento de NF (com protocolo)
- Histórico visível no Payment
- Provider ENOTAS funcional (produção) + MANUAL (upload)
- Build passa + lint OK
🔌 Handoff
- Credenciais ENOTAS no
.env:ENOTAS_API_KEY - Certificado A1 armazenado AES-256-GCM no DB
- Job
invoice-auto-issueno 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.