# Design: Permissão de desbloqueio da Alocação WMS (App do operador)

**Data:** 2026-06-18
**Status:** Aprovado

---

## Contexto

A missão Alocação WMS já é despachável (Designações) e executável (App, rota `alocacaowms`). Hoje o card na home do operador (`estrutura.php`) está visível para todos. Queremos gatear o acesso no mesmo padrão de Pesagem: **bloqueado por padrão**, operador solicita liberação, gestor aprova, e o acesso fica liberado até o fim do dia (`dia_efetivo`).

O fluxo de Solicitações já é majoritariamente genérico. Esta feature adiciona o novo tipo `ACESSO_ALOCACAO_WMS` espelhando exatamente o `ACESSO_PESAGEM`.

---

## Decisões

| Decisão | Escolha |
|---|---|
| Comportamento do card | Bloqueado por padrão (igual Pesagem). Substitui o card "pra todos". |
| Persistência da liberação | Reusa `usuario.dia_efetivo_liberacoes` (JSON), ação `ACESSO_ALOCACAO_WMS`, expira no dia. **Sem coluna nova.** |
| Rejeição | Sem efeito colateral (igual Pesagem). |
| Tela de gestão do gestor | Sem alteração — já é genérica (Aprovar/Rejeitar por tipo). |

---

## Fluxo

```
Operador (home) vê card BLOQUEADO → "Solicitar liberação"
  → App/SolicitarAcessoAlocacaoWms (satélite V2)
  → CriarSolicitacaoLaboratorio (tipo=ACESSO_ALOCACAO_WMS, status=pendente, referencia=USUARIOS/uid)
  → card vira "Em análise" (solicitação pendente do dia)

Gestor (gestao de solicitações, genérica) → Aprovar
  → AprovarSolicitacaoLaboratorio → $mapaStrategies[ACESSO_ALOCACAO_WMS]
  → AcessoAlocacaoWmsAprovadoStrategy::executar
  → usuario.dia_efetivo_liberacoes += { acao_liberada:'ACESSO_ALOCACAO_WMS', data_limite_liberacao: hoje }

Operador recarrega → card LIBERADO → entra em logistica/app/alocacaowms
  → AlocacaoWmsHandler::alocacaowms() guard: sem liberação do dia → tela "sem acesso"
```

---

## Componentes

### Backend — sinal Solicitacoes

1. **`Enums/SolicitacaoTipo.php`** — adicionar `public const ACESSO_ALOCACAO_WMS = 'ACESSO_ALOCACAO_WMS';`

2. **`Validators/CriarSolicitacaoValidator.php`** — adicionar `SolicitacaoTipo::ACESSO_ALOCACAO_WMS` ao array `$tiposValidos` (linhas 37-44).

3. **`Strategies/AcessoAlocacaoWmsAprovadoStrategy.php`** (novo) — cópia fiel de `AcessoPesagemAprovadoStrategy`, trocando a string `'ACESSO_PESAGEM'` por `'ACESSO_ALOCACAO_WMS'` (no filtro e na nova entrada). Grava em `dia_efetivo_liberacoes` via `GoldieUsers` (opt=update).

4. **`Laboratorios/AprovarSolicitacaoLaboratorio.php`** — registrar no `$mapaStrategies`:
   `SolicitacaoTipo::ACESSO_ALOCACAO_WMS => AcessoAlocacaoWmsAprovadoStrategy::class`.

### App — operador

5. **`App/Laboratorios/SolicitarAcessoAlocacaoWms.php`** (novo) — cópia fiel de `SolicitarAcessoPesagem`:
   - construtor `($galaxia, string $opcao, ?array $data = [])` → `executar($galaxia, $data)`
   - `parametrosRequisicao`: `tipo='ACESSO_ALOCACAO_WMS'`, `referencia_tipo='USUARIOS'`, `referencia_id=uid`, `solicitante_id=uid`, `motivo` padrão "Solicito acesso à tela de Alocação WMS".
   - delega a `new CriarSolicitacaoLaboratorio($galaxia, $parametrosRequisicao)`.
   - Precisa estar roteável como satélite V2 do App (espelhar como `SolicitarAcessoPesagem` é registrado/roteado no App).

