Integração Balança Toledo (Guardian) → Romaneio de Matéria-Prima
v01
Orienta a configuração e o funcionamento da integração entre a balança Toledo Guardian e o Romaneio de Matéria-Prima, desde o recebimento automático das pesagens até a geração e atualização dos registros no sistema.
user_manual
public
integracao-balanca-toledo-guardian-romaneio-de-materia-prima
|
Romaneio
13
09/10/2026 09:26
· Bernardo
- Título
- Integração Balança Toledo (Guardian) → Romaneio de Matéria-Prima
- Slug
- integracao-balanca-toledo
- Sistema(s)
- Romaneio
- Categoria
- user_manual
- Tipo
- how-to
- Autor
- Fabiano Massola
- Setor
- Qualidade
- Modulo
- Romaneio
- Publico
- operacional
- Keywords
- ["balança", "Toledo", "Guardian", "romaneio", "pesagem", "integração", "webhook"]
- Versão Doc
- 1
- Revisão
- Paulo Bley
- Aprovado em
- Agosto de 2026
- Release
- ""
- Chamado
- "0000000000"
- Ultima Revisao
- "2026-10-09"
- Versão Pipeline
- ia-forja
---
title: Integração Balança Toledo (Guardian) → Romaneio de Matéria-Prima
slug: integracao-balanca-toledo
sistema: Romaneio
categoria: user_manual
tipo: how-to
autor: Fabiano Massola
setor: Qualidade
modulo: Romaneio
publico: operacional
keywords: ["balança", "Toledo", "Guardian", "romaneio", "pesagem", "integração", "webhook"]
versao_doc: 1
revisao: Paulo Bley
aprovado_em: Agosto de 2026
release: ""
chamado: "0000000000"
ultima_revisao: "2026-10-09"
versao_pipeline: ia-forja
---
## Visão Geral
**Integração entre a balança Toledo Guardian e o Romaneio de Matéria-Prima do Teorema**, desde o envio da pesagem até a geração e atualização do romaneio. Este guia apresenta:
- Configuração na rota webhook do Orion Horse do cliente, com os 4 trechos da URL (servidor, token, CNPJ)
- Recebimento das fichas em JSON, processamento automático a cada 15 segundos, leitura e conversão dos dados
- Regras de de-para, consultas aos cadastros (itens, clientes, veículos) e pedidos de venda
- Gravação dos pesos, fotos e informações no romaneio (entrada e saída)
- Pré-requisitos de funcionamento: tabelas, cadastros e flag "Usa Balança Pesagem"
- Diagnóstico de problemas: consultas SQL para investigar fichas, status, recados de erro e reprocessamento
- Limitações e comportamentos importantes da integração
## Índice
01 · Visão geral do processo [1](#visão-geral-do-processo)
02 · Configuração no cliente [2](#configuração-no-cliente)
03 · Etapa 1 — Recebimento da ficha [5](#etapa-1-recebimento-da-ficha)
04 · Etapa 2 — Fila e processamento automático [6](#etapa-2-fila-e-processamento-automático)
05 · Etapa 3 — Leitura do JSON [7](#etapa-3-leitura-do-json)
06 · Etapa 4 — De-para e consultas [10](#etapa-4-de-para-e-consultas)
07 · Etapa 5 — Gravação do romaneio [13](#etapa-5-gravação-do-romaneio)
08 · Etapa 6 — Fotos [17](#etapa-6-fotos)
09 · Etapa 7 — Recados (avisos) [18](#etapa-7-recados-avisos)
10 · Consultas SQL para o suporte [19](#consultas-sql-para-o-suporte)
11 · Solução de problemas [21](#solução-de-problemas)
12 · Comportamentos importantes e limitações [23](#comportamentos-importantes-e-limitações)
13 · Referência técnica (código-fonte) [23](#referência-técnica-código-fonte)
## 01 · Visão geral do processo
O caminhão passa duas vezes pela balança: na **entrada** (1ª pesagem) e na **saída** (2ª pesagem). A cada pesagem, o software da balança (**Toledo Guardian**) envia uma **ficha** em JSON para o servidor Orion Horse do cliente. O servidor não gera o romaneio na hora: ele **guarda a ficha numa fila** e um processo automático, a cada 15 segundos, transforma as fichas da fila em romaneio.
<table>
<colgroup>
<col style="width: 6%" />
<col style="width: 30%" />
<col style="width: 63%" />
</colgroup>
<thead>
<tr class="header">
<th><strong>#</strong></th>
<th><strong>Etapa</strong></th>
<th><strong>O que acontece</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>1</strong></td>
<td><strong>Balança envia a ficha</strong></td>
<td>O Guardian faz um POST com o JSON da pesagem para a URL do servidor.<br />
rota v1/webhooktoledolocal/toledo/<CNPJ>/<TOKEN></td>
</tr>
<tr class="even">
<td><strong>2</strong></td>
<td><strong>Servidor grava a ficha na fila</strong></td>
<td>A ficha é gravada como veio, na tabela WEBHOOK da base do cliente, com STATUS = 0 (pendente). A balança recebe 200 ok.<br />
tabela WEBHOOK (ORIGIN = 'toledo')</td>
</tr>
<tr class="odd">
<td><strong>3</strong></td>
<td><strong>A cada 15 s, o cron procura fichas pendentes</strong></td>
<td>Só nas bases marcadas com <strong>"Usa Balança Pesagem = Sim"</strong> no Registro de Banco.<br />
CronJob → ProcessBalancaAllDatabases</td>
</tr>
<tr class="even">
<td><strong>4</strong></td>
<td><strong>Lê o JSON e resolve os códigos</strong></td>
<td>Converte pesos e datas, e descobre item, cliente, motorista, veículo, transportadora e pedido de venda consultando os cadastros e a tabela de de-para API_INTEGRATION.<br />
ITENS · CLIENTES_FORNECEDORES · TRA_VEICULOS · VENDAS_MS/DT · LOCAL_ENTREGA</td>
</tr>
<tr class="odd">
<td><strong>5</strong></td>
<td><strong>Grava ou completa o romaneio</strong></td>
<td><strong>Entrada</strong> cria o romaneio. <strong>Saída</strong> completa o mesmo romaneio (casado pelo número do ticket). Também grava as fotos.<br />
ROM_ROMANEIO_MS · ROM_ROMANEIO_FOTOS</td>
</tr>
<tr class="even">
<td><strong>6</strong></td>
<td><strong>Marca a ficha e avisa</strong></td>
<td>A ficha vira STATUS = 1 (processada) ou 2 (erro). Se o romaneio nasceu incompleto ou deu erro, grava um <strong>recado</strong> para o usuário configurado.<br />
WEBHOOK.STATUS · TEO_RECADOS</td>
</tr>
</tbody>
</table>
> **Regra de ouro:** O romaneio é gerado **sempre**, mesmo com dados faltando. O que não for encontrado fica em branco no romaneio e vira um recado. A **única** coisa que impede a geração é a ficha não ter o número do ticket (Codigo) ou um erro de banco.
### Tempo até o romaneio aparecer
Até ~15 segundos depois que a balança recebeu o 200 ok, mais o tempo de processamento. Se o servidor acabou de ser ligado, a primeira verificação acontece 1 segundo após a subida.
## 02 · Configuração no cliente
### A URL do webhook
http://\<SERVIDOR\>/v1/webhooktoledolocal/toledo/\<CNPJ\>/\<TOKEN\>
| **Trecho** | **Significado** |
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| \<SERVIDOR\> | **IP e porta do Orion Horse do cliente**, alcançável a partir do computador do Guardian. Ex.: 192.168.0.10:9000. |
| webhooktoledolocal | **Parte fixa.** É a rota pública (sem login/JWT) que grava a ficha na base do token. |
| toledo | **Parte fixa, sempre em minúsculo.** Vira a coluna WEBHOOK.ORIGIN. O processamento só procura fichas com ORIGIN = 'toledo' exatamente — Toledo ou TOLEDO são gravados, respondem 200, mas **nunca viram romaneio**. |
| \<CNPJ\> | **CNPJ da empresa, só números.** Fica gravado em WEBHOOK.DOCUMENT apenas como registro — nesta rota ele **não é validado** nem usado para escolher a base. |
| \<TOKEN\> | **Token do banco do cliente** (campo Token na tela Registro de Banco). É **ele que decide em qual base a ficha é gravada**. Token errado = erro 500. |
| **Método** | POST |
| **Cabeçalho** | Content-Type: application/json. **Sem** autenticação (não precisa de Bearer/JWT). |
| **Corpo** | JSON da pesagem (ver [seção 05](#json)). |
| **Resposta de sucesso** | 200 com o corpo ok. Significa só que a ficha **entrou na fila** — não que o romaneio já foi gerado. |
### Passo a passo
1. **Descobrir o endereço do servidor**
> IP e porta do Orion Horse na rede da balança. Testar do computador do Guardian (navegador ou ping) que o endereço responde.
2. **Pegar CNPJ e Token**
> No Orion Horse, aba de bancos → abrir o banco do cliente (**Registro de Banco**): copiar o **Documento** (CNPJ) e o **Token**.
3. **Marcar "Usa Balança Pesagem = Sim" (obrigatório)**
> Na mesma tela **Registro de Banco**. Grava SERVER_DATABASES.USA_BALANCA_TOLEDO = 'S'. Sem isso a ficha é recebida (200 ok), mas o processamento **nunca olha essa base**. Vale na hora ao salvar — não precisa reiniciar o servidor.
4. **Empresa e Usuário de notificação (recomendado)**
> Seção Notificações de Usuário da mesma tela, mais abaixo. As listas só carregam depois de clicar no botão de **testar a conexão** (ele fica verde, Conectado!); então escolher a **Empresa para notificação** e o **Usuário para notificação** e clicar em **Salvar**. Define **só** quem recebe o recado quando a ficha gera romaneio incompleto ou dá erro (EMPRESA_NOTIFICATION / USER_NOTIFICATION). Não muda a empresa do romaneio. Sem isso o romaneio gera do mesmo jeito, mas **os erros ficam silenciosos** (só aparecem consultando a tabela WEBHOOK).

**Orion Horse → Banco de Dados:** na Listagem de Bancos, clicar no banco do cliente para abrir o Registro de Banco. (Tokens desfocados de propósito.)

**Registro de Banco:** “Usa Balança Pesagem” em **Sim** (destaque em vermelho), **Documento** (CNPJ da URL) e **Token** (último trecho da URL; o ícone ao lado copia o valor). Depois de alterar, clicar em **Salvar**. (Token desfocado de propósito.)

**Notificações de Usuário** (mesma tela, mais abaixo): primeiro testar a conexão (**Conectado!**), depois escolher a **Empresa para notificação** e o **Usuário para notificação** — quem recebe os recados da balança. A empresa de notificação é só a do recado; não precisa ser a empresa do romaneio (0201).
5. **Configurar o Guardian**
> No Toledo Guardian, cadastrar a URL montada como destino do webhook: método **POST**, corpo **JSON**, sem autenticação.
**Print pendente:** Toledo Guardian → tela de configuração do webhook/integração com a URL do Orion preenchida e o método POST. (salvar como documentacao/img/balanca-toledo/02-guardian-webhook.png)
6. **Conferir os cadastros e o de-para**
> Ver [pré-requisitos](#prereq) abaixo e a [seção 06](#depara).
7. **Fazer uma pesagem de teste**
> Acompanhar com as [consultas SQL](#sql): ficha em WEBHOOK → STATUS vira 1 → romaneio em ROM_ROMANEIO_MS.
### Pré-requisitos na base do cliente
- Tabelas WEBHOOK, API_INTEGRATION, ROM_ROMANEIO_MS (com os campos ...\_ELETRONICA) e ROM_ROMANEIO_FOTOS existentes. Se a WEBHOOK não existir, a base é pulada sem aviso.
- **Empresa do romaneio** cadastrada em EMPRESAS (a que vem no campo Empresa do JSON; se vier vazio, **0201**).
- **Pedido de venda** do tipo Pedido, situação **Liberado a Faturar**, não cancelado, na mesma empresa, com o número enviado em PedidoNumero e o mesmo item da pesagem.
- **Item** (matéria-prima) cadastrado em ITENS, na empresa dona dos itens.
- **Motorista** cadastrado em Clientes/Fornecedores com o CPF que a balança envia.
- **Transportadora** cadastrada em Clientes/Fornecedores com o CNPJ que a balança envia (ou no pedido).
- **Veículo** cadastrado em Veículos com a placa que a balança envia.
**Print pendente:** ERP → Pedido de venda usado no teste, mostrando número, tipo Pedido, situação Liberado a Faturar e o item. (salvar como documentacao/img/balanca-toledo/03-pedido-liberado.png)
## 03 · Etapa 1 — Recebimento da ficha
A rota POST v1/webhooktoledolocal/:origin/:document/:tokendatabase faz **apenas** isto:
1. Abre a conexão com a base do **token da URL** (procura o token na lista de bancos do servidor).
2. Confere que origin, token, document e o corpo não estão vazios.
3. Insere **uma linha nova** em WEBHOOK com o corpo **exatamente como chegou**.
4. Responde ok.
Não valida o conteúdo da ficha, não procura duplicidade e não gera nada. Toda pesagem enviada vira uma linha nova, mesmo se for repetida.
### O que é gravado em WEBHOOK
| **Coluna** | **Valor** |
|-------------------|--------------------------------------|
| ID | Automático (sequência). |
| STATUS | 0 = pendente. |
| REGISTRATION_DATE | Data/hora em que o servidor recebeu. |
| ORIGIN | 2º trecho da URL (toledo). |
| DOCUMENT | 3º trecho da URL (CNPJ). |
| TOKEN_DATABASE | 4º trecho da URL (token). |
| CONTENT | O JSON da balança, sem alteração. |
### Respostas de erro possíveis
| **HTTP** | **Corpo** | **Causa** |
|----------|----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
| 400 | Invalid JSON | O corpo não é JSON válido nem depois de o servidor dobrar as barras invertidas (ex.: aspas faltando, vírgula sobrando). |
| 400 | {"erro":"content não informado."} | Corpo vazio. |
| 500 | {"erro":"Banco de dados nao localizado para o token: …"} | Token da URL não está cadastrado neste servidor. |
| 500 | Outra mensagem | Banco do cliente fora do ar, sem a tabela WEBHOOK, etc. |
| 404 | — | URL errada (faltando um trecho, v1 errado) ou servidor desatualizado. |
> 💡 **Dica:** O Guardian manda caminhos Windows com barra simples (\\servidor\imagens\1.jpg), o que não é JSON válido. O servidor tolera: se o JSON não abrir, ele dobra todas as barras e tenta de novo, tanto na chegada quanto no processamento. Não é preciso configurar nada.
## 04 · Etapa 2 — Fila e processamento automático
Dentro do Orion Horse roda um relógio interno (cron). A cada **15 segundos** ele percorre **todos** os bancos cadastrados no servidor e, para cada um:
1. Se USA_BALANCA_TOLEDO ≠ 'S' → pula, **sem nem conectar**.
2. Conecta na base. Se não existe a tabela WEBHOOK → pula.
3. Verifica se há ficha pendente: select first 1 1 from WEBHOOK where ORIGIN = 'toledo' and STATUS = 0. Se não há → pula.
4. Lê todas as pendentes, **em ordem de ID** (ordem de chegada): select ID, CONTENT from WEBHOOK where ORIGIN = 'toledo' and STATUS = 0 order by ID.
5. Processa uma a uma (etapas 3 a 7). Erro em uma ficha não impede as próximas, e erro em uma base não impede as outras bases.
### Status da ficha (WEBHOOK.STATUS)
| **Status** | **Significado** | **Volta a ser processada?** |
|------------|----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| 0 | Pendente — ainda não processada. | Sim, no próximo ciclo de 15 s. |
| 1 | Processada com sucesso: criou o romaneio, completou a saída, ou era uma entrada repetida (nada a fazer). | Não. |
| 2 | Erro — o romaneio **não** foi gravado (tudo foi desfeito). | **Não.** Fica parada até alguém corrigir a causa e voltar o status para 0 (ver [consulta 7](#sql-reprocessar)). |
**Print pendente:** IBExpert (ou outra ferramenta SQL) com o resultado da consulta 1 da seção 10: fichas com ORIGIN toledo e seus STATUS. (salvar como documentacao/img/balanca-toledo/04-webhook-fila.png)
> ⚠️ **Atenção:** O motivo do erro de uma ficha **não** é gravado no log do servidor nem na tabela WEBHOOK. Ele só aparece no **recado** ao usuário de notificação. Se a notificação não estiver configurada, só dá para ver que a ficha ficou com STATUS = 2; para descobrir a causa é preciso conferir a ficha manualmente contra a [tabela de problemas](#problemas). O log do servidor só registra falhas da base inteira (ex.: não conseguiu conectar), com o texto "Erro ao processar balanca Toledo".
## 05 · Etapa 3 — Leitura do JSON
Nomes dos campos **exatamente** como abaixo (maiúsculas e minúsculas importam, sem espaços). Campo ausente ou com nome diferente é tratado como vazio. Todos os valores chegam como texto.
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 19%" />
<col style="width: 19%" />
<col style="width: 27%" />
</colgroup>
<thead>
<tr class="header">
<th><strong>Campo do JSON</strong></th>
<th><strong>Formato / exemplo</strong></th>
<th><strong>Como é tratado</strong></th>
<th><strong>Vai para</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td colspan="4"><strong>Identificação</strong></td>
</tr>
<tr class="even">
<td>Codigo</td>
<td>Nº do ticket. "0031502"</td>
<td><strong>Obrigatório.</strong> É a chave que liga entrada e saída. Cortado em 10 caracteres.</td>
<td>ROMANEIO_NUMERO_PESAGEM</td>
</tr>
<tr class="odd">
<td>Empresa</td>
<td>"0201", "201" ou "0201 - NOME"</td>
<td>Pega só o código e completa com zeros até 4 dígitos. Vazio → <strong>0201</strong>.</td>
<td>EMPRESA_CODIGO e filtro do pedido</td>
</tr>
<tr class="even">
<td>PedidoNumero</td>
<td>"1669" ou "0000001669"</td>
<td>Se for só números e tiver menos de 10 dígitos, completa com zeros à esquerda até 10.</td>
<td>Busca do pedido; ROMANEIO_NUMERO_PEDIDO</td>
</tr>
<tr class="odd">
<td colspan="4"><strong>Material</strong></td>
</tr>
<tr class="even">
<td>ItemReduzido</td>
<td>"000004"</td>
<td>Código do item <strong>no Teorema</strong>. Se vier, tem prioridade sobre CodigoMaterial e <strong>dispensa o de-para</strong>.</td>
<td>Item</td>
</tr>
<tr class="odd">
<td>CodigoMaterial</td>
<td>"4", "000004"</td>
<td>Código do material na balança. Passa pelo de-para TOLEDO_MATERIAL; se não houver de-para, é usado como o próprio código do item.</td>
<td>Item</td>
</tr>
<tr class="even">
<td>NomeMaterial</td>
<td>"BRITA 1"</td>
<td>Só usado como descrição se o item não for encontrado no cadastro.</td>
<td>ITEM_DESCRICAO (reserva)</td>
</tr>
<tr class="odd">
<td colspan="4"><strong>Veículo, motorista e transportadora</strong></td>
</tr>
<tr class="even">
<td>PlacaVeiculo</td>
<td>"BDA3H53", "BDA-3H53"</td>
<td>Para a busca: maiúsculo, sem traço e sem espaço. Gravada como veio (10 caracteres).</td>
<td>ROMANEIO_PLACA, ROMANEIO_PLACA_ELETRONICA, busca do veículo, fotos</td>
</tr>
<tr class="odd">
<td>PlacaCarreta</td>
<td>—</td>
<td>Lido, <strong>não usado</strong>.</td>
<td>—</td>
</tr>
<tr class="even">
<td>TagAssociado</td>
<td>—</td>
<td>Lido, <strong>não usado</strong>.</td>
<td>—</td>
</tr>
<tr class="odd">
<td>NomeMotorista</td>
<td>"JOÃO DA SILVA"</td>
<td>Texto livre, 70 caracteres.</td>
<td>ROMANEIO_MOTORISTA</td>
</tr>
<tr class="even">
<td>CPFMotorista</td>
<td>"036.529.159-49"</td>
<td>Usado só com os números para achar o cadastro.</td>
<td>Busca do motorista</td>
</tr>
<tr class="odd">
<td>Transportadora</td>
<td>Nome</td>
<td>Só usado como chave do de-para quando o CNPJ vier vazio.</td>
<td>Busca da transportadora</td>
</tr>
<tr class="even">
<td>CNPJTransportadora</td>
<td>"12.345.678/0001-90"</td>
<td>Usado só com os números.</td>
<td>Busca da transportadora</td>
</tr>
<tr class="odd">
<td colspan="4"><strong>Pesos (em kg, vírgula decimal)</strong></td>
</tr>
<tr class="even">
<td>Bruto</td>
<td>"33120,0"</td>
<td rowspan="3">Aceita 33120,0 e 33.120,0. <strong>Dividido por 1000</strong>: o romaneio é gravado em <strong>toneladas</strong> (33120 kg → 33,12). Valor inválido = 0.</td>
<td>ROMANEIO_PESO_BRUTO, ROMANEIO_PESOB_ELETRONICA</td>
</tr>
<tr class="odd">
<td>Tara</td>
<td>"13120,0"</td>
<td>ROMANEIO_PESO_TARA, ROMANEIO_PESOT_ELETRONICA</td>
</tr>
<tr class="even">
<td>Liquido</td>
<td>"20000,0"</td>
<td>ROMANEIO_PESO_LIQUIDO, ROMANEIO_PESO_BALANCA</td>
</tr>
<tr class="odd">
<td>PesagemInicial</td>
<td>"13120,0"</td>
<td>Não é gravado.</td>
<td>—</td>
</tr>
<tr class="even">
<td>PesagemFinal</td>
<td>"33120,0"</td>
<td><strong>Decide se a ficha é de entrada ou de saída</strong>: vazio ou zero = entrada; maior que zero = saída. Não é gravado.</td>
<td>—</td>
</tr>
<tr class="odd">
<td colspan="4"><strong>Datas (dd/mm/aaaa hh:mm:ss)</strong></td>
</tr>
<tr class="even">
<td>DataPesagemInicial</td>
<td>"12/08/2026 08:37:27"</td>
<td>Formato inválido ou vazio = usa a data/hora do processamento.</td>
<td>Data de emissão, hora de entrada</td>
</tr>
<tr class="odd">
<td>DataPesagemFinal</td>
<td>"12/08/2026 08:45:45"</td>
<td>Formato inválido ou vazio = sem hora de saída na criação; na saída usa a hora do processamento.</td>
<td>Hora de saída</td>
</tr>
<tr class="even">
<td colspan="4"><strong>Fotos (caminho do arquivo)</strong></td>
</tr>
<tr class="odd">
<td>FotoTraseiraaposPesagemInicial<br />
FotoSuperioraposPesagemInicial<br />
FotoDianteiraaposPesagemInicial<br />
FotoOCRaposPesagemInicial</td>
<td>Caminho Windows</td>
<td rowspan="2">Ver <a href="#fotos">seção 08</a>. Vazio = foto não gravada.</td>
<td rowspan="2">ROM_ROMANEIO_FOTOS</td>
</tr>
<tr class="even">
<td>FotoTraseiraaposPesagemFinal<br />
FotoSuperioraposPesagemFinal<br />
FotoDianteiraaposPesagemFinal<br />
FotoOCRaposPesagemFinal</td>
<td>Caminho Windows</td>
</tr>
</tbody>
</table>
### Exemplo de ficha de saída (completa)
{
"Empresa": "0201",
"Codigo": "0031502",
"PlacaVeiculo": "BDA3H53",
"PlacaCarreta": "",
"TagAssociado": "",
"PedidoNumero": "0000001641",
"CodigoMaterial": "000004",
"NomeMaterial": "BRITA 1",
"NomeMotorista": "JOAO DA SILVA",
"CPFMotorista": "036.529.159-49",
"Transportadora": "TRANSPORTES EXEMPLO",
"CNPJTransportadora": "12.345.678/0001-90",
"PesagemInicial": "13120,0",
"DataPesagemInicial": "12/08/2026 08:37:27",
"PesagemFinal": "33120,0",
"DataPesagemFinal": "12/08/2026 08:45:45",
"Bruto": "33120,0", "Tara": "13120,0", "Liquido": "20000,0",
"FotoTraseiraaposPesagemInicial": "\\servidor\imagens\31502\1.JPG",
… demais fotos …
}
Na ficha de **entrada** o Guardian manda os mesmos campos, com PesagemFinal, DataPesagemFinal e as fotos finais vazios.
## 06 · Etapa 4 — De-para e consultas
Antes de gravar, o servidor traduz o que veio da balança para os códigos do Teorema. Cada informação tem uma **ordem de tentativa**: a primeira que encontrar vence. O que não for encontrado fica em branco no romaneio.
### A tabela de de-para API_INTEGRATION
Tabela da base do cliente. Cada linha diz: "na empresa X, quando a balança mandar Y, use o código Z do Teorema". O de-para é **opcional** em todos os casos — ele serve para **forçar** um valor quando a busca automática não serve.
| **Coluna** | **Tamanho** | **Conteúdo** |
|-------------|-------------|------------------------------------------------------------|
| COMPANY | 4 | Empresa do romaneio (ex.: 0201). |
| ORIGIN | 20 | Tipo da tradução (lista abaixo). |
| ORIGIN_KEY | 50 | O valor que vem da balança, ou DEFAULT para valores fixos. |
| DESTINY_KEY | 50 | O código do Teorema. |
| ORIGIN | ORIGIN_KEY | DESTINY_KEY | **Quando usar** |
|----------------------|---------------------------------------------------|---------------------|-------------------------------------------------------------------------------------------|
| TOLEDO_MATERIAL | CodigoMaterial como vem da balança | ITEM_REDUZIDO | Quando o código do material na balança é diferente do código reduzido do item no Teorema. |
| TOLEDO_OPERACAO | DEFAULT | OPERACAO_CODIGO | Para usar outra operação no lugar da padrão 0035. |
| TOLEDO_CLIENTE | DEFAULT | CLIFOR_CODIGO | Cliente usado quando **não** há pedido. Com pedido, vale o cliente do pedido. |
| TOLEDO_LOCALESTOQUE | DEFAULT | LOCALESTOQUE_CODIGO | Único jeito de preencher o local de estoque. |
| TOLEDO_FORNECEDOR | DEFAULT | CLIFOR_CODIGO | Único jeito de preencher o fornecedor. |
| TOLEDO_TRANSPORTADOR | CNPJ só números (ou o nome, se o CNPJ vier vazio) | CLIFOR_CODIGO | Quando o CNPJ da balança não bate com o cadastro. |
| TOLEDO_MOTORISTA | CPF só números | CLIFOR_CODIGO | Quando o CPF da balança não bate com o cadastro. |
| TOLEDO_VEICULO | Placa como vem da balança | VEICULO_CODIGO | Quando a placa não bate com o cadastro. |
> **Nota:** A busca no de-para compara ORIGIN_KEY exatamente (só tira espaços das pontas). Para material e placa, a chave é o texto **como a balança envia** ("4" ≠ "000004"; "BDA-3H53" ≠ "BDA3H53"). Para CPF e CNPJ, a chave é **só os números**. E COMPANY tem que ser a empresa do romaneio.
### Empresas usadas nas buscas
Primeiro o servidor define a **empresa do romaneio** (campo Empresa do JSON, ou 0201). Depois lê na tabela EMPRESAS de quais empresas ela usa os cadastros:
select EMPRESA_USA_CLIENTES_DE, EMPRESA_USA_ITENS_DE, EMPRESA_USA_VEICULOS_DE
from EMPRESAS where EMPRESA_CODIGO = :empresa_do_romaneio
| **Nome neste manual** | **Vem de** | **Usada para** |
|-------------------------|---------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| **Empresa de clientes** | EMPRESA_USA_CLIENTES_DE (vazio = a própria) | Buscar motorista e transportadora; empresa gravada para cliente (sem pedido), transportadora, fornecedor e motorista. |
| **Empresa de itens** | EMPRESA_USA_ITENS_DE (vazio = a própria) | Validar o item; empresa do item (sem pedido). |
| **Empresa de veículos** | EMPRESA_USA_VEICULOS_DE (vazio = a própria) | Buscar o veículo; empresa do veículo. |
### Ordem de resolução de cada informação
<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 48%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th><strong>Informação</strong></th>
<th><strong>Ordem de tentativa</strong></th>
<th><strong>Se nada encontrar</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Item</strong></td>
<td><ol type="1">
<li><p>ItemReduzido do JSON.</p></li>
<li><p>De-para TOLEDO_MATERIAL com o CodigoMaterial.</p></li>
<li><p>O próprio CodigoMaterial.</p></li>
</ol>
<p>Se o resultado for só números com menos de 6 dígitos, completa com zeros (4 → 000004). Depois confere se existe: select first 1 1 from ITENS where EMPRESA_CODIGO = :empresa_itens and ITEM_REDUZIDO = :item. Se não existe, o item é <strong>descartado</strong> (fica vazio) e a busca do pedido é feita sem item.</p>
<p>Se ainda estiver vazio: usa o item do <strong>pedido de venda</strong>.</p></td>
<td>Romaneio sem item + recado "sem item".</td>
</tr>
<tr class="even">
<td><strong>Pedido de venda</strong></td>
<td>Só procura se PedidoNumero veio. Consulta descrita <a href="#pedido">logo abaixo</a>.</td>
<td>Campos do pedido em branco + recado "pedido nao encontrado".</td>
</tr>
<tr class="odd">
<td><strong>Cliente</strong></td>
<td><ol type="1">
<li><p>Cliente do <strong>pedido</strong> (VENDAS_MS.CLIFOR_CODIGO + EMPRESA_CLIFOR).</p></li>
<li><p>De-para TOLEDO_CLIENTE / DEFAULT.</p></li>
</ol></td>
<td>Romaneio sem cliente + recado "sem cliente".</td>
</tr>
<tr class="even">
<td><strong>Transportadora</strong></td>
<td><ol type="1">
<li><p>De-para TOLEDO_TRANSPORTADOR com o CNPJ (só números) — ou o nome, se o CNPJ vier vazio.</p></li>
<li><p>Cadastro de Clientes/Fornecedores pelo CNPJ (ver consulta abaixo).</p></li>
<li><p>Transportadora do <strong>pedido</strong> (VENDAS_MS.TRANSPORTADOR_CLIFOR_CODIGO).</p></li>
</ol></td>
<td>Em branco (sem recado).</td>
</tr>
<tr class="odd">
<td><strong>Motorista</strong></td>
<td><ol type="1">
<li><p>De-para TOLEDO_MOTORISTA com o CPF (só números).</p></li>
<li><p>Cadastro de Clientes/Fornecedores pelo CPF.</p></li>
</ol></td>
<td>Em branco + recado "sem motorista" (CPF vazio) ou "motorista nao cadastrado".</td>
</tr>
<tr class="even">
<td><strong>Veículo</strong></td>
<td><ol type="1">
<li><p>De-para TOLEDO_VEICULO com a placa como veio.</p></li>
<li><p>Cadastro de veículos pela placa normalizada.</p></li>
</ol></td>
<td>Em branco + recado "sem placa" ou "veiculo nao cadastrado".</td>
</tr>
<tr class="odd">
<td><strong>Operação</strong></td>
<td><ol type="1">
<li><p>De-para TOLEDO_OPERACAO / DEFAULT.</p></li>
<li><p>Fixa 0035 (PESAGEM SAÍDA).</p></li>
</ol></td>
<td>Nunca fica vazia.</td>
</tr>
<tr class="even">
<td><strong>Local de estoque</strong></td>
<td>Só de-para TOLEDO_LOCALESTOQUE / DEFAULT.</td>
<td>Em branco.</td>
</tr>
<tr class="odd">
<td><strong>Fornecedor</strong></td>
<td>Só de-para TOLEDO_FORNECEDOR / DEFAULT.</td>
<td>Em branco.</td>
</tr>
</tbody>
</table>
### Busca de motorista e transportadora no cadastro
Compara o documento cadastrado sem pontos, traços e barras com os números enviados pela balança, na **empresa de clientes**:
select first 1 CLIFOR_CODIGO from CLIENTES_FORNECEDORES
where EMPRESA_CODIGO = :empresa_clientes
and REPLACE(REPLACE(REPLACE(CLIFOR_DOCUMENTO, '.', ''), '-', ''), '/', '') = :cpf_ou_cnpj_so_numeros
Se houver mais de um cadastro com o mesmo documento, pega o primeiro que o banco devolver.
### Busca do veículo no cadastro
select first 1 VEICULO_CODIGO from TRA_VEICULOS
where EMPRESA_CODIGO = :empresa_veiculos
and REPLACE(REPLACE(UPPER(VEICULO_PLACA), '-', ''), ' ', '') = :placa_maiuscula_sem_traco
### Busca do pedido de venda
select first 2 M.TRANSACAO, M.CONDICAO_CODIGO, M.VENDA_VALOR_FRETE,
M.TRANSPORTADOR_CLIFOR_CODIGO, M.EMPRESA_CLIFOR, M.CLIFOR_CODIGO,
D.VENDA_SEQUENCIA, D.VENDA_VALOR_UNITARIO, D.EMPRESA_ITEM, D.ITEM_REDUZIDO,
LE.LOCALENTREGA_DESCRICAO
from VENDAS_MS M
join VENDAS_DT D on D.TRANSACAO = M.TRANSACAO
left join LOCAL_ENTREGA LE on LE.EMPRESA_CLIFOR = M.EMPRESA_CLIFOR
and LE.CLIFOR_CODIGO = M.CLIFOR_CODIGO
and LE.LOCALENTREGA_CODIGO = M.LOCALENTREGA_CODIGO
where M.EMPRESA_MOVTO = :empresa_do_romaneio
and M.VENDA_NUMERO = :pedido_com_10_digitos
and M.VENDA_TIPO = 'P' -- Pedido
and M.VENDA_SITUACAO = 'L' -- Liberado a Faturar
and M.VENDA_DATA_CANCELAMENTO is null
and D.ITEM_REDUZIDO = :item -- só quando o item foi resolvido antes
order by M.TRANSACAO
- **Não achou** → nenhum campo do pedido é preenchido.
- **Achou dois pedidos diferentes** → o servidor não escolhe: trata como não encontrado.
- **Achou um** → traz os campos abaixo para o romaneio.
| **Do pedido** | **Para o romaneio** |
|------------------------------------------|----------------------------------------------------------------|
| VENDAS_MS.TRANSACAO | TRANSACAO_PEDIDO |
| VENDAS_DT.VENDA_SEQUENCIA | ROMANEIO_NUMERO_SEQUENCIA |
| VENDAS_DT.VENDA_VALOR_UNITARIO | ITEM_PRECO_UNITARIO |
| VENDAS_MS.VENDA_VALOR_FRETE | ROMANEIO_VALOR_FRETE |
| VENDAS_MS.CONDICAO_CODIGO | CONDICAO_CODIGO |
| VENDAS_MS.CLIFOR_CODIGO / EMPRESA_CLIFOR | CLIFOR_CODIGO / EMPRESA_CLIFOR (sempre, substitui o de-para) |
| VENDAS_DT.ITEM_REDUZIDO / EMPRESA_ITEM | ITEM_REDUZIDO / EMPRESA_ITEM (só se o item ainda estava vazio) |
| VENDAS_MS.TRANSPORTADOR_CLIFOR_CODIGO | CLIFOR_CODIGO_TRANSPORTADORA (só se ainda estava vazia) |
| LOCAL_ENTREGA.LOCALENTREGA_DESCRICAO | ROMANEIO_LOCAL_ENTREGA (texto) |
> ⚠️ **Atenção:** Se o material da balança resolve para um item que **existe** no cadastro, mas é **diferente** do item do pedido, a busca do pedido não acha nada (o filtro do item elimina o pedido). O romaneio sai com o item da balança e sem cliente, preço, frete e condição.
## 07 · Etapa 5 — Gravação do romaneio
### Entrada, saída e saída sem entrada
O servidor procura se já existe romaneio para o ticket:
select first 1 TRANSACAO from ROM_ROMANEIO_MS
where EMPRESA_CODIGO = :empresa_do_romaneio
and ROMANEIO_NUMERO_PESAGEM = :Codigo
| **Ficha** | **Romaneio do ticket já existe?** | **O que acontece** |
|-----------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|
| Entrada | Não | **Cria** o romaneio (todos os campos da tabela abaixo), sem hora de saída, com as fotos de entrada. Gera recado se ficou incompleto. |
| Entrada | Sim | Nada (entrada repetida). Ficha marcada como processada. |
| Saída | Sim | **Completa** o romaneio: só pesos, hora de saída e fotos de saída (ver [abaixo](#saida)). Cliente, item, pedido etc. **não** são recalculados. |
| Saída | Não | **Cria** o romaneio já completo, com todas as fotos (caso a entrada não tenha chegado ou tenha dado erro). Gera recado se ficou incompleto. |
Tudo isso roda dentro de uma transação: se qualquer gravação falhar, nada do romaneio fica gravado e a ficha vai para STATUS = 2.
### Numeração
- TRANSACAO: contador global TRANSACAO (procedure PAT_TEO_CONTADOR, empresa 0).
- ROMANEIO_NUMERO: contador ROM_ROMANEIO_MS da empresa do romaneio, com 10 dígitos (0000081036) — o mesmo usado pela tela do ERP.
- Os contadores são reservados **antes** de gravar. Se a gravação falhar, o número fica "pulado".
**Print pendente:** ERP → Romaneio de Matéria-Prima gerado pela balança, mostrando nº do romaneio, nº da pesagem (ticket), pedido, cliente, item, placa, motorista e pesos. (salvar como documentacao/img/balanca-toledo/05-romaneio-erp.png)
### Mapa completo de ROM_ROMANEIO_MS na criação
Legenda: **JSON** balança · **Pedido** pedido de venda · **Cadastro** busca em cadastro · **De-para** API_INTEGRATION · **Fixo** valor fixo/calculado.
| **Coluna** | **Valor gravado** | **Fonte** |
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|-------------------------------------|
| **Identificação** | | |
| TRANSACAO | Contador global | **Fixo** |
| EMPRESA_CODIGO | Empresa do JSON, ou 0201 | **JSON** |
| ROMANEIO_NUMERO | Contador do romaneio da empresa (10 dígitos) | **Fixo** |
| ROMANEIO_NUMERO_PESAGEM | Codigo (ticket) | **JSON** |
| ROMANEIO_SITUACAO | A (ativo) | **Fixo** |
| ROMANEIO_OBSERVACOES | "Importado automaticamente da balança Toledo." | **Fixo** |
| **Pedido de venda** | | |
| ROMANEIO_NUMERO_PEDIDO | PedidoNumero com 10 dígitos — gravado **mesmo se o pedido não foi encontrado**; vazio = NULL | **JSON** |
| TRANSACAO_PEDIDO | VENDAS_MS.TRANSACAO, ou NULL | **Pedido** |
| ROMANEIO_NUMERO_SEQUENCIA | VENDAS_DT.VENDA_SEQUENCIA, ou NULL | **Pedido** |
| CONDICAO_CODIGO | VENDAS_MS.CONDICAO_CODIGO, ou NULL | **Pedido** |
| ROMANEIO_LOCAL_ENTREGA | Descrição do local de entrega do pedido (70), ou NULL | **Pedido** |
| ITEM_PRECO_UNITARIO | VENDAS_DT.VENDA_VALOR_UNITARIO, ou 0 | **Pedido** |
| ROMANEIO_VALOR_FRETE | VENDAS_MS.VENDA_VALOR_FRETE, ou 0 | **Pedido** |
| **Cliente e item** | | |
| EMPRESA_CLIFOR | Do pedido; sem pedido, a empresa de clientes | **Pedido** **Fixo** |
| CLIFOR_CODIGO | Do pedido; sem pedido, de-para TOLEDO_CLIENTE; senão NULL | **Pedido** **De-para** |
| EMPRESA_ITEM | Do pedido se o item veio dele; senão a empresa de itens | **Pedido** **Fixo** |
| ITEM_REDUZIDO | Ver ordem de resolução; NULL se não achou | **JSON** **De-para** **Pedido** |
| ITEM_DESCRICAO | ITENS.ITEM_DESCRICAO; se vazio, NomeMaterial | **Cadastro** **JSON** |
| OPERACAO_CODIGO | De-para TOLEDO_OPERACAO ou 0035 | **De-para** **Fixo** |
| LOCALESTOQUE_CODIGO | De-para TOLEDO_LOCALESTOQUE, ou NULL | **De-para** |
| **Transporte** | | |
| ROMANEIO_PLACA | PlacaVeiculo (10) | **JSON** |
| EMPRESA_VEICULO / VEICULO_CODIGO | Empresa de veículos / veículo achado, ou NULL | **De-para** **Cadastro** |
| ROMANEIO_MOTORISTA | NomeMotorista (70) | **JSON** |
| EMPRESA_CLIFOR_MOTORISTA / CLIFOR_CODIGO_MOTORISTA | Empresa de clientes / motorista achado pelo CPF, ou NULL | **De-para** **Cadastro** |
| EMPRESA_CLIFOR_TRANSPORTADORA / CLIFOR_CODIGO_TRANSPORTADORA | Empresa de clientes / transportadora achada, ou NULL | **De-para** **Cadastro** **Pedido** |
| EMPRESA_CLIFOR_FORNECEDOR / CLIFOR_CODIGO_FORNECEDOR | Empresa de clientes / de-para TOLEDO_FORNECEDOR, ou NULL | **De-para** |
| **Datas e horas** | | |
| ROMANEIO_DATA_EMISSAO | Data de DataPesagemInicial (ou hoje) | **JSON** |
| ROMANEIO_DATA_LANCAMENTO | Data do processamento | **Fixo** |
| ROMANEIO_HORA_ENTRADA | Hora de DataPesagemInicial | **JSON** |
| ROMANEIO_HORA_SAIDA | Hora de DataPesagemFinal; NULL na entrada | **JSON** |
| **Pesos (toneladas = kg ÷ 1000)** | | |
| ROMANEIO_PESO_BRUTO | Bruto ÷ 1000 | **JSON** |
| ROMANEIO_PESO_TARA | Tara ÷ 1000 | **JSON** |
| ROMANEIO_PESO_LIQUIDO | Liquido ÷ 1000 | **JSON** |
| ROMANEIO_PESO_BALANCA | Liquido ÷ 1000 | **JSON** |
| ROMANEIO_PESO_DESCONTO | 0 | **Fixo** |
| **Pesagem eletrônica** | | |
| ROMANEIO_PESAGEM_ELETRONICA | S | **Fixo** |
| ROMANEIO_DADOS_ALTERADOS | N | **Fixo** |
| ROMANEIO_DATA_ELETRONICA | Data da pesagem inicial | **JSON** |
| ROMANEIO_HORAB_ELETRONICA | Hora da pesagem inicial | **JSON** |
| ROMANEIO_HORAT_ELETRONICA | Hora da pesagem final (ou a inicial, se não houver) | **JSON** |
| ROMANEIO_PESOB_ELETRONICA | Bruto ÷ 1000 | **JSON** |
| ROMANEIO_PESOT_ELETRONICA | Tara ÷ 1000 | **JSON** |
| ROMANEIO_PLACA_ELETRONICA | PlacaVeiculo | **JSON** |
| **Custos** | | |
| ROMANEIO_CUSTO_REAL, \_DIRETO, \_SIMPLES, \_USUARIO, \_UNITARIO_LIQ, \_PRODUTO, \_MEDIO, \_MEDIO_GER | 0 | **Fixo** |
### O que a saída altera num romaneio existente
| **Coluna** | **Novo valor** |
|-----------------------------------------------|------------------------------------------------|
| ROMANEIO_PESO_BRUTO | Bruto ÷ 1000 |
| ROMANEIO_PESO_TARA | Tara ÷ 1000 |
| ROMANEIO_PESO_LIQUIDO e ROMANEIO_PESO_BALANCA | Liquido ÷ 1000 |
| ROMANEIO_HORA_SAIDA | Hora de DataPesagemFinal (ou do processamento) |
| ROMANEIO_PESOB_ELETRONICA | Bruto ÷ 1000 |
| ROMANEIO_HORAB_ELETRONICA | Hora da saída |
Nada mais muda. Em especial, ROMANEIO_PESOT_ELETRONICA e ROMANEIO_HORAT_ELETRONICA continuam com o que foi gravado na entrada, e cliente/item/pedido/motorista/veículo não são buscados de novo.
## 08 · Etapa 6 — Fotos
O servidor **não copia** as imagens: grava apenas o **caminho** que o Guardian enviou, em ROM_ROMANEIO_FOTOS. Para a foto abrir no ERP, o computador do usuário precisa ter acesso a esse caminho de rede.
| **Coluna** | **Valor** |
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| ID | Automático. |
| TRANSACAO | Transação do romaneio. |
| ROMFOTO_PATH | Caminho normalizado (abaixo), até 255 caracteres. |
| ROMFOTO_DATA / ROMFOTO_HORA | Data/hora da pesagem correspondente (entrada ou saída); sem data, a do processamento. |
| ROMFOTO_PLACA | PlacaVeiculo. |
| ROMFOTO_TIPO | E = traseira/superior/dianteira da entrada · S = traseira/superior/dianteira da saída · O = foto de OCR (entrada ou saída). |
### Normalização do caminho
- Tira todas as barras do começo e decide: se o que sobra começa com letra de unidade (C:, D:…) é caminho local, sem barra na frente; senão é servidor de rede e recebe exatamente \\ na frente.
- Converte tudo para **minúsculo**.
- Foto com caminho vazio não é gravada.
Exemplos: \Servidor\Imagens\1.JPG → \\servidor\imagens\1.jpg · \\C:\Fotos\1.JPG → c:\fotos\1.jpg.
Na criação pela entrada gravam-se as 4 fotos de entrada; na saída, as 4 de saída; na saída sem entrada prévia, as 8.
**Print pendente:** ERP → mesmo romaneio, na parte de fotos, mostrando as fotos de entrada e saída abertas. (salvar como documentacao/img/balanca-toledo/06-romaneio-fotos.png)
## 09 · Etapa 7 — Recados (avisos)
Gravados em TEO_RECADOS para o usuário de notificação do Registro de Banco. Aparecem na tela de recados do ERP. Se empresa **ou** usuário de notificação estiver vazio, nenhum recado é gravado. Falha ao gravar o recado nunca impede o romaneio.
| **Coluna** | **Valor** |
|---------------------------|------------------------------------|
| EMPRESA_CODIGO | Empresa de notificação. |
| RECADO_CODIGO | Contador TEO_RECADOS (10 dígitos). |
| RECADO_DEQUEM | BALANCA |
| USUARIO_CODIGO | Usuário de notificação. |
| RECADO_DATA / RECADO_HORA | Momento do processamento. |
| RECADO_OBSERVACAO | Mensagem (abaixo). |
| RECADO_LIDO | N |
### Mensagens possíveis
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="header">
<th><strong>Mensagem</strong></th>
<th><strong>Quando</strong></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Romaneio <nº> (ticket <cód>) gerado com pendencias; …</td>
<td><p>Romaneio <strong>criado</strong> com falta de dados. Lista de pendências possíveis, separadas por ;:</p>
<ul>
<li><p>sem placa — PlacaVeiculo vazio.</p></li>
<li><p>veiculo nao cadastrado — placa veio, mas não achou veículo.</p></li>
<li><p>sem item — nenhuma fonte deu um item válido.</p></li>
<li><p>sem cliente — sem pedido encontrado e sem de-para de cliente.</p></li>
<li><p>sem motorista — CPFMotorista vazio.</p></li>
<li><p>motorista nao cadastrado — CPF veio, mas não achou cadastro.</p></li>
<li><p>pedido nao encontrado — PedidoNumero veio, mas a busca não achou (ou achou mais de um).</p></li>
</ul>
<p>Não há recado para transportadora, local de estoque ou fornecedor em branco.</p></td>
</tr>
<tr class="even">
<td>Ficha da balanca NAO importada: <motivo></td>
<td>Erro: nada foi gravado e a ficha ficou com STATUS = 2. Exemplos de motivo: JSON da balanca invalido: Codigo (ticket) vazio. · Falha ao gravar romaneio da balanca Toledo: <erro do banco>.</td>
</tr>
</tbody>
</table>
A saída que só completa um romaneio existente **não** gera recado de pendências.
**Print pendente:** ERP → tela de recados com um recado de “BALANCA” aberto (de preferência um com pendências). (salvar como documentacao/img/balanca-toledo/07-recado.png)
## 10 · Consultas SQL para o suporte
Rodar na **base do cliente** (a do token da URL). Trocar os valores de exemplo.
### 1. Últimas fichas recebidas e seus status
select first 50 ID, STATUS, REGISTRATION_DATE, ORIGIN, DOCUMENT,
substring(CONTENT from 1 for 300) as INICIO_JSON
from WEBHOOK
where lower(ORIGIN) = 'toledo'
order by ID desc
Se aparecer ficha com ORIGIN diferente de toledo em minúsculo, a URL do Guardian está errada.
### 2. Fichas paradas (pendentes há mais de 1 minuto, ou com erro)
select ID, STATUS, REGISTRATION_DATE, CONTENT
from WEBHOOK
where ORIGIN = 'toledo'
and (STATUS = 2 or (STATUS = 0 and REGISTRATION_DATE \< dateadd(-1 minute to current_timestamp)))
order by ID
STATUS = 0 parado = o cron não está passando por essa base (flag "Usa Balança Pesagem", servidor parado). STATUS = 2 = erro na ficha.
### 3. Romaneio de um ticket
select TRANSACAO, ROMANEIO_NUMERO, ROMANEIO_NUMERO_PESAGEM, ROMANEIO_NUMERO_PEDIDO, TRANSACAO_PEDIDO,
CLIFOR_CODIGO, ITEM_REDUZIDO, ITEM_DESCRICAO, VEICULO_CODIGO, CLIFOR_CODIGO_MOTORISTA,
CLIFOR_CODIGO_TRANSPORTADORA, ROMANEIO_PESO_BRUTO, ROMANEIO_PESO_TARA, ROMANEIO_PESO_LIQUIDO,
ROMANEIO_DATA_EMISSAO, ROMANEIO_HORA_ENTRADA, ROMANEIO_HORA_SAIDA
from ROM_ROMANEIO_MS
where EMPRESA_CODIGO = '0201'
and ROMANEIO_NUMERO_PESAGEM = '0031502'
ROMANEIO_HORA_SAIDA vazio = só a entrada chegou.
### 4. Fotos do romaneio
select ID, ROMFOTO_TIPO, ROMFOTO_DATA, ROMFOTO_HORA, ROMFOTO_PATH
from ROM_ROMANEIO_FOTOS
where TRANSACAO = 123456
order by ID
### 5. Recados da balança
select first 30 RECADO_DATA, RECADO_HORA, EMPRESA_CODIGO, USUARIO_CODIGO, RECADO_LIDO, RECADO_OBSERVACAO
from TEO_RECADOS
where RECADO_DEQUEM = 'BALANCA'
order by RECADO_DATA desc, RECADO_HORA desc
### 6. De-para configurado
select COMPANY, ORIGIN, ORIGIN_KEY, DESTINY_KEY
from API_INTEGRATION
where ORIGIN starting with 'TOLEDO\_'
order by COMPANY, ORIGIN, ORIGIN_KEY
### Conferir se o pedido seria encontrado
select M.TRANSACAO, M.VENDA_NUMERO, M.VENDA_TIPO, M.VENDA_SITUACAO, M.VENDA_DATA_CANCELAMENTO,
M.EMPRESA_MOVTO, D.ITEM_REDUZIDO, M.CLIFOR_CODIGO
from VENDAS_MS M
join VENDAS_DT D on D.TRANSACAO = M.TRANSACAO
where M.VENDA_NUMERO = '0000001641'
Para ser encontrado: EMPRESA_MOVTO = empresa do romaneio, VENDA_TIPO = 'P', VENDA_SITUACAO = 'L', sem data de cancelamento, e ITEM_REDUZIDO igual ao item da pesagem; e só um pedido atendendo a tudo isso.
### 7. Reprocessar uma ficha com erro
Depois de **corrigir a causa** (cadastro, JSON, etc.), voltar a ficha para pendente. Ela é processada no próximo ciclo de 15 s.
update WEBHOOK set STATUS = 0 where ID = 987 and ORIGIN = 'toledo' and STATUS = 2
> ⚠️ **Atenção:**
> - Não reprocessar ficha com STATUS = 1: se for uma saída, as fotos de saída são gravadas de novo (duplicadas).
> - Ao reprocessar a entrada e a saída do mesmo ticket, deixar as duas com STATUS = 0: elas são processadas por ordem de ID (a entrada primeiro).
> - Romaneio já criado incompleto **não** é corrigido reprocessando a ficha (a entrada repetida não faz nada). Corrigir direto no ERP.
## 11 · Solução de problemas
| **Sintoma** | **Causa provável** | **O que fazer** |
|-----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| **A balança não consegue enviar** | | |
| Guardian dá erro de conexão / timeout | Servidor parado, IP/porta errados, firewall | Confirmar que o serviço Orion Horse está rodando e que o IP:porta abre a partir do computador da balança. |
| Resposta 404 | URL montada errada | Conferir os 4 trechos: /v1/webhooktoledolocal/toledo/\<CNPJ\>/\<TOKEN\>. |
| Resposta 500 "Banco de dados nao localizado para o token" | Token errado ou de outro servidor | Copiar de novo o token do Registro de Banco deste servidor. |
| Resposta 400 "Invalid JSON" | JSON malformado (não é problema de barra) | Pedir o JSON enviado e validar (aspas, vírgulas, chaves). |
| **Recebe** 200 ok**, mas o romaneio não aparece** | | |
| Ficha fica com STATUS = 0 para sempre | \(a\) "Usa Balança Pesagem" = Não; (b) ORIGIN diferente de toledo minúsculo; (c) servidor/serviço parado | Consulta 1: ver o ORIGIN. Conferir a flag no Registro de Banco. Conferir se o servidor está rodando. |
| Ficha com STATUS = 2 | Erro na gravação: ticket (Codigo) vazio, JSON ilegível, erro de banco (campo, FK, trigger) | Ver o recado "Ficha da balanca NAO importada" (consulta 5). Corrigir e reprocessar (consulta 7). |
| Ficha com STATUS = 1, mas não acho o romaneio | Procurando na empresa errada, ou foi uma entrada repetida | Consulta 3 com a empresa do campo Empresa do JSON (ou 0201). |
| **Romaneio gerado com dados faltando** | | |
| Sem cliente, preço, frete, condição | Pedido não encontrado: número errado, pedido não está Liberado a Faturar, cancelado, outra empresa, **item da balança diferente do item do pedido**, ou dois pedidos possíveis | Rodar "Conferir se o pedido seria encontrado". Ver o recado. |
| Sem item | Sem pedido encontrado **e** o material não existe em ITENS (nem via de-para) | Cadastrar o de-para TOLEDO_MATERIAL, ou mandar ItemReduzido, ou corrigir o pedido. |
| Item errado | CodigoMaterial coincide com outro item do Teorema | Cadastrar o de-para TOLEDO_MATERIAL (tem prioridade sobre o código direto). |
| Sem motorista | CPF vazio, ou não há Cliente/Fornecedor com esse CPF na empresa de clientes | Cadastrar o motorista com o CPF, ou de-para TOLEDO_MOTORISTA. |
| Sem veículo | Placa não cadastrada em Veículos na empresa de veículos | Cadastrar o veículo, ou de-para TOLEDO_VEICULO. |
| Sem transportadora | CNPJ não cadastrado e pedido sem transportadora | Cadastrar, ou de-para TOLEDO_TRANSPORTADOR. |
| Sem local de estoque / fornecedor | Só vêm do de-para | Cadastrar TOLEDO_LOCALESTOQUE / TOLEDO_FORNECEDOR com chave DEFAULT. |
| **Valores estranhos** | | |
| Peso 1000 vezes menor (ou maior) que o esperado | O servidor sempre divide por 1000 (kg → t) | Confirmar se a balança manda em kg e se o item é em toneladas. |
| Peso zerado | Peso com formato inesperado (ex.: ponto como decimal: 33120.5) | O formato esperado é vírgula decimal (33120,5). |
| Data de emissão = hoje e hora errada | DataPesagemInicial fora do formato dd/mm/aaaa hh:mm:ss | Ajustar o formato no Guardian. |
| Romaneio com hora de saída vazia | A saída ainda não chegou, ou chegou com outro Codigo / outra empresa | Consulta 1: procurar a ficha de saída do ticket. |
| Dois romaneios para a mesma pesagem | Entrada e saída chegaram com Codigo diferente, ou com Empresa diferente | O ticket e a empresa têm que ser iguais nas duas fichas. |
| Fotos duplicadas | A ficha de saída foi enviada (ou reprocessada) mais de uma vez | Apagar as linhas extras em ROM_ROMANEIO_FOTOS. |
| Foto não abre no ERP | Caminho de rede inacessível do computador do usuário | Conferir permissão/compartilhamento da pasta de imagens do Guardian. |
| Recados não chegam | Empresa ou usuário de notificação em branco | Preencher os dois no Registro de Banco. |
## 12 · Comportamentos importantes e limitações
- **Feito para a Compensa:** a empresa padrão é 0201 e a conversão kg → toneladas é fixa para qualquer cliente. Um cliente novo com item em kg ou outra empresa precisa de ajuste no servidor (e mandar Empresa no JSON).
- **A saída não corrige a entrada:** cliente, item, pedido, motorista e veículo são definidos na criação. Cadastrar o motorista depois da entrada não preenche o romaneio — corrigir no ERP.
- **Reenvio gera linha nova:** o servidor não bloqueia fichas repetidas. Entrada repetida não faz nada; saída repetida regrava pesos e **duplica as fotos de saída**.
- **Ficha com erro não volta sozinha:** STATUS = 2 só é reprocessado manualmente.
- **CNPJ da URL não é conferido** na rota oficial. Quem decide a base é o token.
- **Campos ignorados:** PlacaCarreta, TagAssociado, PesagemInicial (e PesagemFinal, além de decidir entrada/saída).
- **Pedido com um item:** a integração considera um item por pedido; o item da pesagem precisa ser o item do pedido.
- **Busca por documento/placa pega o primeiro:** cadastros duplicados com o mesmo CPF/CNPJ/placa podem levar ao código errado — usar o de-para para forçar.
> **Nota:** Existe também POST v1/webhook/toledo/\<CNPJ\>/\<TOKEN\> no servidor **da Teorema** (orion2), que é a rota **antiga (não usar em cliente novo)**. Nela a ficha é gravada na base central da Teorema, e o servidor do cliente busca as fichas dele **a cada 5 minutos** (pelo CNPJ do Registro de Banco, que nesse caso **precisa** bater com o da URL). Depois disso segue o mesmo processamento a cada 15 s. É mais lenta e depende de internet; o fluxo oficial é a rota webhooktoledolocal direto no servidor do cliente.
## 13 · Referência técnica (código-fonte)
Para quando o caso precisar ir para o desenvolvimento. Caminhos no repositório Source Rio.
| **Parte** | **Arquivo** | **Rotina** |
|--------------------------------------------------------|---------------------------------------------------------------------------|-------------------------------------------------------------------|
| Rota de recebimento | Projects/Desktop/Orion Server Horse/Controller/WebhookTest.Controller.pas | WebhookToledoLocal |
| Gravação na fila | Projects/Desktop/Orion Server Horse/DAO/Webhook.DAO.pas | TWebHook.RegisterHookLocal |
| Tolerância às barras na chegada | Projects/Desktop/Orion Server Horse/Lib/jhonson/src/Horse.Jhonson.pas | middleware JSON |
| Cron de 15 s | Projects/Desktop/Orion Server Horse/Resources/CronJob.Resource.pas | DoCronCycle, ProcessBalancaAllDatabases |
| Flag "Usa Balança Pesagem" | Projects/Desktop/Orion Server Horse/View/uFrmHome.pas | combo CBXPesagem → SERVER_DATABASES.USA_BALANCA_TOLEDO |
| Importador (de-para, pedido, gravação, fotos, recados) | Default/Common/Pitagoras.Balance.DB.pas | TToledoBalanceImporter (ProcessPending → ImportFromJson → Import) |
| Leitura do JSON, kg → t, datas | Default/Common/Pitagoras.API.Toledo.pas | TToledoScaleTicket |
## Informações do documento
> Autor: Fabiano Massola
> Setor: Qualidade
> Módulo: Romaneio
> Chamado: 0000000000
> Versão do Sistema:
> Versão do documento: 1
> Revisão: Paulo Bley
> Aprovado em: Agosto de 2026
---
> 📎 **Arquivos originais:** [MANUAL_Integração_Balança_Toledo_Romaneio.docx](https://drive.google.com/uc?export=download&id=1lRBO5Q6JJme8SJUoXQaO87noXvDSrovr)
Tags IA:
integracao
balanca
toledo
Prioridade: 7