📄 Card 71 [M13] — Faturas (Agrupamento de Cobranças)
📚 Referência Genius: Configuração financeira — "Uma fatura é quando as contas de um cliente com mesma data de vencimento são agrupadas em uma única cobrança."
🎯 Objetivo
Implementar o conceito de Fatura — agrupar mensalidades/contas do mesmo responsável com mesma data de vencimento em uma única cobrança:
- Quando gerar mensalidade (Job Bull mensal), se já houver cobrança do mesmo responsável na mesma data → agrupa em 1 Fatura
- Fatura tem valor total, 1 PIX/boleto único
- Reduz custos de emissão (1 boleto ao invés de N)
- Visualização única pro responsável (em vez de múltiplas parcelas)
- Configurável por filial (toggle on/off)
📚 Documentação de Referência
prisma/schema.prisma—Paymentexistente (adicionarInvoicerelation)docs/execucao/10-m2-financeiro-pix.md— geração PIX/boleto
🛠️ Especificação Técnica
Schema Prisma (novo)
model Invoice {
id String @id @default(cuid())
code String @unique // "FAT-2026-0001"
branchId String
branch Branch @relation(fields: [branchId], references: [id])
payerId String // userId do responsável financeiro
payer User @relation(fields: [payerId], references: [id])
dueDate DateTime
totalAmount Decimal @db.Decimal(12, 2)
status InvoicePayerStatus @default(PENDING) // PENDING, PAID, PARTIAL, CANCELLED
payments Payment[] // 1+ Payments agrupados
pixCode String?
boletoCode String?
pixUrl String?
boletoUrl String?
paidAt DateTime?
paidAmount Decimal? @db.Decimal(12, 2)
createdAt DateTime @default(now())
}
enum InvoicePayerStatus { PENDING PAID PARTIAL CANCELLED }
⚠️ Conflito de nomes:
Invoicejá existe no Card 69 (NFSe). Renomear:
- Card 69 NFSe →
TaxInvoice(Nota Fiscal)- Card 71 (este) →
BillingInvoice(Fatura de cobrança)
Rotas
/master/faturas— admin/local/faturas— por filial/pais/faturas— responsável vê suas faturas (reutiliza página PIX/boleto do Card 10)
Procedures tRPC (master.billingInvoices, local.billingInvoices, parent.billingInvoices)
list(filtros: status, período, responsável)detail(com Payments componentes)generatePix/generateBoleto(valor total da fatura)markPaid(manual ou webhook)cancel
Lógica de agrupamento
// Job Bull payment-generator (mensal dia 1):
async function generateMonthlyPayments() {
for (const enrollment of activeEnrollments) {
const dueDate = nextDueDate(enrollment);
// Busca fatura existente para o responsável na mesma data
let invoice = await prisma.billingInvoice.findFirst({
where: { payerId: enrollment.financialResponsibleId, dueDate, status: 'PENDING' }
});
if (!invoice) {
invoice = await prisma.billingInvoice.create({ ... });
}
// Cria o Payment vinculado à fatura
await prisma.payment.create({ ..., billingInvoiceId: invoice.id });
// Atualiza totalAmount da fatura
await prisma.billingInvoice.update({ where: { id: invoice.id }, data: { totalAmount: { increment: monthlyFee } } });
}
}
Configuração por filial
Branch.useInvoices: Boolean @default(false)— toggle on/off- Se
false: gera Payment individual com PIX/boleto próprio (comportamento atual)
✅ Critérios de Aceite
- Configuração por filial (usar faturas ou não)
- Quando on: mensalidades do mesmo responsável + mesma data viram 1 fatura
- Fatura tem valor total + 1 PIX + 1 boleto (ao invés de N)
- Responsável vê 1 cobrança na área financeira (em vez de múltiplas)
- Marcar fatura como paga → todos os Payments agrupados vão a PAID
- Cancelamento cancela todos os Payments componentes
- Build passa + lint OK
🔌 Handoff
- Job Bull
payment-generatoratualizado (Card 20) - Página
/pais/financeiroatualizada para mostrar fatura agrupada (Card 10)
🎯 Próximo
Card 72: Modelos de Documento Customizáveis
EXECUCAO — 2026-08-15
1. O que foi implementado
BillingInvoice (FAT-AAAA-NNNN): agrupa Payments do mesmo pagador+dia reutilizando fatura PENDING (incrementa total), PIX/boleto via mocks existentes, markPaid quita todos os Payments, cancel propaga. /local/faturas (agrupar/gerar/quitar) + /pais/faturas (visão do responsável com PIX copy).
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.