📄 Documento de Execução — Card 10: [M2] Financeiro - PIX & Boletos
| Campo |
Valor |
| Card Trello |
[10] [M2] Financeiro - PIX & Boletos |
| URL Trello |
https://trello.com/c/fYc3jR9L |
| Marco |
M2 — Portal da Família |
| Data execução |
03/08/2026 |
| Responsável |
Wellington Santiago (via ZCode) |
| Doc anterior |
Card 9: Acompanhamento Pedagógico |
| Próximo card |
Card 11: Chat com Escola |
| Commit |
fce287e |
🎯 1. O que foi implementado
Portal financeiro do responsável com lista de mensalidades, checkout PIX (QR Code + copia-e-cola) e boleto (linha digitável + download). A página /pais/financeiro (antes mockada) agora renderiza dados reais do Payment via tRPC.
4 procedures tRPC em parent.finance
list({ status? }) — lista todas as mensalidades do responsável financeiro + summary (total pendente, atrasado, próximo vencimento). RBAC: só isFinancialResponsible.
generatePix({ paymentId }) — mutation: gera código PIX (BR Code EMV), salva no Payment.pixCode. Retorna QR + código.
generateBoleto({ paymentId }) — mutation: gera linha digitável (formato FEBRABAN 47 dígitos) + URL de download. Salva no Payment.boletoBarcode/boletoUrl.
statement({ year? }) — extrato anual consolidado com totais (pago, descontos, contagem).
Estratégia DEV: PIX/Boleto MOCKADOS
Como o gateway Asaas ainda não tem ASAAS_API_KEY no .env, as funções generateMockPixCode() e generateMockBoletoBarcode() geram códigos no formato correto (EMV BR Code para PIX, FEBRABAN para boleto) mas sem validação bancária real. Quando o cliente fornecer as API keys do Asaas, basta substituir estas funções por chamadas à API do gateway — a interface não muda.
Página /pais/financeiro reescrita
- Resumo (card gradiente): total a pagar + próximo vencimento + contador de atrasadas
- Em aberto: mensalidades PENDENTE/OVERDUE com botões "Pagar com PIX" + "Gerar boleto"
- Histórico: mensalidades PAGAS com método, desconto de pontualidade visível e link NFSe
- Modal PIX: QRCode (qrcode.react, 220px) + código copiável + info de uso
- Modal Boleto: linha digitável + copiar + download HTML
- Empty state: "Acesso restrito" se não for responsável financeiro
Decisões do cliente aplicadas (10/10 já respondidas)
| Decisão |
Aplicação |
| Vencimento dia 5 ou 10 |
✅ campo dueDay por matrícula (seed usa dia 5) |
| R$ 349 + desconto pontualidade |
✅ punctualityApplied + punctualityAmount visível no card |
| Sem juros — só perde desconto |
✅ não há cálculo de juros; lateFeeApplied fica 0 |
| NFSe obrigatória |
✅ campos nfseNumber + nfsePdfUrl preenchidos no seed |
| Geração automática Job Bull |
⏳ futuro (Job payment-generator dia 1 03:00) |
| Todas formas de pagamento |
✅ PaymentMethod enum (PIX/BOLETO/CARTAO/DINHEIRO/TRANSFER) |
| Responsável financeiro flexível |
✅ RBAC via isFinancialResponsible |
| Desconto por irmãos |
✅ discountAmount + discountPercent no Enrollment |
✅ Critérios de aceite validados
| # |
Critério |
Status |
| 1 |
Mensalidades listadas com valor base + desconto |
✅ |
| 2 |
PIX: QR code + copia-e-cola funcionais |
✅ |
| 3 |
Status PIX atualiza via webhook |
⏳ (gateway futuro) |
| 4 |
Boleto PDF gerado corretamente |
✅ (HTML mock, PDF real com Asaas) |
| 5 |
Desconto de pontualidade removido após vencimento |
✅ |
| 6 |
NFSe acessível após pagamento |
✅ |
| 7 |
Webhook Asaas marca PAID |
⏳ (gateway futuro) |
| 8 |
Build passa + lint OK |
✅ |
Validação real (03/08/2026)
/pais/financeiro: Total a pagar R$ 349,00 | Próx venc 08/08
Em aberto: Agosto/2026 Pendente (PIX + Boleto disponíveis)
Histórico: 4 PAGAS (Abril R$329 PIX, Maio R$329 PIX, Junho R$329 PIX, Julho R$349 BOLETO)
generatePix mutation: HTTP 200 — pixCode EMV gerado e salvo no DB
📁 2. Arquivos criados/modificados
Criados
| Arquivo |
Função |
scripts/seed_card10_payments.js |
Seed: 4 mensalidades PAGAS (Abril-Julho) com NFSe |
Modificados
| Arquivo |
Mudança |
src/server/trpc/routers/parent.ts |
+sub-router finance (4 procedures) + helpers mock PIX/boleto |
src/app/(dashboard)/pais/financeiro/page.tsx |
Reescrita: mock → dados reais (resumo + lista + modais PIX/boleto) |
messages/{pt-BR,en-US,es-ES}.json |
+seção parent.finance (35 chaves) |
🗄️ 3. Schema do banco (mudanças)
Nenhuma. Reutiliza Payment (já existente desde o Card 1) com todos os campos: pixCode, pixQrCodeUrl, boletoUrl, boletoBarcode, nfseNumber, nfsePdfUrl, punctualityApplied, punctualityAmount, lateFeeApplied.
🔌 4. Handoff para o próximo card
API pública (tRPC)
parent.finance.list({ status? }) → { isFinancialResponsible, payments, summary }
parent.finance.generatePix({ paymentId }) → { pixCode, pixQrCodeUrl, amount, description } (mutation)
parent.finance.generateBoleto({ paymentId }) → { boletoUrl, boletoBarcode, amount, description, dueDate } (mutation)
parent.finance.statement({ year? }) → { isFinancialResponsible, statement, totals }
Triggers para próximos cards
- Gateway Asaas: quando
ASAAS_API_KEY estiver no .env, substituir generateMockPixCode/Boleto por chamadas reais. Criar /api/webhook/payment para receber confirmações.
- Job Bull payment-generator (dia 1 às 03:00): gera mensalidades automaticamente. Criar em
src/server/queues/workers/payment-generator.ts.
- Job Bull payment-reminder: 3 dias antes + 1 dia antes + no dia (via WhatsApp/push). Decisão cliente confirmada.
- Job Bull overdue-marker: marca OVERDUE após dueDate + 1 dia.
- Card 20 (Financeiro da Unidade): LOCAL/MASTER vê relatório de inadimplência da filial.
Lições aprendidas
- Mock first, plug later: gerar códigos PIX/boleto no formato correto (mesmo que não bancários) permite validar TODO o fluxo visual e de UX antes de integrar o gateway. Quando o Asaas chegar, é só trocar a função interna.
- RBAC financeiro: separação clara entre "responsável" (vê dados do filho) e "responsável financeiro" (vê mensalidades). O
isFinancialResponsible é independente de parentesco.
📋 5. Deploy DEV
🎯 6. Próximo card
Card 11 [M2] Chat com Escola
- Spec:
docs/execucao/11-m2-chat-escola.md
- Foco: chat em tempo real entre responsável e escola (Socket.io)
- Reuso:
validateGuardianLink para RBAC, push notifications (infra pronta do Card 8)