# Implementação frontend — bipagem-codigo-barras-fator

## Correção de rota — ExecucaoCard (controlador correto para modo Luz/fila única)

Na separação em modo Luz (fila única), quem processa o scan é o `ExecucaoCard`, não o `SeparacaoV2`.
As três correções abaixo foram aplicadas ao controlador correto.

### A) `luz/separacao/item_card.php` (linha ~150)

`'validar_codigo' => false` era hardcoded, ignorando o `true` passado pelo wrapper
(`separacao/item.php` via `$galaxia->luz('SeparacaoItemCard', [..., 'validar_codigo' => true])`).
Corrigido para `'validar_codigo' => $validar_codigo ?? true` — repassa o valor recebido do `$data`
que o `SeparacaoHandler::Luz_SeparacaoItemCard` extrai como variável antes de incluir a view.

### B) `shared/components/execucao/execucao_card.php`

- Após montar `$codigosValidos` (4 campos do produto), instancia
  `ProdutoCodigoBarraSonda::listarPorProdutos([$produtoIdParaSonda])` (1 query, N+1 zero).
- Monta `$codigosFator` (chaves em maiúsculo): primeiro fator 1 para os campos do produto,
  depois sobrescreve/adiciona com o fator real da tabela (tabela vence na precedência).
- Acrescenta os códigos da tabela em `$codigosValidos` (validação passa a aceitar esses códigos).
- Guard para `produto_id = 0` ou ausente: mapa vazio, sem erro.
- Degrada graciosamente em `catch(\Throwable)` com `error_log`.
- Expõe o mapa em `<script id="data-codigos-fator" type="application/json">` logo após o
  `data-codigos-validos` existente (mesmo padrão).

### C) `shared/components/execucao/execucao_card.js`

- Propriedade `codigosFator: {}` declarada no topo do objeto `ExecucaoCard`.
- `init`: lê `#data-codigos-fator`, normaliza chaves `toUpperCase().trim()`, atribui a
  `this.codigosFator` (try/catch → `{}`).
- `processarScan`: descobre `const fator = this.codigosFator[codigoNorm] || 1`.
  - Bloqueio por teto: `this.qtdBipada + fator > this.qtdTotal` (não-KG); evita ultrapassar
    o total mesmo com fator grande.
  - `this.qtdBipada += fator` (era `++`).
  - `queueUpdate('incremento', fator, 'scan')` (era `1`).
- `incrementarQuantidade` / `decrementarQuantidade` (botões +/-): **inalterados**, sempre ±1.
- KG: isento do teto (comportamento existente preservado).

### Validação de sintaxe (correção ExecucaoCard)

```
node --check componentes/Missoes/Logistica/sinais/App/html/shared/components/execucao/execucao_card.js  → OK
php -l componentes/Missoes/Logistica/sinais/App/html/shared/components/execucao/execucao_card.php      → No syntax errors detected
php -l componentes/Missoes/Logistica/sinais/App/html/luz/separacao/item_card.php                       → No syntax errors detected
```

---



## Arquivos modificados

### JS

- `componentes/Missoes/Logistica/sinais/App/html/separacao/item.js`
  - `buildCodeMap` (linhas ~705-737): guard `Object.keys(item.codigosBarras).length > 0` adicionado (paridade com carregamento); `item._codigosSet` populado em ambos os ramos (codigosBarras e codigos_validos).
  - `processarScan` item-selecionado (linhas ~2182-2241): validação migrada de `codigos_validos.map+includes` para `_codigosSet.has` com lazy-init; `ajustarQuantidade(1,...)` trocado por `ajustarQuantidade(q,...)` onde `q` vem do `codeMap[cleanCode].quantidade`; ramo "item sem códigos + validarCodigo ligado" passa a bloquear com `efeitoErro('Prod. sem código cadastrado!')` (AC6.3).
  - `_persistirDadosBackground` extrato (linha ~2092): campo `fator: ultimoDelta` adicionado ao payload.

- `componentes/Missoes/Logistica/sinais/App/html/carregamento/item.js`
  - `config.validarCodigo` (linha 54): `false → true` (AC6.2).
  - `init` fallback (linhas ~465-470): quando `#data-validar-codigo-conf` está ausente no DOM, `this.config.validarCodigo` passa a ser `true` em vez de `false`.
  - `processarScan` item-selecionado (linha ~2810): `ajustarQuantidade(1,...)` trocado por `ajustarQuantidade(q,...)` onde `q = (this.codeMap[cleanCode] && this.codeMap[cleanCode].quantidade) || 1`.
  - `_persistirDadosBackground` extrato (linha ~2716): campo `fator: ultimoDelta` adicionado.
  - `montarBipagem` payload lote (linha ~4420): campo `fator: delta` adicionado. `quantidade_delta` não renomeado.

### PHP

- `componentes/Missoes/Logistica/sinais/App/html/shared/components/v2/execucao_bipagem.php` (linha 51)
  - **Risco #4 confirmado e corrigido:** a linha `$validarCodigo = false;` sobrescrevia incondicionalmente qualquer valor passado pelo caller, inclusive o `$validarCodigo = true` da separação. Corrigido para `$validarCodigo = $validarCodigo ?? true;` — honra o caller; default `true` para novos callers sem a variável definida.

## Verificação da view de carregamento (item 3 do escopo)

**O que foi encontrado:**

