Pular para conteúdo

Arquitetura — Workflows MO e MP

Atualizado: 2026-07-08 · por: sessão automática · fix Distribuir MO (lookup por código+norm) + humanizador Code2 3 categorias · rev: 3

Visão geral

BPEX (orçamento aprovado vira PC)
   │ GET webhook  (httpMethod default — NÃO setar POST)
   ▼
n8n.bepex.com.br/webhook/{path}
   │
   ├─ Workflow MP (66DDyQXmXQqyV3Ah)  ← Categoria = COMPRA MP
   └─ Workflow MO (WwDzIseoYVxbzJZK)  ← Categoria = COMPRA MO

Cada workflow termina chamando o BPEX de volta (status de sucesso) pra atualizar o status do PC.


Workflow MP (66DDyQXmXQqyV3Ah)

Cadeia de nós (em ordem)

  1. Webhook (GET, path UUID, sem httpMethod explícito)
  2. Code — define appkey / appsecret da empresa Omie correta com base no pedido_compra.empresa_id (Onix/Atares/LGR/Dale/BPX) e comprador (id de comprador no Omie por empresa)
  3. Edit Fields — extrai body.itens
  4. Acha código do cliente — POST Omie ConsultarCliente por CNPJ/CPF
  5. Split Out — quebra body.itens em N items (1 por linha do orçamento BPEX; pode haver duplicatas de descrição MP)
  6. Dedupe descrições MP (Code) — agrega por omie.mp.descricao único; preserva pairedItem original
  7. Acha código do produto — POST Omie ListarProdutosResumido com filtrar_apenas_descricao (batching 1/1.5s pra evitar consumo redundante)
  8. IF Produto encontradototal_de_registros > 0?
  9. trueSet Achado (extrai codigo_produto do Omie; descricao = a do BEPEX, para o lookup do Distribuir bater)
  10. falseConsultarProduto por codigo (consulta pelo omie.mp.codigo BPX)
    • IF Existe pelo codigocodigo_produto > 0 (produto já existe no Omie pelo código)?
    • true (existe) → Alum equivalente? (IF boolean) — é alumínio e as descrições só diferem na posição do token "ALUMINIO"/espaços?
      • trueSet Reaproveitado (reusa codigo_produto do Omie; descricao = a do BEPEX) — trata como o mesmo produto e segue
      • falseStop and Error codigo conflito (conflito real: mesmo código, descrição diferente — NÃO sobrescreve)
    • false (não existe) → IncluirProduto (cadastra novo no Omie) → Set Criado
  11. Merge Achado/Criado (mode append, numberInputs: 3 — Set Achado / Set Criado / Set Reaproveitado) — junta os ramos, ainda agregado por descrição (6 items deduplicados se PC tem 13 com 7 duplicatas)
  12. Distribuir codigo_produto (Code) — reexpande pros 13 items originais, anexando _codigo_produto_resolvido via lookup por descrição. Faz spread completo de it.json original.
  13. Edit Fields1 — monta cada item Omie: nCodProd, nQtde, nValUnit, cObs. Importante: lê de $json.X (do próprio item, vindo do spread no Distribuir), não de $('Split Out').item.X (paired-item quebra após dedupe+expand).
  14. Aggregate — junta os 13 items num array produtos
  15. adiciona pedido de compra — POST Omie IncluirPedCompra com cabeçalho, frete e produtos_incluir
  16. status de sucesso — POST callback ao BPEX atualizando status do PC

Tratamento de erro

  • Error Trigger (pflBwIjA8OBpKFHj) é o settings.errorWorkflow do workflow
  • O Error Trigger chama Code1 (humaniza mensagem de erro) → HTTP Request (callback BPEX com status "Deu errado: ...")

Workflow MO (WwDzIseoYVxbzJZK)

Estrutura similar à de MP, mas com 2 diferenças intencionais:

  1. Usa projeto — antes de criar o pedido, garante que o projeto (= pedido_venda.id) existe no Omie. Se não existe, cria via IncluirProjeto com nome = pedido_venda.id. Se não tiver permissão (caso da Dale), falha.
  2. Não tem omie.mp.codigo — MO usa omie.mo.codigo que é por orçamento (não por matéria-prima base).

