# Integração One Beat

# Introdução

Este material explica o funcionamento do módulo **onebeat\_pedidos\_faturados**, que faz parte do sistema ISNAPP. O texto foi escrito em duas camadas: uma linguagem simples para quem usa o dia a dia da operação, e detalhes técnicos para quem gerencia a área de Tecnologia da Informação.

<div class="caixa-simples" id="bkmrk-em-poucas-palavras%3A-">**Em poucas palavras:** este programa pega as informações dos pedidos feitos pelas lojas, verifica o que já foi recebido e o que ainda falta chegar, e envia tudo para uma tabela especial que o sistema **OneBeat** usa para tomar decisões de estoque.</div><div class="caixa-tecnica" id="bkmrk-resumo-t%C3%A9cnico%3A-bibl">**Resumo técnico:** biblioteca PHP (CoreVersion 3) que sincroniza movimentações de pedidos do ERP para a tabela `franquia_1beat` no banco `franquia_osklen_relatorio`, com controle incremental por ponteiro de execução, lock de concorrência em arquivo e campos de status (`INATIVO`, `CONFIRMADO`) e quantidade cortada (`QTDE_CORTADA`).</div>## Para quem é esta documentação?

<table id="bkmrk-perfil-o-que-voc%C3%AA-va"><tbody><tr><th>Perfil</th><th>O que você vai encontrar</th></tr><tr><td>Usuário da operação / loja</td><td>Explicações sem termos difíceis sobre o que o sistema faz com os pedidos</td></tr><tr><td>Gestor ou diretor de T.I.</td><td>Arquitetura, bancos de dados, fluxos, instalação e regras de negócio</td></tr><tr><td>Equipe de suporte</td><td>Fluxos de execução, mensagens de erro e glossário</td></tr></tbody></table>

## Arquivos do módulo

<table id="bkmrk-arquivo-fun%C3%A7%C3%A3o-contr"><tbody><tr><th>Arquivo</th><th>Função</th></tr><tr><td>`controle.php`</td><td>Lógica principal: coleta, transforma e grava os pedidos</td></tr><tr><td>`instalador.php`</td><td>Cria o banco e a tabela de destino na primeira instalação</td></tr><tr><td>`visual.html`</td><td>Tela simples de confirmação de carregamento do módulo</td></tr></tbody></table>

![O módulo fica no meio: lê os pedidos do ERP e prepara os dados para o OneBeat.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-i3bkfghd.png)

Figura 1 — O módulo fica no meio: lê os pedidos do ERP e prepara os dados para o OneBeat.

# O que este sistema faz?

Imagine que uma loja da franquia faz um pedido de produtos para a matriz. O pedido é registrado no sistema. Depois, conforme os produtos chegam na loja, o sistema registra o que foi recebido.

Este módulo acompanha essa história e responde quatro perguntas importantes:

- **1. Quanto foi pedido?** — A quantidade total de cada produto no pedido.
- **2. Quanto já chegou?** — A quantidade que a loja já recebeu.
- **3. Quanto ainda falta?** — A diferença entre o pedido e o recebido que ainda pode chegar.
- **4. Quanto foi cortado?** — A parte do pedido que a matriz decidiu não enviar mais (quando o item tem corte).