O arquivo `carregamento/item.php` não define `$validarCodigo`. Ele faz `$parametrosVisualizacao = get_defined_vars()` e repassa ao componente. O componente `execucao_bipagem.php` (linha 51) definia `$validarCodigo = false` incondicionalmente — portanto o carregamento recebia `'0'` no `#data-validar-codigo-conf`, e o JS leria `false`.

A separação (`separacao/item.php`) define `$validarCodigo = true` antes do `get_defined_vars()`, mas o componente sobrescrevia com `false` também — o campo no DOM chegava `'1'` só porque o JS lê do DOM **depois** de o PHP renderizar; o PHP gerava `'0'` na view da separação também. Esse era um bug silencioso: a separação funcionava com validação porque o fallback do JS era `false` do DOM `'0'`, mas o `config.validarCodigo` do objeto separação já nasce `true` (linha 54 do separacao/item.js), e a leitura do DOM no `init` sobrescrevia para `false`.

**Correção aplicada:** `$validarCodigo = $validarCodigo ?? true;` no componente. Agora:
- Separação: passa `$validarCodigo = true` → componente renderiza `'1'` → JS confirma `true`.
- Carregamento: não passa `$validarCodigo` → componente usa default `true` → renderiza `'1'` → JS confirma `true`.

## i18n

Chaves adicionadas nas 3 línguas (`linguagens/pt-br.json`, `linguagens/en.json`, `linguagens/es.json`):

| Chave (MD5) | PT-BR | EN | ES |
|---|---|---|---|
| `e5743610068f1ce1e2b457447862cab7` | Código não pertence a este item! | Code does not belong to this item! | ¡El código no pertenece a este ítem! |
| `53e94261b63142a2e5bb366f637ad52e` | Produto sem código cadastrado! | Product has no registered code! | ¡Producto sin código registrado! |
| `0faa05ea3016bb887b21e098a25055aa` | Quantidade excedida! Limite: %s | Quantity exceeded! Limit: %s | ¡Cantidad excedida! Límite: %s |
| `1d38f3e586b0846dd1e24624aa467371` | Código inválido: produto não cadastrado (%s) | Invalid code: product not registered (%s) | Código inválido: producto no registrado (%s) |
| `ade1782b22eb5b703ad9e7339be870ce` | Código incorreto! (%s) não pertence a %s | Wrong code! (%s) does not belong to %s | ¡Código incorrecto! (%s) no pertenece a %s |

**O que ficou hardcoded:** as mensagens de erro em JS (`efeitoErro(...)`) e em PHP (`MissoesBipagem`) permanecem como strings literais — o sistema de i18n do projeto usa `show()` exclusivamente em PHP; não há mecanismo de tradução no JS. As chaves acima são registradas para eventual uso futuro quando `show()` for aplicado nas mensagens do PHP (`MissoesBipagem`). Nenhum mecanismo novo de tradução foi introduzido no JS, conforme diretriz do techplan.

## Endpoints consumidos

Nenhum endpoint novo. A bipagem continua dispatchada via Satélite `MissoesBipagem` pela Galáxia. O lote envia para o endpoint existente com `quantidade_delta` (inalterado) e agora também `fator` (aditivo). Nenhuma alteração em `Routes.php`.

## Validação de sintaxe

```
node --check componentes/Missoes/Logistica/sinais/App/html/separacao/item.js     → sem saída (OK)
node --check componentes/Missoes/Logistica/sinais/App/html/carregamento/item.js  → sem saída (OK)
php -l componentes/Missoes/Logistica/sinais/App/html/shared/components/v2/execucao_bipagem.php → No syntax errors detected
python3 -m json.tool linguagens/pt-br.json → OK
python3 -m json.tool linguagens/en.json    → OK
python3 -m json.tool linguagens/es.json    → OK
```

## Smoke test sugerido

1. **Separação — fator aplicado (US2/AC2.1):**
   - Abrir missão de separação com item que tem código de caixa `fator=10` cadastrado em `produtos_codigos_barras`.
   - Bipar 1× o código de caixa → contador deve saltar de 0 para 10; barra de progresso reflete 10; 1 linha no extrato local com `quantidade_delta=10` e `fator=10`.

2. **Separação — bloqueio por teto (US4/AC4.1):**
   - Com o mesmo item pedindo 7 unidades, bipar o código de caixa fator=10 → deve bloquear com efeito de erro e vibração; contador permanece 0.
   - Bipar 7× código unitário (fator=1) → deve completar normalmente.

3. **Separação — AC6.3 (item sem código + validarCodigo ligado):**
   - Item cujo produto não tem `codigo_barras`, `codigo_produto`, nem registro em `produtos_codigos_barras`.
   - Bipar qualquer código → deve exibir "Prod. sem código cadastrado!" e bloquear.

4. **Carregamento — validação ligada (AC6.2):**
   - Abrir missão de carregamento; bipar código que não pertence ao item selecionado → deve rejeitar com erro (antes aceitava qualquer beep).

5. **Carregamento — fator aplicado (US2/AC2.1):**
   - Bipar código de caixa fator=10 com item selecionado → contador salta 10; 1 extrato.

6. **Não-regressão (AC2.2):**
   - Produto sem registro em `produtos_codigos_barras`; bipar código do produto (`codigo_barras` do produto) → soma 1, comportamento atual preservado.

7. **Verificar `#data-validar-codigo-conf` no DOM:**
   - Inspecionar o HTML renderizado de carregamento e separação → ambos devem ter `value="1"` no input `#data-validar-codigo-conf` (antes, separação rendia `'0'` apesar da intenção ser `true`).
