--- name: assinaturas-comissao-module description: "Módulo de assinatura digital de comissões — controller, rotas, ícone na sidebar com badge e modal de status. URL pública é /recibo/assinar/{token} (NÃO /assinatura/{token})." metadata: node_type: memory type: project originSessionId: e41195c3-9cad-46c0-aa7c-2a7fba7c3815 --- Módulo criado em 12/mai/2026 para gerenciar e visualizar status de assinaturas digitais de recibos de comissão de professores. ## Backend - **Controller:** `app/Controllers/AssinaturaController.php` - **Tabela:** `lancamentos_financeiros` com `assinatura_token`, `assinatura_img`, `assinatura_data`, `assinatura_ip` (apenas `referencia_tipo='comissao_professor'`) - **View pública:** `app/Views/assinatura/assinar.php` ### Rotas - `GET /recibo/assinar/{token}` (PÚBLICO) — tela onde o professor assina. **A URL é `recibo/assinar`, NÃO `assinatura`** (linha 132 do Routes.php). Esquecer disso gera 404. - `POST /recibo/salvar-assinatura` (público, com token no body) — salva - `GET /direcao/api/assinaturas/lista?mes=YYYY-MM` — lista comissões do mês com status - `GET /direcao/api/assinaturas/pendentes?mes=YYYY-MM` — só contador (badge) - `POST /direcao/api/assinaturas/enviar-link/{lanc_id}` — envia link via WhatsApp pro professor ### Filtros de visibilidade - **Badge:** conta todos os pendentes do mês (independente de prof ativo/inativo) - **Lista no modal:** pendentes aparecem sempre + assinados só de profs ativos (regra: prof inativo só aparece enquanto não assinou) - Query usa LEFT JOIN com `professores` via `usuario_id` para checar `p.ativo` ### Busca de retiradas/inclusões (view assinar.php) **Why:** Recálculos de comissão geram novo lançamento mas as retiradas continuam com `lancamento_id` apontando pro antigo. Buscar só por `lancamento_id = lf.id` perde retiradas; buscar por `professor_id + mes_referencia` pega retiradas de OUTROS lançamentos. **Solução adotada:** buscar retiradas com `lancamento_id IN (lançamentos de comissão do mesmo professor no mesmo mes_referencia)` + `status='aplicada'`. Isso captura recálculos "irmãos" mas não vaza retiradas de outros professores. **How to apply:** Se for mexer no controller, manter o padrão de "irmãos" + status='aplicada'. Ver `AssinaturaController::assinar()`. ### Cálculo do valor exibido Valor Líquido na view = `totalComissao (somatório das aulas) + totalInclusoes − totalRetiradas`. Recalculado dinamicamente, NÃO usa `lancamento.valor` direto (pode estar desatualizado em casos de recálculo manual). ## Frontend (sidebar + modal) - **Ícone na sidebar:** botão "Assinaturas" no topo, com badge vermelho. Implementado em `app/Views/layouts/main.php` antes da `