# Spec 023 — Cobrança recorrente & visibilidade Desk (empresa / billing)

**Criado:** 2026-06-17  
**Solicitado por:** Roger  
**Status:** Spec — implementação pendente (motor cobrança → ver **Spec 024** FOSSBilling)  
**Prioridade:** P1 (financeiro + operação)  
**Sistemas:** Wizard VM112 · Desk VM122 · Motor de cobrança (fase 2)  
**Módulo Desk:** `billing-recurrence` (novo — Spec 015)  
**Depende de:** Spec 012 (tickets onboarding), Spec 018 (Serviços / clientes), Spec 021 (webhooks)  
**Relacionado:** Card wizard «Dados da empresa e cobrança» (imagem Roger, 2026-06-17) · **[Spec 043 — mapa campos FOSS/OP/Odoo](../043-desk-client-activation-sync/contracts/activation-field-mapping.md)**

---

## Resumo

Quando o utilizador **preenche e confirma** o card **«Dados da empresa e cobrança»** no wizard VM112, o Desk deve **reflectir imediatamente** o estado comercial/financeiro em três superfícies:

1. **Dashboard** — KPI + feed de sessões/tickets em fase billing  
2. **Audit Overview** — domínio/tenant com badge «Empresa / Cobrança»  
3. **Serviços** — ícone de **recorrência activa** no card do cliente + link para **conta do cliente** (ficha financeira)

A fase 1 é **visibilidade e orquestração no Desk** (eventos, estados, links). A fase 2 liga o motor de **cobrança recorrente** (assinatura, boleto, PIX, inadimplência) ao `company_profile` já capturado.

**Regra de ouro:** o wizard **não cobra** no passo empresa — apenas recolhe dados e emite `company.validated`. A recorrência **activa-se** após validação OPS + provisionamento do plano no motor financeiro.

---

## Problema

| Hoje | Necessidade |
|------|-------------|
| Evento `company.validated` gera ticket `[billing-validation]` e `billing_state` no payload | Ops não vê **de relance** quantos clientes estão em cobrança pendente / activa |
| Card empresa existe no wizard (CNPJ, morada, `email_billing`, `confirm_billing`) | Mesmo momento deve aparecer no **Dashboard**, **Overview** e **Serviços** |
| Serviços (Spec 018) mostra só saúde técnica (e-mail tenant activo) | Falta indicador **💳 recorrência** e atalho para **conta do cliente** |
| Sem motor de cobrança ligado ao Desk | Boletos, débitos e MRR dispersos ou manuais |

---

## Gatilho (wizard VM112)

### Momento UX

O card **«Dados da empresa e cobrança»** é exibido após passos de conta/domínio (gate `company_gate`). O utilizador pode:

- Preencher agora (`confirm_billing` + `confirm_accurate`)  
- Adiar — política ainda não registada na sessão (banner azul na imagem)

### Webhook (já parcialmente implementado)

```json
{
  "event": "company.validated",
  "domain": "myvexx.com",
  "session_id": "<uuid>",
  "data": {
    "billing_state": "awaiting_billing_validation",
    "company_profile": {
      "trade_name": "Myvexx",
      "legal_name": "Myvexx Ltda",
      "tax_id_type": "cnpj",
      "tax_id": "00000000000191",
      "email_billing": "financeiro@myvexx.com",
      "payment_method": "",
      "confirm_billing": true,
      "address": { "country": "BR", "city": "...", "postal_code": "..." }
    }
  }
}
```

### Estados `billing_state` (Desk — normalizar)

| Estado | Significado | UI |
|--------|-------------|-----|
| `policy_pending` | Card visto mas empresa ainda não confirmada | Cinza — «Política pendente» |
| `awaiting_billing_validation` | `company.validated` — aguarda OPS | Âmbar — «Validar cobrança» |
| `billing_active` | Plano + recorrência criados no motor financeiro | Verde — «Recorrência activa» |
| `billing_paused` | Suspenso manualmente (inadimplência / pedido cliente) | Vermelho suave |
| `billing_cancelled` | Cancelado — manter histórico | Cinza riscado |

Transição inicial automática no webhook: → `awaiting_billing_validation`.

---

## Superfícies Desk (fase 1 — visibilidade)

### 1. Dashboard

| Elemento | Comportamento |
|----------|---------------|
| **KPI «Cobrança pendente»** | Contagem tickets/sessões com `billing_state = awaiting_billing_validation` (48h) |
| **KPI «Recorrência activa»** | Contagem clientes com `billing_active` |
| **Sessões activas** | Badge `billing` no card quando `current_stage >= company_validated` |
| **Tickets recentes** | Prefixo `[billing-validation]` já existe — destacar com ícone 💳 |
| **Feed rápido** | Últimos 5 `company.validated` com domínio + razão social (mascarar CNPJ para NOC) |

