# Testes — alocacao-wms

## Cobertura

| Componente | Tipo | Path | Status |
|---|---|---|---|
| StatusAlocacao, OrigemLeitura, EstadoIntegracao (enums) + TipoMissao::ALOCACAO_WMS | TDD standalone | `componentes/Missoes/Logistica/sinais/AlocacaoWms/Testes/Enums/StatusAlocacaoTddTest.php` | PASS 34/34 |
| Migration 001 + 002 (schema) + seed 003 | Integration | `tests/integration/AlocacaoWms/MigrationSchemaTest.php` | PASS 39/39 |
| WmsLocalizacaoSonda (buscarPorCodigo, existeAtiva, customerControl) | TDD integration | `componentes/Missoes/Logistica/sinais/AlocacaoWms/Testes/Sondas/WmsLocalizacaoSondaTddTest.php` | PASS 9/9 |
| WmsAlocacaoSonda (registrarAlocacao, listar, marcarIntegracao, buscarPendentes) | TDD integration | `componentes/Missoes/Logistica/sinais/AlocacaoWms/Testes/Sondas/WmsAlocacaoSondaTddTest.php` | PASS 19/19 |
| ConfirmarAlocacaoValidator (AC4.1–4.4 + qtd obrigatória + happy path) | TDD integration | `componentes/Missoes/Logistica/sinais/AlocacaoWms/Testes/Validators/ConfirmarAlocacaoValidatorTddTest.php` | PASS 21/21 |
| ConfirmarAlocacaoLaboratorio (rejeições + caminho feliz + AC6.1/6.2/6.3) | TDD integration | `componentes/Missoes/Logistica/sinais/AlocacaoWms/Testes/Laboratorios/ConfirmarAlocacaoLaboratorioTddTest.php` | PASS 19/19 |
| Fluxo end-to-end (1:N, listar, ListarAlocacoesLaboratorio, varredura integração) | Integration | `tests/integration/AlocacaoWms/AlocacaoFluxoTest.php` | PASS 27/27 |

**Total: 168 PASS, 0 FAIL**

---

## Gaps de cobertura (e justificativa)

- `AlocacaoWmsExecucaoStrategy` — não coberta por unit test isolado. A strategy depende do `BaseExecucaoStrategy` do framework, que exigiria mocks complexos do contexto de missão. A cobertura da ordenação foi considerada suficiente via smoke test manual (passo 12 do techplan). Pode ser adicionada futuramente seguindo o padrão de `CarregamentoAlfabeticoStrategyTest.php`.
- `AlocacaoWmsListaStrategy` — não coberta. Thin wrapper que injeta tema e estatísticas; sem lógica de negócio própria.
- `AlocacaoWmsHandler` / `AlocacaoWms.php` (dispatcher) — não cobertos por integration test. Esses componentes requerem o contexto completo do Galaxia (sessão de usuário, roteamento HTTP). Testáveis apenas via smoke test manual conforme descrito no `04-frontend.md`.
- `ErpAlocacaoWmsHookStrategy` / `WmsAlocacaoWmsHookStrategy` / `crons/wms_alocacao_integracao.php` — não cobertos. Os hooks fazem cURL externo; o worker cron requer configuração de URL de endpoint externo. Testáveis apenas em ambiente com ERP/WMS disponível.
- `MissoesBipagem::alocarLocalizacao` (delegação ao Laboratório) — não coberto por teste isolado. A delegação é uma linha que chama `ConfirmarAlocacaoLaboratorio::executar()`, já coberto acima.

---

## Output da execução