Cadeia de nós (em ordem) — atualizada 2026-05-12

  1. Webhook (GET, path UUID, sem httpMethod explícito)
  2. Code — define appkey/appsecret da empresa Omie correta + comprador
  3. Edit Fields — extrai body.itens
  4. Split Out — quebra em N itens (1 por linha do pedido)
  5. Dedupe descrições MO (Code) — agrega por omie.mo.descricao único, preserva pairedItem. Adicionado 2026-05-12 para evitar consumo redundante com itens de mesma descrição.
  6. Acha código do produto — POST Omie ListarProdutosResumido com filtrar_apenas_descricao (batchSize 2)
  7. Distribuir codigo_produto MO (Code) — re-expande para todos os itens originais de Split Out, anexando _codigo_produto_resolvido. Adicionado 2026-05-12. Fix 2026-07-08 (Opção B): o lookup é feito por código BPX (list.find(x => x.codigo === bCod)) — não por posição [0]. O codigo_produto do Omie só é reutilizado se (1) o código BPX bate E (2) as descrições são iguais após normalizar espaços e caixa. Qualquer outra divergência → _codigo_produto_resolvido = null → Code2 reporta mensagem específica ao humano. Faz spread completo de it.json.
  8. Edit Fields1 — monta cada item Omie: nCodProd ($json._codigo_produto_resolvido), nQtde ($json.quantidade), nValUnit ($json.valor), cObs. Lê de $json.X (spread do Distribuir), não de $('Split Out').item.X.
  9. Aggregate — junta todos os itens num array produtos
  10. Acha código do fornecedor — POST Omie ConsultarCliente
  11. Merge — junta ramo de fornecedor com ramo de projeto
  12. adiciona pedido de compra — POST Omie IncluirPedCompra
  13. status de sucesso — POST callback ao BPEX

Ramo paralelo de projeto (dispara junto com Edit Fields em step 2): - Acha código do projetoIF Projeto encontradoSet nCodProj (achou) / Upsert Projeto → Set nCodProj (criou)Merge

Pendência conhecida

  • Dale Omie: app_key ${OMIE_APP_KEY_DALE} não tem permissão "Cadastro de Projetos / Inclusão" liberada no painel Omie da Dale. Documentado em BACKLOG.md da pasta-raiz e na memória project_dale_omie_pendencia.

Fluxos auxiliares (callback de erro)

Workflow MP/MO falha (qualquer nó)
   │
   ▼
Error Trigger workflow pflBwIjA8OBpKFHj
   │
   ├─ Get an execution (puxa runData via REST)
   ├─ Code1 (humaniza mensagem de erro)
   └─ HTTP Request (POST BPEX → "Deu errado: <mensagem>")

Humanizações conhecidas no Code1: - tag [cProduto] ou produtos sem código → "Produto(s) não cadastrado(s) no Omie: " - já existe no Omie com descrição diferente → passa-through (msg do Stop and Error) - Pedido de compra j(á cadastrado) → "Pedido já cadastrado no omie anteriormente" - Cannot read properties of undefined (reading 'toLowerCase') → "empresa emissora não definida" - tag [nValUnit] → "Existe campo valor unitário não preenchido" - existem registros para a → "Cliente provavelmente não cadastrado no Omie" - Consumo redundante → "Omie bloqueou por consumo redundante (aguarde alguns minutos e reenvie)"


