# Cota mínima de bipagem — Spec

## Contexto e problema

Na execução de missões logísticas (separação e carregamento, sinal `App`), o operador pode concluir cada item por **bipagem** (scanner) ou **manualmente** (botões +/−). Como o manual está sempre disponível, muitos operadores digitam tudo e nunca adotam o leitor de código de barras — o que enfraquece a rastreabilidade e a confiança no estoque. A dor recai sobre o gestor (quer adoção do scanner e dados confiáveis) e sobre o operador (precisa criar o hábito). A feature obriga que uma **fração mínima dos itens da missão seja concluída 100% por scanner**, empurrando o operador ao código de barras de forma gradual e configurável.

## Escopo

- ✅ Faz parte:
  - Regra de **cota mínima de itens bipados** por missão, calculada sobre SKUs com código bipável (mecânica detalhada em "Regras de negócio").
  - Configuração **por empresa (tenant)**: master on/off, percentual obrigatório e toggles independentes para separação e carregamento.
  - **Congelamento (snapshot)** da política na criação da missão, junto do snapshot de códigos de barras — mudar a política não afeta missões já geradas.
  - **Enforcement em tempo real no front**: bloquear os botões +/− nos itens bipáveis ainda limpos quando a cota de manuais zera; avisar antes de gastar a última unidade da cota.
  - **Backstop no servidor**: recusar finalizar a missão quando a quantidade de itens qualificados (100% por scanner) for menor que a meta; registrar a violação.
  - Aplicação nos dois fluxos: **separação e carregamento**, cada um com seu toggle.
  - **i18n nas 3 línguas** (`pt-br`, `en`, `es`) para todas as strings novas desta feature.
- ❌ Fora de escopo:
  - **Fluxo de retorno** (não valida código hoje; permanece sem cota).
  - **Pesagem / itens por KG**: itens concluídos por peso não contam para a cota e ficam fora do denominador.
  - **Contagem por unidades**: o percentual é sempre sobre SKUs (linhas de item), nunca sobre soma de quantidades.
  - **Recuperação de item já manchado**: um toque manual mancha o item permanentemente; não há como "limpar" e devolvê-lo à condição de elegível para a meta.
  - **Tela de admin sofisticada**: basta a configuração por empresa.
  - Itens **sem código bipável** e itens **já manchados** continuam aceitando manual normalmente (não são afetados pela cota).
  - Alterar o débito conhecido de i18n das mensagens de bipagem **já existentes** (só as strings novas nascem internacionalizadas).

## User stories

### US1 — Adoção do scanner via cota mínima
**Como** gestor da empresa **eu quero** exigir que uma fração mínima dos itens de cada missão seja concluída 100% por scanner **para** acostumar os operadores ao código de barras e melhorar a rastreabilidade.

**Critérios de aceite:**
- AC1.1: Com a regra ativa, percentual de 10% e missão com N=25 SKUs bipáveis, a meta exigida é 3 itens 100% por scanner (`ceil(0,10 × 25) = 3`).
- AC1.2: Com `pct = 0`, ou N = 0 (nenhum SKU bipável), ou regra desativada, a cota é desligada e a missão se comporta como hoje (manual sempre liberado).
- AC1.3: A meta calculada nunca é maior que N (se `ceil` resultasse acima de N, é limitada a N).
- AC1.4: Itens sem código bipável e itens de pesagem (KG) não entram no denominador N e não contam para a meta.

### US2 — Bloqueio do manual ao estourar a cota (tempo real)
**Como** operador de separação/carregamento **eu quero** ser impedido de concluir tudo no manual quando a cota de manuais acaba **para** ser obrigado a bipar os itens restantes da meta.

**Critérios de aceite:**
- AC2.1: A cota de manuais inicial é `N − meta`; cada item bipável ainda limpo que recebe sua **primeira** entrada manual consome 1 da cota.
- AC2.2: Com a cota zerada, os botões +/− ficam **desabilitados** nos itens bipáveis ainda limpos; esses itens só avançam por scanner.
- AC2.3: Itens já manchados (que já receberam manual) continuam aceitando +/− mesmo com a cota zerada.
- AC2.4: Itens sem código bipável continuam aceitando +/− mesmo com a cota zerada.
- AC2.5: O bloqueio é mission-wide: consumir cota num item afeta a disponibilidade do manual nos demais itens limpos da mesma missão.
- AC2.6: O estado de cota e de itens manchados é reconstruído corretamente após refresh da página (não reinicia a cota nem perde o registro de itens já manchados).

