EJERCICIO 05 · FLOWFIELDS

FlowFields

Dificultad: 6/10
Ejercicios anteriores

¿Qué tienes construido hasta ahora?

  • Enum "Rental Status" con los estados de maquinaria, extensible.
  • Tabla "Maquinaria" (50100): PK "No.", campos "Estado", "Categoria", "Fecha Alta", claves secundarias.
  • Tabla "Cabecera Alquiler" (50103): PK "No.", vinculada desde líneas.
  • Tabla "Linea Alquiler" (50101): PK compuesta, TableRelation hacia "Maquinaria" y "Cabecera Alquiler".
  • Tabla "Historial Estado Maquina" (50102): AutoIncrement, TableRelation condicional según "Tipo Origen".
  • Pages "Maquinaria List" y "Maquinaria Card" con OnValidate y filtro por estado.

Hasta ahora las tablas guardan datos, pero no calculan nada por sí solas. En este ejercicio añadirás FlowFields a las tablas que ya tienes para que muestren totales, contadores y comprobaciones de existencia sin necesidad de triggers ni campos físicos extra.

Este es el resumen de los FlowFields que vas a crear a lo largo del ejercicio:

Tabla Campo Función Qué calcula
"Maquinaria" "No. Alquileres" count Líneas en "Linea Alquiler" para esa máquina
"Maquinaria" "Tiene Historial" exist Si existe algún cambio de estado registrado
"Maquinaria" "Ultimo Cambio Estado" max Fecha más reciente en el historial
"Cabecera Alquiler" "No. Lineas" count Número de líneas de ese alquiler
"Cabecera Alquiler" "Descripcion Maquina" lookup Descripción de la máquina de la primera línea
Ejercicio 01
Count · Exist

Contadores y existencia en Maquinaria

Objetivo: Añadir a la tabla "Maquinaria" dos FlowFields que indiquen cuántas líneas de alquiler tiene cada máquina y si alguna vez ha tenido un cambio de estado registrado en el historial.

Instrucciones

  • Abre Maquinaria.Table.al y añade dos campos nuevos al bloque fields.
  • Campo "No. Alquileres" (Integer): FieldClass = FlowField con CalcFormula = count("Linea Alquiler" where ("No. Maquina" = field("No."))).
  • Campo "Tiene Historial" (Boolean): FieldClass = FlowField con CalcFormula = exist("Historial Estado Maquina" where ("No. Maquina" = field("No."))).
  • Ambos campos son de solo lectura: añade la propiedad Editable = false a cada uno.

Pista de Código

AL — Maquinaria.Table.al (campos nuevos)
        field(10; "No. Alquileres"; Integer)
        {
            FieldClass  = FlowField;
            CalcFormula = count("Linea Alquiler"
                                where ("No. Maquina" = field("No.")));
            Editable    = false;
        }
        field(11; "Tiene Historial"; Boolean)
        {
            FieldClass  = FlowField;
            CalcFormula = exist("Historial Estado Maquina"
                                where ("No. Maquina" = field("No.")));
            Editable    = false;
        }
⚠️ Recuerda: Los FlowFields son de solo lectura. Si intentas asignarles un valor directamente en código, el compilador lanzará un error. Siempre usa CalcFields antes de leerlos desde AL.
Ejercicio 02
Max · CalcFields

Fecha del último cambio de estado

Objetivo: Añadir a "Maquinaria" un FlowField con max que recupere la fecha más reciente del historial de cambios de estado, y después leerlo correctamente desde código con CalcFields.

Instrucciones

  • Añade el campo "Ultimo Cambio Estado" (DateTime) a la tabla "Maquinaria".
  • Configúralo como FlowField con CalcFormula = max("Historial Estado Maquina"."Fecha Cambio" where ("No. Maquina" = field("No."))).
  • En el trigger OnAfterGetRecord de MaquinariaCard.Page.al, llama a Rec.CalcFields("Ultimo Cambio Estado") para que el campo se calcule al abrir la ficha.
  • Expón el campo en el group(General) de la ficha, debajo de "Estado".

Pista de Código

AL — Maquinaria.Table.al (campo nuevo)
        field(12; "Ultimo Cambio Estado"; DateTime)
        {
            FieldClass  = FlowField;
            CalcFormula = max("Historial Estado Maquina"."Fecha Cambio"
                              where ("No. Maquina" = field("No.")));
            Editable    = false;
        }
AL — MaquinariaCard.Page.al (trigger)
    trigger OnAfterGetRecord()
    begin
        Rec.CalcFields("Ultimo Cambio Estado"); // forzamos el cálculo antes de mostrar
    end;
