Trabajar con datos JSON en Business Central es una tarea habitual cuando interactuamos con APIs, servicios externos o almacenamos información estructurada. Afortunadamente, Microsoft ofrece una herramienta estándar que hace esta labor mucho más sencilla: la Codeunit "JSON Management".

En este post, te mostraré cómo aprovechar sus capacidades para manipular datos JSON de manera eficiente. Además, integraremos algunas funciones útiles para simplificar tareas cotidianas.

¡Vamos manos a la obra! 😤


🧩 ¿Qué es la Codeunit JSON Management?

La Codeunit "JSON Management" es una herramienta estándar de Business Central que facilita el manejo de datos en formato JSON. Permite trabajar con objetos, colecciones y valores individuales de manera clara y eficiente, sin necesidad de escribir lógica compleja desde cero.

🎯 Principales capacidades:

  • Inicializar objetos JSON
  • Extraer y modificar valores
  • Trabajar con arreglos JSON (JsonArray)
  • Convertir entre texto y objetos JSON

Esta Codeunit es esencial cuando necesitas comunicarte con servicios externos a través de APIs REST o cualquier fuente que use JSON como formato de intercambio de datos.


🧩 Extrayendo datos con GetValueText

Una de las tareas más comunes al trabajar con JSON es extraer el valor de una clave específica. Veamos cómo hacerlo con la Codeunit JSON Management:

procedure GetValueText(Json: Text; Tag: Text) ReturnValue: Text;
var
    JSONManagement: Codeunit "JSON Management";
begin
    Clear(JSONManagement);
    JSONManagement.InitializeObject(Json);
    ReturnValue := JSONManagement.GetValue(Tag);
end;

🔍 ¿Qué ocurre aquí?

  1. Inicializamos un objeto JSON usando InitializeObject.
  2. Buscamos el valor asociado a la clave indicada con GetValue(Tag).
  3. Devolvemos el valor encontrado como un Text.

🛠️ Aplicación práctica:
Supongamos que recibes un JSON con información de un pedido y necesitas el CustomerName. Con esta función, lo obtienes en una sola llamada.


🧱 Convirtiendo Text en JsonObject con GetValueJsonObject

A veces, el valor asociado a una clave no es un texto simple, sino un objeto JSON anidado. En esos casos, necesitamos convertirlo a un JsonObject:

procedure GetValueJsonObject(Json: Text; Tag: Text) ReturnValue: JsonObject;
var
    ValueText: Text;
begin
    ValueText := this.GetValueText(Json, Tag);
    ReturnValue.ReadFrom(ValueText);
end;

🔍 ¿Qué hace esta función?

  1. Obtiene el valor como Text utilizando la función GetValueText.
  2. Convierte el texto en un JsonObject mediante ReadFrom(ValueText).

🛠️ Aplicación práctica:
Cuando una respuesta JSON de una API devuelve un objeto con múltiples propiedades, esta función permite manejarlo como un JsonObject para acceder fácilmente a sus campos.


📦 Accediendo a elementos de un JsonArray con GetValueFromJsonArray

Los datos JSON suelen contener listas o arreglos, por ejemplo, una lista de productos o transacciones. Para acceder a un elemento específico por su índice, usamos esta función:

procedure GetValueFromJsonArray(Json: Text; Index: Integer) ReturnValue: Text;
var
    JSONManagement: Codeunit "JSON Management";
begin
    Clear(JSONManagement);
    JSONManagement.InitializeCollection(Json);
    JSONManagement.GetObjectFromCollectionByIndex(ReturnValue, Index);
end;

🔍 ¿Qué sucede aquí?

  1. Inicializamos una colección JSON con InitializeCollection.
  2. Accedemos al elemento del índice solicitado con GetObjectFromCollectionByIndex.
  3. Devolvemos el valor en formato Text.

🛠️ Aplicación práctica:
Ideal cuando se trabaja con listas de artículos, líneas de factura o cualquier conjunto de datos repetidos dentro de un JSON.


Verificando la existencia de un valor con HasValue

Antes de acceder a una clave en un JSON, es importante comprobar si existe. Esta función se encarga de hacerlo:

procedure HasValue(Json: Text; Tag: Text) ReturnValue: Boolean
var
    ValueText: Text;
begin
    Clear(ReturnValue);
    ValueText := this.GetValueText(Json, Tag);
    if ValueText <> '' then
        ReturnValue := true;
end;

🔍 ¿Cómo funciona?

  1. Busca el valor de la clave solicitada usando GetValueText.
  2. Comprueba si el valor está vacío y devuelve true si existe.

🛠️ Aplicación práctica:
Es muy útil al trabajar con estructuras JSON dinámicas, donde no todas las claves están garantizadas.


🚀 ¿Por qué usar la Codeunit JSON Management?

🌟 Ventajas clave

  • Integración nativa: No necesitas bibliotecas externas, todo se gestiona dentro de Business Central.
  • Código simplificado: Funciones claras y bien definidas para tareas comunes.
  • Eficiencia garantizada: Operaciones optimizadas por Microsoft, listas para producción.

🌐 Aplicaciones prácticas

  • Integración con APIs REST: Procesamiento de respuestas JSON en integraciones con CRM, e-commerce y otros sistemas.
  • Procesamiento de datos estructurados: Análisis de grandes volúmenes de información en formato JSON.
  • Exportación e importación de datos: Generación y consumo de JSON para intercambio de datos con aplicaciones externas.

🎯 Ejemplo práctico:
Imagina una integración con un sistema de logística. Al recibir un JSON con el estado de un envío, puedes usar la Codeunit JSON Management para extraer el campo status y reflejarlo en Business Central.



