# Citrus — Ajustes pós-validação do fechamento (v1.0)

**Data:** 2026-06-24
**Origem:** validação do sistema com o cliente; lista de ajustes solicitados para a primeira versão.
**Área:** card/fechamento, profissional (bônus de líder) e escopo de acesso do líder.

Todos os ajustes seguem os padrões existentes: models de negócio estendem `BaseActiveRecord`
(soft-delete + auditoria + timestamps), controllers usam `PermissaoBehavior` + `VerbFilter`,
listagens têm export via `ExportHelper`, máscaras monetárias via `data-mask-money`.

---

## Frente 1 — "Valor da nota" + flag por desconto

### Regra de negócio (confirmada com o cliente)
- **Valor a receber** = `total_diarias + total_bonus − total_desconto`
  (é o atual `total_liquido`, apenas renomeado na exibição — **não** muda o cálculo).
- **Valor da nota** = `total_diarias + total_bonus − Σ(descontos marcados para a nota)`.
  - Descontos marcados (`considera_nota = 1`) **abatem** o Valor da nota. *(Correção pós-validação 2026-06-25: a flag deve **diminuir** a nota, não somar.)*
  - Descontos não marcados (ex.: **falta** — não declarada na nota) **não afetam** o Valor da nota.

> **Rótulo do checkbox (a confirmar na revisão):** o cliente descreveu como "desconsiderar no
> valor da nota", mas o item marcado **soma** na nota. Proposta: rotular **"Considerar no valor
> da nota"** (marcado = adiantamento, entra na nota; desmarcado = falta, fica fora). Ajustar a
> palavra conforme preferência do cliente.

### Modelo de dados
- **Migration** `add_considera_nota_to_card_item`: coluna `considera_nota` TINYINT(1) NOT NULL
  DEFAULT 0 em `card_item` (relevante apenas para `tipo = desconto`).
- **Migration** `add_total_nota_to_card`: coluna `total_nota` DECIMAL(10,2) NOT NULL DEFAULT 0 em `card`.

### Lógica
- `Card::recalcularTotais()` passa a calcular e persistir `total_nota`:
  `total_nota = total_diarias + total_bonus + Σ(item->subtotal onde tipo=desconto e considera_nota=1)`.
- `Card::rules()` inclui `total_nota` em `number`.

### UI — tela do card (`views/card/fechar.php`)
- Cada linha de **desconto** ganha um checkbox `considera_nota` (persistido em `card/salvar`).
- Recálculo ao vivo do "Valor da nota" no JS já existente de subtotais.
- Bloco de totais: **Valor a receber** com menos destaque; **Valor da nota** com mais destaque.

### UI — PDF (`views/card/_pdf.php`)
- Renomear a linha "Total líquido" → **"Valor a receber"** (fonte/realce menores).
- Adicionar abaixo **"Valor da nota"** com mais destaque.

### Persistência em `card/salvar`
- `CardController::actionSalvar` lê `considera_nota[<item_id>]` dos descontos e grava por item,
  depois chama `recalcularTotais()`.

---

## Frente 2 — Bônus mensal do líder no card

### Regra
- Campo já existente: `Profissional.valor_bonus_mensal` (obrigatório para perfil líder).
- Ao **criar** o card de um profissional que é **líder**, inserir **uma linha de bônus**:
  - `subtotal = valor_bonus_mensal / 2` (card é quinzenal), arredondado a 2 casas.
  - `descricao = "Bônus mensal de líder (½ de R$ <valor_bonus_mensal>)"`.
- Comportamento: **linha de bônus comum, editável/removível pelo financeiro.** Inserida **uma única
  vez na criação** do card; **não** é regenerada nem alterada no recálculo de diárias.

### Lógica
- Em `Card::abrirParaEdicao()` (somente no ramo de card novo, após `recalcularDiarias()`):
  se `profissional->temPerfil('lider')` e `valor_bonus_mensal > 0`, criar o `CardItem`
  (tipo = bonus) e chamar `recalcularTotais()`.
- `recalcularDiarias()` continua apagando/regenerando **apenas** itens `tipo = diaria` — a linha do
  bônus de líder sobrevive ao recálculo.

