# Documentação técnica — Planos, funcionalidades, cadastro externo, assinatura e Pagar.me

**Última atualização:** 2026-06-08

Este documento cobre o **catálogo de planos** (`planos`), **funcionalidades** e vínculo **plano × funcionalidade** (`plano_funcionalidade`), o **cadastro público** de cliente/tenant (senha ou **SSO**), **upgrade de plano**, a **cobrança** via **Pagar.me** (cartão + webhook) e a tela **Pagamentos / Minha assinatura**. Documentos relacionados: **`Doc_Modulo_Tenant.md`**, **`Doc_Modulo_Assinatura_Contrato.md`**, **`Doc_Modulo_Pessoa_Usuario.md`** § 6.5–6.6.

---

## 1. Modelos e tabelas

### 1.1 `Plano` (`planos`)

| Campo (fillable) | Uso |
|------------------|-----|
| `idprodserv` | Produto/serviço que materializa o plano (preço, DRE, etc.). |
| `idempresa` | Empresa “fornecedora” do plano (normalmente a operadora SaaS). |
| `nome`, `valor`, `status` | Identificação, preço, ATIVO/INATIVO. |
| `codigo` | Slug comercial (`trial`, `start`, `gestao`, `pro`, `consultivo`) — usado em `cadastro/{plano}`. |
| `descricao_curta`, `descricao_comercial` | Textos para admin e landing. |
| `gratuito` | Trial ou plano sem checkout; com `trial_dias` > 0 trata-se de **teste limitado**, não gratuito permanente. |
| `trial_dias` | Duração do teste (padrão `NOLAPIS_TRIAL_DIAS`, default 14). |
| `limite_usuarios`, `limite_empresas` | Limites do plano; `null` = ilimitado. |
| `creditos_ia` | Créditos mensais **preparados** (IA ainda não ativa no produto). |
| `suporte_nivel` | `ticket`, `prioritario`, `consultivo`. |
| `ordem`, `destaque`, `consultivo`, `sob_consulta` | Exibição e fluxo comercial. |
| `permite_usuario_adicional`, `valor_usuario_adicional` | Estrutura para cobrança de usuário extra (ex.: R$ 19,90). |

**Escopo:** `TenantScope` — como há `idempresa`, o isolamento segue **`empresa.idtenant`** (ver `TenantScope`).

**Controller:** `PlanoController` — CRUD, `fetch`, normalização monetária, toggle `gratuito`.

### 1.2 `Funcionalidade` (`funcionalidades`)

| Campo | Uso |
|-------|-----|
| `nome`, `alias` | Nome exibido e identificador lógico (potencial uso futuro em *feature flags* ou permissões). |
| `quantitativo` | Flag de UI (sim/não) no cadastro. |
| `status` | ATIVO/INATIVO. |

**Escopo:** `TenantScope` registrado, porém a tabela **`funcionalidades`** está na **lista de exclusão** do `TenantScope` — na prática **não** é aplicado `WHERE idtenant` nesse model; o catálogo tende a ser **global** no banco salvo filtros manuais.

**Controller:** `FuncionalidadeController` — CRUD + `fetch` (atenção: typo `admin.funciondalide` na rota do `fetch`).

**Autorização por plano:** `App\Services\PlanoService` consulta `plano_funcionalidade` + `alias`. Middleware `plano.funcionalidade:{alias}` (ex.: `dre_gerencial`, `dfc_gerencial`) bloqueia rotas e redireciona com mensagem de upgrade.

### 1.3 `PlanoFuncionalidade` (`plano_funcionalidade`)

Tabela pivô enriquecida: `idplano`, `idfuncionalidade`, `status`, **`qtd`** (limite ou quantidade contratada, conforme regra de negócio futura).

**Escopo:** `TenantScope` + exclusão no scope (como `funcionalidades` / `planos` em certos ramos) — tratar como catálogo **compartilhado** ou alinhado ao tenant operador, conforme ambiente.