💡 Recuerda: En las pages, BC calcula automáticamente los FlowFields al renderizar el campo en pantalla. El CalcFields manual es necesario cuando lees el valor desde código (triggers, codeunits…) antes de que la interfaz lo muestre.
Ejercicio 03
Count · Lookup

Totales y descripción en Cabecera Alquiler

Objetivo: Enriquecer la tabla "Cabecera Alquiler" con un contador de líneas y un campo que recupere mediante lookup la descripción de la máquina asociada a la cabecera, sin duplicar ese dato físicamente.

Instrucciones

  • Abre CabeceraAlquiler.Table.al y añade dos campos nuevos.
  • Campo "No. Lineas" (Integer): count sobre "Linea Alquiler" filtrando por "No. Alquiler" = field("No.").
  • Para el lookup necesitas un campo de apoyo: añade primero el campo físico "No. Maquina Principal" (Code[20]) con TableRelation = "Maquinaria". Este campo guardará la máquina representativa del alquiler.
  • Campo "Descripcion Maquina" (Text[100]): lookup sobre "Maquinaria"."Descripcion" donde "No." = field("No. Maquina Principal").

Pista de Código

AL — CabeceraAlquiler.Table.al (campos nuevos)
        field(6; "No. Maquina Principal"; Code[20])
        {
            TableRelation = "Maquinaria"; // campo físico de apoyo para el lookup
        }
        field(7; "No. Lineas"; Integer)
        {
            FieldClass  = FlowField;
            CalcFormula = count("Linea Alquiler"
                                where ("No. Alquiler" = field("No.")));
            Editable    = false;
        }
        field(8; "Descripcion Maquina"; Text[100])
        {
            FieldClass  = FlowField;
            CalcFormula = lookup("Maquinaria"."Descripcion"
                                  where ("No." = field("No. Maquina Principal")));
            Editable    = false;
        }
💡 Bonus: Ahora que "Cabecera Alquiler" tiene "No. Lineas", podrías usarlo en el trigger OnValidate del campo "Estado" para impedir cerrar un alquiler si tiene cero líneas. Pista: Rec.CalcFields("No. Lineas"); if Rec."No. Lineas" = 0 then Error(...);
Ejercicio 04
Pages · CalcFields

Muestra los FlowFields en pantalla

Objetivo: Añadir los FlowFields creados a las pages existentes y verificar que BC los calcula automáticamente al renderizarlos, sin necesidad de CalcFields manual en la mayoría de los casos.

Instrucciones

  • En MaquinariaList.Page.al, añade los campos "No. Alquileres" y "Tiene Historial" al repeater. BC los calculará fila a fila automáticamente.
  • En MaquinariaCard.Page.al, añade "Ultimo Cambio Estado" al group(General) debajo de "Estado". El CalcFields del ejercicio anterior ya lo cubre.
  • Crea una page de tipo Card para "Cabecera Alquiler" (ID 50104, nombre "Cabecera Alquiler Card") que muestre todos sus campos, incluyendo "No. Lineas" y "Descripcion Maquina".

Pista de Código

AL — fragmento repeater en MaquinariaList.Page.al
                field("No. Alquileres"; Rec."No. Alquileres")  { ApplicationArea = All; }
                field("Tiene Historial"; Rec."Tiene Historial") { ApplicationArea = All; }
AL — CabeceraAlquilerCard.Page.al
page 50104 "Cabecera Alquiler Card"
{
    PageType    = Card;
    SourceTable = "Cabecera Alquiler";
    UsageCategory = None;

    layout
    {
        area(content)
        {
            group(General)
            {
                field("No.";                  Rec."No.")                  { ApplicationArea = All; }
                field("Descripcion";         Rec."Descripcion")         { ApplicationArea = All; }
                field("No. Maquina Principal"; Rec."No. Maquina Principal") { ApplicationArea = All; }
                field("Descripcion Maquina";  Rec."Descripcion Maquina")  { ApplicationArea = All; }
                field("Fecha Inicio";         Rec."Fecha Inicio")         { ApplicationArea = All; }
                field("Fecha Fin";            Rec."Fecha Fin")            { ApplicationArea = All; }
                field("Estado";              Rec."Estado")              { ApplicationArea = All; }
                field("No. Lineas";          Rec."No. Lineas")          { ApplicationArea = All; }
            }
        }
    }
}
⚠️ Recuerda: En pages, BC calcula los FlowFields automáticamente al mostrarlos. Pero si necesitas su valor dentro de un trigger de la misma page (por ejemplo en OnAction), debes llamar primero a Rec.CalcFields(...), ya que fuera de la renderización el valor estará vacío.
← Volver a Ejercicios