Dif. 8/10

Herramientas Avanzadas de AL

Esta sección cubre los elementos avanzados del desarrollo en Business Central: el flujo de procesos del sistema, el diseño de páginas RoleCenter con cues y actividades, la personalización de la cinta de acciones, y los XMLports para importar y exportar datos.

1. Flujo de Procesos de Business Central

Business Central organiza su funcionamiento alrededor de procesos de negocio que siguen un flujo estándar. Entender este flujo es fundamental para saber dónde encaja cada objeto AL que desarrollamos.

Fase Descripción Objetos AL involucrados
1. Configuración Crear datos maestros (clientes, productos, socios, libros) y configurar el sistema. Tablas, Páginas Card/List
2. Entrada de datos El usuario introduce documentos o transacciones (pedidos, préstamos, facturas). Páginas Document, Worksheet
3. Validación El sistema valida los datos mediante triggers y lógica de negocio. Triggers de tabla, Codeunits
4. Contabilización (Posting) El documento borrador se convierte en un documento publicado y genera movimientos contables. Codeunits de posting, Reports ProcessingOnly
5. Informes y análisis El usuario consulta los datos mediante informes, queries y dashboards. Reports, Queries, RoleCenter
// Flujo típico de un proceso de préstamo en nuestra aplicación:
//
// 1. CONFIGURACIÓN → Crear Socios y Libros (tablas maestras)
// 2. ENTRADA       → Crear un nuevo Préstamo (tabla de documento)
// 3. VALIDACIÓN    → OnValidate verifica que el socio existe y el libro está disponible
// 4. PROCESO       → Codeunit cambia el estado del libro a "Prestado"
// 5. INFORMES      → Report muestra préstamos activos, vencidos, estadísticas
//
// Cada fase usa objetos AL diferentes, pero todos están conectados
// a través de TableRelation, Codeunits y Events.

2. Páginas del Centro de Roles (RoleCenter)

El RoleCenter es la página principal que ve el usuario al iniciar sesión en Business Central. Cada rol de usuario (contable, gerente, bibliotecario) tiene su propio RoleCenter personalizado con accesos directos, indicadores y actividades relevantes para su trabajo diario.

Componente Qué es Tipo de Part
Headline Título dinámico en la parte superior con información contextual o saludos HeadlinePart
Activities (Cues) Contadores visuales que muestran el número de elementos pendientes CardPart con CueGroup
Acciones Enlaces rápidos a las páginas y funciones más usadas del rol Actions en el RoleCenter
// Página RoleCenter básica para un bibliotecario
page 50500 "RC Bibliotecario"
{
    PageType  = RoleCenter;
    Caption   = 'Centro de Roles — Bibliotecario';

    layout
    {
        area(RoleCenter)
        {
            // Headline dinámico
            part(Titular; "Headline Biblioteca")
            {
                ApplicationArea = All;
            }

            // Cues — indicadores numéricos
            part(Actividades; "Actividades Biblioteca")
            {
                ApplicationArea = All;
            }
        }
    }

    actions
    {
        area(Embedding)
        {
            action(Socios)
            {
                Caption         = 'Socios';
                ApplicationArea = All;
                RunObject       = page "Lista Socios";
                Image           = CustomerList;
            }
            action(Libros)
            {
                Caption         = 'Catálogo de Libros';
                ApplicationArea = All;
                RunObject       = page "Lista Libros";
                Image           = ItemList;
            }
            action(Prestamos)
            {
                Caption         = 'Préstamos';
                ApplicationArea = All;
                RunObject       = page "Lista Prestamos";
                Image           = Documents;
            }
        }
    }
}

3. Estructura: Titulares, Actividades y Cues

HeadlinePart — El titular dinámico

Una HeadlinePart es una página especial que muestra un "titular de periódico" en la parte superior del RoleCenter. Es ideal para dar la bienvenida, mostrar datos clave del día o destacar alertas.

page 50501 "Headline Biblioteca"
{
    PageType = HeadlinePart;
    Caption  = 'Titulares';

    layout
    {
        area(Content)
        {
            field(Bienvenida; BienvenidaTxt)
            {
                ApplicationArea = All;
            }
            field(PrestamosHoy; PrestamosHoyTxt)
            {
                ApplicationArea = All;
            }
        }
    }

    trigger OnOpenPage()
    var
        Prestamo: Record Prestamo;
    begin
        BienvenidaTxt := 'Buenos días, ' + UserId;

        Prestamo.SetRange("Fecha Prestamo", Today);
        PrestamosHoyTxt := StrSubstNo('Hoy se han registrado %1 préstamos nuevos',
                                       Prestamo.Count);
    end;

    var
        BienvenidaTxt: Text[100];
        PrestamosHoyTxt: Text[100];
}

Cues — Los indicadores numéricos

Los Cues son contadores visuales que aparecen como tarjetas de colores en el RoleCenter. Cada cue muestra un número (ej. "5 préstamos vencidos") y al hacer clic abre la página filtrada con esos registros.

Para implementar cues necesitas:

// 1. Tabla de Cues — los FlowFields calculan los contadores
table 50501 "Cues Biblioteca"
{
    Caption = 'Cues Biblioteca';

    fields
    {
        field(1; "Clave"; Code[10]) { }

        field(10; "Prestamos Activos"; Integer)
        {
            FieldClass = FlowField;
            CalcFormula = count(Prestamo where(Estado = const(Activo)));
            Caption = 'Préstamos Activos';
        }
        field(20; "Prestamos Vencidos"; Integer)
        {
            FieldClass = FlowField;
            CalcFormula = count(Prestamo where(Estado = const(Vencido)));
            Caption = 'Préstamos Vencidos';
        }
        field(30; "Total Socios"; Integer)
        {
            FieldClass = FlowField;
            CalcFormula = count(Socio);
            Caption = 'Total Socios';
        }
    }

    keys
    {
        key(PK; "Clave") { Clustered = true; }
    }
}

// 2. Página CardPart con CueGroup
page 50502 "Actividades Biblioteca"
{
    PageType    = CardPart;
    Caption     = 'Actividades';
    SourceTable = "Cues Biblioteca";

    layout
    {
        area(Content)
        {
            cuegroup(Prestamos)
            {
                Caption = 'Préstamos';

                field(PrestActivos; Rec."Prestamos Activos")
                {
                    ApplicationArea = All;
                    DrillDownPageId = "Lista Prestamos";
                    Caption = 'Activos';
                }
                field(PrestVencidos; Rec."Prestamos Vencidos")
                {
                    ApplicationArea = All;
                    DrillDownPageId = "Lista Prestamos";
                    Caption = 'Vencidos';

                    // Cambia de color según el valor
                    Style = Unfavorable;
                    StyleExpr = Rec."Prestamos Vencidos" > 0;
                }
            }
            cuegroup(General)
            {
                Caption = 'General';
                field(Socios; Rec."Total Socios")
                {
                    ApplicationArea = All;
                    DrillDownPageId = "Lista Socios";
                    Caption = 'Total Socios';
                }
            }
        }
    }

    trigger OnOpenPage()
    begin
        Rec.Reset();
        if not Rec.Get() then begin
            Rec.Init();
            Rec.Insert();
        end;
    end;
}

💡 Cómo funcionan los Cues

  • La tabla de cues solo tiene un registro (singleton). Por eso el OnOpenPage hace Get() sin parámetros.
  • Los campos FlowField calculan los contadores automáticamente con SQL.
  • DrillDownPageId define qué página se abre al hacer clic en el cue.
  • Usa Style = Unfavorable para que el número aparezca en rojo cuando hay problemas.

4. Diseñador de Acciones y Cinta de Opciones

Las acciones en Business Central son los botones y enlaces que el usuario ve en la barra superior de cada página. Se organizan en áreas y grupos, y cada una puede ejecutar código AL, abrir otra página o lanzar un informe.

Área de acción Dónde aparece Uso típico
area(Processing) Barra de acciones principal Acciones que modifican datos (Registrar, Aprobar, Enviar)
area(Navigation) Menú "Navegar" / "Relacionado" Abrir páginas relacionadas (Historial, Movimientos)
area(Reporting) Menú "Informes" Lanzar informes y documentos
area(Creation) Menú "Nuevo" (en listas) Crear nuevos registros o documentos
area(Promoted) Barra principal (destacado) Acciones frecuentes que se quieren hacer muy visibles
// Acciones en una página de tarjeta de socio
page 50110 "Tarjeta Socio"
{
    PageType    = Card;
    SourceTable = Socio;

    // ... layout omitido ...

    actions
    {
        // Acciones principales (barra superior)
        area(Processing)
        {
            action(RegistrarPrestamo)
            {
                Caption         = 'Nuevo Préstamo';
                ApplicationArea = All;
                Image           = NewDocument;
                Promoted        = true;
                PromotedCategory = Process;
                PromotedIsBig   = true;

                trigger OnAction()
                var
                    GestPrest: Codeunit "Gestion Prestamos";
                begin
                    GestPrest.RegistrarPrestamo(Rec."No.", '');
                end;
            }
        }

        // Acciones de navegación
        area(Navigation)
        {
            group(Historial)
            {
                Caption = 'Historial';

                action(VerPrestamos)
                {
                    Caption         = 'Préstamos del Socio';
                    ApplicationArea = All;
                    Image           = Documents;
                    RunObject       = page "Lista Prestamos";
                    RunPageLink     = "No. Socio" = field("No.");
                    // Abre la lista filtrada por este socio
                }
            }
        }

        // Acciones de informes
        area(Reporting)
        {
            action(ImprimirFicha)
            {
                Caption         = 'Ficha del Socio';
                ApplicationArea = All;
                Image           = Report;
                RunObject       = report "Ficha Socio Word";
            }
        }
    }
}

💡 Promoted actions (acciones destacadas)

  • Usa Promoted = true para que la acción aparezca directamente en la barra superior de la página.
  • PromotedIsBig = true hace que el botón sea más grande y visible.
  • PromotedCategory agrupa las acciones destacadas: Process, Report, Category4 a Category10.
  • No abuses de las acciones destacadas. Solo pon las que el usuario usa a diario.

