# API para voltar o status da comanda para consumo após abortar operação.

# 📌 API – Cancelar Faturamento de Comandas

**Endpoint:**  
`POST /api/v1/mesas-comandas/cancelar-faturamento`

---

## 🎯 Para que serve

Esta API é usada quando o PDV **iniciou o faturamento** de uma ou mais comandas (elas ficaram em **`conferencia`**) mas **o atendimento NÃO foi concluído**.

Ao chamar esta API, o Servidor de Comandas:

- remove a trava de faturamento;
- altera o status da comanda de **`conferencia` → `consumo`**;
- registra auditoria do cancelamento.

✅ Use quando:

- o operador cancelou a venda no PDV;
- houve erro antes de concluir o atendimento (ex.: falha de cadastro de item);
- o cliente desistiu antes de finalizar.

🚫 Não use quando:

- a venda foi concluída e você quer liberar a comanda para novo cliente → use **`confirmar-faturamento`**.

---

## 🔁 Onde entra no fluxo do PDV

Fluxo típico:

1. PDV chama **`iniciar-faturamento`** → recebe `comandasParaFaturar` (essas entram em `conferencia`)
2. PDV tenta concluir a venda (pagamento/emissão fiscal são do PDV)
3. Se desistiu/cancelou → chama **`cancelar-faturamento`** enviando **somente as mesas que entraram em conferência**

> ⚠️ Boa prática obrigatória:  
> Envie para `cancelar-faturamento` **somente** as comandas que retornaram em `comandasParaFaturar` no `iniciar-faturamento`.

---

## 🔐 Autenticação

Segue o padrão de autenticação do Servidor de Comandas (definido pelo projeto).

> Se houver falha, o servidor retornará HTTP 401/403.

---

## 📥 Request

### Body (JSON)

<div class="TyagGW_tableContainer" id="bkmrk-campo-tipo-obrigat%C3%B3r"><div class="group TyagGW_tableWrapper flex flex-col-reverse w-fit" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="2056" data-start="1774"><thead data-end="1816" data-start="1774"><tr data-end="1816" data-start="1774"><th data-col-size="sm" data-end="1782" data-start="1774">Campo</th><th data-col-size="sm" data-end="1789" data-start="1782">Tipo</th><th data-col-size="sm" data-end="1803" data-start="1789">Obrigatório</th><th data-col-size="sm" data-end="1816" data-start="1803">Descrição</th></tr></thead><tbody data-end="2056" data-start="1836"><tr data-end="1910" data-start="1836"><td data-col-size="sm" data-end="1852" data-start="1836">`numeroMesas`</td><td data-col-size="sm" data-end="1865" data-start="1852">`number[]`</td><td data-col-size="sm" data-end="1869" data-start="1865">✅</td><td data-col-size="sm" data-end="1910" data-start="1869">IDs das comandas a cancelar (em lote)</td></tr><tr data-end="1983" data-start="1911"><td data-col-size="sm" data-end="1925" data-start="1911">`numeroPdv`</td><td data-col-size="sm" data-end="1936" data-start="1925">`string`</td><td data-col-size="sm" data-end="1940" data-start="1936">✅</td><td data-col-size="sm" data-end="1983" data-start="1940">Número/identificação do PDV solicitante</td></tr><tr data-end="2056" data-start="1984"><td data-col-size="sm" data-end="2000" data-start="1984">`operador_id`</td><td data-col-size="sm" data-end="2011" data-start="2000">`string`</td><td data-col-size="sm" data-end="2015" data-start="2011">✅</td><td data-col-size="sm" data-end="2056" data-start="2015">Identificação do operador solicitante</td></tr></tbody></table>

</div></div>### Exemplo

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk--4"><div class="sticky top-[calc(--spacing(9)+var(--header-height))] @w-xl/main:top-9"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">  
</div></div>```json
{
  "numeroMesas": [4069, 4070, 4075],
  "numeroPdv": "12",
  "operador_id": "1275"
}

```