### US3 — Aviso antes de gastar a última unidade da cota
**Como** operador **eu quero** ser avisado antes de consumir a última unidade da cota de manuais **para** entender que, a partir dali, serei obrigado a bipar o restante.

**Critérios de aceite:**
- AC3.1: Ao tentar a entrada manual que zeraria a cota (manchar o último item permitido), um modal/aviso é exibido explicando que os itens limpos restantes só poderão ser concluídos por scanner.
- AC3.2: O operador pode confirmar (gasta a última unidade) ou cancelar (não mancha o item, cota preservada).
- AC3.3: O aviso só aparece quando a regra está ativa e a próxima entrada manual de fato zeraria a cota — não em todo toque manual.

### US4 — Backstop server-side na finalização
**Como** gestor **eu quero** que a finalização da missão seja recusada quando a meta de itens bipados não foi atingida **para** garantir a regra mesmo se o operador burlar o front (refresh, devtools).

**Critérios de aceite:**
- AC4.1: Na finalização, o servidor recomputa a quantidade de itens qualificados (item 100% por scanner) e compara com `meta_itens` do snapshot da missão.
- AC4.2: Se `qualificados < meta_itens`, a finalização é **recusada** e o operador recebe mensagem indicando quantos itens ainda precisam ser concluídos por scanner.
- AC4.3: A definição de "item 100% por scanner" usada no backstop é autoritativa: o item conta como qualificado somente quando toda a quantidade foi concluída por leitura **e** não houve nenhuma entrada manual.
- AC4.4: A violação (tentativa de finalizar abaixo da meta) é **registrada**.
- AC4.5: Missões cujo snapshot tem cota desligada (regra inativa na criação, `pct=0` ou N=0) finalizam normalmente, sem checagem extra.

### US5 — Configuração da regra por empresa
**Como** gestor da empresa **eu quero** ligar/desligar a regra e definir o percentual obrigatório por empresa, com toggles separados para separação e carregamento **para** controlar o rollout de forma gradual.

**Critérios de aceite:**
- AC5.1: A configuração tem master on/off (`ativo`), percentual (`pct`) e dois toggles de fluxo independentes (`ativo_separacao`, `ativo_carregamento`).
- AC5.2: O default de fábrica é **desligado** (compatibilidade retroativa); empresas sem configuração explícita não sofrem nenhuma mudança de comportamento.
- AC5.3: A configuração é isolada por empresa (tenant) — alterar numa empresa não afeta outra.
- AC5.4: Com a regra ativa só em separação, missões de carregamento não aplicam a cota (e vice-versa).

### US6 — Snapshot da política na criação da missão
**Como** gestor **eu quero** que cada missão congele a política vigente no momento da criação **para** que mudanças posteriores na configuração não alterem missões já geradas.

**Critérios de aceite:**
- AC6.1: Na criação da missão, com a regra aplicável ao fluxo, são congelados na missão: percentual, denominador N, meta de itens e cota de manuais.
- AC6.2: Alterar a configuração da empresa **não** altera os valores congelados de missões já criadas.
- AC6.3: O denominador N congelado reflete os SKUs bipáveis daquela missão específica no momento da criação.
- AC6.4: Front (tempo real) e backstop (servidor) usam os mesmos valores congelados na missão como fonte da verdade.

## Personas envolvidas

| Persona | Papel | Ponto de contato com a feature |
|---|---|---|
| Operador de separação | Executor (picking) | Bipa/conta itens na execução; sofre o bloqueio do manual e o aviso de última cota |
| Operador de carregamento | Executor (loading) | Bipa/conta itens na execução; mesmo bloqueio e aviso da separação |
| Gestor / administrador da empresa | Decisor / configurador | Liga/desliga a regra, define o percentual e os toggles por fluxo; vê missões recusadas |
| Auditor / gestor logístico | Acompanhamento | Acompanha violações registradas e a evolução da adoção do scanner |