![Exemplos praticos: sem corte (3 pendentes) e com corte (3 cortadas), partindo de 10 pedidas e 7 recebidas.](https://kb.illimitar.pro/uploads/images/gallery/2026-07/embedded-image-fzq8ykzv.png)

Figura 2 — Dois exemplos com o mesmo pedido (10) e recebimento (7): sem corte ficam 3 pendentes; com corte ficam 3 cortadas e 0 pendentes.

## Quando isso acontece?

O processo roda **automaticamente**, sem que ninguém precise clicar em botões. Ele verifica se há pedidos novos ou alterados desde a última vez que rodou e atualiza as informações.

<div class="caixa-simples" id="bkmrk-analogia%3A-%C3%A9-como-um-">**Analogia:** é como um carteiro que passa na loja todo dia, olha a lista de pedidos, anota o que mudou e leva a informação atualizada para o OneBeat.</div>## O que acontece com pedidos cancelados ou abertos?

Se um pedido for **cancelado**, o sistema marca o registro como *inativo* (`INATIVO = 1`) e informa ao OneBeat que ele **não está confirmado** (`CONFIRMADO = 0`). O registro permanece na tabela, mas com a data de exclusão preenchida.

Se o pedido ainda estiver **aberto** (não finalizado), ele também fica com `CONFIRMADO = 0`, indicando que ainda não está apto para consumo pelo OneBeat. Diferente do cancelado, o registro **não** é marcado como inativo.

![Pedidos cancelados ficam inativos; pedidos abertos ficam não confirmados.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-6o9sfn1m.png)

Figura 3 — Pedidos cancelados ficam inativos; pedidos abertos ficam não confirmados para o OneBeat.

## E quando parte do pedido é cortada?

<div class="caixa-simples" id="bkmrk-corte-simples">**Corte de item:** quando a matriz decide não enviar mais uma parte do pedido (por exemplo, faltou estoque), o sistema registra essa quantidade em `QTDE_CORTADA` em vez de deixá-la como pendente. Assim o OneBeat sabe que aquela diferença não vai mais chegar.</div>## O que o usuário vê na tela?

A tela do módulo (`visual.html`) mostra apenas uma mensagem de confirmação: **"Carregado onebeat\_pedidos\_faturados com sucesso!"**. Não há formulários nem botões para o usuário comum.

<div class="caixa-tecnica" id="bkmrk-para-o-diretor-de-t.">**Para o diretor de T.I.:** a interface é mínima por design. O valor do módulo está na rotina `executar()`, executada via agendador (cron) ou chamada direta à URL `/bibliotecas/6b5b2af8-ab25-4135-9551-b3cb3e055f1a/onebeat_pedidos_faturados/executar`.</div>

# Instalação e preparação

O arquivo `instalador.php` cuida dessa preparação em **quatro etapas**, chamadas `v1`, `v2`, `v3` e `v4`. Cada etapa deve ser executada na ordem.

![Fluxo de instalacao: v1 cria o banco, v2 cria a tabela, v3 e v4 aplicam migracoes.](https://kb.illimitar.pro/uploads/images/gallery/2026-07/embedded-image-x7zyvxbb.png)

Figura 4 — Fluxo de instalação: v1 cria o banco, v2 cria a tabela, v3 e v4 aplicam migrações.

## Etapa 1 — Criar o banco de dados (v1)

<table id="bkmrk-item-detalhe-m%C3%A9todo-"><tbody><tr><th>Item</th><th>Detalhe</th></tr><tr><td>Método</td><td>`instalador::v1()`</td></tr><tr><td>Ação</td><td>`CREATE DATABASE IF NOT EXISTS franquia_osklen_relatorio`</td></tr><tr><td>Retorno de sucesso</td><td>`setSubmit(true, "Feito")`</td></tr><tr><td>Em caso de erro</td><td>Exceção registrada via `error_byexception()`</td></tr></tbody></table>

<div class="caixa-tecnica" id="bkmrk-url-de-instala%C3%A7%C3%A3o%3A%2Fb">**URL de instalação:**  
`/bibliotecas/6b5b2af8-ab25-4135-9551-b3cb3e055f1a/onebeat_pedidos_faturados/install`  
O instalador herda de `biblioteca` e usa a classe `util` para executar SQL com permissão elevada (`query($sql, true)`).</div>## Etapa 2 — Criar a tabela (v2)

A tabela `franquia_1beat` é criada com todos os campos necessários para armazenar pedidos, recebimentos e informações da filial. Detalhes completos no capítulo 7.

<table id="bkmrk-caracter%C3%ADstica-valor"><tbody><tr><th>Característica</th><th>Valor</th></tr><tr><td>Motor</td><td>InnoDB</td></tr><tr><td>Charset</td><td>utf8mb4</td></tr><tr><td>Chave primária</td><td>ID\_PRODUTO\_GRADE + COD\_FILIAL + ID\_FILIAL + ID\_MOVIMENTACAO\_PAI + CNPJ\_FILIAL</td></tr><tr><td>Índice adicional</td><td>IDX\_1BEAT\_SKU (campo SKU)</td></tr></tbody></table>

![Estrutura criada pelo instalador: um banco com uma tabela principal.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-xxndcfle.png)

Figura 5 — Estrutura criada pelo instalador: um banco com uma tabela principal.

## Etapa 3 — Migração de colunas (v3)

A etapa v3 evolui a tabela para o formato atual de controle de status e quantidades cortadas. Executa em transação e é idempotente (verifica colunas antes de alterar).

<table id="bkmrk-v3-acoes"><tbody><tr><th>Ação</th><th>Detalhe</th></tr><tr><td>Adiciona `INATIVO`</td><td>Coluna int (0/1) que substitui o antigo enum `SITUACAO`</td></tr><tr><td>Migra dados</td><td>Registros com `SITUACAO = 'DESATIVO'` recebem `INATIVO = 1`</td></tr><tr><td>Remove `SITUACAO`</td><td>Enum obsoleto removido após migração</td></tr><tr><td>Remove `DATA_ATUALIZACAO`</td><td>Atualizações passam a ser rastreadas por `DATA_TRANSFERENCIA`</td></tr><tr><td>Adiciona `QTDE_CORTADA`</td><td>Quantidade cortada por item (decimal 10,2)</td></tr></tbody></table>

## Etapa 4 — Confirmação e exclusão (v4)

A etapa v4 adiciona campos de controle para o consumo pelo OneBeat. Também executa em transação e é idempotente.

<table id="bkmrk-v4-acoes"><tbody><tr><th>Ação</th><th>Detalhe</th></tr><tr><td>Adiciona `CONFIRMADO`</td><td>Flag int (0/1) — indica se o pedido está apto para o OneBeat</td></tr><tr><td>Adiciona `DATA_EXCLUSAO_MOVIMENTACAO`</td><td>Timestamp com a data de exclusão/cancelamento do pedido</td></tr></tbody></table>

<div class="caixa-alerta" id="bkmrk-ambientes-antigos">**Ambientes já instalados:** se a instalação parou na v2, execute v3 e v4 para que a tabela tenha todas as colunas usadas pelo módulo atual.</div>## Dependências

<div class="caixa-tecnica" id="bkmrk-classe-base-bibliote">- Classe base `biblioteca` (framework ISNAPP)
- Classe `util` do token `12262a22-30ab-11e9-bb4c-127101af6b0d`
- Array `$requires` está vazio — sem dependências de outras bibliotecas versionadas
- Bancos do tenant já devem existir: `{banco}`, `{banco}_relatorio`, `{banco}_integrador`

</div><div class="caixa-alerta" id="bkmrk-aten%C3%A7%C3%A3o%3A-a-instala%C3%A7%C3%A3">**Atenção:** a instalação só precisa ser feita *uma vez* por ambiente. Executar novamente é seguro graças ao `IF NOT EXISTS`, mas não é necessário em rotina.</div>

# Arquitetura do sistema

O módulo é uma **biblioteca ISNAPP** (padrão de extensão do ERP) composta por três arquivos e integrada a múltiplos bancos MySQL.

![Arquitetura em camadas: apresentação, lógica PHP e múltiplos bancos MySQL.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-knhkbliz.png)

Figura 6 — Arquitetura em camadas: apresentação, lógica PHP e múltiplos bancos MySQL.

## Bancos de dados envolvidos

<table id="bkmrk-vari%C3%A1vel-php-nome-do"><tbody><tr><th>Variável PHP</th><th>Nome do banco</th><th>Uso</th></tr><tr><td>`$banco`</td><td>Dinâmico (tenant)</td><td>Pedidos, itens, entidades, recebimentos</td></tr><tr><td>`$bancoRelatorio`</td><td>`{banco}_relatorio`</td><td>Tabela `log` com ponteiro de última execução</td></tr><tr><td>`$bancoIntegrador`</td><td>`{banco}_integrador`</td><td>Stage de integração LX (`stage_pedido_lx`)</td></tr><tr><td>`$bancoMasterRelatorio`</td><td>`franquia_osklen_relatorio`</td><td>Tabela de destino `franquia_1beat` (compartilhada)</td></tr></tbody></table>

<div class="caixa-simples" id="bkmrk-para-entender-sem-ja">**Para entender sem jargão:** o sistema lê informações de três "pastas" diferentes no banco de dados e grava o resultado organizado em uma "pasta central" que o OneBeat consulta.</div>## Tabelas de origem (leitura)

<table id="bkmrk-tabela-banco-papel-m"><tbody><tr><th>Tabela</th><th>Banco</th><th>Papel</th></tr><tr><td>`movimentacao`</td><td>{banco}</td><td>Cabeçalho dos pedidos e recebimentos</td></tr><tr><td>`movimentacao_detalhe`</td><td>{banco}</td><td>Itens (produtos) de cada movimentação</td></tr><tr><td>`movimentacao_movimentacao`</td><td>{banco}</td><td>Vínculo pai-filho (pedido → recebimento)</td></tr><tr><td>`entidade`</td><td>{banco}</td><td>Dados da filial (loja)</td></tr><tr><td>`juridica`</td><td>{banco}</td><td>CNPJ da filial</td></tr><tr><td>`stage_pedido_lx`</td><td>{banco}\_integrador</td><td>Integração com sistema LX (LEFT JOIN)</td></tr><tr><td>`log`</td><td>{banco}\_relatorio</td><td>Controle de ponteiro (`procedure = 'franquia_1beat'`)</td></tr></tbody></table>

## Classe principal

**Classe:** `onebeat_pedidos_faturados` extends `util`

**Token:** `6b5b2af8-ab25-4135-9551-b3cb3e055f1a`

**CoreVersion:** 3

**Métodos públicos principais:**

<div class="caixa-tecnica" id="bkmrk-index%28%29-%E2%80%94-exibe-visu">- `index()` — exibe visual.html
- `executar()` — execução principal (sincronização)
- `verificaLock()` — controle de concorrência
- `getPonteiroExecucao()` — última data processada
- `getPedidoUltimaVerificacao()` — data do pedido mais recente
- `getPedidosRecebidos()` — INSERT/UPDATE na tabela destino
- `atualizaPonteiroExecucao()` — grava novo ponteiro

</div><div class="caixa-tecnica" id="bkmrk-remove-pedidos-comentado">**Nota:** o método `removePedidosStatus()` existe no código mas está *comentado*. A lógica de status (INATIVO, CONFIRMADO) é tratada diretamente no INSERT.</div>## Mecanismo de lock (concorrência)

Para evitar que duas execuções rodem ao mesmo tempo, o módulo usa um **arquivo de lock** no diretório temporário do sistema operacional:

`/tmp/{banco}.onebeat_pedidos_faturados_executar.lock`

<div class="caixa-tecnica" id="bkmrk-usa-flock%28lock_ex-%7C-">Usa `flock(LOCK_EX | LOCK_NB)` — lock exclusivo não-bloqueante. Se outro processo já estiver rodando, lança exceção: *"Ja tem outro processo em execucao, aguarde o termino"*. O lock é liberado no bloco `finally` via `__liberaLock()`.</div>

# Fluxo de execução principal

<div class="caixa-simples" id="bkmrk-"></div>![Fluxograma completo do método executar(), com 5 etapas e liberação do lock no finally.](https://kb.illimitar.pro/uploads/images/gallery/2026-07/embedded-image-cm13hdad.png)

Figura 7 — Fluxograma completo do método executar(), com 5 etapas e liberação do lock no finally.

## Detalhamento de cada etapa

<table id="bkmrk-%23-m%C3%A9todo-o-que-faz-%28"><tbody><tr><th>\#</th><th>Método</th><th>O que faz (simples)</th><th>O que faz (técnico)</th></tr><tr><td>1</td><td>`verificaLock()`</td><td>Garante que só uma cópia rode por vez</td><td>`flock` exclusivo em arquivo temporário</td></tr><tr><td>2</td><td>`getPonteiroExecucao()`</td><td>Pergunta: "desde quando devo buscar?"</td><td>`MAX(execucao)` em `log` onde `procedure='franquia_1beat'`</td></tr><tr><td>3</td><td>`getPedidoUltimaVerificacao()`</td><td>Acha o pedido mais novo no período</td><td>`MAX(data)` em movimentação PEDIDO &gt; ponteiro</td></tr><tr><td>4</td><td>`getPedidosRecebidos()`</td><td>Copia e calcula quantidades e status</td><td>INSERT com CTEs + ON DUPLICATE KEY UPDATE</td></tr><tr><td>5</td><td>`atualizaPonteiroExecucao()`</td><td>Marca que terminou até tal data</td><td>INSERT/UPDATE em `log`</td></tr></tbody></table>

## Processamento incremental

O módulo **não reprocessa tudo** a cada execução. Ele usa um "marcador de página" (ponteiro) para buscar apenas pedidos alterados entre a última execução e a data do pedido mais recente.

![Apenas pedidos entre o ponteiro e a data mais recente são processados em cada execução.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-gexpp800.png)

Figura 8 — Apenas pedidos entre o ponteiro e a data mais recente são processados em cada execução.

## Mensagens de erro comuns

<div class="caixa-erro" id="bkmrk-%22ja-tem-outro-proces">- **"Ja tem outro processo em execucao, aguarde o termino"** — outra instância do `executar()` está ativa.
- **"Não foram encontrados pedidos para atualizar"** — não há pedidos novos desde o ponteiro.
- **"Nao foi possivel criar o arquivo de lock"** — problema de permissão no diretório temporário.
- **"Erro ao inserir/atualizar pedidos recebidos na franquia\_1beat."** — falha no INSERT/UPDATE principal.

</div><div class="caixa-tecnica" id="bkmrk-tratamento-de-erros%3A">**Tratamento de erros:** exceções no `executar()` são capturadas e enviadas a `error_byexception()`. Os métodos intermediários (`getPedidosRecebidos`, `atualizaPonteiroExecucao`) também possuem try/catch interno que retorna `null` em falha. O lock é sempre liberado no bloco `finally`.</div>

# Como os dados são processados

O método `getPedidosRecebidos()` executa um único comando SQL complexo que usa **CTEs** (Common Table Expressions — subconsultas nomeadas) para organizar os dados em etapas.

![As CTEs organizam pedidos, itens e recebimentos antes do INSERT final.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-yhvf8pxn.png)

Figura 9 — As CTEs organizam pedidos, itens e recebimentos antes do INSERT final.

## Etapa por etapa

### 1. CTE `m` — Pedidos no período

Seleciona movimentações do tipo PEDIDO alteradas entre o ponteiro e a data limite. Faz LEFT JOIN com `stage_pedido_lx` para integração LX.

### 2. CTE `mi` — Itens do pedido

Para cada pedido, soma as quantidades de cada produto (grade) nos itens ativos do pedido. Também captura o flag `pedido_corte_item` (usado no cálculo de QTDE\_CORTADA e QTDE\_PENDENTE).

### 3. CTE `mr` — Recebimentos vinculados

Busca movimentações filhas (recebimentos) ligadas ao pedido pai, apenas com situação `Finalizado`.

### 4. CTE `mri` — Itens recebidos

Soma as quantidades recebidas de cada produto em cada recebimento vinculado ao pedido.

### 5. SELECT final — Montagem do registro

Junta pedido + itens pedidos + itens recebidos + dados da filial (nome, CNPJ, código).

![Cálculo da quantidade pendente: pedido menos recebido, nunca negativo.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-gbswx0yp.png)

Figura 10 — Cálculo de pendente e cortada: depende do flag `pedido_corte_item` no item.

## Campos calculados

<table id="bkmrk-campo-destino-como-%C3%A9"><tbody><tr><th>Campo destino</th><th>Como é calculado</th></tr><tr><td>`QTDE_PEDIDA`</td><td>Soma dos itens do pedido (`mi.qtde`)</td></tr><tr><td>`QTDE_RECEBIDA`</td><td>Soma dos itens recebidos (`COALESCE(mri.qtde, 0)`)</td></tr><tr><td>`QTDE_CORTADA`</td><td>Se `pedido_corte_item = 'S'`: `MAX(0, pedida - recebida)`; senão: `0`</td></tr><tr><td>`QTDE_PENDENTE`</td><td>Se `pedido_corte_item = 'S'`: `0`; senão: `MAX(0, pedida - recebida)`</td></tr><tr><td>`ENTRADA_CONFIRMADA`</td><td>`1` se situação = FINALIZADO, senão `0`</td></tr><tr><td>`INATIVO`</td><td>`1` se situação = Cancelado, senão `0`</td></tr><tr><td>`CONFIRMADO`</td><td>`0` se Cancelado ou Aberto; `1` nas demais situações</td></tr><tr><td>`DATA_EXCLUSAO_MOVIMENTACAO`</td><td>`m.data_exclusao` se Cancelado; senão `NULL`</td></tr><tr><td>`DATA_TRANSFERENCIA`</td><td>`NOW()` no momento da gravação</td></tr><tr><td>`SKU`</td><td>Código do produto (`mi.codigo`)</td></tr><tr><td>`CHAVE_NFE`</td><td>Chave da nota fiscal do pedido</td></tr></tbody></table>

<div class="caixa-tecnica" id="bkmrk-pedido-corte-item">**Flag `pedido_corte_item`:** vem de `movimentacao_detalhe.pedido_corte_item` (prioriza o valor do recebimento, se existir). Quando igual a `'S'`, a diferença entre pedido e recebido vai para `QTDE_CORTADA` em vez de `QTDE_PENDENTE`.</div>## Atualização de registros existentes

O INSERT usa `ON DUPLICATE KEY UPDATE`, ou seja:

<div class="caixa-tecnica" id="bkmrk-se-o-registro-n%C3%A3o-ex">- Se o registro **não existe** (chave primária nova) → insere.
- Se o registro **já existe** → atualiza: QTDE\_RECEBIDA, QTDE\_PEDIDA, QTDE\_CORTADA, QTDE\_PENDENTE, ENTRADA\_CONFIRMADA, DATA\_TRANSFERENCIA, INATIVO, CONFIRMADO e DATA\_EXCLUSAO\_MOVIMENTACAO (esta última só quando INATIVO = 1).

</div>Chave primária: `ID_PRODUTO_GRADE + COD_FILIAL + ID_FILIAL + ID_MOVIMENTACAO_PAI + CNPJ_FILIAL`

## Filtros aplicados

<table id="bkmrk-filtro-valor-motivo-"><tbody><tr><th>Filtro</th><th>Valor</th><th>Motivo</th></tr><tr><td>`modulo`</td><td>'PEDIDO'</td><td>Apenas movimentações de pedido</td></tr><tr><td>`tipo_estoque`</td><td>'PEDIDO'</td><td>Confirma tipo de estoque</td></tr><tr><td>`m.data`</td><td>&gt; ponteiro AND &lt;= limite</td><td>Janela incremental</td></tr><tr><td>`md.situacao`</td><td>'ATIVO'</td><td>Itens não excluídos</td></tr><tr><td>`md.id_produto_grade`</td><td>IS NOT NULL</td><td>Produtos com grade definida</td></tr><tr><td>`mr.situacao`</td><td>'Finalizado'</td><td>Recebimentos concluídos</td></tr></tbody></table>

## Dicionário da coluna CONFIRMADO

<table id="bkmrk-situa%C3%A7%C3%A3o-valor-abert-1"><tbody><tr><th>Situação no ERP</th><th>CONFIRMADO</th></tr><tr><td>Cancelado ou Aberto</td><td>0</td></tr><tr><td>Demais situações (Confirmado, Recebido, Finalizado, etc.)</td><td>1</td></tr></tbody></table>

# Estrutura da tabela de destino

<div class="caixa-simples" id="bkmrk-"></div>![Campos da tabela organizados por grupo: produto, filial, quantidades, pedido e controle.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-ajiehjmp.png)

Figura 11 — Campos da tabela organizados por grupo: produto, filial, quantidades, pedido e controle.

## Todos os campos

<table id="bkmrk-campo-tipo-significa"><tbody><tr><th>Campo</th><th>Tipo</th><th>Significado (simples)</th><th>Detalhe técnico</th></tr><tr><td>`SKU`</td><td>varchar(45)</td><td>Código do produto</td><td>Vem de `movimentacao_detalhe.codigo`</td></tr><tr><td>`CHAVE_NFE`</td><td>varchar(45)</td><td>Número da nota fiscal</td><td>Chave da NF-e do pedido</td></tr><tr><td>`ID_FILIAL`</td><td>int</td><td>Identificador da loja</td><td>FK para `entidade.id`</td></tr><tr><td>`NOME_FILIAL`</td><td>varchar(45)</td><td>Nome da loja</td><td>`entidade.nome`</td></tr><tr><td>`CNPJ_FILIAL`</td><td>varchar(50)</td><td>CNPJ da loja</td><td>`juridica.cnpj` — parte da PK</td></tr><tr><td>`COD_FILIAL`</td><td>varchar(45)</td><td>Código interno da loja</td><td>`entidade.codigo` — parte da PK</td></tr><tr><td>`QTDE_PEDIDA`</td><td>decimal(10,2)</td><td>Quanto foi pedido</td><td>Soma dos itens do pedido</td></tr><tr><td>`QTDE_CORTADA`</td><td>decimal(10,2)</td><td>Quanto foi cortado (não será mais entregue)</td><td>Quando `pedido_corte_item = 'S'`: pedida − recebida (mín. 0)</td></tr><tr><td>`QTDE_RECEBIDA`</td><td>decimal(10,2)</td><td>Quanto já chegou</td><td>Soma dos recebimentos finalizados</td></tr><tr><td>`QTDE_PENDENTE`</td><td>decimal(10,2)</td><td>Quanto falta</td><td>pedida − recebida (mín. 0), ou 0 se item cortado</td></tr><tr><td>`DESCRICAO`</td><td>longtext</td><td>Nome/descrição do produto</td><td>Texto do item do pedido</td></tr><tr><td>`ID_MOVIMENTACAO_PAI`</td><td>int</td><td>Número do pedido no sistema</td><td>ID da movimentação pai — parte da PK</td></tr><tr><td>`ID_PRODUTO_GRADE`</td><td>int</td><td>Identificador do produto com tamanho/cor</td><td>Parte da PK</td></tr><tr><td>`ENTRADA_CONFIRMADA`</td><td>int</td><td>Pedido já foi finalizado? (1=sim, 0=não)</td><td>Baseado em `m.situacao = 'FINALIZADO'`</td></tr><tr><td>`DATA_EMISSAO`</td><td>timestamp</td><td>Data em que o pedido foi emitido</td><td>`movimentacao.data_emissao`</td></tr><tr><td>`DATA_TRANSFERENCIA`</td><td>timestamp</td><td>Quando os dados foram enviados ao OneBeat</td><td>`NOW()` na gravação</td></tr><tr><td>`INATIVO`</td><td>int</td><td>Registro inativo? (1=sim, 0=não)</td><td>`1` se pedido Cancelado; substitui o antigo `SITUACAO`</td></tr><tr><td>`CONFIRMADO`</td><td>int</td><td>Pedido confirmado para o OneBeat? (1=sim, 0=não)</td><td>`0` se Cancelado/Aberto; `1` demais</td></tr><tr><td>`DATA_EXCLUSAO_MOVIMENTACAO`</td><td>timestamp</td><td>Data em que o pedido foi cancelado/excluído</td><td>`movimentacao.data_exclusao` se Cancelado</td></tr><tr><td>`EXTRA`</td><td>json</td><td>Campo reservado para dados extras</td><td>Não preenchido pelo módulo atualmente</td></tr><tr><td>`DATA_CRIACAO`</td><td>timestamp</td><td>Quando o registro foi criado</td><td>DEFAULT CURRENT\_TIMESTAMP</td></tr></tbody></table>

## Chave primária e índices

![Chave primária composta por 5 campos garante um registro único por produto/pedido/filial.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-n2wenyar.png)

Figura 12 — Chave primária composta por 5 campos garante um registro único por produto/pedido/filial.

Índice adicional: `IDX_1BEAT_SKU` no campo `SKU` para consultas rápidas por código de produto.

# Regras de negócio e situações

O módulo lê a situação do pedido na tabela `movimentacao` e traduz para o campo `SITUACAO` da tabela destino.

<table id="bkmrk-" style="width:100%;max-width:720px;margin:1.5rem auto;border:0;border-collapse:separate;border-spacing:0 0.75rem;table-layout:fixed;font-family:inherit;font-size:0.95rem;"><colgroup> <col style="width:44%;"></col> <col style="width:6%;"></col> <col style="width:50%;"></col> </colgroup><tbody><tr><td style="text-align:center;font-weight:600;color:#2c3e50;border:0;padding:0;">Situação no ERP</td><td style="border:0;padding:0;"> </td><td style="text-align:center;font-weight:600;color:#2c3e50;border:0;padding:0;">Na tabela OneBeat</td></tr><tr><td style="text-align:center;vertical-align:middle;border:0;padding:0 0.5rem 0 0;"><div style="background:#d5f5e3;border:2px solid #27ae60;padding:0.75rem 1rem;color:#1e8449;line-height:1.6;">Aberto  
Confirmado  
Recebido  
Atendido Parcialmente  
Finalizado</div></td><td style="text-align:center;vertical-align:middle;color:#3498db;font-size:1.5rem;border:0;padding:0;">→</td><td style="text-align:center;vertical-align:middle;border:0;padding:0 0 0 0.5rem;"><div style="background:#d5f5e3;border:2px solid #27ae60;padding:0.75rem 1rem;color:#1e8449;font-weight:600;">ATIVO</div></td></tr><tr><td style="text-align:center;vertical-align:middle;border:0;padding:0 0.5rem 0 0;"><div style="background:#fadbd8;border:2px solid #e74c3c;padding:0.75rem 1rem;color:#c0392b;font-weight:600;">Cancelado</div></td><td style="text-align:center;vertical-align:middle;color:#3498db;font-size:1.5rem;border:0;padding:0;">→</td><td style="text-align:center;vertical-align:middle;border:0;padding:0 0 0 0.5rem;"><div style="background:#fadbd8;border:2px solid #e74c3c;padding:0.75rem 1rem;color:#c0392b;font-weight:600;">DESATIVO</div></td></tr></tbody></table>

Figura 13 — Pedidos abertos e cancelados viram DESATIVO e são removidos da tabela após a sincronização.

## Regra da quantidade pendente

<div class="caixa-simples" id="bkmrk-regra-simples%3A-o-que">**Regra simples:** o que falta = o que foi pedido menos o que já chegou. Se por algum motivo o recebido for maior que o pedido, o sistema considera que **nada falta** (zero).</div><table id="bkmrk-pedido-recebido-pend"><tbody><tr><th>Pedido</th><th>Recebido</th><th>Pendente</th><th>Explicação</th></tr><tr><td>10</td><td>7</td><td>3</td><td>Caso normal: faltam 3 unidades</td></tr><tr><td>10</td><td>10</td><td>0</td><td>Pedido completo</td></tr><tr><td>10</td><td>0</td><td>10</td><td>Nada recebido ainda</td></tr><tr><td>5</td><td>8</td><td>0</td><td>Recebido a mais: pendente nunca fica negativo</td></tr></tbody></table>

## Entrada confirmada

O campo `ENTRADA_CONFIRMADA` indica se o pedido foi finalizado no ERP:

<table id="bkmrk-valor-significado-co"><tbody><tr><th>Valor</th><th>Significado</th><th>Condição</th></tr><tr><td>1</td><td>Entrada confirmada</td><td>`m.situacao = 'FINALIZADO'`</td></tr><tr><td>0</td><td>Entrada não confirmada</td><td>Qualquer outra situação</td></tr></tbody></table>

## Recebimentos considerados

Para contar como "recebido", uma movimentação filha deve atender **todos** estes critérios:

<div class="caixa-tecnica" id="bkmrk-estar-vinculada-ao-p">- Estar vinculada ao pedido pai via `movimentacao_movimentacao`
- Ter situação `'Finalizado'` (com F maiúsculo)
- Ter itens ativos com `id_produto_grade` preenchido

</div>Recebimentos em andamento ou cancelados **não entram** no cálculo de QTDE\_RECEBIDA.

## Processamento incremental

![O módulo foi projetado para rodar repetidamente, processando apenas o que mudou desde a última vez.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-bci1zivx.png)

Figura 14 — O módulo foi projetado para rodar repetidamente, processando apenas o que mudou desde a última vez.

## Concorrência — apenas uma execução por vez

<div class="caixa-alerta" id="bkmrk-regra-de-seguran%C3%A7a%3A-">**Regra de segurança:** se duas execuções tentarem rodar ao mesmo tempo, a segunda será bloqueada com a mensagem *"Ja tem outro processo em execucao, aguarde o termino"*. Isso evita dados duplicados ou corrompidos.</div>## O que acontece quando não há pedidos novos?

Se não existir nenhum pedido com data maior que o ponteiro, o método `getPedidoUltimaVerificacao()` lança uma exceção: *"Não foram encontrados pedidos para atualizar"*. A execução é interrompida, o lock é liberado, e nada é alterado na tabela destino.

## Ponteiro inicial

<div class="caixa-tecnica" id="bkmrk-na-primeira-execu%C3%A7%C3%A3o">Na primeira execução (sem registro em `log`), o ponteiro padrão é `2000-01-01 00:00:00`, ou seja, todos os pedidos desde essa data serão considerados.</div>

# Glossário e referência rápida

<table id="bkmrk-onebeat-sistema-exte"><tbody><tr><th>Termo</th><th>Definição</th></tr><tr><td>**OneBeat**</td><td>Sistema externo de gestão de estoque e abastecimento que consome os dados desta tabela.</td></tr><tr><td>**ERP / ISNAPP**</td><td>Sistema principal da empresa onde os pedidos são criados e os recebimentos registrados.</td></tr><tr><td>**Pedido faturado**</td><td>Pedido de produtos emitido pela matriz para uma loja, com nota fiscal associada.</td></tr><tr><td>**Recebimento**</td><td>Registro de que a loja recebeu (ou parte de) um pedido. Fica ligado ao pedido original.</td></tr><tr><td>**Filial / Loja**</td><td>Unidade da franquia que faz o pedido e recebe os produtos.</td></tr><tr><td>**SKU**</td><td>Código único do produto (como um "RG" do item no estoque).</td></tr><tr><td>**Grade**</td><td>Variação do produto (tamanho, cor). Exemplo: camiseta azul tamanho M.</td></tr><tr><td>**Ponteiro de execução**</td><td>Data/hora da última sincronização bem-sucedida. O sistema só busca pedidos alterados depois dessa data.</td></tr><tr><td>**Lock (trava)**</td><td>Mecanismo que impede duas cópias do programa de rodar ao mesmo tempo.</td></tr><tr><td>**CTE (Common Table Expression)**</td><td>Técnica SQL que organiza a consulta em etapas nomeadas (m, mi, mr, mri).</td></tr><tr><td>**ON DUPLICATE KEY UPDATE**</td><td>Comando SQL que insere um registro novo ou atualiza se ele já existir (pela chave primária).</td></tr><tr><td>**Biblioteca ISNAPP**</td><td>Módulo extensível do ERP, identificado por um token UUID único.</td></tr><tr><td>**Tenant / Banco dinâmico**</td><td>Cada cliente/franquia tem seu próprio banco de dados ({banco}), separado dos demais.</td></tr><tr><td>**Stage (integrador)**</td><td>Área intermediária de integração com sistemas externos, como o LX.</td></tr><tr><td>**NF-e / CHAVE\_NFE**</td><td>Nota Fiscal Eletrônica. A chave é o número de 44 dígitos que identifica a nota.</td></tr><tr><td>**INATIVO**</td><td>Flag int (0/1) que indica se o registro está inativo. Substitui o antigo campo `SITUACAO`. Valor 1 para pedidos cancelados.</td></tr><tr><td>**CONFIRMADO**</td><td>Flag int (0/1) que indica se o pedido está apto para consumo pelo OneBeat. Zero para pedidos cancelados ou abertos.</td></tr><tr><td>**QTDE\_CORTADA**</td><td>Quantidade cortada de um item — parte do pedido que não será mais entregue.</td></tr><tr><td>**pedido\_corte\_item**</td><td>Flag nos itens do pedido (`movimentacao_detalhe`). Quando igual a `'S'`, a diferença entre pedido e recebido vai para QTDE\_CORTADA em vez de QTDE\_PENDENTE.</td></tr><tr><td>**DATA\_EXCLUSAO\_MOVIMENTACAO**</td><td>Data em que o pedido foi cancelado ou excluído no ERP. Preenchida apenas para pedidos cancelados.</td></tr></tbody></table>

## URLs do módulo

<table id="bkmrk-fun%C3%A7%C3%A3o-url-tela-visu"><tbody><tr><th>Função</th><th>URL</th></tr><tr><td>Tela visual</td><td>`/bibliotecas/6b5b2af8-ab25-4135-9551-b3cb3e055f1a/onebeat_pedidos_faturados`</td></tr><tr><td>Execução (executar)</td><td>`/bibliotecas/6b5b2af8-ab25-4135-9551-b3cb3e055f1a/onebeat_pedidos_faturados/executar`</td></tr><tr><td>Instalação</td><td>`/bibliotecas/6b5b2af8-ab25-4135-9551-b3cb3e055f1a/onebeat_pedidos_faturados/install`</td></tr></tbody></table>

## Checklist de implantação (T.I.)

![Checklist recomendado para implantação do módulo.](https://kb.illimitar.pro/uploads/images/gallery/2026-06/embedded-image-vz1ggczi.png)

Figura 15 — Checklist recomendado para implantação do módulo.

## Resumo dos arquivos

<table id="bkmrk-arquivo-classe-respo"><tbody><tr><th>Arquivo</th><th>Classe</th><th>Responsabilidade</th></tr><tr><td>`controle.php`</td><td>`onebeat_pedidos_faturados`</td><td>Sincronização de pedidos</td></tr><tr><td>`instalador.php`</td><td>`instalador`</td><td>Criação de banco e tabela</td></tr><tr><td>`visual.html`</td><td>—</td><td>Mensagem de carregamento</td></tr></tbody></table>

## Identificadores do módulo

<table id="bkmrk-propriedade-valor-to"><tbody><tr><th>Propriedade</th><th>Valor</th></tr><tr><td>Token</td><td>`6b5b2af8-ab25-4135-9551-b3cb3e055f1a`</td></tr><tr><td>Classe</td><td>`onebeat_pedidos_faturados`</td></tr><tr><td>CoreVersion</td><td>3</td></tr><tr><td>Banco destino</td><td>`franquia_osklen_relatorio`</td></tr><tr><td>Tabela destino</td><td>`franquia_1beat`</td></tr><tr><td>Procedure no log</td><td>`franquia_1beat`</td></tr></tbody></table>

<div class="caixa-simples" id="bkmrk-d%C3%BAvidas-frequentes%3A-">**Dúvidas frequentes:**- *"O sistema não atualizou meu pedido"* — verifique se o agendamento do `executar()` está ativo e se o pedido tem data maior que o ponteiro.
- *"Apareceu erro de processo em execução"* — aguarde a execução anterior terminar ou verifique se há lock órfão em `/tmp/{banco}.onebeat_pedidos_faturados_executar.lock`.
- *"Pedido cancelado ainda aparece"* — na próxima execução ele será marcado com `INATIVO = 1` e `CONFIRMADO = 0`. O registro permanece na tabela com a data de exclusão preenchida.
- *"Pedido aberto aparece no OneBeat"* — o registro existe na tabela, mas com `CONFIRMADO = 0`, indicando que ainda não está apto para consumo.

</div>## Índice da documentação

<table id="bkmrk-%23-cap%C3%ADtulo-arquivo-0"><tbody><tr><th>\#</th><th>Capítulo</th><th>Arquivo</th></tr><tr><td>01</td><td>Introdução</td><td>`01_introducao.html`</td></tr><tr><td>02</td><td>O que faz</td><td>`02_o_que_faz.html`</td></tr><tr><td>03</td><td>Instalação</td><td>`03_instalacao.html`</td></tr><tr><td>04</td><td>Arquitetura</td><td>`04_arquitetura.html`</td></tr><tr><td>05</td><td>Fluxo de execução</td><td>`05_fluxo_execucao.html`</td></tr><tr><td>06</td><td>Processamento de dados</td><td>`06_processamento_dados.html`</td></tr><tr><td>07</td><td>Estrutura da tabela</td><td>`07_estrutura_tabela.html`</td></tr><tr><td>08</td><td>Regras de negócio</td><td>`08_regras_negocio.html`</td></tr><tr><td>09</td><td>Glossário</td><td>`09_glossario.html`</td></tr></tbody></table>