### Observação
- Cards de líderes criados antes desta mudança não terão a linha; o financeiro pode adicioná-la
  manualmente. Sem backfill automático na v1.0.

---

## Frente 3 — Diárias sempre agrupadas por obra (bug Ana Paula, id 26)

### Causa-raiz (confirmada por leitura de código)
- A tela do card exibe as diárias a partir dos `CardItem` **armazenados**
  (`fechar.php:36`, gerados por `Card::recalcularDiarias()`).
- `recalcularDiarias()` só roda (a) na criação do card e (b) em "recalcular" explícito, e **apenas
  com `status = rascunho`** (`Card.php:78`).
- A contagem "Nº diárias" da lista é uma query **ao vivo** sobre `efetivo` (`CardController.php:150-154`).
- Logo: o card foi gerado/fechado quando só existia o efetivo de uma obra; o efetivo da segunda obra
  foi registrado depois (ou após o fechamento) e o card nunca o incorporou. A agregação por obra em si
  está correta (`Card.php:98-111`) — o problema é item desatualizado.

### Correção
1. **Investigar** o registro 26 no container (`docker compose exec php ./yii` ou query) para confirmar.
2. Ao **abrir** um card em rascunho, recalcular diárias (hoje só recalcula na criação), garantindo
   que novas obras/dias apareçam.
3. Para cards **fechado/pago**, exibir **aviso de divergência** quando a contagem de efetivo ao vivo
   ≠ soma de diárias do card ("Efetivo ao vivo: X · Card: Y"), com ação de reabrir+recalcular —
   em vez de esconder silenciosamente uma obra.
4. Garantir (com teste) que a exibição itere **todas** as obras com diária.

### Testes
- Unit: `recalcularDiarias()` com efetivo em duas obras gera dois itens de diária distintos.

---

## Frente 4 — Anexos de documentos (bônus/desconto e pagamento)

### Modelo de dados
- **Nova tabela** `documento` (estende `BaseActiveRecord` — soft-delete + auditoria + timestamps):
  - `id`
  - `owner_tipo` VARCHAR(20) — `'card_item'` | `'card_pagamento'`
  - `owner_id` INT — id do `card_item` (bônus/desconto) ou do `card` (pagamento)
  - `nome_original` VARCHAR(255)
  - `arquivo` VARCHAR(255) — caminho relativo em `uploads/documentos/`
  - `mime` VARCHAR(100)
  - `created_at`, `updated_at`, `deleted_at`
- Migration `create_documento_table` + entradas em `permissao` para as novas actions.

### Componente `DocumentoHelper` (espelha `components/ImagemHelper`)
- Entrada **imagem** (jpg/png) → converte para **PDF** via mpdf (`$mpdf->Image()` ou wrapper HTML)
  e salva **apenas** o PDF.
- Entrada **PDF** → salva como está.
- Valida mime (jpg/png/pdf) e tamanho; nomeia o arquivo de forma única em `uploads/documentos/`.

### Regras por contexto
- **Bônus / Desconto:** **1 documento por linha** (substituível — excluir + reanexar). Controle de
  upload em cada linha de bônus/desconto no `fechar.php`.
- **Pagamento:** ao **marcar como pago**, abrir **modal** com upload de **múltiplos** documentos
  (nota fiscal, comprovantes). Documentos ficam visíveis na tela do card com excluir/reanexar.

### Controller (`CardController`)
- `actionUploadDoc` (POST) — recebe arquivo + owner_tipo + owner_id; aplica `DocumentoHelper`; cria `documento`.
- `actionExcluirDoc` (POST) — soft-delete do `documento`.
- `actionBaixarDoc` (GET) — `sendFile()` do PDF.
- Behaviors: `PermissaoBehavior` + `VerbFilter` (upload/excluir só POST).

### Fluxo "marcar como pago"
- Hoje `mudar-status` para `pago` é um POST direto. Passa a abrir um **modal** que: confirma o
  pagamento e permite anexar 0..N documentos antes/depois. Os documentos de pagamento (`owner_tipo =
  card_pagamento`, `owner_id = card.id`) ficam listados na tela do card com excluir/reanexar.

---

## Frente 5 — Histórico de status com responsável