Pegadinhas críticas (consolidado)

  1. Webhook httpMethod: BPEX manda GET. Default do n8n é GET. NÃO setar httpMethod: POST em PATCHes — quebra prod silencioso com 404. Memória: feedback_n8n_webhook_httpmethod.
  2. errorWorkflow ao clonar: clone via REST herda settings.errorWorkflow do workflow original. Se você desativar o original, callbacks de erro silenciam. Atualizar pro ID do clone após PATCH. Memória: feedback_n8n_clone_errorworkflow.
  3. pairedItem manual em Code expand: pairedItem: { item: i } aponta pro INPUT do Code, não pro nó upstream que você imagina. Em Set/Edit Fields downstream, usar $json.X (com spread no Code) e nunca $('NóLonge').item.json.X. Memória: feedback_n8n_paireditem_manual.
  4. codigo_produto_integracao obrigatório na ATARES: o IncluirProduto precisa enviar esse campo, senão 500 (SOAP-ENV:Client-103). Solução: passar mesmo valor de codigo BPX. Memória: reference_omie_atares_codigo_produto_integracao.
  5. Retry de execução no n8n usa snapshot antigo: NUNCA validar fix via retry — disparar webhook de novo.
  6. n8n SQLite tem retenção curta (~20 execs por workflow) — bugs antigos não auditáveis depois.
  7. Code1/Code2 humanizador: nunca usar || chain misturando message e description: error.message do n8n é sempre "The service was not able to process your request" para erros HTTP — truthy, então o || nunca chega em error.description (onde o Omie coloca o faultstring). Padrão correto: const errorRaw = ..message..; const errorDesc = ..description..; const errorMessage = errorRaw + ' ' + errorDesc;. Descoberto 2026-05-12.
  8. Dedupe é obrigatório antes de qualquer nó que chama Omie por descrição quando há itens duplicados: sem dedupe, itens com mesma omie.mo.descricao / omie.mp.descricao geram chamadas idênticas e o Omie retorna SOAP-ENV:Client-6 consumo redundante. O par Dedupe+Distribuir é o padrão para resolver isso (ver MP e MO). Descoberto 2026-05-12 (exec 427584, MO, 9 itens com 5 duplicatas de BPX68231137-MO). Validado em prod 2026-05-12 com PC real 1816 (exec 430068: 9 itens → Dedupe=5 → Acha produto 5× → Distribuir=9 → status sucesso ✅). Exec sintético 430061 (3→2→3) também ok.
  9. Code node usa empresa.nome, não empresa_id: seleção do tenant Omie lê body.pedido_compra.empresa.nome.toLowerCase() com includes-match. Se empresa não existir no body, explode com "Cannot read properties of undefined (reading 'nome')" → humanizado como "empresa emissora não definida". Appkeys corretos estão em referencia-tecnica.md.
  10. Set Achado DEVE exportar descricao com chave do BEPEX, não do Omie (MP): o Distribuir codigo_produto faz lookup por omie.mp.descricao (BEPEX). Se Set Achado exportar produto_servico_resumido[0].descricao (descrição do Omie), o lookup falha quando as descrições divergem → _codigo_produto_resolvido = null → erro "tag [cProduto]". Padrão correto: Set Achado e Set Criado ambos usam $('Dedupe descrições MP').itemMatching($itemIndex).json.omie.mp.descricao. Descoberto 2026-05-14, causava ~70% de falhas. Validado em prod 2026-05-15 (execs 440809, 440840, 440901 — todos sucesso ✅).
  11. Equivalência de alumínio no ramo de conflito (MP) — quando o produto é achado pelo código mas o ListarProdutosResumido por descrição falhou (0 registros), o nó Alum equivalente? decide se é conflito real ou só divergência de formato do alumínio. Regra: para alumínio (uma das descrições contém "ALUMINIO") e quando, removido o token "ALUMINIO" e normalizados espaços, as descrições batem — aí reusa o codigo_produto do Omie via Set Reaproveitado em vez de parar. Motivação: o Omie tem produtos de alumínio cadastrados como "ALUMINIO <dims>" (via SYNC) enquanto o BEPEX manda "<dims> ALUMINIO". É medida temporária até a base de alumínio no Omie ser normalizada; qualquer outra divergência (dimensão, separador decimal, não-alumínio) continua no Stop and Error. Cronologia e validação (exec 633727, Omie PC 3911) no bugs-fix-log.md (2026-07-07).