---

## ✅ O que o servidor faz (regras por comanda)

O servidor avalia **cada idMesa individualmente** e pode cancelar algumas e bloquear outras (retorno parcial).

### Quando a comanda é cancelada com sucesso

- Se `status = conferencia` **e** (se existir) `numeroPdvEmConferencia == numeroPdv` do request  
    → servidor altera status para `consumo` e retorna em `comandasCanceladasParaFaturar`.

### Quando a comanda é bloqueada

A comanda entra em `comandasBloqueadasParaCancelar` nos casos:

<div class="TyagGW_tableContainer" id="bkmrk-situa%C3%A7%C3%A3o-motivo-camp"><div class="group TyagGW_tableWrapper flex flex-col-reverse w-fit" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="3145" data-start="2660"><thead data-end="2695" data-start="2660"><tr data-end="2695" data-start="2660"><th data-col-size="md" data-end="2671" data-start="2660">Situação</th><th data-col-size="sm" data-end="2680" data-start="2671">Motivo</th><th data-col-size="sm" data-end="2695" data-start="2680">Campo extra</th></tr></thead><tbody data-end="3145" data-start="2710"><tr data-end="2755" data-start="2710"><td data-col-size="md" data-end="2731" data-start="2710">Comanda não existe</td><td data-col-size="sm" data-end="2750" data-start="2731">`NAO_ENCONTRADA`</td><td data-col-size="sm" data-end="2755" data-start="2750">—</td></tr><tr data-end="2852" data-start="2756"><td data-col-size="md" data-end="2795" data-start="2756">`status = conferencia` por outro PDV</td><td data-col-size="sm" data-end="2824" data-start="2795">`EM_CONFERENCIA_OUTRO_PDV`</td><td data-col-size="sm" data-end="2852" data-start="2824">`numeroPdvEmConferencia`</td></tr><tr data-end="2907" data-start="2853"><td data-col-size="md" data-end="2874" data-start="2853">`status = consumo`</td><td data-col-size="sm" data-end="2902" data-start="2874">`NAO_ESTA_EM_CONFERENCIA`</td><td data-col-size="sm" data-end="2907" data-start="2902">—</td></tr><tr data-end="2949" data-start="2908"><td data-col-size="md" data-end="2927" data-start="2908">`status = livre`</td><td data-col-size="sm" data-end="2944" data-start="2927">`STATUS_LIVRE`</td><td data-col-size="sm" data-end="2949" data-start="2944">—</td></tr><tr data-end="3003" data-start="2950"><td data-col-size="md" data-end="2977" data-start="2950">`status = transferencia`</td><td data-col-size="sm" data-end="2998" data-start="2977">`EM_TRANSFERENCIA`</td><td data-col-size="sm" data-end="3003" data-start="2998">—</td></tr><tr data-end="3095" data-start="3004"><td data-col-size="md" data-end="3053" data-start="3004">`status = consumo` com lançamento em andamento</td><td data-col-size="sm" data-end="3077" data-start="3053">`EM_LANCAMENTO_ITENS`</td><td data-col-size="sm" data-end="3095" data-start="3077">`pos_lancando`</td></tr><tr data-end="3145" data-start="3096"><td data-col-size="md" data-end="3120" data-start="3096">qualquer outro status</td><td data-col-size="sm" data-end="3140" data-start="3120">`STATUS_INVALIDO`</td><td data-col-size="sm" data-end="3145" data-start="3140">—</td></tr></tbody></table>

</div></div>---

## 📤 Response

### ✅ 200 – Cancelamento total ou parcial

Retorna **200** quando **pelo menos 1 comanda** foi cancelada com sucesso.

#### Estrutura

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk--7"><div class="sticky top-[calc(--spacing(9)+var(--header-height))] @w-xl/main:top-9"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">  
</div></div>```json
{
  "comandasCanceladasParaFaturar": [],
  "comandasBloqueadasParaCancelar": []
}

```

