Assinaturas
Assinaturas
O modulo de assinaturas controla o acesso dos usuarios aos recursos da plataforma AgrSis. Cada usuario possui uma assinatura vinculada a um plano, que define limites e funcionalidades disponiveis.
Tipos de plano
Os planos sao segmentados por perfil de usuario (profile_type): producer, supplier ou consultant.
Plano gratuito
- Todos os precos (
price_monthly,price_quarterly,price_yearly) saonull. - Serve como ponto de partida e como fallback quando uma assinatura paga expira ou e cancelada.
- Pode ser marcado como
is_defaultpara ser atribuido automaticamente no cadastro. - Nao possui periodo de vigencia (
current_period_endficanull).
Plano pago
- Possui ao menos um preco definido entre mensal, trimestral ou anual.
- Cada plano tem uma lista de features (tabela
plan_feature_values) com valores especificos — tipolimit(numero) ouboolean. - O admin pode criar, editar, ativar/desativar e reordenar planos pelo painel.
Trial
Quando o plano padrao possui trial_days > 0, o usuario recebe a assinatura com status trial.
- O valor padrao de trial e configuravel por plano (campo
trial_daysna tabelasubscription_plans). trial_ends_ate calculado comonow() + trial_days.current_period_ende igual atrial_ends_atdurante o trial.- Notificacoes de expiracao sao enviadas nos dias 7, 3, 1 e 0 antes do vencimento do trial.
- Ao expirar, o status muda para
expirede o usuario e movido para o plano gratuito com statusexpired(fallback).
Prorrogacao de trial (admin)
O administrador pode prorrogar o trial via endpoint POST /api/v1/admin/subscriptions/{id}/extend-trial:
- Aceita assinaturas com status
trialouexpired. - Parametro
days(1 a 365). - Se a assinatura estiver expirada, o novo prazo parte de
now(). - Se estiver em trial, o prazo e somado ao
trial_ends_atatual.
Ciclos de cobranca
Ao assinar um plano pago, o usuario escolhe um ciclo (billing_cycle):
| Ciclo | Chave | Duracao do periodo |
|---|---|---|
| Mensal | monthly | 1 mes |
| Trimestral | quarterly | 3 meses |
| Anual | yearly | 12 meses |
O preco e determinado pelo metodo getPriceForCycle() do modelo SubscriptionPlan, que retorna o campo correspondente (price_monthly, price_quarterly ou price_yearly).
Metodos de pagamento
Os metodos habilitados sao configurados na tabela de settings (chave payment_methods_enabled) e podem incluir:
- PIX (
pix) — gera cobranca com QR Code e copia-e-cola; vencimento em 1 dia. - Boleto (
boleto) — gera boleto com vencimento em 3 dias. - Cartao de credito (
credit_card) — cobranca imediata; pagamento marcado comopaidna hora.
Todos os pagamentos sao processados via ASAAS (classe AsaasGateway), que implementa a interface PaymentGatewayInterface. O gateway so e ativado se as chaves asaas_enabled e asaas_api_key estiverem configuradas nas settings.
Ambientes do ASAAS
- Sandbox:
https://sandbox.asaas.com/api/v3(settingasaas_environment = sandbox) - Producao:
https://api.asaas.com/api/v3(settingasaas_environment = production)
Tokenizacao de cartao
Na primeira cobranca com cartao de credito, o ASAAS retorna um creditCardToken. Esse token e salvo na assinatura junto com os ultimos 4 digitos (card_last_digits) e a bandeira (card_brand).
Nas renovacoes seguintes, a cobranca e feita usando apenas o token, sem necessidade de reenviar os dados completos do cartao. O payload enviado ao ASAAS contem somente creditCardToken.
Renovacao automatica
O campo auto_renew (padrao true) controla se a assinatura sera renovada automaticamente. O processamento e feito pelo comando agendado subscriptions:process-renewals.
Alerta 7 dias antes
- Assinaturas ativas com
auto_renew = trueecurrent_period_endigual anow() + 7 diasrecebem uma notificacao. - Se o usuario possui cartao tokenizado, a mensagem informa que a renovacao sera automatica (ex.: "sera renovada via cartao final 1234").
- Sem token, a mensagem orienta o usuario a renovar manualmente.
Cobranca no dia do vencimento
No dia em que current_period_end <= now():
- Com token de cartao: a cobranca e feita automaticamente via
generateCardPaymentusando o token. O periodo e renovado (current_period_start = now(),current_period_endcalculado pelo ciclo). O usuario recebe notificacao de renovacao com o valor e os ultimos digitos do cartao. - Sem token: o usuario recebe notificacao orientando a renovar manualmente pelo portal.
- Falha na cobranca: o usuario recebe notificacao de falha e e orientado a renovar manualmente.
Uma verificacao de duplicata impede que pagamentos sejam criados se ja existe um pagamento pending ou paid nos ultimos 3 dias para a mesma assinatura.
Desativar renovacao
O usuario pode desativar a renovacao automatica via:
POST /api/v1/subscription/cancel— desativaauto_renewsem cancelar a assinatura imediatamente.POST /api/v1/subscription/toggle-auto-renew— alterna o valor deauto_renew.
Ao desativar, o plano continua ativo ate o fim do periodo pago (current_period_end). Quando o periodo expira com auto_renew = false, o sistema move o usuario para o plano gratuito.
Fallback para plano gratuito
Quando uma assinatura paga expira ou e cancelada, o metodo fallbackToFreePlan() cria uma nova assinatura no plano gratuito do mesmo profile_type, com status expired.
Situacoes que disparam o fallback:
- Trial expirado
- Assinatura paga expirada com
auto_renew = false - Cancelamento apos estorno de pagamento
Webhook de pagamento
O endpoint de webhook recebe eventos do ASAAS e atualiza o status do pagamento:
| Evento ASAAS | Status interno |
|---|---|
PAYMENT_CONFIRMED, PAYMENT_RECEIVED | paid |
PAYMENT_OVERDUE | past_due |
PAYMENT_DELETED, PAYMENT_RESTORED | cancelled |
PAYMENT_REFUNDED | refunded |
Quando o pagamento e confirmado (paid), a assinatura e ativada e o periodo e renovado. Quando fica atrasado (past_due), o status da assinatura muda para past_due e o usuario e notificado.
Gestao administrativa
O painel administrativo oferece os seguintes recursos:
Planos
- Listar planos com contagem de assinantes (
GET /api/v1/admin/subscription-plans) - Criar plano com nome, perfil, precos e trial days (
POST /api/v1/admin/subscription-plans) - Editar plano incluindo marcar como default (
PUT /api/v1/admin/subscription-plans/{id}) - Gerenciar features de cada plano (
PUT /api/v1/admin/subscription-plans/{id}/features) - Desativar plano — soft delete via
is_active = false(DELETE /api/v1/admin/subscription-plans/{id})
Ao marcar um plano como is_default, todos os outros planos do mesmo profile_type sao desmarcados.
Assinaturas
- Listar assinaturas com filtro por status e paginacao (
GET /api/v1/admin/subscriptions) - Alterar plano de uma assinatura com observacao obrigatoria e registro em audit log (
PUT /api/v1/admin/subscriptions/{id}/change-plan) - Ativar manualmente uma assinatura por N dias, com observacao obrigatoria e
auto_renew = false(POST /api/v1/admin/subscriptions/{id}/activate) - Prorrogar trial de 1 a 365 dias (
POST /api/v1/admin/subscriptions/{id}/extend-trial) - Historico de acoes administrativas via audit log (
GET /api/v1/admin/subscriptions/{id}/logs)
Pagamentos
- Listar pagamentos com filtro por status (
GET /api/v1/admin/subscription-payments) - Estornar pagamento total ou parcial via ASAAS, com opcao de cancelar a assinatura (
POST /api/v1/admin/subscription-payments/{id}/refund)- So permite estorno de pagamentos com status
paid - Valor parcial nao pode exceder o valor pago
- Se
cancel_subscription = true, a assinatura e cancelada e o usuario cai no plano gratuito
- So permite estorno de pagamentos com status
Metricas do dashboard
O endpoint GET /api/v1/admin/subscription-metrics retorna:
- Assinantes ativos (trial + active)
- Contagem separada de trials e pagos ativos
- Assinaturas expiradas
- Receita do mes atual
- ARR (Annual Recurring Revenue) — soma anualizada das assinaturas ativas pagas
- Assinaturas expirando neste mes e no proximo
- Historico de receita dos ultimos 6 meses
Notificacoes
As notificacoes de assinatura sao enviadas via sistema interno e, conforme configuracao do NotificationChannelConfig, podem ser encaminhadas por email e/ou WhatsApp.
| Tipo | Quando |
|---|---|
trial_expiring | 7, 3, 1 e 0 dias antes do fim do trial |
trial_expired | Trial expirou |
payment_confirmed | Pagamento confirmado (webhook ou cartao) |
payment_overdue | Pagamento atrasado |
subscription_renewed | Assinatura renovada automaticamente |
subscription_charge_created | Alerta 7 dias antes do vencimento / renovar |
Status da assinatura
| Status | Significado |
|---|---|
trial | Periodo de teste ativo |
active | Assinatura paga ativa |
past_due | Pagamento atrasado |
expired | Periodo encerrado (trial ou pago) |
cancelled | Cancelada manualmente ou por estorno |
Comandos agendados
| Comando | Funcao |
|---|---|
subscriptions:process-renewals | Alerta 7 dias antes e renova assinaturas no dia do vencimento |
| Verificacao de expirados | Executada pelo metodo checkExpired() do SubscriptionService, que expira trials e assinaturas com auto_renew = false |