**Controller:** `PlanoFuncionalidadeController` — CRUD, `fetch` (URL de edição no `fetch` aponta para **`admin.forma-pagamento.edit`** — provável **bug de cópia**).

**Rotas:** `admin.plano-funcionalidade.*`, `plano-funcionalidade.search`, `fetch`.

---

## 2. Cadastro externo (entrada no sistema)

### 2.1 Rotas públicas (`middleware guest`)

| Rota | Função |
|------|--------|
| `GET cadastro/{plano}/{pessoa?}` | `CadastroController::create` — formulário; `pessoa` opcional (representante pré-selecionado se `tipo == R`). |
| `POST cadastro/{plano}/validar-cupom` | Valida cupom no cadastro (JSON). |
| `POST cadastro/{plano}/gerar-pix` | `CadastroController::store` — transação de criação + checkout (nome legado da rota). |
| `GET cadastro/{tenant}/status` | JSON com `tenant.status` (polling de liberação). |
| `POST cadastro/webhook/pagarme` | `WebhookController::handle` — eventos Pagar.me. |
| `GET auth/{provedor}/redirect?intent=cadastro&plano=` | OAuth Google/Microsoft no passo 2 — ver **`Doc_Modulo_Pessoa_Usuario.md`** § 6.5. |

### 2.2 Fluxo `store` (resumo)

1. Deriva **CPF/CNPJ** e tipo Pagar.me (`individual` / `company`).
2. **Autenticação do lead:** senha local **ou** sessão `sso_cadastro` (Google/Microsoft). SSO → `users.auth_tipo = sso`, `tenant.auth_padrao = sso`; senha → `auth_tipo = senha`.
3. **Plano gratuito / trial:** `v_status = ATIVO`; plano pago → `INATIVO` até confirmação de pagamento.
4. **Pessoa** (representante): cria ou reutiliza por `cpfcnpj` + `idempresa` do **`$plano->prodserv->idempresa`**.
5. **Tenant** vinculado à pessoa; **User** ADMIN se e-mail novo; **Empresa** do tenant; **pessoas padrão** fornecedor/cliente.
6. **Contrato de assinatura** (`AssinaturaContratoService::provisionar`) — ver **`Doc_Modulo_Assinatura_Contrato.md`**.
7. **Plano pago:** NF + parcela `PENDENTE`; **cartão** tokenizado via Pagar.me (`AssinaturaCartaoService::associarCartao`, `card_token` no POST). Trial/gratuito: login automático após commit (senha ou sessão já autenticada no fluxo SSO).
8. **Cupom/promoção:** `CupomAssinaturaService` — escopo `NOVA_ASSINATURA` (§ 7.5).

**Inconsistência de campo:** `createTenant` usa `is_tenant_admin` no array; o fillable do `Tenant` é **`is_admin_tenant`** — alinhar com a migration real.

### 2.3 `PagarMeService`

- **Endpoint:** `POST https://api.pagar.me/core/v5/orders`
- **Autenticação:** Basic com `config('pagarme.api_key')` (`PAGARME_API_KEY` no `.env`).
- **Pagamento:** apenas **Pix** no payload atual (`expires_in` 30 dias).
- **Itens:** um item com `amount` em centavos, `code` = `idplano`.

### 2.4 `WebhookController` (pós-pagamento)

- **URL:** `cadastro.handle` — **guest** (proteção por assinatura).
- **Validação:** header `X-Hub-Signature` = `sha1=` + HMAC-SHA1 do corpo com a mesma **api_key** (tratar algoritmo conforme doc atual da Pagar.me).
- **Evento tratado:** `type === 'order.paid'` → `processChargeSucceeded`.

**Efeitos previstos (intenção do código):**

- Ativar **tenant**, **usuários** do tenant, **pessoa** do tenant.
- Marcar **parcela** como **`QUITADO`**, preencher `datatransacao`, ajustar `saldoatual` da parcela (lógica manual, **não** idêntica ao `NfParcelaService`).
- Se houver **comissão** de representante: criar NF de receita para o representante (trecho com possíveis **typos** `idoessoa`, `QUITADO` no cabeçalho da NF, `status` da parcela de comissão `PENDENTE` com `datatransacao` — revisar antes de produção).

