Voltar para Central de ajuda
FT-MAPPING-ARRAYS-V1· V3.7De-para

Mapping — arrays e items (SAP to_Item, lines, partners)

Suporte a estruturas item-level: SAP to_Item.results[], linhas de pedido, e PARCEIROS como array (to_Partner[*] por PartnerFunction → NAD+BY/IV/PE automáticos). Ver também "Instâncias qualificadas".

Atualizado em 09/10/2026

Mapping — arrays e items



Atualizado 2026-05-06. Resolve o gap onde mappings de items SAP retornavam null silenciosamente.

Sintaxe de path



Origem (source_field) e destino (destination_field) aceitam:

SintaxeSignificadoExemplo
header.fieldPath simples aninhadoto_Item.Material (legacy: pega 1º item de array)
path[N].fieldIndex numérico explícitoto_Item[0].Material
path[].fieldWildcard — todos os itemsto_Item[].Material (recomendado)
to_Item[*]OData V2 V auto-resolveaceita tanto array direto quanto { results: [...] }


Cenários



1. Sales Order com items → JSON multi-line



Source: payload SAP OData V2 (to_Item.results = [...])

[
  { "source_field": "SalesOrder",                "destination_field": "BEG.BEG03",         "transform": "direct" },
  { "source_field": "TransactionCurrency",       "destination_field": "CUR.CUR02",         "transform": "direct" },
  { "source_field": "to_Item[*].SalesOrderItem", "destination_field": "items[*].PO101",    "transform": "direct" },
  { "source_field": "to_Item[*].Material",       "destination_field": "items[*].PO107",    "transform": "direct" },
  { "source_field": "to_Item[*].RequestedQuantity","destination_field":"items[*].PO102",   "transform": "direct" }
]


Resultado:

{
  "BEG.BEG03": "13",
  "CUR.CUR02": "USD",
  "items": [
    { "PO101": "10", "PO107": "TG11", "PO102": "100" },
    { "PO101": "20", "PO107": "TG12", "PO102": "50" }
  ]
}


2. Aggregations no header (totals derivados de items)



[
  { "source_field": "to_Item[*].NetAmount", "destination_field": "header.totalAmount", "transform": "sum" },
  { "source_field": "to_Item[*]",           "destination_field": "header.lineCount",    "transform": "count" }
]


Transforms novos: sum, count, first, last. Operam em path com [*] ou OData wrapper.

3. Broadcast — campo escalar do header replicado em cada item



[
  { "source_field": "to_Item[*].Material",   "destination_field": "items[*].productId", "transform": "direct" },
  { "source_field": "TransactionCurrency",   "destination_field": "items[*].currency",  "transform": "direct" }
]


currency aplica USD em todos os items. Constants também broadcasta.

Backward compat (mappings AI-suggested antigos)



Mapping suggesteado pela IA antes de 2026-05-06 usava to_Item.Material (sem [*]). Esses mappings:

  • Header destination (PO1.PO107): resolve no PRIMEIRO item do array (legacy compat). Gera warning sugerindo to_Item[*].Material se quiser todos.
  • **Destination com [*]** (items[*].productId): expande automaticamente pra todos os items do array fonte. Não precisa editar — funciona como esperado.


100 mensagens em prod ganharam dados sem reprocessamento manual. Se quiser reaproveitar, basta clicar Reprocessar no monitor ou usar bulk em /admin/queue.

