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

## Arquivos criados

- `componentes/Constelacoes/Produtos/CodigosBarra/Migrations/001_create_produtos_codigos_barras.sql` — DDL idempotente PostgreSQL com `BIGSERIAL`, `CREATE TABLE IF NOT EXISTS`, `CREATE INDEX IF NOT EXISTS`, `block NOT NULL` sem DEFAULT, `block_*` auxiliares nullable.

## Arquivos alterados

- `componentes/Constelacoes/Produtos/CodigosBarra/Sondas/ProdutoCodigoBarraSonda.php` — adicionados `resolverPorCodigo(string $codigo, ?int $produtoId = null): ?object` e `listarPorProdutos(array $produtoIds): array`.
- `componentes/Constelacoes/Logistica/MissaoLogistica/Satelites/MissoesBipagem.php` — `use` da Sonda; `resolverProduto` consulta Sonda antes dos campos do produto (precedência da tabela); `buscarItemDaMissao` propaga `_fator_bipagem`/`_tipo_codigo_barras` ao item; `biparItem` lê fator do item e passa a `alterarQuantidade`; assinatura de `alterarQuantidade` ganha `$tipoCodigoBarras = null`; `atualizarItemNoBanco` idem + payload do extrato ganha `fator` e `tipo_codigo_barras`.
- `componentes/Constelacoes/Logistica/MissaoLogistica/Presenters/MissaoPresenter.php` — `use` da Sonda; `montarJsonFrontendBase` faz 1x `listarPorProdutos` antes do loop e monta `codigosBarras = { cod: fator }` por item (campos do produto fator 1 primeiro, Sonda por último para a tabela vencer).
- `componentes/Missoes/Logistica/sinais/App/html/shared/components/v2/execucao_bipagem.php` — 1 linha adicionada: `'codigosBarras' => $itemBase['codigosBarras'] ?? []` no `array_merge`.

## Arquivos NÃO alterados (confirmado)

- `SeparacaoPresenter.php` — não sobrescreve `codigosBarras`; chave da base sobrevive.
- `PesagemPresenter.php` — idem.
- `separacao/item.js`, `carregamento/item.js` — fora do escopo desta task (Dev Frontend).
- Código morto: `Inteligencias/ProdutoCodigoBarra`, `sql/produto_codigo_barra.sql`, `Satelites/ProdutosCodigosBarra` — não tocados.

## Desvios do techplan

Nenhum. Implementação seguiu o §1 ao §4 do techplan à risca.

**Nota sobre `produto_id` em `codigosBarras`:** o campo numérico `produto_id` do item foi adicionado como código com fator 1 no `codigosBarras` da base (igual ao que `SeparacaoPresenter` e `PesagemPresenter` já fazem em `codigos_validos`). O techplan menciona "4 campos do produto na base igual ao `codigos_validos` ampliado dos Presenters específicos". Implementado com guarda `!== '0'` para não incluir IDs zerados.

## Comandos de verificação executados

```
php -l componentes/Constelacoes/Produtos/CodigosBarra/Sondas/ProdutoCodigoBarraSonda.php         → No syntax errors detected
php -l componentes/Constelacoes/Logistica/MissaoLogistica/Satelites/MissoesBipagem.php            → No syntax errors detected
php -l componentes/Constelacoes/Logistica/MissaoLogistica/Presenters/MissaoPresenter.php          → No syntax errors detected
php -l componentes/Constelacoes/Logistica/MissaoLogistica/Presenters/SeparacaoPresenter.php       → No syntax errors detected
php -l componentes/Constelacoes/Logistica/MissaoLogistica/Presenters/PesagemPresenter.php         → No syntax errors detected
php -l componentes/Missoes/Logistica/sinais/App/html/shared/components/v2/execucao_bipagem.php    → No syntax errors detected
```

## Contrato para o Dev Frontend

### Contrato `codigosBarras` (JS)

O JSON de cada item agora contém:

```json
{
  "id": 123,
  "codigosBarras": {
    "7891234560001": 1.0,
    "17891234560008": 10.0,
    "SKU-ABC": 1.0
  },
  "codigos_validos": ["7891234560001", "SKU-ABC"],
  ...
}
```

- Chave: código de barras (string, já `trim`-ado pelo PHP).
- Valor: fator float (1.0 para códigos do produto; N para registros de `produtos_codigos_barras`).
- `codigos_validos` continua presente (compat retroativa).
- `codigosBarras` pode ser `{}` se o produto não tiver nenhum código cadastrado (campo nem tabela).

### O que o Dev Frontend precisa fazer (task de frontend)

Conforme §5 do techplan:

1. **`separacao/item.js` — `buildCodeMap`:** guard `Object.keys(item.codigosBarras).length > 0` (paridade com carregamento); popular `_codigosSet`.
2. **`separacao/item.js` — `processarScan` item-selecionado:** trocar `ajustarQuantidade(1,...)` por `ajustarQuantidade(qDoMapa, ...)`.
3. **`separacao/item.js` — ramo "sem código":** com `validarCodigo` ligado, bloquear (AC6.3).
4. **`carregamento/item.js` — `config.validarCodigo`:** mudar default `false → true` (AC6.2).
5. **`carregamento/item.js` — `processarScan` item-selecionado:** trocar `ajustarQuantidade(1,...)` por `ajustarQuantidade(qDoMapa, ...)`.
6. **Extrato (ambos):** adicionar `fator: ultimoDelta` ao payload enviado ao backend (auditoria AC3.2 — o backend de lote lê `quantidade_delta` que já é o fator, mas `fator` explícito melhora auditoria).

### Comportamento do backend após esta task

- `biparItem` com código de fator 10 em item com pedido >= 10 → resposta de sucesso com `quantidade_bipada += 10`, 1 extrato com `delta=10, fator=10`.
- `biparItem` com código de fator 10 em item com pedido 7 → resposta de erro "Quantidade excedida! Limite: 7", nada gravado.
- `adicionarQuantidade` / `reduzirQuantidade` (botões +/-) → delta ±1, `fator=1` no extrato, `tipo_codigo_barras=null` — sem regressão.
- Produto sem registro na Sonda → fator 1.0 (AC2.2), comportamento atual preservado.

## Próximos passos para o Tester

- Rodar `FatorBipagemIntegrationTest.php` (a criar, conforme §plano de teste) contra `dev_gx_goldie`.
- Smoke manual: separação com caixa fator 10 (≥10 pedido → soma; 7 pedido → bloqueado).
- Não-regressão: produto sem `produtos_codigos_barras` → bipar código do produto soma 1.
- Verificar payload do extrato no banco: `fator` e `tipo_codigo_barras` devem aparecer no JSONB.
