<!--
ARQUIVO-FATO (constituição, Duas fontes da verdade) — o manifesto de remessa: a consulta e o fechamento à mão.
Publicado cru em https://docs.xadm.biz/aplicacoes/integrador-server/raw/integracao-remessa.md.
Outros repos IMPORTAM este arquivo no build (curl -f → docs/_importado/) e o embutem — não o
copiam. O maxsul-pied tira daqui as fixtures da reconciliação por remessa.

Fragmento: sem frontmatter, headings a partir de ### (entra sob um ## da página
hospedeira; o --8<-- não rebaixa nível). Editar aqui muda o contrato para todos
os consumidores no próximo build DELES — os fatos abaixo saem do código deste
repo (RemessaController, RemessaResponse, ResolverManualRequest, ResolverManualResponse,
IntegracaoRemessa), nunca de memória.
-->

### Consultar remessas

```
GET /api/v1/integracao/remessas?origem=<origem>[&chave=<chave>]...[&status=<status>]
```

Fora do namespace `/xadm` de propósito: remessa é dado de controle do Integrador, não espelho do
ERP. Toda rota `/api/**` exige `Authorization: Bearer <token>`; sem ele, `401`.

| parâmetro | efeito |
|---|---|
| `origem` | obrigatória — hoje só `INT-PIED` tem manifesto |
| `chave` | `pied_x_ped` do pedido ou `cgc_cpf` do cliente. **Aceita repetição** (`&chave=A&chave=B`) — uma chamada por rodada, não uma por pedido |
| `status` | filtra por `ABERTA`, `ENTREGUE`, `TRAVADA` ou `RESOLVIDA_MANUAL` |

**Chave inexistente não é `404`**: é `200` com lista vazia. Quem consome decide pelo conteúdo.

```json
[
  { "id": "0199…", "chaveNegocio": "260079421", "status": "TRAVADA", "totalItens": 5,
    "criadoEm": "2026-09-08T14:02:11Z",
    "itensRejeitados": [
      { "tabela": "propriedades", "linhaId": "0199…", "codRetorno": "120",
        "msgRetorno": "Cliente CPF 072.508.149-07 não cadastrado.", "bloqueado": false },
      { "tabela": "contratos", "linhaId": "0199…", "codRetorno": "120",
        "msgRetorno": "Pedido (10738.24) não cadastrado.", "bloqueado": true } ] },
  { "id": "0199…", "chaveNegocio": "260081234", "status": "RESOLVIDA_MANUAL", "totalItens": 4,
    "criadoEm": "2026-09-09T10:40:02Z", "itensRejeitados": [],
    "resolucaoManual": { "em": "2026-09-10T16:20:00Z",
      "observacao": "Lançado manualmente no X-Adm: kit sem produto cadastrado.",
      "operador": "fulano@maxsul.com.br" } }
]
```

| campo | valor |
|---|---|
| `id` | id da remessa |
| `chaveNegocio` | `pied_x_ped` ou `cgc_cpf` |
| `status` | ver a tabela de estados abaixo |
| `totalItens` | quantos itens a remessa **declara** — a coluna, não um `COUNT(*)`; é o que detecta lista rasgada |
| `criadoEm` | quando a remessa nasceu |
| `itensRejeitados` | os itens em `1XX`, **só nas `TRAVADA`**. Nas demais vem `[]` — **nunca ausente** |
| `resolucaoManual` | **só nas `RESOLVIDA_MANUAL`**: `em`, `observacao` e `operador` (este some quando não foi informado). Nas demais, o campo some |

Em cada item rejeitado vêm `tabela`, `linhaId`, `codRetorno`, `msgRetorno` e `bloqueado`. O
**`bloqueado` separa a causa do colateral**: `true` quer dizer que um pai desta linha, na mesma
remessa, também está em `1XX`. **Quem reporta ao operador nomeia a mensagem do item não
bloqueado**. No exemplo, a causa é o cliente; o "Pedido não cadastrado" é consequência.

### Os estados

| `status` | significa | viva? |
|---|---|---|
| `ABERTA` | ainda não entregue, sem rejeição terminal | sim |
| `TRAVADA` | alguma linha em `1XX`; só o re-arme a reabre | sim |
| `ENTREGUE` | todas as linhas aceitas (`006`) — histórico | não |
| `RESOLVIDA_MANUAL` | o operador lançou o pedido à mão no X-Adm e fechou a remessa por comando — histórico | não |

**Uma remessa viva por `(origem, chave)`**: é invariante de banco. As não vivas acumulam. Os três
primeiros estados são **derivados** dos `cod_retorno`. `RESOLVIDA_MANUAL` é o único que **nasce de
comando** e que a derivação nunca reabre.

Um consumidor que encontre um status que não conhece deve tratá-lo como **não travado e não
enviável**. É o que mantém a adição de um estado não quebrante.

### Fechar à mão uma remessa travada

```
POST /api/v1/integracao/remessas/resolver-manual?origem=INT-PIED&chave=<xPed>
Content-Type: application/json

{ "observacao": "Lançado manualmente no X-Adm: kit sem produto cadastrado.",
  "operador": "fulano@maxsul.com.br" }
```

Serve para o pedido que **não se resolve reenviando** (ex.: o produto-kit que o ERP não criou) e que o
operador lançou direto no X-Adm. Sem isto, a remessa seguiria `TRAVADA` para sempre. Quem chama é o
botão **"Importado manualmente"** do painel do maxsul-pied.

| corpo | regra |
|---|---|
| `observacao` | **obrigatória**, até 2000 caracteres — é o que sobra para reconstruir o caso |
| `operador` | opcional, até 100 caracteres. O Bearer é estático e não identifica pessoa |

```json
{ "chave": "260079421", "resolvidas": 1 }
```

| HTTP | quando |
|---|---|
| `200` | fechou (`resolvidas: 1`), **ou** não havia remessa viva (`resolvidas: 0`: nunca existiu, já entregue ou já resolvida) |
| `400` | `origem` ausente ou diferente de `INT-PIED`; `chave` ausente; `observacao` ausente, branca ou longa demais; `operador` longo demais |
| `401` | Bearer ausente ou inválido |
| `409` | a remessa viva está `ABERTA` (ainda em entrega), está `TRAVADA` **com linha ainda pendente** (`000`/`001`/`9XX`), ou mudou de estado durante o comando — consulte e tente de novo |

**Só `TRAVADA`.** Fechar uma `ABERTA` enquanto o cliente pode estar mandando as linhas arrisca
duplicar no ERP.

**E sem linha pendente.** Numa `TRAVADA` o filho de um pai `1XX` fica `000`, bloqueado. Fechar a
remessa a tira do manifesto, e o cliente passaria a mandar esse filho por presença — duplicando no
ERP o que o operador lançou à mão. Nesse caso o caminho é corrigir o dado e re-armar.

**Não mexe nas linhas.** As `1XX` continuam `1XX` e o cliente não as coleta. Muda só a remessa.

**Idempotente:** a segunda chamada devolve `resolvidas: 0`, porque a remessa já não está viva.

**Depois dele, o re-arme da chave responde `409`.** Re-armar reenviaria ao ERP o que o operador já
lançou. E se a chave ganhar uma remessa viva nova, o re-arme dela não reabre as linhas de pedido
(`contratos`/`itensped`/`formulas`) que também são itens da resolvida.