## Dados / entidades-chave (alto nível)

- **Missão logística**: a unidade de trabalho onde a cota é calculada e aplicada; carrega o snapshot congelado da política.
- **Item da missão (SKU/linha)**: a unidade contada para a cota; tem quantidade pedida, quantidade concluída por scanner e quantidade concluída manualmente; pode ter ou não código bipável.
- **Configuração da regra por empresa**: o conjunto `ativo`, `pct`, `ativo_separacao`, `ativo_carregamento`, isolado por tenant.
- **Snapshot da cota na missão**: os valores congelados na criação — percentual, denominador N, meta de itens e cota de manuais.
- **Extrato de execução**: o histórico append-only de ações (scan vs. manual) usado para reconstruir o estado e auditar; fonte para o backstop derivar os itens qualificados.
- **Registro de violação**: o evento gravado quando se tenta finalizar abaixo da meta.

## Regras de negócio

1. **Denominador N** = nº de SKUs da missão com código bipável no snapshot de códigos. Itens sem código e itens de pesagem (KG) ficam fora de N.
2. **Meta** = `ceil(pct/100 × N)` itens que precisam ser concluídos 100% por scanner. A meta nunca excede N.
3. **Cota de manuais** = `N − meta` = quantos itens bipáveis podem receber entrada manual.
4. **Consumo de cota:** cada item bipável ainda limpo que recebe sua primeira entrada manual consome 1 da cota. A partir do 1º toque manual, o item está "manchado" e não consome cota novamente.
5. **Bloqueio do manual:** com a cota zerada, os botões +/− ficam desabilitados nos itens bipáveis ainda limpos; itens já manchados e itens sem código continuam aceitando manual.
6. **Item 100% por scanner (autoritativo, server-side):** o item qualifica para a meta somente quando toda a quantidade foi concluída por leitura **e** não houve nenhuma entrada manual.
7. **Manchamento permanente:** uma vez que o item recebeu manual, ele não pode voltar a ser elegível para a meta — não há recuperação.
8. **Desligamento:** se `ativo = false` no fluxo aplicável, `pct = 0` ou `N = 0`, a regra fica desligada e não há cota nem bloqueio nem backstop.
9. **Snapshot imutável:** a política é congelada na criação da missão; mudanças posteriores na config da empresa só valem para missões geradas depois.
10. **Por fluxo:** separação e carregamento têm toggles independentes; a cota só vale no fluxo habilitado.
11. **Multi-tenant:** a configuração e a aplicação são isoladas por empresa.
12. **Defesa em 2 camadas:** o front bloqueia em tempo real (UX); o servidor é a autoridade final, recomputa na finalização e recusa+registra violação se a meta não foi atingida.

## Métricas de sucesso

- Em missões com a regra ativa, a fração de itens concluídos 100% por scanner atinge ou supera o percentual configurado, de forma consistente.
- Crescimento da adoção do scanner ao longo do rollout (mais leituras de código vs. entradas manuais por missão).
- Zero regressão em empresas com a regra desligada (default): comportamento idêntico ao atual.
- Backstop efetivo: tentativas de finalizar abaixo da meta são recusadas e registradas (taxa de violações tende a cair conforme operadores se adaptam).
- Bloqueios e avisos de cota não geram missões travadas sem saída (sempre há caminho via scanner para concluir).

## Dúvidas em aberto

- [ ] **Onde mora a Sonda de config por empresa** — nova Sonda dedicada vs. estender algo existente em `MissaoLogistica`. (TL)
- [ ] **Estado da migration dos counters** `quantidade_bipada_scan` / `quantidade_bipada_manual` — aplicada ou débito a criar? Sem eles, o backstop precisa derivar do extrato. (TL)
- [ ] **Forma de o front receber a cota** — via Presenter junto do snapshot de códigos → `data-*` nos componentes de execução. (TL)
- [ ] **Estado mission-wide de itens manchados no front** — derivar dos counters por item já renderizados vs. store local; estratégia de reconciliação após refresh. (TL)
- [ ] **Textos exatos** do modal de aviso da última cota e da mensagem de bloqueio do manual (e da recusa de finalização) — conteúdo de UX a definir nas 3 línguas.