Erros estruturados (do #67)



Todos os erros do mapping seguem o tipo MappingError:

  • missing_required (error): source ausente em campo required
  • source_path_invalid (warning): source ausente em campo opcional
  • type_mismatch (error): tipo incompatível com transform (sum em string, truncate em number)
  • transform_failed (error): config inválida (parseInt → NaN, JSON.parse falhou)


Sugestão de origem via fuzzy match continua funcionando — to_Iten.Material sugere to_Item[*].Material se houver match próximo.

Não suportado nesta versão



  • Wildcards aninhados (a.b[].c[].d): só primeiro [*] expande
  • Filter por condição (items[?type=='foo'].field): backlog
  • Joins entre arrays (linhas + impostos por linha): backlog


Esses ficam como sub-items futuros do roadmap se virarem prioridade.

Migração automática (2026-05-06)



Os 3 mappings ativos de Sales Order foram migrados pra sintaxe [*] baseado no catálogo X12 850 (loops PO1, N1, REF, DTM, ITD, etc.). 30 fields convertidos.

Daqui pra frente (desde 27/09/2026), o suggester dá [*] a cada coleção pelo catálogo da própria mensagem — o caminho de cada campo que repete, com todas as coleções do caminho — em qualquer formato do catálogo (X12, EDIFACT, IDoc, NF-e, FHIR, HL7 v2, OData e as mensagens da sua empresa). Não há lista de formatos no código: mensagem nova no catálogo já vem com as coleções dela.

SAP OData V2 — tratamento dedicado (v1.3.0)





40% das mensagens SAP OData chegam com to_Item.__deferred quando o connector não fez $expand. Antes: items vazios silenciosamente. Agora gera warning acionável:

Origem to_Item: navigation property "to_Item" não foi expandida na query OData. Adicionar $expand=to_Item no connector da integração.
Fix: editar query OData do connector pra incluir $expand=to_Item,to_Partner,to_PricingElement,to_Text (separados por vírgula).

Conversão de datas SAP (/Date(timestamp)/)



SAP serializa datas no formato Microsoft JSON: /Date(1473206400000)/. O transform date_format agora converte de verdade.

{ "transform": "date_format", "transform_config": { "format": "iso" } }


Options de format:
  • iso (default): 2016-09-07T00:00:00.000Z — ISO 8601 datetime UTC
  • date: 2016-09-07 — só data
  • epoch_ms: 1473206400000 — milliseconds desde epoch (number)


Aceita também:
  • /Date(ms+offset)/ — ignora offset, usa UTC
  • YYYYMMDD bare (ex: "20160907")


__metadata ignorado em sugestões



OData V2 envolve cada entity em { "__metadata": { "uri": "...", "type": "..." } }. Antes essas chaves apareciam em fuzzy suggestions (typo Materil podia sugerir __metadata.uri). Agora __metadata e __deferred são silenciosamente ignorados — só dados de negócio aparecem nas sugestões.

OData V4 + tipos Edm — v1.4.0



V4 wrapper { value: [...] }



OData V4 usa value no lugar de results. Tudo que vale pra V2 vale pra V4: path[*].field, aggregations, smart fallback, índice numérico.

to_Item.value[*].Material   ← OData V4 explícito
to_Item[*].Material         ← funciona pra V2 e V4 (recomendado)
to_Item.Material            ← legacy, primeiro item de array (V2 ou V4)


Transform time_format (Edm.Time)



Edm.Time vem em ISO 8601 duration: PT12H30M0S. Transform converte pra HH:MM:SS:

{ "source_field": "startTime", "destination_field": "start_at", "transform": "time_format" }


Resultado: "PT12H30M0S" → "12:30:00". Aceita partes faltando (PT9H → 09:00:00), trunca seconds fracionados.

Transform to_number (Edm.Decimal/Edm.Double)



SAP serializa decimais como string ("1755.00") pra preservar precisão. Pra cliente JSON que quer number nativo:

{ "source_field": "NetAmount", "destination_field": "net", "transform": "to_number" }


Resultado: "1755.00" (string) → 1755 (number). Strings non-numéricas passam direto sem error (defensivo).

Não suportado nesta versão (backlog)



  • Pagination __next / @odata.nextLink: connector atual REST genérico só pega 1ª página. Connector OData dedicado é item #72 (M, ~3h)
  • Wildcards aninhados: a.b[].c[].d só primeiro [*] expande
  • Filter por condição: items[?type=='foo'].field
  • Joins entre arrays: linhas + impostos por linha


Um registro por item de uma lista da origem



Quando um documento da origem precisa virar vários registros no destino (um produto com N plantas → N registros de produto × loja), escolha no topo do editor do mapeamento, em Registros no destino, a opção Um registro por item de e a lista da origem (por exemplo to_Plant[*]).

  • Lista vazia num documento (produto sem planta, artigo genérico sem EAN): sai 0 registro e a mensagem fica Sem itens no monitor, com o motivo — não é erro, não tenta de novo e nada é enviado. Para que isso pare a mensagem com erro, escolha Lista vazia num documento: erro ao lado da lista. Navegação da origem que não veio expandida continua sendo erro (falta o $expand no conector).
  • Lista dentro de lista (o EAN de cada unidade de medida, to_ProductUnitsOfMeasure[].to_InternationalArticleNumber[]): sai um registro por item da lista de dentro, com os campos do item pai (a unidade) e do documento.
  • Ativar confere o que o mapeamento gera: um registro por item e, em cada registro, os campos obrigatórios do destino. Uma regra que lê de outra lista (não da escolhida) é barrada, porque daria vários valores num campo só do registro.


  • O mapeamento roda uma vez por item da lista: os campos dentro da lista vêm daquele item e os campos do documento (o código do produto, o lote) se repetem em cada registro.
  • Conexão que envia array (cadastro em lote, "Enviar como array JSON"): os registros vão juntos no corpo. Se o documento tiver mais registros que Mensagens por envio na conexão, a mensagem leva os primeiros e o resto vai em mensagens irmãs (#2, #3), cada uma reprocessável sozinha. Documento alterado na origem refaz as partes: as que faltam nascem, as que mudaram saem de novo e as que sobraram (e não saíram) ficam Canceladas, com o motivo. A parte já enviada que o documento não tem mais ganha um aviso na mensagem ("registro removido da origem, já enviado ao destino; pode precisar de exclusão no destino") — o Lefia não exclui sozinho: a eliminação marcada na origem vira a ação do próprio mapeamento.
  • Conexão de um documento por corpo (EDI, IDoc, API que recebe um objeto): cada registro sai numa mensagem própria.
  • Lista vazia no documento: a mensagem para com o motivo ("a lista veio vazia"), nunca sai um corpo vazio.
  • Destino cujo catálogo já é uma lista ([].campo): os registros saem na lista; campo fora dela (sem []) para a mensagem com o motivo, porque não há onde colocá-lo.
  • Documento que para na conversão (valor reprovado, campo fora da lista, qualificador ausente): as partes que ainda não saíram ficam Canceladas com o mesmo motivo e as já enviadas ganham um aviso (o destino pode estar com o conteúdo anterior). Corrija o documento e reprocesse a mensagem principal: todas as partes saem de novo.

Histórico de versões

  • V3.7

    UI editor visual de filter_lookup — drawer recursivo com cláusulas + grupos AND/OR aninhados. 13 operadores em PT (é igual a, está em, maior que, contém, é nulo, etc.). 5 match strategies (Primeiro/Último/Único/Somar todos/Juntar como texto) em radio cards. Field selector com datalist autocomplete inferido do source_field nested. Botões "+ Cláusula" e "+ Grupo OR/AND aninhado" alternam por nível. Cor por depth (verde/azul/âmbar). JSON.stringify ↔ JSON.parse ponte entre Record<string,string> storage e FilterNode rich schema.

    25/05/2026 · updated

  • V3.6

    Novo transform "filter_lookup" — regras condicionais com AND/OR aninhado multi-clause. Schema FilterNode recursivo + 13 operadores (eq/neq/in/gt/contains/isNull/...) + 5 match strategies (first/last/single/sum_all/join_all). Engine handle nested 2-level (caso SAP pricing: filter ConditionType==PR00 em to_PricingElement[*]). 42 tests.

    25/05/2026 · new

  • V3.5

    Sessão 24/05 — épico canonical loopPath fechado 100% (4 PRs sequenciais). #259 audit + gap doc. #260 helper buildLoopPath + NF-e refator. #261 FHIR nested + EDIFACT single-level. #262 xsd-generic refator. 1688 tests, 0 todos.

    24/05/2026 · updated

  • V3.0

    Engine writeDest detecta destino dotted e usa write deep com heurística EDIFACT ([CS]\d{3} middle = composite). Serializer EDIFACT usa : entre composite sub-elements.

    20/05/2026 · updated

  • 1.4.0

    OData V4 wrapper { value: [...] } suportado (pareia com V2 results). Transforms novos: to_number (Edm.Decimal/Double string → number), time_format (Edm.Time PT12H30M0S → HH:MM:SS). 16 testes adicionais.

    06/05/2026 · updated

  • 1.3.0

    OData V2 SAP — tratamento completo: __deferred detectado e gera warning acionável ("Adicionar $expand=to_Item no connector"), transform date_format real converte /Date(timestamp)/ pra ISO 8601 (formats: iso/date/epoch_ms), fuzzy suggest ignora __metadata e __deferred. Audit em prod: 203 mensagens (40%) com __deferred agora têm warning explícito vs falha silenciosa antes.

    06/05/2026 · updated

  • 1.2.0

    Catálogo expandido: HL7 v2 (loops OBX/OBR/DG1/AL1/IN1/NK1/ROL/NTE/ORC/RXA), JSON Purchase Order proprietário (items/lines/partners/taxes), MLLP como alias de HL7 v2. resolveFormat agora cobre "JSON Webhook", "REST JSON", "Webhook JSON", "X12-850 via AS2", "X12 855", "X12 856 ASN", e variações. Removido CTT do X12 850 loops (é summary segment único). Re-migração: +4 mappings, +6 fields.

    06/05/2026 · updated

  • 1.1.0

    Catálogo de formatos (X12 850/810/855/856, EDIFACT ORDERS/INVOIC/DESADV, OData JSON, NFe, NFSe). Migração automática dos 3 mappings ativos legacy: 30 fields convertidos pra sintaxe [*]. AI suggester pós-processa toda sugestão. Re-backfill em 313 mensagens com estrutura PO1[*], N1[*] correta.

    06/05/2026 · updated

  • 1.0.0

    Mapping suporta arrays/items: sintaxe path[*].field, OData wrapper auto, transforms sum/count/first/last. Backward compat: mappings AI-suggested antigos `to_Item.X` resolvem no 1º item (header) ou expandem pra todos (destination [*]). Audit em prod identificou 100 mensagens com campos/items recuperados.

    06/05/2026 · new