**Risco de integração:** o serviço envia `idnfparcela` em **`customer.metadata`**, enquanto o webhook lê **`payload['data']['order']['metadata']['idnfparcela']`**. Se a Pagar.me não espelhar metadados no objeto `order`, **`$idnfparcela` será nulo** e a parcela não será atualizada. Recomenda-se alinhar payload e documentação da API v5.

---

## 3. Tela “Pagamentos e Assinaturas” (`PagamentoController`)

- **Rota:** `admin.pagamentos.index` (resource `pagamentos`).
- **Dados:** `Nf::withoutGlobalScope(TenantScope::class)` onde **`idpessoa`** = **`auth()->user()->tenant->idpessoa`** — ou seja, **todas** as NFs da pessoa titular do tenant (histórico de faturas de assinatura), com `parcelaWithoutGlobalScope` e `nfitemWithoutGlobalScope`.
- **View:** lista data de emissão, nome do plano (**sempre** `auth()->user()->tenant->plano->nome` — não difere por linha se houver várias NFs de planos distintos), valor NF, vencimento da **primeira parcela**, badge de status.

**Inconsistência:** a view compara status de **parcela** com **`CONCLUÍDO`**, enquanto o restante do sistema usa **`QUITADO`** para quitação de parcela — badges “Pago” podem não aparecer corretamente após webhook.

**Botão Pagar:** modal se parcela `PENDENTE` e existir `qrcodeurl` / `chavepix` na NF (preenchidos no retorno do checkout, quando implementado).

---

## 4. Histórico de cobrança

- **Fonte principal:** registros em **`nf`** + **`nfparcela`** ligados à **pessoa do tenant**, como acima.
- **`usershist`:** model **`UserHist`** existe com fillable mínimo (`iduser`); **não** há, no trecho analisado, pipeline que grave histórico de cobrança por usuário.
- **Auditoria financeira completa** (parcelas quitadas, saldo de agência, fluxo): ver **`Doc_Modulo_Financeiro.md`** e **`Doc_Modulo_Status_Fluxo_Cores.md`**.

---

## 5. `PagamentoComponent` (Livewire)

Componente de **pagamento misto no PDV** (formas de pagamento, troco) — **não** é a tela de assinatura SaaS; usa `FormaPagamento::habilitadoPdv()`. Mantido aqui só para não confundir com `PagamentoController`.

---

## 6. Menu e permissões

- Sidebar **Tecnologia:** `planos`, `funcionalidades`, `plano-funcionalidade` (junto com tenants, fluxo, etc.).
- Gestão de **tenants** continua restrita a **`admin.tenant`** + papel adequado (ver **`Doc_Modulo_Tenant.md`**).

---

## 7. Nova grade comercial de planos

| Código | Nome | Valor/mês | Usuários | Observação |
|--------|------|-----------|----------|------------|
| `trial` | Teste Grátis | R$ 0 | 1 | 14 dias (configurável); `tenant.trial_expira_em` |
| `start` | NoLapis Start | R$ 49,90 | 1 | MEI / micro |
| `gestao` | NoLapis Gestão | R$ 99,90 | 3 | Destaque; DRE/DFC, contratos |
| `pro` | NoLapis Pro | R$ 179,90 | 8 | Conciliação, cartão, Kanban |
| `consultivo` | NoLapis Consultivo | R$ 399,90+ | 15 | Sem checkout; página de contato |

Planos legados (Bronze/Prata/Ouro) permanecem no banco; novos cadastros usam `codigo`.

**Seeder idempotente:** `database/seeders/PlanosComerciaisSeeder.php` — `php artisan db:seed --class=PlanosComerciaisSeeder`.

**Site WordPress:** conteúdo sugerido em `docs/planos-site-wordpress.md`.

### 7.1 `PlanoService`