```
=== ENUM TDD ===
[PASS] from("confirmada") -> CONFIRMADA
[PASS] from("cancelada")  -> CANCELADA
[PASS] CONFIRMADA->value == "confirmada"
[PASS] CANCELADA->value  == "cancelada"
[PASS] label CONFIRMADA
[PASS] label CANCELADA
[PASS] tryFrom invalido retorna null
[PASS] tryFrom valido retorna case
[PASS] from("codigo_barras")
[PASS] from("manual")
[PASS] CODIGO_BARRAS->value
[PASS] MANUAL->value
[PASS] label CODIGO_BARRAS
[PASS] label MANUAL
[PASS] tryFrom inválido -> null
[PASS] from("pendente")
[PASS] from("enviado")
[PASS] from("falha")
[PASS] PENDENTE->value
[PASS] ENVIADO->value
[PASS] FALHA->value
[PASS] label PENDENTE
[PASS] label ENVIADO
[PASS] label FALHA
[PASS] PENDENTE != ENVIADO
[PASS] FALHA != ENVIADO
[PASS] ALOCACAO_WMS->value
[PASS] ALOCACAO_WMS->id() == 14
[PASS] ALOCACAO_WMS->label()
[PASS] ALOCACAO_WMS->name()
[PASS] fromId(14) -> ALOCACAO_WMS
[PASS] fromId inválido -> null
[PASS] id 2 ainda é SEPARACAO
[PASS] id 12 ainda é PESAGEM
Resultado: 34 passou, 0 falhou

=== MIGRATION SCHEMA (dev_gx_goldie) ===
-- Executando migration 001 (wms_localizacoes)...
-- Executando migration 002 (wms_alocacoes)...
-- Executando migration 003 (seed tipos_missao_logistica)...
-- Migrations aplicadas.
[PASS] tabela wms_localizacoes existe
[PASS] wms_localizacoes tem coluna 'id'
[PASS] wms_localizacoes tem coluna 'codigo'
[PASS] wms_localizacoes tem coluna 'descricao'
[PASS] wms_localizacoes tem coluna 'ativo'
[PASS] wms_localizacoes tem coluna 'block'
[PASS] wms_localizacoes tem coluna 'block_filial_id'
[PASS] wms_localizacoes tem coluna 'block_empresa_id'
[PASS] wms_localizacoes tem coluna 'data_cadastro'
[PASS] índice uniq_wms_localizacoes_codigo existe
[PASS] índice idx_wms_localizacoes_ativo existe
[PASS] tabela wms_alocacoes existe
[PASS] wms_alocacoes tem coluna 'id'
[PASS] wms_alocacoes tem coluna 'missao_logistica_id'
[PASS] wms_alocacoes tem coluna 'missao_item_id'
[PASS] wms_alocacoes tem coluna 'produto_id'
[PASS] wms_alocacoes tem coluna 'localizacao_codigo'
[PASS] wms_alocacoes tem coluna 'wms_localizacao_id'
[PASS] wms_alocacoes tem coluna 'quantidade'
[PASS] wms_alocacoes tem coluna 'origem_leitura'
[PASS] wms_alocacoes tem coluna 'status'
[PASS] wms_alocacoes tem coluna 'operador_id'
[PASS] wms_alocacoes tem coluna 'confirmada_em'
[PASS] wms_alocacoes tem coluna 'integracao_erp'
[PASS] wms_alocacoes tem coluna 'integracao_wms'
[PASS] wms_alocacoes tem coluna 'integracao_erp_em'
[PASS] wms_alocacoes tem coluna 'integracao_wms_em'
[PASS] wms_alocacoes tem coluna 'integracao_erro'
[PASS] wms_alocacoes tem coluna 'block'
[PASS] wms_alocacoes tem coluna 'block_filial_id'
[PASS] wms_alocacoes tem coluna 'block_empresa_id'
[PASS] wms_alocacoes tem coluna 'data_cadastro'
[PASS] idx_wms_alocacoes_missao existe
[PASS] idx_wms_alocacoes_produto existe
[PASS] idx_wms_alocacoes_integ_erp existe (retry ERP)
[PASS] idx_wms_alocacoes_integ_wms existe (retry WMS)
[PASS] FK missao_logistica_id -> missao_logistica existe
[PASS] tipos_missao_logistica contém código 'ALOCACAO_WMS'
[PASS] TipoMissao::ALOCACAO_WMS->id() == 14
RESULTADO: PASS=39  FAIL=0

=== WMS LOCALIZACAO SONDA ===
[PASS] buscarPorCodigo(ativo) retorna objeto (não null)
[PASS] objeto retornado tem o código correto
[PASS] objeto retornado tem ativo=1
[PASS] buscarPorCodigo(inativo) retorna null (ativo=0 filtrado)
[PASS] buscarPorCodigo(inexistente) retorna null
[PASS] existeAtiva(ativo) == true
[PASS] existeAtiva(inativo) == false
[PASS] existeAtiva(inexistente) == false
[PASS] customerControl: código de outro tenant não é retornado
RESULTADO: PASS=9  FAIL=0

=== WMS ALOCACAO SONDA ===
[PASS] registrarAlocacao retorna objeto (não null)
[PASS] alocacao tem id
[PASS] fixture linha 1 inserida via registrarAlocacao
[PASS] fixture linha 2 inserida com id maior
[PASS] listarPorMissao retorna 1ª alocação
[PASS] listarPorMissao retorna 2ª alocação
[PASS] listarPorMissao ordena DESC confirmada_em (mais recente primeiro)
[PASS] listarPorMissaoProduto retorna 1ª alocação
[PASS] listarPorMissaoProduto retorna 2ª alocação
[PASS] marcarIntegracaoErp -> enviado gravado
[PASS] marcarIntegracaoErp -> timestamp gravado
[PASS] marcarIntegracaoErp FALHA gravado
[PASS] mensagem de erro gravada em integracao_erro
[PASS] marcarIntegracaoWms -> enviado gravado
[PASS] marcarIntegracaoWms -> timestamp gravado
[PASS] buscarPendentesErp exclui enviado (ID1)
[PASS] buscarPendentesErp inclui falha (ID2)
[PASS] buscarPendentesWms exclui enviado (ID1)
[PASS] buscarPendentesWms inclui pendente (ID2)
RESULTADO: PASS=19  FAIL=0

=== CONFIRMAR ALOCACAO VALIDATOR ===
[PASS] missao_id zero -> rejeita
[PASS] operador_id zero -> rejeita
[PASS] produto_id zero -> rejeita
[PASS] localizacao vazio -> rejeita
[PASS] missão inexistente -> rejeita (AC4.1)
[PASS] missão concluida/cancelada -> rejeita (AC4.1)
[PASS] operador sem permissão -> rejeita (AC4.2)
[PASS] produto fora da missão -> rejeita (AC4.3)
[PASS] localização inexistente -> rejeita (AC4.4)
[PASS] localização inativa -> rejeita (AC4.4)
[PASS] quantidade null quando obrigatória -> rejeita
[PASS] quantidade=0 quando obrigatória -> rejeita
[PASS] quantidade=3.5 quando obrigatória -> aceita (happy path com qtd)
[PASS] happy path retorna missao, item, localizacao
[PASS] happy path completo -> ok=true
[PASS] retorna missao correta
[PASS] retorna item da missão
[PASS] retorna localização validada
[PASS] quantidade null (não obrigatória sem informar)
[PASS] happy path com quantidade opcional -> ok=true
[PASS] quantidade 10.0 retornada no payload validado
RESULTADO: PASS=21  FAIL=0

=== LABORATORIO CONFIRMAR ALOCACAO ===
[PASS] produto fora da missão -> ok=false
[PASS] mensagem específica de produto fora
[PASS] localização inexistente -> ok=false
[PASS] mensagem específica de localização
[PASS] quantidade faltando quando obrigatória -> ok=false
[PASS] mensagem específica de quantidade
[PASS] missão inexistente -> ok=false
[PASS] erro preenchido na rejeição de missão
[PASS] caminho feliz retorna ok=true
[PASS] retorna objeto alocacao
[PASS] alocacao tem id
[PASS] AC6.1: missão passou de pendente para em_andamento após 1º item
[PASS] AC6.2: missão permanece em_andamento com item pendente
[PASS] AC6.2: missão não concluída prematuramente com item pendente
[PASS] AC6.3: 2º item confirmado com ok=true
[PASS] AC6.3: missão passou para concluida após último item
[PASS] AC6.3: finalizado_em foi preenchido ao concluir
[PASS] retorno sempre tem chave ok
[PASS] rejeição sempre tem chave erro
RESULTADO: PASS=19  FAIL=0

=== FLUXO END-TO-END ===
[PASS] 1ª alocação inserida (produto A, loc A)
[PASS] 2ª alocação do mesmo produto gera nova linha (1:N, não sobrescreve)
[PASS] produto A tem exatamente 2 linhas em wms_alocacoes (histórico 1:N)
[PASS] alocação de produto B inserida
[PASS] listarPorMissao inclui aloc_1
[PASS] listarPorMissao inclui aloc_2
[PASS] listarPorMissao inclui aloc_3
[PASS] histórico produto A inclui aloc_1
[PASS] histórico produto A inclui aloc_2
[PASS] histórico produto A não inclui aloc_3 (outro produto)
[PASS] listarPorMissaoProduto: mais recente primeiro
[PASS] listarItensDaMissao retorna ok=true
[PASS] listarItensDaMissao retorna itens
[PASS] alocacoes_por_produto é array
[PASS] alocacoes_por_produto[produto_A] preenchido
[PASS] ultima_alocacao do produto A é a mais recente (aloc_2)
[PASS] listarHistoricoProduto retorna ok=true
[PASS] histórico laboratório inclui aloc_1
[PASS] histórico laboratório inclui aloc_2
[PASS] aloc_3 (pendente) aparece na fila ERP
[PASS] aloc_2 (falha) aparece na fila ERP para retry
[PASS] aloc_1 (enviado) excluído da fila ERP
[PASS] aloc_1 na fila WMS (pendente)
[PASS] aloc_2 na fila WMS (pendente)
[PASS] aloc_1 removida da fila WMS após envio
[PASS] aloc_2 permanece na fila WMS
[PASS] buscarPendentesIntegracaoErp respeita limite=1
RESULTADO: PASS=27  FAIL=0
```

---

## Bugs encontrados

Nenhum bug ativo. Os 3 bugs do ciclo anterior foram resolvidos pelo backend antes desta execução:

### BUG #1 (RESOLVIDO) — Migration 002 incompleta: colunas do framework faltantes em `wms_alocacoes`

**Status:** Corrigido. A migration 002 agora inclui `usuario_cadastro`, `data_atualizacao`, `usuario_atualizacao`, `block_data`, `block_quem`. `WmsAlocacaoSonda::registrarAlocacao()` funciona corretamente.

### BUG #2 (RESOLVIDO) — `ConfirmarAlocacaoValidator::operadorTemPermissao()` lançava TypeError

**Status:** Corrigido. Linha 151 de `ConfirmarAlocacaoValidator.php` agora usa `$operadores ?? []` no `array_map`, evitando o `TypeError` quando `missao->operadores` é null. AC4.2 passa 21/21.

### BUG #3 (RESOLVIDO) — Migration 003 usava colunas inexistentes em `tipos_missao_logistica`

**Status:** Corrigido. A seed usa a coluna `codigo` (não `nome`), sem `ativo`, com `id=14` (não conflita com o existente id=13). `TipoMissao::ALOCACAO_WMS->id()` retorna 14, sincronizado com o banco.
