# Design: Seleção de campo ativo + edição antes de confirmar (execução Alocação WMS)

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

---

## Contexto

Na tela de execução da Alocação WMS (`App/html/alocacaowms/item.js`), o operador bipa produto e localização (em qualquer ordem) e confirma. Hoje, depois de preencher os dois campos, ele fica **preso**: tocar num card já preenchido é bloqueado (`_bindCamposTap` retorna cedo em `.preenchido`), e re-bipar tem destino ambíguo (sobrescreve `campoAtivo` ou localização por padrão). Cenário relatado: bipou produto → localização, quis trocar o produto e não conseguiu.

Este ajuste dá ao operador controle explícito de **qual campo está ativo** (alvo do próximo bipe) e a capacidade de **voltar atrás / trocar** um campo antes de confirmar. Só muda o *targeting* de campo na interação — nada de lógica de alocação/backend.

## Decisões (do brainstorming)

| Decisão | Escolha |
|---|---|
| Tocar card já preenchido | Marca como ativo, **mantém o valor**; próximo bipe substitui. `✕` limpa explicitamente. |
| Atalho "recomeçar" (limpar os 2) | Não — edição campo a campo já cobre. |

## Modelo de interação

Conceito central: **campo ativo** = o alvo do próximo código bipado/digitado. Estados: `'produto'`, `'localizacao'` ou `null` (neutro). Destaque visual `.ativo` no card ativo (só um por vez).

### Regras de roteamento (`_processarCodigo`)
1. **Campo ativo definido** → preenche/**substitui** aquele campo. Depois:
   - preencheu *produto* e *localização* vazia → auto-avança ativo para `'localizacao'`;
   - senão → ativo volta a `null`.
2. **Neutro (`null`)**:
   - produto vazio → produto (e auto-avança para `'localizacao'`);
   - senão localização vazia → localização;
   - **ambos preenchidos** (decisão coesa, honra "bipar = selecionar produto"):
     - se o código bate com um produto da lista de pendentes (`_buscarItemPorCodigo`) → troca para esse produto (seleção);
     - senão (código ambíguo) → não sobrescreve; toast "Toque no campo que deseja trocar.".

### Tap num card (cheio ou vazio)
- Define-o como ativo (`.ativo`), **mantém o valor atual**, revela o input manual daquele campo (divulgação progressiva já existente). Próximo bipe substitui.

### ✕ (limpar campo)
- Limpa o campo e o deixa ativo (próximo bipe recoloca).

### Cenário resolvido
Ambos preenchidos → tocar no card Produto (ativo, valor mantido) → bipar novo produto → substitui. Sem ficar preso; sem reset global.

## Componentes / mudanças

### `App/html/alocacaowms/item.js`
- **Nova função pura** `_decidirAlvo(estado)` → `'produto' | 'localizacao' | null`, encapsulando as regras de roteamento (recebe `{produtoCodigo, localizacaoCodigo, campoAtivo}`). Sem efeitos colaterais — testável.
- `_processarCodigo`: usa `_decidirAlvo` para escolher o destino; quando o alvo for um campo já preenchido (substituição), limpar o estado daquele campo antes de setar; aplicar auto-avanço produto→localização. No caso `_decidirAlvo === null` (neutro+ambos-cheios): tentar `_buscarItemPorCodigo` — se achar produto, selecionar (troca); senão, toast e não sobrescrever.
- `_bindCamposTap`: remover o early-return em `.preenchido`; tocar em qualquer card define `campoAtivo`, aplica `.ativo`, mantém valor, revela input manual.
- Setters `_setProdutoCodigo`/`_setLocalizacao` e `_selecionarItemPorElemento`: manter coerência do `.ativo` (limpar destaque ao concluir o preenchimento; aplicar auto-avanço).
- Botões de limpar (`_bindLimparBotoes`): após limpar, marcar o campo como ativo.
- **Sem mudança** na persistência (valores setados), `_atualizarBotaoConfirmar`, `_enviarSugestao`, confirmar, backend.

### CSS (no `<style>` do `item.php`)
- Garantir um estilo visível de `.wms-scan-field.ativo` (realce de borda/glow na cor da marca) para sinalizar o campo ativo. (Se já houver, ajustar para boa visibilidade.)

### i18n
- Nova string `show('Toque no campo que deseja trocar.')` no toast — auto-harvest + EN/ES (tratado conforme o estado dos `linguagens/*.json`).

## Testes

Há lógica pura testável agora: **TDD em `_decidirAlvo(estado)`**, via teste JS standalone (`node`), cobrindo:
- neutro + produto vazio → `'produto'`;
- neutro + produto cheio + localização vazia → `'localizacao'`;
- neutro + ambos cheios → `null`;
- ativo `'produto'` → `'produto'` (mesmo com produto cheio);
- ativo `'localizacao'` → `'localizacao'`.

O resto (DOM, `.ativo` visual, toast, tap) por `node --check` + `php -l` + smoke manual no coletor/dev.

## Critérios de aceite

1. Bipar produto e localização em sequência (sem tocar) continua funcionando (produto → auto-avança p/ localização).
2. Com ambos preenchidos, tocar no card Produto o marca ativo (valor mantido, destaque visível) e o próximo bipe substitui o produto — re-rodando a seleção do item.
3. Idem para trocar a localização.
4. Com ambos preenchidos e nenhum campo ativo: bipar um produto da lista de pendentes troca para esse produto; bipar um código ambíguo (não-produto) não sobrescreve nada e mostra o toast orientando a tocar no campo.
5. `✕` limpa o campo e o deixa ativo para re-bipe.
6. `_decidirAlvo` passa os 5 casos de teste.
7. Confirmar e backend inalterados.

## Fora de escopo

- Botão/atalho "recomeçar".
- Qualquer mudança na lógica de alocação, validação ou backend.
- Mudanças nos estados `iniciar`/`concluido`/`erro`.