| Método | Uso |
|--------|-----|
| `tenantAtual()` | Tenant da sessão/usuário |
| `planoDoTenant()` | Plano vinculado ao tenant |
| `temFuncionalidade($alias)` | Recurso habilitado (`qtd` > 0) |
| `quantidadeFuncionalidade($alias)` | Limite/quantidade (ex. IA) |
| `limiteUsuarios()` / `limiteEmpresas()` | Limites efetivos (+ usuários adicionais contratados) |
| `creditosIaMensais()` | Campo `creditos_ia` (futuro) |
| `isTrial()` / `trialExpirado()` | Período de teste |
| `podeAdicionarUsuario()` | Validação em `UserController::store` |

### 7.2 Tenant

| Campo | Uso |
|-------|-----|
| `trial_expira_em` | Fim do teste grátis |
| `usuarios_adicionais_contratados` | Estrutura para limite efetivo ampliado |

### 7.3 Catálogo de funcionalidades × código

- Configuração mestre: `config/funcionalidades_catalogo.php` (descrição, módulo, rota, controller, padrões de busca no código).
- Comando: `php artisan planos:sincronizar-funcionalidades` — preenche `descricao`, `modulo`, `rota_referencia`, `controller_referencia`, `vinculo_verificado` e define **INATIVO** quando não há correspondência no repositório (ex.: suporte consultivo, IA).
- Admin: botão **Sincronizar com código** em Funcionalidades; edição de funcionalidade com **planos associados** (checkboxes); edição de plano com **módulos do plano** agrupados como o menu (Painéis, Comercial, Suprimentos, etc.) — `config/funcionalidades_menu_secoes.php`, `App\Support\MenuSecaoFuncionalidade`.
- Menu lateral: componente `<x-can-plano-funcionalidade alias="dre_gerencial">` oculta itens quando o tenant não tem o recurso (tenant operador `is_admin_tenant` vê tudo).

### 7.4 Cadastro público

- Middleware `plano.resolve`: `cadastro/{plano}` aceita **id** ou **codigo**.
- Plano `consultivo`: view `pages/cadastro-consultivo` (WhatsApp/e-mail em `config/nolapis_comercial.php`).
- Correção: checkout Pagar.me dispara quando existe parcela pendente (condição anterior impedia a chamada).

### 7.5 Cupons e promoções de assinatura

**Não** usar o módulo **Campanhas** (gamificação de vendas internas). Descontos SaaS usam tabelas próprias:

| Tabela | Uso |
|--------|-----|
| `cupons` | Código digitado (ex.: `ACIUB20`), escopo, duração, planos elegíveis |
| `promocoes` | Desconto automático (sem código) em cadastro ou upgrade |
| `cupom_uso` | Auditoria de aplicação por tenant/contrato |
| `contrato` | `idcupom`, `idpromocao`, `desconto_parcelas_restantes` + `valoracordocontrato` / `descontocontrato` |

**Serviço:** `App\Services\CupomAssinaturaService` — validação, cálculo, gravação no contrato, consumo de parcelas com desconto na recorrência (`ContratoService`).

| Escopo | Onde aplica |
|--------|-------------|
| `NOVA_ASSINATURA` | Cadastro público (`?cupom=CODIGO` ou campo no formulário) |
| `UPGRADE` | Tela **Evoluir plano** (cupom opcional ou promoção automática) |
| `AMBOS` | Cadastro e upgrade |

| Duração | Comportamento |
|---------|---------------|
| `PRIMEIRA_PARCELA` | Só a 1ª cobrança com desconto |
| `N_MESES` | Desconto por N ciclos (`desconto_parcelas_restantes`) |
| `PERMANENTE` | `valoracordocontrato` fixo até mudança manual |

**Cupom de cortesia (presente / licença gratuita limitada):** percentual **100%**, duração **Permanente**, **máximo de usos** obrigatório (ex.: 1). No cadastro do plano pago (`/cadastro/gestao?cupom=CODIGO`) o cliente ativa sem cartão; ao esgotar os usos o código deixa de funcionar. Promoção automática **não** pode zerar plano pago.