### 2. Audit Overview

| Elemento | Comportamento |
|----------|---------------|
| **Domínio na lista** | Badge «Empresa» quando funil ≥ `company_validated` |
| **Modal domínio** | Secção **Cobrança** com: estado, `trade_name`, `email_billing` (mascarado NOC), data confirmação |
| **Card tenant VM112** | Contador «X domínios em validação billing» nas últimas 24h |

### 3. Serviços (`overview-home` — Spec 018)

| Elemento | Comportamento |
|----------|---------------|
| **Linha do cliente** | Ícone pequeno **💳** ou `servicos-billing-dot--active` quando `billing_active` |
| **Tooltip** | «Recorrência activa — clique para conta do cliente» |
| **Clique no ícone** | Abre **ficha Conta do cliente** (drawer/modal) — não confundir com tile E-mail Tenant |
| **Stats row** | Novo contador: «N recorrências activas» |

### Ficha «Conta do cliente» (nova — v1)

Painel lateral ou modal com:

- Dados empresa (`company_profile` — RBAC Spec 003)  
- Estado billing + link externo motor financeiro (Odoo partner / Lago customer) quando fase 2  
- Histórico: `company.validated`, activação recorrência, últimos pagamentos (webhook fase 2)  
- Acções OPS (fase 1): «Marcar validado», «Activar recorrência» (manual)  
- Acções OPS (fase 2): «Criar assinatura», «Reenviar boleto», «Suspender por inadimplência»

---

## Modelo de dados Desk (fase 1)

### Tabela `billing_accounts` (nova)

```sql
CREATE TABLE billing_accounts (
  id INTEGER PRIMARY KEY,
  domain TEXT NOT NULL,
  session_id TEXT,
  ticket_id INTEGER,
  tax_id TEXT,
  legal_name TEXT,
  trade_name TEXT,
  email_billing TEXT,
  company_profile_json TEXT,
  billing_state TEXT NOT NULL DEFAULT 'awaiting_billing_validation',
  recurrence_active INTEGER NOT NULL DEFAULT 0,
  external_customer_id TEXT,      -- Odoo res.partner id ou Lago external_id
  external_subscription_id TEXT,
  payment_provider TEXT,          -- asaas | iugu | stripe | manual
  plan_code TEXT,                 -- email_tenant_monthly, etc.
  activated_at TEXT,
  activated_by TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);
CREATE UNIQUE INDEX idx_billing_domain ON billing_accounts(domain);
```

### Upsert no webhook

Em `_process_ingress`, após `company.validated`:

1. `billing_store.upsert_from_company_validated(...)`  
2. Ligar `ticket_id` e `webhook_event_id`  
3. Não activar `recurrence_active` até confirmação OPS ou webhook do motor financeiro

### API (fase 1)

| Método | Rota | Descrição |
|--------|------|-----------|
| GET | `/api/v1/billing/accounts` | Lista (filtro `billing_state`, `domain`) |
| GET | `/api/v1/billing/accounts/{id}` | Ficha conta cliente |
| GET | `/api/v1/billing/accounts/by-domain/{domain}` | Lookup para Serviços |
| PATCH | `/api/v1/billing/accounts/{id}` | OPS: mudar estado, `recurrence_active` |
| GET | `/api/v1/billing/summary` | KPIs dashboard |

---

## Motor de cobrança recorrente (fase 2)

### Requisitos Ligbox (Brasil)

- Assinatura mensal/anual por domínio ou por utilizador  
- **Boleto** + **PIX** + cartão (futuro)  
- CNAB retorno / conciliação bancária  
- NFSe / nota fiscal de serviço (quando aplicável)  
- Inadimplência: lembretes, suspensão serviço, dunning  
- API para o Desk criar cliente + plano a partir de `company_profile`

### Comparativo — aderência para o caso Ligbox

| Critério | **Odoo 16** (+ OCA Brasil) | **Lago** (getlago/lago) |
|----------|---------------------------|-------------------------|
| Já na stack Roger | ✅ API V16 existente (`813f08e7…`) | ❌ Novo deploy |
| Boleto nativo BR | ✅ `l10n_br_account_payment_brcobranca` (OCA) + CNAB | ⚠️ Via **Stripe** (`boleto` em BRL) — não CNAB tradicional |
| PIX | ✅ Módulos ASAAS / Iugu / PagBank | ⚠️ Stripe PIX (se configurado) |
| NFSe / fiscal BR | ✅ OCA `l10n_br_*` + integradores | ❌ Não é ERP fiscal |
| Assinatura recorrente | ✅ `sale_subscription` + ASAAS Subscriptions | ✅ Core product — excelente API |
| Metering (por caixa, GB) | ⚠️ Possível, menos natural | ✅ Event-based — ideal |
| Controle débitos / aging | ✅ Contabilidade + follow-up pagamentos | ✅ Dunning + invoices |
| Self-host | ✅ Já conhecido | ✅ Docker (Railway/K8s) |
| Integração Desk | JSON-RPC / REST Odoo | REST API limpa |
| Curva para MSP BR | **Menor** — um sistema fiscal + cobrança | **Maior** se precisar Odoo à parte para NF |