6. **`App/Handlers/AlocacaoWmsHandler.php`** — guard no início de `alocacaowms()` (espelha `PesagemHandler::pesagem()` linhas ~30-57):
   - busca fresca `UserDb->findById(uid)`, decodifica `dia_efetivo_liberacoes`, procura `acao_liberada==='ACESSO_ALOCACAO_WMS'` com `data_limite_liberacao >= hoje`.
   - se não liberado → `renderAppView('html/shared/lista_unificada', ['mensagemVazio' => 'Você não possui acesso à tela de Alocação WMS. Solicite liberação na tela inicial.'])` (ou equivalente já usado).
   - O guard fica na **lista** (`alocacaowms()`), não no item — espelhando Pesagem.

7. **`App/html/estrutura.php`** — substituir o card simples de Alocação WMS (adicionado antes) pelo bloco de 3 estados, espelhando o bloco da Pesagem (linhas ~387-505):
   - **liberado** → card normal clicável (rota `logistica/app/alocacaowms`).
   - **solicitação pendente do dia** → card "Em análise".
   - **bloqueado** → card + botão "Solicitar liberação" que dispara o satélite `SolicitarAcessoAlocacaoWms` (`setVersao(2)->setConstelacao('Logistica')->setEstrela('App')->setSatelite('SolicitarAcessoAlocacaoWms')->setOpcao('solicitar')->acaoElemento('')`), com modal de confirmação (espelhar IIFE da Pesagem).

---

## TDD

1. **`CriarSolicitacaoValidatorAlocacaoWmsTddTest`** (unit/integração) — `validar(['tipo'=>'ACESSO_ALOCACAO_WMS', 'referencia_tipo'=>'USUARIOS','referencia_id'=>1,'solicitante_id'=>1])` retorna `[]` (sem erro de tipo inválido). RED antes de adicionar ao `$tiposValidos`.

2. **`AcessoAlocacaoWmsAprovadoStrategyTddTest`** (integração, dev_gx_goldie):
   - cria/usa um usuário de teste; snapshot do `dia_efetivo_liberacoes` original.
   - `executar((object)['solicitante_id'=>uid, 'id'=>0])` → relê o usuário e confirma entrada `acao_liberada='ACESSO_ALOCACAO_WMS'` com `data_limite_liberacao = hoje`.
   - confirma idempotência (rodar 2x não duplica a entrada).
   - cleanup: restaura `dia_efetivo_liberacoes` original.

Frontend (`estrutura.php`, satélite routing, guard) — validação por inspeção + smoke manual no `dev-genesis` (não dá para dirigir o browser via CLI).

---

## Critérios de aceite

1. Card de Alocação WMS na home aparece **bloqueado** para operador sem liberação do dia.
2. Clicar "Solicitar liberação" cria uma `solicitacoes_globais` com `tipo=ACESSO_ALOCACAO_WMS`, `status=pendente`; card vira "Em análise".
3. Solicitação aparece na tela de gestão do gestor (genérica) com botões Aprovar/Rejeitar.
4. Ao aprovar, `usuario.dia_efetivo_liberacoes` ganha a entrada `ACESSO_ALOCACAO_WMS` com data de hoje.
5. Operador recarrega → card liberado → acessa `logistica/app/alocacaowms`.
6. Sem liberação do dia, o guard do `AlocacaoWmsHandler` bloqueia o acesso direto à lista.
7. Validator aceita `ACESSO_ALOCACAO_WMS`; idempotência da solicitação preservada (não duplica pendente).

---

## Fora de escopo

- Mudanças na tela de gestão do gestor (genérica).
- Coluna nova no usuário (reusa `dia_efetivo_liberacoes`).
- Strategy de rejeição (sem efeito colateral, igual Pesagem).
- Auto-aprovação ou regras de nível de acesso além das existentes.