---

### `comandasCanceladasParaFaturar[]` (sucesso)

Lista de comandas que foram efetivamente destravadas:

<div class="TyagGW_tableContainer" id="bkmrk-campo-descri%C3%A7%C3%A3o-idme"><div class="group TyagGW_tableWrapper flex flex-col-reverse w-fit" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="3708" data-start="3504"><thead data-end="3525" data-start="3504"><tr data-end="3525" data-start="3504"><th data-col-size="sm" data-end="3512" data-start="3504">Campo</th><th data-col-size="sm" data-end="3525" data-start="3512">Descrição</th></tr></thead><tbody data-end="3708" data-start="3536"><tr data-end="3564" data-start="3536"><td data-col-size="sm" data-end="3547" data-start="3536">`idMesa`</td><td data-col-size="sm" data-end="3564" data-start="3547">ID da comanda</td></tr><tr data-end="3618" data-start="3565"><td data-col-size="sm" data-end="3583" data-start="3565">`codigoComanda`</td><td data-col-size="sm" data-end="3618" data-start="3583">Código/identificador da comanda</td></tr><tr data-end="3664" data-start="3619"><td data-col-size="sm" data-end="3642" data-start="3619">`statusAlteradoPara`</td><td data-col-size="sm" data-end="3664" data-start="3642">Sempre `"consumo"`</td></tr><tr data-end="3708" data-start="3665"><td data-col-size="sm" data-end="3678" data-start="3665">`mensagem`</td><td data-col-size="sm" data-end="3708" data-start="3678">Mensagem para exibição/log</td></tr></tbody></table>

</div></div>---

### `comandasBloqueadasParaCancelar[]` (bloqueios)

Lista de comandas que não puderam ser canceladas:

<div class="TyagGW_tableContainer" id="bkmrk-campo-descri%C3%A7%C3%A3o-idme-1"><div class="group TyagGW_tableWrapper flex flex-col-reverse w-fit" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="4202" data-start="3817"><thead data-end="3838" data-start="3817"><tr data-end="3838" data-start="3817"><th data-col-size="sm" data-end="3825" data-start="3817">Campo</th><th data-col-size="sm" data-end="3838" data-start="3825">Descrição</th></tr></thead><tbody data-end="4202" data-start="3849"><tr data-end="3894" data-start="3849"><td data-col-size="sm" data-end="3860" data-start="3849">`idMesa`</td><td data-col-size="sm" data-end="3894" data-start="3860">ID da comanda (quando existir)</td></tr><tr data-end="3951" data-start="3895"><td data-col-size="sm" data-end="3913" data-start="3895">`codigoComanda`</td><td data-col-size="sm" data-end="3951" data-start="3913">Código da comanda (quando existir)</td></tr><tr data-end="4001" data-start="3952"><td data-col-size="sm" data-end="3968" data-start="3952">`statusAtual`</td><td data-col-size="sm" data-end="4001" data-start="3968">Status atual (quando existir)</td></tr><tr data-end="4035" data-start="4002"><td data-col-size="sm" data-end="4013" data-start="4002">`motivo`</td><td data-col-size="sm" data-end="4035" data-start="4013">Código do bloqueio</td></tr><tr data-end="4073" data-start="4036"><td data-col-size="sm" data-end="4049" data-start="4036">`mensagem`</td><td data-col-size="sm" data-end="4073" data-start="4049">Mensagem explicativa</td></tr><tr data-end="4145" data-start="4074"><td data-col-size="sm" data-end="4101" data-start="4074">`numeroPdvEmConferencia`</td><td data-col-size="sm" data-end="4145" data-start="4101">Apenas quando `EM_CONFERENCIA_OUTRO_PDV`</td></tr><tr data-end="4202" data-start="4146"><td data-col-size="sm" data-end="4163" data-start="4146">`pos_lancando`</td><td data-col-size="sm" data-end="4202" data-start="4163">Apenas quando `EM_LANCAMENTO_ITENS`</td></tr></tbody></table>