### Recomendação (Roger)

**Aderência principal: Odoo 16** — já tens instância e API; o ecossistema **OCA Brasil** cobre boleto/CNAB, e módulos **ASAAS** ou **Iugu** fecham PIX + assinatura recorrente + webhooks de pagamento sem reinventar fiscal.

**Lago** é excelente como **motor de subscrição/metering** (preço por utilizador, usage API) se no futuro quiseres billing estilo SaaS puro **desacoplado** do fiscal — mas para **boletos, débitos e conformidade BR**, continuarias a precisar de Odoo (ou similar) em paralelo.

#### Arquitectura sugerida

```
Wizard VM112  ──webhook──►  Desk VM122  ──orquestra──►  Odoo 16
     │                         │                           │
 company.validated      billing_accounts              res.partner
 company_profile        UI Dashboard/Overview/        sale.subscription
                        Serviços + ícone 💳            ASAAS/Iugu (boleto/PIX)
                                                      webhooks → Desk (fase 2)
```

**Opção híbrida (fase 3+):** Lago calcula usage (caixas extra, storage) → Odoo emite NF + boleto consolidado. Só vale a pena com volume e pricing complexo.

#### Projetos GitHub de referência

| Projeto | Uso |
|---------|-----|
| [odoo/odoo](https://github.com/odoo/odoo) | Core ERP + Subscriptions |
| [OCA/l10n-brazil](https://github.com/OCA/l10n-brazil) | Localização fiscal BR |
| [getlago/lago](https://github.com/getlago/lago) | Metering + subscriptions API (complementar) |
| ASAAS / Iugu Odoo modules | Pagamentos BR (boleto, PIX, recorrência) |

---

## Webhooks fase 2 (motor → Desk)

| Evento | Acção Desk |
|--------|------------|
| `billing.subscription.created` | `recurrence_active=1`, `billing_state=billing_active` |
| `billing.invoice.paid` | Registo pagamento; ícone 💳 verde |
| `billing.invoice.overdue` | Badge inadimplência; ticket automático |
| `billing.subscription.cancelled` | `billing_cancelled` |

Fonte: Odoo (sale.subscription + payment transaction) ou ASAAS webhooks via worker Desk.

---

## RBAC (Spec 003)

| Acção | super_admin | ops_lead | technician | noc |
|-------|:-----------:|:--------:|:----------:|:---:|
| Ver KPI billing dashboard | ✅ | ✅ | ✅ | ✅ (contagens) |
| Ver `company_profile` completo | ✅ | ✅ | ✅ | ❌ mascarado |
| Abrir conta do cliente | ✅ | ✅ | ✅ | ❌ |
| Activar / suspender recorrência | ✅ | ✅ | ❌ | ❌ |
| Link motor financeiro | ✅ | ✅ | ✅ | ❌ |

---

## UI — ícone recorrência (Serviços)

```html
<!-- Na linha do cliente (accounts.js) -->
<span class="servicos-billing-badge servicos-billing-badge--active"
      title="Recorrência activa"
      data-billing-account="{id}">
  💳
</span>
```

CSS: bolinha verde 8px ou emoji discreto à direita do nome; `cursor:pointer`; separado do badge «activo» técnico do e-mail tenant.

---

## Fora de escopo v1

- Emissão real de boleto/NF (fase 2)  
- Portal do cliente pagar fatura (fase 3)  
- Multi-moeda  
- Pricing dinâmico usage-based (Lago — fase 3)

---

## Critérios de aceite (fase 1)

1. Webhook `company.validated` cria/atualiza `billing_accounts`  
2. Dashboard mostra KPI «Cobrança pendente» > 0 após teste wizard  
3. Overview mostra badge «Empresa» no domínio  
4. Serviços: ícone 💳 só quando `recurrence_active=1`; clique abre ficha conta  
5. NOC não vê CNPJ completo nem `email_billing`  
6. Módulo `billing-recurrence` activável em Módulos Desk

---

## Plano de implementação

| Fase | Entrega |
|------|---------|
| **1a** | `billing_store` + routes + hook webhook + API summary |
| **1b** | Dashboard KPI + badges sessão/ticket |
| **1c** | Overview badge + secção cobrança no modal |
| **1d** | Serviços: ícone + modal conta cliente + PATCH manual OPS |
| **2** | Integração Odoo: `res.partner` + subscription ASAAS |
| **3** | Webhooks pagamento + inadimplência + suspensão serviço |
