ligbox-ops-platform/specs/023-billing-recurrence-desk-visibility/spec.md
Ligbox Spec Hub 3a2c64834b Initial import: ligbox-ops-platform + specs + LAPTOP + obsidian merge (CT130)
Source: VM122 /opt + obsidian-infra + LAPTOP
Hub: CT130 spec-hub 10.10.10.130
2026-06-19 17:26:41 +00:00

300 lines
12 KiB
Markdown

# 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)
---
## 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 |