</div></div>---

## ✅ Exemplo — 200 (cancelamento completo)

```json
{
  "comandasCanceladasParaFaturar": [
    {
      "idMesa": 4069,
      "codigoComanda": "21",
      "statusAlteradoPara": "consumo",
      "mensagem": "Faturamento cancelado com sucesso. Comanda retornou para consumo."
    },
    {
      "idMesa": 4070,
      "codigoComanda": "22",
      "statusAlteradoPara": "consumo",
      "mensagem": "Faturamento cancelado com sucesso. Comanda retornou para consumo."
    }
  ],
  "comandasBloqueadasParaCancelar": []
}

```

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk--11"><div class="sticky top-[calc(--spacing(9)+var(--header-height))] @w-xl/main:top-9"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div></div>---

## ✅ Exemplo — 200 (parcial)

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk--13"><div class="sticky top-[calc(--spacing(9)+var(--header-height))] @w-xl/main:top-9"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">  
</div></div>```json
{
  "comandasCanceladasParaFaturar": [
    {
      "idMesa": 4069,
      "codigoComanda": "21",
      "statusAlteradoPara": "consumo",
      "mensagem": "Faturamento cancelado com sucesso. Comanda retornou para consumo."
    }
  ],
  "comandasBloqueadasParaCancelar": [
    {
      "idMesa": 4070,
      "codigoComanda": "22",
      "statusAtual": "conferencia",
      "motivo": "EM_CONFERENCIA_OUTRO_PDV",
      "numeroPdvEmConferencia": "15",
      "mensagem": "Comanda está em conferência por outro PDV."
    },
    {
      "idMesa": 4072,
      "codigoComanda": "24",
      "statusAtual": "transferencia",
      "motivo": "EM_TRANSFERENCIA",
      "mensagem": "Comanda está em transferência de itens e não pode ser cancelada."
    }
  ]
}

```

---

## 200 — nenhuma comanda cancelável

Retorna erro quando **0 comandas** puderam ser canceladas.

### Exemplo — 200

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk--15"><div class="sticky top-[calc(--spacing(9)+var(--header-height))] @w-xl/main:top-9"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">  
</div></div>```json
{
  "comandasCanceladasParaFaturar": [],
  "comandasBloqueadasParaCancelar": [
    {
      "idMesa": 4070,
      "codigoComanda": "22",
      "statusAtual": "livre",
      "motivo": "STATUS_LIVRE",
      "mensagem": "Comanda está livre e não possui faturamento para cancelar."
    },
    {
      "idMesa": 4073,
      "codigoComanda": "26",
      "statusAtual": "consumo",
      "motivo": "NAO_ESTA_EM_CONFERENCIA",
      "mensagem": "Comanda não está em conferência."
    },
    {
      "codigoComanda": "9999",
      "motivo": "NAO_ENCONTRADA",
      "mensagem": "Comanda não encontrada."
    }
  ]
}

```

---

## 🧾 Enum `motivo` (mínimo)

- `NAO_ENCONTRADA`
- `NAO_ESTA_EM_CONFERENCIA`
- `STATUS_LIVRE`
- `EM_TRANSFERENCIA`
- `EM_LANCAMENTO_ITENS`
- `EM_CONFERENCIA_OUTRO_PDV`
- `STATUS_INVALIDO`

---

## ✅ Boas práticas para integradores (PDV)

- Sempre trate **retorno parcial**.
- Envie apenas as comandas que você recebeu em `comandasParaFaturar` no `iniciar-faturamento`.
- Se vier `EM_CONFERENCIA_OUTRO_PDV`, isso é **tratativa gerencial/manual** (não tente “resolver” pelo PDV).
- Após cancelar, o PDV deve:
    
    
    - limpar o contexto da venda local;
    - permitir que a comanda seja faturada novamente.