- Dado **já existe**: `card_status_historico.usuario_id` é gravado em `Card::mudarStatus()` (`Card.php:162`).
- Adicionar relação `CardStatusHistorico::getUsuario()` → `Profissional`.
- Em `views/card/_status.php`, exibir "por &lt;nome&gt;" em cada transição (join pelo `usuario_id`).
- Sem migration.

---

## Frente 6 — Filtros do fechamento, escopo do líder e lista enriquecida

### 6a. Filtros (substituir `views/card/_search.php`)
- Novo `CardSearch` model com campos:
  - `data_inicial`, `data_final` — **obrigatórios** (sem período preenchido, a lista vem vazia).
  - `obra_id` — opcional (restrito ao escopo do líder, ver 6b).
  - `profissional_id` — opcional.
  - `status` — opcional (`rascunho` | `fechado` | `pago` | `pendente`).
- Remover o filtro por quinzena (dropdown atual).
- `CardController::actionIndex` deriva as **quinzenas que se sobrepõem** ao período
  `[data_inicial, data_final]` (enumerar meses do intervalo e selecionar as quinzenas cujo intervalo
  intersecta o período), e monta a lista a partir delas — mantendo o comportamento atual de listar
  quem trabalhou mesmo sem card —, aplicando os filtros de obra/profissional/status.

### 6b. Escopo do líder (todas as telas)
- Helper central `Obra::visiveisPara($identity)` (query/IDs de obras visíveis):
  - **Líder-puro** (`temPerfil('lider')` **sem** gerente/administrativo): apenas obras onde
    `lider1_id = identity.id OR lider2_id = identity.id`.
  - Gerente/Administrativo: todas as obras ativas.
- Aplicar em: filtro de obra do fechamento, listagem/cadastro de obras, relatórios e **todo dropdown
  de obra**. Refatorar o registro de efetivo (que já faz a restrição) para usar o mesmo helper.

### 6c. Lista de cards enriquecida (`views/card/index.php` + export)
- Por linha exibir:
  - **Quinzena** a que se refere (`Quinzena::rotulo`).
  - **Obras trabalhadas** (distinct das obras dos itens de diária do card).
  - **Ícones de download** por documento de pagamento, quando houver.
- Export Excel acompanha as colunas novas (via `ExportHelper`).

---

## Resumo das mudanças de schema
| Migration | Mudança |
|---|---|
| `add_considera_nota_to_card_item` | `card_item.considera_nota` TINYINT(1) DEFAULT 0 |
| `add_total_nota_to_card` | `card.total_nota` DECIMAL(10,2) DEFAULT 0 |
| `create_documento_table` | tabela `documento` (polimórfica, soft-delete) |
| (seed permissão) | actions `upload-doc`, `excluir-doc`, `baixar-doc` em `permissao` |

Nenhuma coluna nova para o bônus de líder (linha de bônus comum) nem para o histórico (dado já existe).

## Sequência de implementação sugerida (PRs incrementais)
1. **Valor da nota** + bônus de líder (migrations + cálculo + PDF + tela). Maior valor.
2. **Bug diárias por obra** (investigação + recálculo ao abrir + aviso de divergência).
3. **Anexos** (tabela + `DocumentoHelper` + bônus/desconto + modal de pagamento + download).
4. **Histórico com responsável** (pequeno).
5. **Filtros + escopo de líder + lista enriquecida**.

## Estratégia de testes
- **Unit:** `recalcularTotais` (valor da nota com/sem descontos marcados); inserção do bônus de líder
  na criação; `recalcularDiarias` com duas obras; `Obra::visiveisPara` (líder-puro vs gerente);
  derivação de quinzenas a partir do período; conversão imagem→PDF do `DocumentoHelper`.
- **Functional:** anexar/excluir documento no fluxo de pagamento; filtro obrigatório por período;
  líder-puro não vê obras de terceiros.

## Pontos a confirmar na revisão
1. Rótulo do checkbox: **"Considerar no valor da nota"** (proposto) vs "Desconsiderar no valor da nota".
2. Bug das diárias: recalcular ao abrir (rascunho) **+** aviso de divergência (fechado/pago) — ok?
