# Documentação técnica — PDV (Ponto de Venda)

Este documento descreve a tela **`/PDV`**, os componentes **Livewire** (`PdvComponent`, `PagamentoComponent`, `PdvMenuCaixaComponent`), o serviço **`PdvNfService`** (gravação no ERP como NF de venda), o **caixa** (`caixas`, `caixa_movimentos`), cancelamento de itens e tabelas **`pdv_*`**. A forma de pagamento habilitada no PDV está em **`Doc_Modulo_Financeiro.md`** (§ 2.4.2). Produtos usam **`ProdutoServico`** (**`Doc_Modulo_Produto_Servico.md`**).

---

## 1. Rotas e acesso

| Rota | Middleware | Função |
|------|------------|--------|
| `GET /PDV` | `auth`, `single.session` | View `admin.pdv.create` — monta **`livewire:pdv-component`**. Nome da rota: **`pdv.create`**. |
| `POST /PDV/store` | (sem grupo admin explícito no trecho analisado) | Closure com **`dd($request->all())`** — **não** integrada ao fluxo Livewire; provável resquício de teste. |

O PDV **não** apareceu no trecho pesquisado do `sidebar`; o operador acessa pela URL ou link customizado.

---

## 2. Estrutura da página

- **Layout:** `resources/views/admin/pdv/layout.blade.php` (estendido por `admin/pdv/create.blade.php`).
- **Componente principal:** **`PdvComponent`** (`livewire.pdv-component`) — carrinho, busca de produto, teclas de atalho (via JS que dispara eventos Livewire), cliente/CPF, desconto total.
- **Pagamento:** **`PagamentoComponent`** — modal com formas **`FormaPagamento::habilitadoPdv()`** (`pdv = 'S'`), múltiplos lançamentos, troco, observações.
- **Menu caixa (F10):** **`PdvMenuCaixaComponent`** — abertura/fechamento de caixa, sangria/suprimento, resumo.

Comunicação: `PdvComponent` dispara **`abrirPagamento`** para `PagamentoComponent::class`; ao confirmar, **`PagamentoComponent`** dispara **`confirmarPagamento`** com payload (total, pagamentos com `idformapagamento`, troco, observações). O listener em **`PdvComponent`** chama **`finalizarVenda`**.

---

## 3. `PdvComponent` — fluxo de venda

### 3.1 Produtos

- Busca por **código de barras** (`ProdutoServico.codigobarras`) em **`buscarProdutoPorCodigo`**.
- **Autocomplete** ao digitar em `codproduto` (≥ 2 caracteres): query em produtos **`ativo()`** por nome `prodserv`, e por colunas **`codigo`** / **`codigobarras`** se existirem na tabela (`Schema::hasColumn`).
- **Modal F8:** lista até 80 produtos com o mesmo filtro.
- **`addProduto`:** valida quantidade e valor unitário (parse formato BR); agrega quantidade se o mesmo `idprodserv` já estiver no carrinho; recalcula total (soma dos itens − **`descontoTotal`**).

### 3.2 Itens e atalhos

- Tabela de itens com filtro local (`produtosSearchTable` → `itensFiltrados`), highlight por índice, eventos para incrementar/decrementar highlight e remover (DEL abre cancelamento com motivo).
- **`cancelarVenda`:** limpa carrinho e totais.

### 3.3 Cancelamento de item com motivo

- Modal obriga **`idmotivo_cancelamento`** (`PdvMotivoCancelamento`, `ativo = 'S'`).
- Persiste **`PdvItemCancelamento`** (usuário, produto, quantidades, valores, motivo) e remove a linha do carrinho.

### 3.4 Cliente

- Campos **`cliente`** (nome) e **`cpfcnpj`** repassados ao **`PdvNfService`** na finalização.

---

## 4. `PagamentoComponent`

- Carrega formas com **`FormaPagamento::habilitadoPdv()`**; se vazio, a view alerta para cadastrar em **Forma de pagamento** e marcar “Habilitar no PDV”.
- **`adicionarPagamento`:** exige `valorAtual` > 0 e forma selecionada; empilha `{ idformapagamento, formapagamento, valor }`.
- **`confirmarPagamento`:** exige `totalPago` > 0; envia para o pai **`confirmarPagamento`** com `pagamentos`, `troco` (**`trocoCalculado`**), `observacoes`, e total em string/número.

---

## 5. `PdvNfService::registrarVendaPdv`

Registra **uma NF de venda** sem passar pelo `VendaController` tradicional:

1. **`resolveIdEmpresa`:** `idempresa` do primeiro produto do carrinho; se falhar, **primeira** `Empresa` sem escopo global (cuidado em multi-empresa).
2. **`resolveIdPessoa`:** se CPF/CNPJ informado, busca pessoa na empresa (normalizando máscara) ou **cria** pessoa; senão, tenta **“Consumidor Final”**; senão, primeira pessoa da empresa; senão, cria “Consumidor Final”.
3. Cria **`Nf`** com **`withoutGlobalScopes`**: `tipo = C`, `saida = V`, **`status = CONCLUÍDO`**, `idformapagamento` = primeira forma dos pagamentos (ou resolvida por mapa), `descontonf` / `totalnf` / `valornf` coerentes com total e desconto, `criadopor` = usuário atual, **`idcaixa`** = caixa aberto do operador (no PDV, obrigatório antes de pagar/finalizar; o parâmetro do serviço permanece opcional para outros usos).
4. Cria **`NfItem`** por linha do carrinho (`withoutGlobalScopes`).
5. Para **cada** pagamento com valor > 0: cria **`NfParcela`** `tipo = C`, **`status = QUITADO`**, `datatransacao = now()`, `datavencimento` = hoje, `idformapagamento` resolvido por **`idformapagamento`** do payload ou por chave textual (`dinheiro`, `debito`, `credito`, `pix`, `vale`) via **`FORMA_BUSCA`** + `LIKE` em `formapagamento`, com fallback na primeira forma do banco.

**Observações:**

- Uso massivo de **`withoutGlobalScopes`** evita `TenantScope` na gravação; os dados devem ser consistentes com **`idempresa`** / tenant.
- **Parcelas quitadas** no ato **não** acionam, neste serviço, **`NfParcelaService::concluirParcela`** — **não** há movimentação automática de **`agencia.saldoatual`** aqui (diferente das telas crédito/débito documentadas no financeiro).
- **`troco`** e **`observacoes`** entram no método mas **não** foram persistidos em campos específicos no trecho analisado do serviço (apenas `observacoes` → `nf.observacao` se vier no payload do modal).

---

## 6. Caixa — `PdvMenuCaixaComponent`

- **`Caixa`:** um registro **aberto** por **`user_id`** (`status = aberto`), com `valor_abertura`, depois `data_fechamento`, `valor_fechamento`, `fechado`.
- **`CaixaMovimento`:** `tipo` **`S`** = sangria, **`P`** = suprimento; `valor`, `observacao`.
- **Vínculo com a venda:** a finalização no PDV **exige** caixa aberto; a NF recebe **`nf.idcaixa`** apontando para esse caixa (coluna nullable na tabela **`nf`** para outras origens de NF).
- **Resumo na UI:** `totalSangrias`, `totalSuprimentos`, `fundoTroco` (valor de abertura); **`totalVendido`** soma **`totalnf`** das **`Nf`** com **`idcaixa`** igual ao caixa aberto, **`tipo = C`**, **`saida = V`** e **`status`** concluído (`CONCLUÍDO` / `CONCLUIDO`).
- **Atualização em tempo real:** após venda bem-sucedida, o **`PdvComponent`** dispara **`atualizarResumoCaixa`** para **`PdvMenuCaixaComponent`** para recalcular o resumo se o modal estiver em uso.

**Regra de negócio:** não é possível abrir o **pagamento (F12)** nem **finalizar** a venda sem **caixa aberto** para o usuário logado; o sistema exibe alerta (`alertaPdv` na view) e pode abrir o **menu caixa (F10)** para abertura. O operador pode **Fechar** o aviso manualmente ou ele some ao **abrir o caixa** com sucesso (evento **`caixaPdvPronto`** do menu para o `PdvComponent`).

**Observações:** com essa regra, **`nf.idcaixa`** fica sempre preenchido nas vendas concluídas pelo PDV. A tabela **`vendas`** não é usada neste fluxo.

---

## 7. Tabelas `pdv_*`

| Tabela | Model | Uso |
|--------|--------|-----|
| **`pdv_motivo_cancelamento`** | `PdvMotivoCancelamento` | Motivos ativos (`ativo = 'S'`); seed em migration. |
| **`pdv_item_cancelamento`** | `PdvItemCancelamento` | Log de item removido do carrinho com motivo e usuário. |

---

## 8. Referência rápida de arquivos

| Arquivo | Função |
|---------|--------|
| `routes/web.php` | Rotas `/PDV` e `/PDV/store`. |
| `resources/views/admin/pdv/create.blade.php` | Entrada do PDV. |
| `app/Livewire/PdvComponent.php` | Carrinho, busca, finalização. |
| `app/Livewire/PagamentoComponent.php` | Modal de pagamentos e troco. |
| `app/Livewire/PdvMenuCaixaComponent.php` | Caixa, sangria, suprimento. |
| `app/Services/PdvNfService.php` | Persistência NF + itens + parcelas. |
| `app/Models/Caixa.php`, `CaixaMovimento.php` | Sessão de caixa do operador. |
| `app/Models/PdvMotivoCancelamento.php`, `PdvItemCancelamento.php` | Cancelamento auditável. |

---

*Documento baseado na leitura do código. Valide necessidade de integrar `NfParcelaService`/`idagencia` se o PDV deve movimentar saldo de caixa bancário.*
