Assinaturas e Faturamento
Última atualização: 2026-04-08
Adapter centralizado: Toda comunicação HTTP com o Mercado Pago está em
_shared/payment-gateway.ts. Para trocar de provedor, alterar apenas esse arquivo.URLs dinâmicas: Links de pagamento e back URLs são gerados via
_shared/environment.ts, derivando o domínio base (olp.digitaloustaging.olp.digital) automaticamente a partir doSUPABASE_URL.Canal de notificação: Lembretes e avisos de faturamento são enviados via WhatsApp (Wasender). Ref: docs/architecture/THIRD_PARTY_INTEGRATIONS.md
1. Planos
Tabela: planos
| Campo | Tipo | Descrição |
|---|---|---|
nome | text | Nome do plano |
preco_mensal | numeric | Preço base mensal |
preco_anual | numeric | Preço anual (se aplicável) |
valor_por_aluno_extra | numeric | Valor por aluno contratado (multiplicado pelo total) |
alunos_minimo / alunos_maximo | int | Faixa de elegibilidade |
trial_dias | int | Duração do trial em dias |
is_trial | bool | Se é plano de teste |
tipo_cobranca | text | mensal ou anual |
features | jsonb | Features habilitadas |
Fórmula de Cálculo
Valor Mensal = Preço Base + (Alunos Contratados × Valor por Aluno Extra)2. Assinaturas
Tabela: escola_assinaturas
Ciclo Contratual
data_inicio→ início do contratomeses_contratados→ duração total (calculado a partir do rangemes_inicio→data_fim_contrato)data_fim_contrato→ último dia do mês final do contratodia_vencimento→ dia do mês para faturas (1-28, default 10)renovacao_automatica→ se renova ao expirar
Criação de Assinatura (CreateAssinaturaSchema)
A criação de assinatura usa validação Zod com os seguintes campos:
| Campo | Tipo | Regra |
|---|---|---|
escola_id | UUID | Obrigatório |
plano_id | UUID | Obrigatório |
status_assinatura | enum | 'ativa' ou 'trial' (default: 'ativa') |
alunos_contratados | int | Mínimo 1 |
dia_vencimento | int | 1-28 (default 10) |
mes_inicio | string | YYYY-MM, deve ser posterior ao mês atual |
data_fim_contrato | string | YYYY-MM, >= mes_inicio |
valor_personalizado | number | Opcional, override do cálculo automático |
renovacao_automatica | boolean | Default true |
Geração de faturas por range: Ao criar a assinatura, são geradas faturas skeleton (sem link_pagamento) para cada mês do range [mes_inicio, data_fim_contrato]. O cron faturamento-cron completa esses skeletons.
Status
| Status | Significado |
|---|---|
trial | Período de teste (validado por trial_ate) |
ativa | Assinatura paga ativa |
suspensa | Pagamento atrasado — acesso bloqueado |
cancelada | Cancelamento solicitado |
encerrada | Contrato finalizado |
Gateway MercadoPago
| Campo | Uso |
|---|---|
gateway_customer_id | ID do cliente no MercadoPago |
gateway_subscription_id | ID da assinatura (se recorrente) |
3. Faturas
Tabela: escola_faturas
Numeração Sequencial
Trigger gerar_numero_fatura gera automaticamente: OLP-2026-0001, OLP-2026-0002, etc.
Status de Pagamento
| Status | Descrição |
|---|---|
pendente | Gerada, aguardando pagamento |
pago | Pagamento confirmado |
atrasado | Vencimento ultrapassado |
cancelado | Fatura cancelada |
Integração MercadoPago
| Campo | Descrição |
|---|---|
gateway_preference_id | Preference ID do Checkout Pro |
link_pagamento | URL init_point para pagamento (uso interno do painel) |
gateway_payment_id | ID do pagamento confirmado |
pix_qrcode / pix_copia_cola | Dados PIX |
boleto_pdf_url / codigo_barras | Dados do boleto |
lembrete_d5_enviado_em | Timestamp do envio do lembrete D-5 (evita reenvio) |
Fluxo de Pagamento
1. Admin/cron gera link → Edge Function cria Preference no MercadoPago
2. preference_id salvo em gateway_preference_id
3. init_point salvo em link_pagamento (uso exclusivo do painel)
4. WhatsApp enviado SEM link — apenas informativo direcionando ao painel
5. Usuário acessa painel → "Pagamentos" → botão "Efetuar Pagamento" → MercadoPago
6. Webhook recebe notificação → valida pagamento → atualiza faturaNota: O pipeline anterior de URL curta (
olp.digital/pagar/{token}) foi descontinuado em 2026-04-16. Mensagens WhatsApp não contêm links de pagamento — olink_pagamentoé consumido apenas peloCheckoutLinkDialogdentro do painel autenticado.
4. Geração Automática de Faturas
Job: gerar-faturas-mensal
- Edge Function:
faturamento-cron(actiongerar_faturas) - Schedule:
0 6 28-31 * *(dias 28-31 de cada mês, 03:00 BRT / 06:00 UTC) - Lógica: Roda nos dias 28-31 mas só executa se
amanhã.getDate() === 1(último dia do mês) - Paradigma: O cron completa faturas existentes (skeleton → com link MP + WhatsApp + notificação). Se não existir skeleton, cria nova fatura (fallback).
- Guard: Uma fatura é considerada completa quando
link_pagamento IS NOT NULL. Skeletons (criados pelocreate_assinatura) são elegíveis para processamento. - Regra: Ciclo anual encerra em dezembro — não gera faturas além desse mês
- Alerta: Se existem assinaturas ativas mas nenhuma fatura foi processada, dispara alerta
faturamento.alerta_faturas_sem_linkvia ntfy
Regra de Ouro: "Sempre Mês Seguinte"
A primeira fatura de novos planos ou alterações é gerada para o primeiro dia do mês subsequente, evitando cobranças imediatas.
Recálculo Automático
Ao alterar alunos_contratados ou dia_vencimento, faturas pendentes futuras são recalculadas automaticamente.
5. Lembrete D-5
Job: lembrete-d5-diario
- Edge Function:
faturamento-cron(actionlembrete_d5) - Schedule:
0 9 * * *(diariamente, 06:00 BRT / 09:00 UTC) - Lógica: Busca faturas pendentes com vencimento em 5 dias que ainda não receberam lembrete (
lembrete_d5_enviado_em IS NULL) - Canal: Mensagem enviada via WhatsApp (Wasender) para o contato da escola
- Controle: Após envio bem-sucedido, marca
lembrete_d5_enviado_em = now()para evitar reenvios
Comportamento
| Cenário | Ação |
|---|---|
| Fatura pendente, vence em 5 dias, sem lembrete | Envia WhatsApp + marca timestamp |
| Fatura pendente, vence em 5 dias, já lembrada | Ignora (idempotente) |
| Fatura paga ou cancelada | Ignora |
6. Trial
Verificação: subscription-helper.ts
const resultado = await verificarAssinaturaEscola(supabase, escolaId, 'sistema');
if (!resultado.valida) {
// resultado.code: 'TRIAL_EXPIRADO' | 'SEM_ASSINATURA'
}Comportamento
| Cenário | Resultado |
|---|---|
Assinatura ativa ou trial válido | valida: true |
| Trial expirado | valida: false, code: 'TRIAL_EXPIRADO' |
| Sem assinatura | valida: false, code: 'SEM_ASSINATURA' |
| Erro técnico | valida: true (fail-open) |
Onde é Verificado
| Contexto | Edge Function |
|---|---|
| Login sistema | send-otp, verify-otp |
| Portal aluno | portal-escola (lookup) |
7. Ciclo Contratual Multi-Ano
Action: get_ciclo_contratual (admin-faturas)
Retorna dados completos do ciclo contratual de uma escola, com filtro por ano.
Parâmetros: escola_id (obrigatório), ano (opcional — default: ano corrente)
Retorno:
| Campo | Descrição |
|---|---|
faturas | Lista de faturas do ano filtrado |
metricas | Cálculos do ano: total_faturas, pagas, pendentes, valor_total, valor_pago, valor_pendente, taxa_adimplencia |
metricas_gerais | Cálculos de todo o contrato (sem filtro de ano) |
assinatura | Dados da assinatura ativa |
plano | Dados do plano |
anos_disponiveis | Lista de anos com faturas |
Nota: No frontend, metricas_gerais é independente do filtro de ano — ao trocar de ano, apenas a seção superior recarrega.
8. Administração
Edge Functions
| Função | Ações Principais |
|---|---|
admin-assinaturas | CRUD de assinaturas, recálculo de faturas |
admin-faturas | Listagem, get_ciclo_contratual, geração manual de links, marcação de pago |
admin-planos | CRUD de planos |
admin-escola-dados | create_assinatura (validação Zod CreateAssinaturaSchema) — criação na tela de detalhes |
escola-pagamentos | Visão da escola: faturas, links de pagamento (usado por gestão/diretor) |
mercadopago-preference | Gerar link de pagamento (Checkout Pro) |
mercadopago-webhook | Receber notificações de pagamento |
faturamento-cron | Geração mensal de faturas + lembrete D-5 |
Hooks Frontend
| Hook | Uso |
|---|---|
useAdminAssinaturas | Gestão de assinaturas (admin) |
useAdminFaturas | Gestão de faturas (admin) |
useAdminPlanos | Gestão de planos (admin) |
useMercadoPago | Geração de links e polling (admin) |
useEscolaPagamentos | Faturas e pagamentos (visão escola — gestão/diretor) |
9. Faturas Migradas
Faturas importadas de sistemas legados são marcadas com migrada = true. Não possuem gateway_preference_id e servem apenas como histórico financeiro.
10. Auto-Ativação de Escola
Ao ativar uma assinatura paga (status_assinatura = 'ativa'), se a escola estiver com status = 'em_analise', seu status é automaticamente alterado para ativa.
Regra conservadora: Só ativa escolas em em_analise. Escolas já ativa, suspensa ou encerrada não são alteradas.
Pontos de ativação (3 caminhos):
| Edge Function | Action | Contexto |
|---|---|---|
admin-escola-dados | create_assinatura | Tela de detalhes da escola |
admin-assinaturas | create | Tela de assinaturas |
admin-assinaturas | convert_trial_to_paid | Converter trial para pago |
11. Referências
- CRON Jobs — Detalhes do faturamento-cron e lembrete-d5
- Edge Functions — Catálogo completo
- Audit Log — Logs de operações financeiras
- Integrações — Wasender (WhatsApp) + MercadoPago