**Admin:** `admin/cupons`, `admin/promocoes` (menu Instâncias). Seeder exemplo: `php artisan db:seed --class=CupomAssinaturaSeeder` (cupom `ACIUB20`).

### 7.6 Upgrade de plano (Evoluir plano)

**Menu:** Instâncias → **Evoluir plano** (ou rota `admin.plano-upgrade.index`).

| Rota | Função |
|------|--------|
| `GET admin/plano-upgrade` | Comparativo de planos, matriz de funcionalidades, promoções automáticas |
| `POST admin/plano-upgrade/validar-cupom` | Cupom escopo `UPGRADE` |
| `POST admin/plano-upgrade/remover-cupom` | Limpa cupom da sessão |
| `POST admin/plano-upgrade` | Confirma upgrade/downgrade |

**Serviços:** `PlanoUpgradeService` (comparativo), `AssinaturaContratoService::alterarPlano`, `TenantPlanoHistoricoService`, `CupomAssinaturaService` (contexto `UPGRADE`).

**Comportamento:** exibe planos superiores/inferiores ao atual; suporta periodicidade **mensal/anual** quando `Plano::ofereceCobrancaAnual()`; aplica promoção automática por plano; registra histórico em `tenant_plano_historico` e `contrato_historico`. Middleware `plano.funcionalidade` redireciona para esta tela quando o tenant tenta acessar recurso não incluído no plano.

---

## 8. Referência rápida de arquivos

| Arquivo | Função |
|---------|--------|
| `app/Models/Plano.php`, `Funcionalidade.php`, `PlanoFuncionalidade.php` | Dados de catálogo e vínculos. |
| `app/Services/PlanoService.php` | Regras centralizadas de plano/funcionalidade/limites. |
| `app/Http/Middleware/CheckPlanoFuncionalidade.php` | Bloqueio por `alias`. |
| `app/Http/Middleware/ResolvePlanoBinding.php` | Resolução de plano por código na URL. |
| `database/seeders/PlanosComerciaisSeeder.php` | Grade comercial + funcionalidades. |
| `config/nolapis_comercial.php` | Trial, contato consultivo. |
| `docs/planos-site-wordpress.md` | Copy para site institucional. |
| `app/Http/Controllers/Admin/PlanoController.php` | CRUD planos. |
| `app/Http/Controllers/Admin/FuncionalidadeController.php` | CRUD funcionalidades. |
| `app/Http/Controllers/Admin/PlanoFuncionalidadeController.php` | CRUD vínculos. |
| `app/Http/Controllers/CadastroController.php` | Onboarding + NF/parcela + chamada gateway. |
| `app/Services/CupomAssinaturaService.php` | Cupons/promoções na assinatura. |
| `app/Http/Controllers/Admin/CupomController.php` | CRUD cupons. |
| `app/Http/Controllers/Admin/PromocaoController.php` | CRUD promoções automáticas. |
| `app/Services/PagarMeService.php` | Criação de *order* Pix. |
| `app/Http/Controllers/WebhookController.php` | `order.paid` → ativação e parcela. |
| `config/pagarme.php` | Chave API. |
| `app/Http/Controllers/Admin/PagamentoController.php` | Lista “Minha assinatura”. |
| `resources/views/admin/pagamentos/index.blade.php` | UI de histórico simplificado. |
| `app/Http/Controllers/Admin/PlanoUpgradeController.php` | Tela Evoluir plano |
| `app/Services/PlanoUpgradeService.php` | Comparativo planos × funcionalidades |
| `app/Http/Controllers/SocialAuthController.php` | OAuth no cadastro (intent=cadastro) |
| `routes/web.php` | Rotas `cadastro.*`, `pagamentos`, `plano-upgrade.*`, `auth.social.*` |

---

*Documento baseado na leitura do código. Corrija condições mortas, metadados do webhook e typos antes de depender do fluxo em produção; valide assinatura do webhook com a versão atual da API Pagar.me.*