🔄 Conversión bidireccional Registro ↔ JSON con Advanced Mgt. Json

Además de la Codeunit JSON Management estándar, existe una codeunit personalizada —Advanced Mgt. Json— que permite convertir registros completos de Business Central a JSON y viceversa, usando RecordRef y FieldRef para que funcione con cualquier tabla sin escribir código específico por tabla.

El código original está basado en el trabajo de Erik Hougaard y ha sido modificado y adaptado.


📥 Importar JSON a un registro: UploadJson2Rec

procedure UploadJson2Rec(RecVariant: Variant): Variant
var
    RecordRefe: RecordRef;
begin
    RecordRefe.GetTable(RecVariant);
    exit(UploadJson2Rec(RecordRefe.Number()));
end;

procedure UploadJson2Rec(TableNo: Integer): Variant
var
    JObject: JsonObject;
    FileName: Text;
    DocInStream: InStream;
begin
    if not UploadIntoStream('', '', '', FileName, DocInStream) then
        exit;

    Clear(JObject);
    JObject.ReadFrom(DocInStream);

    exit(Json2Rec(JObject, TableNo));
end;

UploadJson2Rec abre un diálogo de selección de archivo, lee el JSON del fichero elegido y lo convierte en un registro de la tabla indicada. Tiene dos sobrecargas: una acepta un Variant (infiere el número de tabla) y otra acepta directamente el número de tabla.


🔁 Convertir JsonObject a registro: Json2Rec

procedure Json2Rec(JObject: JsonObject; RecVariant: Variant): Variant
var
    RecordRefe: RecordRef;
begin
    RecordRefe.GetTable(RecVariant);
    exit(Json2Rec(JObject, RecordRefe.Number()));
end;

procedure Json2Rec(JObject: JsonObject; TableNo: Integer): Variant
var
    RecordRefe: RecordRef;
    FieldRefe: FieldRef;
    FieldHash: Dictionary of [Text, Integer];
    i: Integer;
    JsonKey: Text;
    JToken: JsonToken;
    JsonValueKey: JsonValue;
    RecVariant: Variant;
begin
    RecordRefe.OPEN(TableNo);
    for i := 1 to RecordRefe.FieldCount() do begin
        FieldRefe := RecordRefe.FieldIndex(i);
        FieldHash.Add(GetJsonFieldName(FieldRefe), FieldRefe.Number);
    end;
    RecordRefe.Init();
    foreach JsonKey in JObject.Keys() do begin
        if JObject.Get(JsonKey, JToken) then begin
            if JToken.IsValue() then begin
                JsonValueKey := JToken.AsValue();
                FieldRefe := RecordRefe.Field(FieldHash.Get(JsonKey));
                AssignValueToFieldRef(FieldRefe, JsonValueKey);
            end;
        end;
    end;
    RecordRefe.Insert();
    RecVariant := RecordRefe;
    exit(RecVariant);
end;

Json2Rec toma un JsonObject ya cargado y lo convierte en un registro insertado en la tabla indicada. Internamente construye un Dictionary mapeando nombre de campo JSON → número de campo, y luego recorre las claves del JSON asignando cada valor al campo correspondiente mediante FieldRef.


📤 Convertir registro a JsonObject: Rec2Json

procedure Rec2Json(Rec: Variant): JsonObject
var
    RecordRefe: RecordRef;
    FieldRefe: FieldRef;
    JObject: JsonObject;
    JValue: JsonValue;
    i: Integer;
    Tet001Lbl: Label 'Parameter Rec is not a record', comment = 'ESP="El parámetro Rec no es un registro"';
begin
    if not Rec.IsRecord then
        error(Text001Lbl);
    RecordRefe.GetTable(Rec);
    for i := 1 to RecordRefe.FieldCount() do begin
        FieldRefe := RecordRefe.FieldIndex(i);
        case FieldRefe.Class of
            FieldRefe.Class::Normal:
                begin
                    Clear(JValue);
                    JValue := FieldRef2JsonValue(FieldRefe);
                    if Not JValue.IsNull then
                        JObject.Add(GetJsonFieldName(FieldRefe), JValue);
                end;

            FieldRefe.Class::FlowField:
                begin
                    FieldRefe.CalcField();
                    JValue := FieldRefToJsonValue(FieldRefe);
                    if Not JValue.IsNull then
                        JObject.Add(GetJsonFieldName(FieldRefe), JValue);
                end;
        end;
    end;
    exit(JObject);
end;

Rec2Json es la operación inversa: recorre todos los campos de un registro (campos normales y FlowFields) y construye un JsonObject con ellos. Los FlowFields se calculan antes de añadirse. Si el valor de un campo es nulo, no se añade al JSON.

🛠️ Aplicaciones prácticas del bloque AdvancedMgtJson:

  • Exportar cualquier registro de BC a un fichero JSON sin código específico por tabla.
  • Importar un fichero JSON y crear registros automáticamente en cualquier tabla.
  • Sincronización de datos entre entornos o empresas usando JSON como formato intermedio.
  • Base para herramientas de migración o copia de datos genéricas.

🏁 Conclusión

La Codeunit "JSON Management" de Business Central es una herramienta poderosa que facilita la manipulación de datos estructurados en formato JSON. Con las funciones descritas, puedes extraer, convertir, verificar y procesar información de manera clara y eficiente. Además, el bloque Advanced Mgt. Json amplía estas capacidades con conversión bidireccional genérica entre cualquier registro y JSON.

Si quieres ver el código completo, está en GitHub (MgtJson) y en GitHub (AdvancedMgtJson).

¡Hasta la próxima!