Informes y Documentos
RequestPage
Dificultad: 7/10¿Qué pasa si tienes 1 millón de facturas y lanzas un Report sin filtros? El motor de BC bloqueará todo tratando de generar 45.000 páginas en PDF, destrozando la memoria del servidor. Para esto existe el RequestPage: la pantalla previa que aparece antes de que el informe empiece a procesar datos.
Estructura básica
La sección requestpage va dentro del Report, al mismo nivel que dataset:
requestpage
{
SaveValues = true; // BC recuerda la última configuración del usuario
layout
{
area(Content)
{
group(Opciones)
{
Caption = 'Opciones del Informe';
field(IncluirDevueltos; IncluirDevueltos)
{
ApplicationArea = All;
Caption = 'Incluir préstamos ya devueltos';
ToolTip = 'Marca esta casilla para ver también los préstamos devueltos.';
}
}
}
}
trigger OnOpenPage()
begin
// Valores por defecto al abrir la RequestPage
IncluirDevueltos := false;
end;
}
¿Qué es la RequestPage?
Es una "mini ventana popup" que aparece siempre antes de que el motor empiece a recorrer los DataItems del informe. Esta ventana interrumpe al motor en seco y le da al usuario controles para acotar los datos: campos de fecha "Desde... Hasta...", selectores booleanos como Incluir Clientes Morosos, rangos de código, etc.
Los filtros estándar de los DataItems aparecen en la RequestPage de forma automática. Tú solo defines las opciones adicionales que quieras añadir.
SaveValues — Recordar la última configuración
SaveValues = true hace que BC recuerde la última configuración que usó el usuario. Muy
cómodo para informes que se lanzan a diario con los mismos parámetros.
Añadir filtros de fecha
El caso más habitual: permitir que el usuario filtre el informe por un rango de fechas. Las variables definidas en la RequestPage son globales del Report, accesibles desde cualquier trigger y DataItem:
requestpage
{
SaveValues = true;
layout
{
area(Content)
{
group(Opciones)
{
Caption = 'Opciones';
field(IncluirDevueltos; IncluirDevueltos)
{
ApplicationArea = All;
Caption = 'Incluir préstamos devueltos';
}
}
group(Fechas)
{
Caption = 'Rango de fechas';
field(FechaDesde; FechaFiltroDesde)
{
ApplicationArea = All;
Caption = 'Fecha inicio: Desde';
}
field(FechaHasta; FechaFiltroHasta)
{
ApplicationArea = All;
Caption = 'Fecha inicio: Hasta';
}
}
}
}
trigger OnOpenPage()
begin
// Valores por defecto: año en curso completo
FechaFiltroDesde := DMY2Date(1, 1, Date2DMY(Today(), 3)); // 1 de enero del año actual
FechaFiltroHasta := Today();
IncluirDevueltos := false;
end;
}
Usar las opciones en los DataItems
Las variables de la RequestPage se aplican en OnPreDataItem(), no en
OnAfterGetRecord(). Así BC filtra antes de traer los datos, no después:
⚠️ Filtra siempre en OnPreDataItem
Si filtraras en OnAfterGetRecord, BC primero traería
todos los registros y luego los descartaría uno a uno, lo cual es muy ineficiente.
Filtra siempre en OnPreDataItem para que SQL solo devuelva lo que necesitas.
dataitem(Prestamo; Prestamo)
{
DataItemLink = "No. Socio" = FIELD("No.");
trigger OnPreDataItem()
begin
// Aplicamos los filtros de fecha que el usuario eligió en la RequestPage
if FechaFiltroDesde <> 0D then
SetFilter("Fecha Inicio", '>=%1', FechaFiltroDesde);
if FechaFiltroHasta <> 0D then
SetFilter("Fecha Inicio", '<=%1', FechaFiltroHasta);
// Si el usuario NO marcó "Incluir devueltos", los excluimos
if not IncluirDevueltos then
SetFilter(Estado, '<>%1', Estado::Devuelto);
end;
}
Ejemplo completo: Report con RequestPage integrada
report 50102 "Informe Completo Prestamos"
{
Caption = 'Informe Completo de Préstamos';
UsageCategory = ReportsAndAnalysis;
ApplicationArea = All;
dataset
{
dataitem(Socio; Socio)
{
column(Socio_No; "No.") { }
column(Socio_Nombre; Nombre) { }
column(Socio_Total; TotalDiasSocio) { }
trigger OnPreDataItem()
begin
SetCurrentKey(Nombre);
end;
trigger OnAfterGetRecord()
begin
TotalDiasSocio := 0;
end;
dataitem(Prestamo; Prestamo)
{
DataItemLink = "No. Socio" = FIELD("No.");
column(Prest_No; "No.") { }
column(Prest_Inicio; "Fecha Inicio") { }
column(Prest_Dias; "Dias Prestamo") { }
column(Prest_Estado; Estado) { }
trigger OnPreDataItem()
begin
// Filtros dinámicos desde la RequestPage
if FechaFiltroDesde <> 0D then
SetFilter("Fecha Inicio", '>=%1', FechaFiltroDesde);
if FechaFiltroHasta <> 0D then
SetFilter("Fecha Inicio", '<=%1', FechaFiltroHasta);
if not IncluirDevueltos then
SetFilter(Estado, '<>%1', Estado::Devuelto);
SetCurrentKey("Fecha Inicio");
SetAscending("Fecha Inicio", false);
end;
trigger OnAfterGetRecord()
begin
TotalDiasSocio += "Dias Prestamo";
end;
}
}
}
requestpage
{
SaveValues = true;
layout
{
area(Content)
{
group(Opciones) { Caption = 'Opciones';
field(IncluirDevueltos; IncluirDevueltos) { ApplicationArea = All; Caption = 'Incluir devueltos'; }
}
group(Fechas) { Caption = 'Rango de fechas';
field(FechaDesde; FechaFiltroDesde) { ApplicationArea = All; Caption = 'Desde'; }
field(FechaHasta; FechaFiltroHasta) { ApplicationArea = All; Caption = 'Hasta'; }
}
}
}
trigger OnOpenPage()
begin
FechaFiltroDesde := DMY2Date(1, 1, Date2DMY(Today(), 3));
FechaFiltroHasta := Today();
IncluirDevueltos := false;
end;
}
var
TotalDiasSocio : Integer;
IncluirDevueltos: Boolean;
FechaFiltroDesde: Date;
FechaFiltroHasta: Date;
rendering
{
layout(RDLCLayout)
{
Type = RDLC;
LayoutFile = 'src/layouts/InformeCompleto.rdlc';
}
}
trigger OnPreReport()
begin
// Validamos que la fecha Desde no sea posterior a Hasta
if (FechaFiltroDesde <> 0D) and (FechaFiltroHasta <> 0D) then
if FechaFiltroDesde > FechaFiltroHasta then
Error('La fecha "Desde" no puede ser posterior a la fecha "Hasta".');
end;
trigger OnPostReport()
begin
Message('Informe generado correctamente.');
end;
}
💡 Tips
SaveValues = trueguarda la última configuración del usuario. Ideal para informes que se ejecutan a diario con los mismos parámetros.- Las variables de la RequestPage son globales del Report: accesibles desde cualquier DataItem y trigger sin necesidad de pasarlas como parámetros.
- Usa
OnOpenPage()de la RequestPage para poner valores por defecto inteligentes (ej. año en curso, sin devueltos...). - Aplica los filtros siempre en
OnPreDataItem, nunca enOnAfterGetRecord. El primero filtra en SQL antes de traer datos; el segundo los trae todos y los descarta uno a uno. - Valida las opciones del usuario en
OnPreReport(): es el último punto antes de que el motor empiece a leer datos.