# Documentação técnica — Assinatura SaaS (contrato de recorrência)

Contratos com **`modalidade = RECORRENCIA`**: cobrança recorrente do **software NoLapis** (tenant cliente). Diferente de **`modalidade = CONTRATO`** (contrato comercial locação/serviço) — ver **`Doc_Modulo_Contrato.md`**. Planos, cadastro, cupons e upgrade: **`Doc_Modulo_Planos_Assinatura_Pagamento.md`**.

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

---

## 1. Entidades principais

| Entidade | Uso |
|----------|-----|
| **`contrato`** | Cabeçalho da assinatura SaaS (`modalidade = RECORRENCIA`, `tipo = C`, `recorrencia = mensal` ou anual conforme upgrade). |
| **`contratoitem`** | Linha do plano (`prodserv` do catálogo comercial). |
| **`tenant.idcontrato_assinatura`** | Contrato ativo do tenant. |
| **`tenant_plano_historico`** | Histórico de mudanças de plano. |
| **`contrato_historico`** | Upgrade, downgrade, churn, criação, reativação. |

**Cobrança:** 1ª parcela no cadastro (cartão tokenizado Pagar.me ou trial/gratuito); mensais via `assinatura:gerar-cobrancas`. Na listagem financeira, origem **REC** (Recorrência).

### 1.1 Modalidade × tipo

| Campo | Valores | Uso |
|--------|---------|-----|
| `tipo` | `C` / `D` | Crédito (receita) / débito (despesa) no financeiro |
| `modalidade` | `CONTRATO` / `RECORRENCIA` | Comercial (locação, serviço) vs assinatura SaaS |
| `assinatura_saas` | boolean legado | Mantido; novos registros SaaS usam `modalidade = RECORRENCIA` |

Migration `2026_06_04_120000`: contratos que tinham `assinatura_saas = 1` passam a `RECORRENCIA`; demais permanecem `CONTRATO`.

---

## 2. Provisionamento automático

**Serviço:** `App\Services\AssinaturaContratoService`

| Origem | Ação |
|--------|------|
| `CadastroController::store` | Após criar tenant → `provisionar(..., 'cadastro')`; NF inicial com `idcontrato`. Lead via **SSO** ou senha — ver **`Doc_Modulo_Tenant.md`** § 11. |
| `PlanoUpgradeController::store` | Upgrade/downgrade → `alterarPlano()` + histórico. |
| `TenantController::store` / `update` | Cria ou `alterarPlano`; `sincronizarStatusTenant` se status mudou. |
| `WebhookController` (Pagar.me pago) | Ativa tenant → `sincronizarStatusTenant(ATIVO)`. |
| Comando `assinatura:sincronizar-contratos` | Retroativo para tenants sem `idcontrato_assinatura`. |

Contrato criado com: `tipo = C`, `modalidade = RECORRENCIA`, `recorrencia = mensal`, item do `prodserv` do plano, `idtenant` + `idplano`, vínculo em `tenant.idcontrato_assinatura`.

---

## 3. Mudança de plano e churn

- **Upgrade / downgrade / alteração:** `AssinaturaContratoService::alterarPlano()` atualiza valores e item; registra em `contrato_historico` e `tenant_plano_historico`. UI: **`admin/plano-upgrade`** (`PlanoUpgradeController`, `PlanoUpgradeService`).
- **Churn:** tenant `INATIVO` → contrato `INATIVO` + `datafimrecorrencia` + histórico `churn`.
- **Reativação:** tenant `ATIVO` → contrato volta a `ATIVO` (histórico `reativacao`).

Recorrência mensal seguinte: `php artisan assinatura:gerar-cobrancas` (`ContratoService` + `NfService`).

**Cupons / promoções:** desconto gravado em `contrato.valoracordocontrato`, `descontocontrato` e `desconto_parcelas_restantes`; consumo a cada ciclo via `CupomAssinaturaService` — ver **`Doc_Modulo_Planos_Assinatura_Pagamento.md`** § 7.5–7.6.

---

## 4. Dashboard de assinaturas

- **Rota:** `GET /admin/tenants/dashboard` (`admin.tenants.dashboard`)
- **Serviço:** `DashboardAssinaturaService` — KPIs e gráficos **apenas** `contrato.modalidade = RECORRENCIA`
- **Gráfico de itens:** agrupa por `contratoitem` (produto/serviço contratado), não pelo catálogo `planos`
- **Status do contrato:** `ATIVO`, `TRIAL` (teste, 30 dias padrão), `PENDENTE`, `CANCELADO` (churn), `INATIVO` (nunca ativou). Alerta dashboard: expira em 7 dias (`NOLAPIS_TRIAL_ALERTA_DIAS`).
- **Histórico:** `contrato_historico` — exibe item da linha do contrato; plano anterior/novo só em mudanças de catálogo
- **Escopo:** `TenantScope` na tabela `contrato` (via `idempresa` da operadora logada). Revendas/franquias veem apenas contratos da própria operadora.
- **Menu:** Painéis → **Assinaturas**

Contratos comerciais (`CONTRATO`) não entram neste painel; use **Cadastros → Contratos**.

---

## 5. Colunas e migrations (`2026_06_04_*`)

- `contrato`: `idtenant`, `idplano`, `assinatura_saas`, **`modalidade`**, `idcupom`, `idpromocao`, `desconto_parcelas_restantes`
- `tenant`: `idcontrato_assinatura`
- `contrato_historico`: eventos comerciais

---

## 6. Configuração

`config/nolapis_comercial.php`:

| Chave | Env | Uso |
|-------|-----|-----|
| `assinatura_antecedencia_dias` | `NOLAPIS_ASSINATURA_ANTECEDENCIA` | Antecedência da NF recorrente (padrão 7) |
| `assinatura_idempresa` | `NOLAPIS_ASSINATURA_IDEMPRESA` | Fallback da empresa operadora |

**Empresa do contrato:** `AssinaturaContratoService::resolverIdempresaOperadora()` usa, nesta ordem: `planos.idempresa` → `prodserv.idempresa` (e grava no plano se estava vazio) → env → primeira empresa do tenant admin. Planos antigos sem `idempresa` (ex.: Bronze) passam a funcionar via `prodserv`.

---

## 7. Pós-deploy

```bash
php artisan migrate
php artisan assinatura:sincronizar-contratos
```

Para clientes já existentes sem contrato de assinatura vinculado ao tenant.

---

## 8. Referência rápida

| Arquivo | Função |
|---------|--------|
| `app/Services/AssinaturaContratoService.php` | Provisionar, alterar plano, sincronizar status |
| `app/Services/PlanoUpgradeService.php` | Comparativo de planos na tela Evoluir plano |
| `app/Http/Controllers/Admin/PlanoUpgradeController.php` | Upgrade/downgrade + cupom |
| `app/Services/DashboardAssinaturaService.php` | KPIs painel Assinaturas |
| `app/Console/Commands/SincronizarContratosAssinatura.php` | `assinatura:sincronizar-contratos` |
