EJERCICIO 05 · FLOWFIELDS
FlowFields
Dificultad: 6/10Ejercicios 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,TableRelationhacia"Maquinaria"y"Cabecera Alquiler". - Tabla
"Historial Estado Maquina"(50102):AutoIncrement,TableRelationcondicional según"Tipo Origen". - Pages
"Maquinaria List"y"Maquinaria Card"conOnValidatey 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.aly añade dos campos nuevos al bloquefields. - Campo
"No. Alquileres"(Integer):FieldClass = FlowFieldconCalcFormula = count("Linea Alquiler" where ("No. Maquina" = field("No."))). - Campo
"Tiene Historial"(Boolean):FieldClass = FlowFieldconCalcFormula = exist("Historial Estado Maquina" where ("No. Maquina" = field("No."))). - Ambos campos son de solo lectura: añade la propiedad
Editable = falsea 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
OnAfterGetRecorddeMaquinariaCard.Page.al, llama aRec.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.aly añade dos campos nuevos. - Campo
"No. Lineas"(Integer):countsobre"Linea Alquiler"filtrando por"No. Alquiler" = field("No."). - Para el
lookupnecesitas un campo de apoyo: añade primero el campo físico"No. Maquina Principal"(Code[20]) conTableRelation = "Maquinaria". Este campo guardará la máquina representativa del alquiler. - Campo
"Descripcion Maquina"(Text[100]):lookupsobre"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"alrepeater. BC los calculará fila a fila automáticamente. - En
MaquinariaCard.Page.al, añade"Ultimo Cambio Estado"algroup(General)debajo de"Estado". ElCalcFieldsdel ejercicio anterior ya lo cubre. - Crea una page de tipo
Cardpara"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.