5. XMLports: Componentes, Propiedades y Triggers

Un XMLport es un objeto AL diseñado para importar y exportar datos entre Business Central y archivos externos (XML, CSV, texto plano). Es la herramienta estándar para migraciones de datos, integraciones con otros sistemas y cargas masivas.

Componente Descripción
schema Define la estructura del fichero: qué elementos y atributos tendrá el XML/CSV de salida.
requestpage Igual que en reports: pantalla previa para que el usuario configure opciones antes de ejecutar.
Direction Define si el XMLport es de Import, Export o Both.
Format Formato del fichero: Xml, VariableText (CSV) o FixedText.

Propiedades principales

Propiedad Dónde Qué hace
Direction XMLport Import, Export o Both
Format XMLport Xml, VariableText (CSV), FixedText
FieldSeparator XMLport (CSV) Carácter separador de campos (ej. ; o ,)
TextEncoding XMLport UTF8, UTF16, MSDos, Windows
TableElementName tableelement Nombre del nodo XML para cada registro

Triggers del XMLport

Trigger Cuándo se ejecuta
OnPreXmlPort Antes de procesar cualquier dato (inicialización)
OnPostXmlPort Después de procesar todos los datos (resumen, mensaje final)
OnBeforeInsertRecord Antes de insertar cada registro (validación, transformación)
OnAfterInsertRecord Después de insertar cada registro (acciones post-inserción)
OnBeforeModifyRecord Antes de modificar un registro existente
OnAfterGetRecord Después de leer cada registro (en exportación)
// XMLport para exportar socios a CSV
xmlport 50500 "Exportar Socios CSV"
{
    Direction      = Export;
    Format         = VariableText;  // CSV
    FieldSeparator = ';';
    TextEncoding   = UTF8;
    Caption        = 'Exportar Socios a CSV';

    schema
    {
        textelement(Root)
        {
            tableelement(SocioElement; Socio)
            {
                fieldelement(No; Socio."No.") { }
                fieldelement(Nombre; Socio.Nombre) { }
                fieldelement(Email; Socio.Email) { }
                fieldelement(Tipo; Socio.Tipo) { }
            }
        }
    }

    trigger OnPostXmlPort()
    begin
        Message('Exportación completada.');
    end;
}

6. XMLport SourceType: Texto, Tabla y Campo

Los elementos del schema de un XMLport pueden tener diferentes SourceType que determinan de dónde vienen los datos.

SourceType Elemento Descripción
Table tableelement Representa una tabla de BC. Se itera sobre cada registro. Es el contenedor principal.
Field fieldelement / fieldattribute Representa un campo de la tabla del tableelement padre.
Text textelement / textattribute Texto fijo o variable no vinculado a ninguna tabla. Se gestiona con código AL.
// XMLport para importar socios desde CSV
xmlport 50501 "Importar Socios CSV"
{
    Direction      = Import;
    Format         = VariableText;
    FieldSeparator = ';';
    TextEncoding   = UTF8;
    Caption        = 'Importar Socios desde CSV';

    schema
    {
        textelement(Root) // textelement = nodo raíz sin tabla
        {
            tableelement(SocioImport; Socio) // tableelement = vinculado a tabla Socio
            {
                // fieldelement = vinculados a campos de la tabla
                fieldelement(No; Socio."No.") { }
                fieldelement(Nombre; Socio.Nombre) { }
                fieldelement(Email; Socio.Email) { }

                // textelement dentro de tableelement = dato del CSV
                // que no corresponde directamente a un campo
                // (lo procesamos manualmente en un trigger)
                textelement(TipoTexto) { }

                trigger OnBeforeInsertRecord()
                begin
                    // Convertir el texto del CSV al enum de tipo de socio
                    case UpperCase(TipoTexto) of
                        'NORMAL':  Socio.Tipo := Socio.Tipo::Normal;
                        'PREMIUM': Socio.Tipo := Socio.Tipo::Premium;
                        else
                            Socio.Tipo := Socio.Tipo::Normal;
                    end;

                    ContadorImportados += 1;
                end;
            }
        }
    }

    trigger OnPostXmlPort()
    begin
        Message('Importación completada. Socios importados: %1', ContadorImportados);
    end;

    var
        ContadorImportados: Integer;
}

💡 Element vs. Attribute (XML)

  • En formato XML, un fieldelement genera un nodo hijo: <Nombre>Ana</Nombre>
  • Un fieldattribute genera un atributo en el nodo padre: <Socio Nombre="Ana"/>
  • En formato CSV (VariableText), esta distinción no aplica — todo se serializa como columnas separadas.

⚠️ Buenas prácticas con XMLports

  • Siempre valida los datos en OnBeforeInsertRecord antes de insertarlos. Un CSV mal formado puede insertar basura.
  • Usa TextEncoding = UTF8 para evitar problemas con acentos y caracteres especiales en castellano.
  • Muestra un mensaje con el contador de registros procesados en OnPostXmlPort para que el usuario sepa el resultado.
  • Si el XMLport es Direction = Both, asegúrate de que la estructura sea coherente para importación y exportación.
← Volver a Teoría