Todos os artigos
FT-MAPPING-ARRAYS-V1· V3.7Mappings & EDI Hub

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 5/30/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, o AI suggester pós-processa toda sugestão usando o catálogo de formatos — segments que são loops naturais (PO1, LIN, det, items, etc.) recebem [*] automaticamente. Não precisa editar manual.

Formatos com loops conhecidos:
  • X12 850 (PO), 855 (PO ack), 810 (invoice), 856 (ship notice)
  • EDIFACT ORDERS, INVOIC, DESADV
  • JSON OData-style (items, partners, lines, taxes)
  • NFe / NFSe XML (det, dup, ListaServicos.Servico)


Formatos sem catálogo ainda: HL7 v2, MLLP, JSON Purchase Order proprietário (esses passam direto sem [*]). Adicionar é trivial — editar src/lib/mapping/destination-formats.ts.

SAP OData V2 — tratamento dedicado (v1.3.0)



Navigation property não expandida (__deferred)



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 (PT9H09: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

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.

    5/25/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.

    5/25/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.

    5/24/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.

    5/21/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.

    5/6/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.

    5/6/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.

    5/6/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.

    5/6/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.

    5/6/2026 · new