Study guide

6.3 Document Reports & Request Page Programming

Microsoft Dynamics 365 Business Central Developer MB-820

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Business Central Architecture & Platform Foundation

1.1 Business Central Architecture & Extensions Model 1.2 Customization Lifecycle: Cloud (SaaS) vs. On-Premises 1.3 Base Application, System Application & AppSource

2 Chapter 2: Development Environment & Configuration

2.1: Development Environment Setup: VS Code, AL: Go! Projects & Sandboxes 2.2: AL Configuration Files: app.json & launch.json Parameters 2.3: Multi-Root Workspaces & Project Dependencies

3 Chapter 3: Extension Lifecycle: Debugging, Deployment, Multilanguage & Maintenance

3.1 Debugging & Snapshot Debugging in Visual Studio Code 3.2 Extension Deployment & Schema Synchronization Modes 3.3 Multilanguage Development with XLIFF & Translation Files 3.4 Extension Maintenance, Deprecation & Breaking Changes

4 Chapter 4: Tables, Table Extensions & Data Modeling

4.1: Building Tables, Fields, Keys & Data Types 4.2: Table Extensions & Table Modifications 4.3: FlowFields, FlowFilters & Table Relations 4.4: Enums, Enum Extensions & Extensible Types

5 Chapter 5: Pages, Page Extensions & Role Centers

5.1: Page Types, Anatomy & Control Structure 5.2: Building Card, List & Document Pages 5.3: Page Extensions & Page Customizations 5.4: Role Centers, Headlines & Cue Data Modeling

6 Chapter 6: Reports & Document Generation

6.1 Report Architecture, DataItems & Dataset Design 6.2 Report Layouts: RDLC, Word, Excel & Multilanguage 6.3 Document Reports & Request Page Programming 6.4 Processing-Only Reports & Report Substitutions

7 Chapter 7: XMLports & Data Exchange

7.1 XMLport Architecture, Formats & Properties 7.2 XMLport Node Hierarchy, Triggers & Stream Manipulation

8 Chapter 8: Codeunits, Events, Triggers & Interfaces

8.1 Codeunit Types, Execution & SingleInstance Codeunits 8.2 Events, Publishers, Subscribers & Event Isolation 8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation 8.4 Installation & Upgrade Codeunits, Data Transfer & Archive

9 Chapter 9: Entitlements, Permissions & Queries

9.1 Permission Sets & Permission Set Extensions 9.2 Inherent Permissions, Inherent Entitlements & Security Scoping 9.3 Query Objects: Joins, Aggregation & Query as Report Data Source

10 Chapter 10: UI Customization, User Assistance & Onboarding

10.1 Profile Objects & Custom Page Views in AL 10.2 User Assistance: ToolTips, Teaching Tips & In-App Tours 10.3 Assisted Setup, Guided Experience & Onboarding Checklists

11 Chapter 11: Business Central Design Patterns & Data Process Model

11.1 Functional Table Types: Master Data, Supplemental & Setup Patterns 11.2 Document Standards: Header, Line, History & Journal Architectures 11.3 Data Process Model & Posting Routine Architecture

12 Chapter 12: AL Language Fundamentals, Data Types & Variables

12.1 AL Syntax, Variable Scope, Primitive & Complex Data Types 12.2 Expressions, Control Flow Statements & Built-in Functions 12.3 Access Modifiers (Public, Internal, Local) & Code Scoping

13 Chapter 13: Data Manipulation, Streams & Error Handling

13.1 Record Operations: Get, FindSet, ModifyAll & Filter Functions 13.2 Streams, File Management & TempBlob 13.3 Error Handling: ErrorInfo, TryFunctions & Collectible Errors

14 Chapter 14: Testing, Test Toolkit & Automation

14.1 Testing Architecture & the Test Toolkit 14.2 Authoring Test Codeunits & UI Handler Functions

15 Chapter 15: Telemetry, Performance Optimization & Analyzers

15.1 Telemetry Configuration & Azure Application Insights 15.2 Custom Telemetry Signals with Session.LogMessage & KQL 15.3 Performance Profiler, SetLoadFields & Query Optimization 15.4 AL Analyzers: CodeCop, AppSourceCop, UICop & PTECop

16 Chapter 16: REST Web Services & JSON in AL

16.1 HttpClient, HttpRequestMessage & REST API Consumption 16.2 JSON Processing: JsonObject, JsonArray, JsonValue & JsonToken

17 Chapter 17: API Pages, OData, Read Scale-Out & OAuth

17.1 API Pages (PageType=API), OData Web Services & REST Endpoints 17.2 Bound and Unbound OData Actions with [ServiceEnabled] 17.3 Read Scale-Out Architecture & DataAccessIntent Configuration 17.4 Microsoft Entra ID App Registrations & OAuth 2.0 Integration

6.3 Document Reports & Request Page Programming

Key Takeaways Explain This Topic AI

Professional Business Central document reports utilize the Integer dataitem loop pattern (CopyLoop) to render the original document and multiple numbered copies in a single print job.

PageLoop integer dataitems isolate line item pagination, running balances, and transport headers/footers per document copy.

The requestpage block defines user options, date ranges, and output filters, allowing users to customize execution parameters prior to dataset generation.

Setting SaveValues = true on the request page persists user selections across sessions on a per-user, per-report basis in the tenant database.

The OnQueryClosePage trigger on request pages validates user parameters before processing begins, returning false or throwing an error to prevent report execution if inputs are invalid.

Last updated: August 2026

6.3 Document Reports & Request Page Programming

Commercial ERP document reports—such as Sales Invoices, Purchase Orders, and Order Confirmations—require complex operational capabilities that extend far beyond simple tabular data dumps. In enterprise environments, document reports must reliably handle multi-copy generation with dynamic watermarks ("ORIGINAL", "COPY 1", "COPY 2"), per-copy page numbering resets, transport running balances across multi-page tables, and interactive request page parameters. For developers preparing for the MB-820 certification exam, mastering the structural patterns and lifecycle triggers of document reporting is a crucial requirement.

1. The Professional Document Report Pattern ( CopyLoop & PageLoop )

In standard Business Central document reporting, invoices, shipments, and orders must frequently be printed in duplicate or triplicate for logistics, accounting, and customer archiving. Rather than requiring users to manually run the report multiple times, the report architecture utilizes nested Integer DataItem loops (conventionally named CopyLoop and PageLoop ). report 50120 "Standard Sales Order Conf."

  • {
  • UsageCategory = Documents;
  • ApplicationArea = Basic, Suite;
  • DefaultRenderingLayout = RDLC_Layout;
  • dataset
  • {
  • dataitem(Header; "Sales Header")
  • {
  • DataItemTableView = sorting("Document Type", "No.") where("Document Type" = const(Order));
  • RequestFilterFields = "No.", "Sell-to Customer No.", "Posting Date";
  • dataitem(CopyLoop; Integer)
  • {
  • DataItemTableView = sorting(Number);
  • column(CopyNo; Number) { }
  • column(CopyText; CopyText) { }
  • column(OutputNo; OutputNo) { }
  • dataitem(PageLoop; Integer)
  • {
  • DataItemTableView = sorting(Number);
  • column(CompanyInfoName; CompanyInfo.Name) { }
  • column(CompanyInfoAddress; CompanyInfo.Address) { }
  • column(CompanyInfoVATRegNo; CompanyInfo."VAT Registration No.") { }
  • column(DocumentTitle; DocumentTitle) { }
  • column(BillToCustomerNo; Header."Bill-to Customer No.") { IncludeCaption = true; }
  • column(BillToCustName; Header."Bill-to Name") { }
  • dataitem(Line; "Sales Line")
  • {
  • DataItemLink = "Document Type" = field("Document Type"),
  • "Document No." = field("No.");
  • DataItemLinkReference = Header;
  • DataItemTableView = sorting("Document Type", "Document No.", "Line No.");
  • column(LineNo; "Line No.") { }
  • column(ItemNo; "No.") { IncludeCaption = true; }
  • column(Description; Description) { IncludeCaption = true; }
  • column(Quantity; Quantity) { IncludeCaption = true; }
  • column(UnitPrice; "Unit Price") { IncludeCaption = true; }
  • column(LineAmount; "Line Amount") { IncludeCaption = true; }
  • }
  • dataitem(VATCounter; Integer)
  • {
  • DataItemTableView = sorting(Number);
  • column(VATBase; TempVATAmountLine."VAT Base") { AutoFormatType = 1; }
  • column(VATAmount; TempVATAmountLine."VAT Amount") { AutoFormatType = 1; }
  • column(VATIdentifier; TempVATAmountLine."VAT Identifier") { }
  • trigger OnPreDataItem()
  • begin
  • VATCounter.SetRange(Number, 1, TempVATAmountLine.Count());
  • end;
  • trigger OnAfterGetRecord()
  • begin
  • TempVATAmountLine.GetLine(Number);
  • end;
  • }
  • trigger OnPreDataItem()
  • begin
  • PageLoop.SetRange(Number, 1, 1);
  • end;
  • }
  • trigger OnPreDataItem()
  • begin
  • NoOfLoops := 1 + Abs(NoOfCopies);
  • CopyLoop.SetRange(Number, 1, NoOfLoops);
  • OutputNo := 1;
  • end;
  • trigger OnAfterGetRecord()
  • begin
  • if Number > 1 then begin
  • CopyText := FormatDocument.GetCopyText();
  • OutputNo += 1;
  • end else
  • CopyText := '';
  • end;
  • }
  • }
  • }
  • requestpage
  • {
  • // Request page implementation
  • }
  • var
  • CompanyInfo: Record "Company Information";
  • TempVATAmountLine: Record "VAT Amount Line" temporary;
  • FormatDocument: Codeunit "Format Document";
  • NoOfCopies: Integer;
  • NoOfLoops: Integer;
  • OutputNo: Integer;
  • CopyText: Text[30];
  • DocumentTitle: Text[50];
  • }
  • Breakdown of the Multi-Loop Hierarchy

DataItem Level DataItem Name & Type Architectural Purpose & Execution Mechanics

Level 1 (Root) Header ( Sales Header ) Queries and iterates through the selected sales orders based on table filters and request page criteria.

Level 2 (Copy) CopyLoop ( Integer ) Evaluates NoOfCopies in OnPreDataItem and sets its range from 1 to (1 + NoOfCopies) . Iteration 1 represents the "ORIGINAL" document; iterations 2+ represent duplicate copies with CopyText watermarks.

Level 3 (Page) PageLoop ( Integer ) Filtered strictly to SetRange(Number, 1, 1) to execute once per copy. Acts as the primary grouping anchor for page headers, customer billing information, and subtotal resets in the layout.

Level 4 (Lines) Line ( Sales Line ) Linked directly to Header via DataItemLinkReference = Header and DataItemLink . Emits line item details for every copy loop iteration.

Level 4 (Summary) VATCounter ( Integer ) Iterates through the in-memory TempVATAmountLine temporary table buffer to render tax summary grids after all document lines have processed.

Loading diagram... Document Report DataItem Hierarchy & Iteration Execution Tree

2. Pagination, Page Breaks & Transport Balances

In commercial document printing, long sales orders and invoices regularly span multiple physical pages. Adhering to international accounting and tax standards requires precise control over page breaks and carried-forward totals.

Transport Headers & Transport Footers (Carried-Forward Balances)

When line items overflow onto a second or third page:

Transport Footer (Page Bottom) : Displays a running subtotal of all lines printed up to the bottom of the current page, labeled as "Carried Forward: $X,XXX.XX" .

Transport Header (Page Top) : Displays the identical carried-forward balance at the top of the next page, labeled as "Brought Forward: $X,XXX.XX" .

Implementation : In AL and RDLC, developers track cumulative line amounts in AL variables or RDLC running total expressions ( =RunningValue(Fields!LineAmount.Value, Sum, "PageLoopGroup") ), toggling visibility based on page position.

RDLC Grouping and Page Breaks

To guarantee that multiple documents (or copies of the same document) print cleanly without page number bleeding:

Group Break Placement : On the Tablix group bound to Header and CopyLoop , developers configure PageBreak.BreakLocation = Between (or After ).

Page Number Reset : Setting PageBreak.ResetPageNumber = True ensures each invoice and each copy begins on Page 1, resetting the built-in Globals!PageNumber counter.

KeepTogether Property : Applying KeepTogether = True to individual Tablix rows or entire summary sections (e.g., VAT Breakdown or Total Summary grids) prevents the rendering engine from splitting a single summary block across physical page breaks.

3. Report Request Page Architecture & UI Design

The requestpage block allows developers to capture user options, specify runtime filters, and validate parameters prior to dataset generation. requestpage

  • {
  • SaveValues = true;
  • SaveLayout = false;
  • layout
  • {
  • area(Content)
  • {
  • group(Options)
  • {
  • Caption = 'Options';
  • field(NoOfCopiesField; NoOfCopies)
  • {
  • ApplicationArea = All;
  • Caption = 'No. of Copies';
  • ToolTip = 'Specifies the number of copies to print in addition to the original document.';
  • MinValue = 0;
  • MaxValue = 10;
  • }
  • field(ShowInternalInfoField; ShowInternalInfo)
  • {
  • ApplicationArea = All;
  • Caption = 'Show Internal Information';
  • ToolTip = 'Specifies if internal notes and hidden work lines should be included.';
  • }
  • field(LogInteractionField; LogInteraction)
  • {
  • ApplicationArea = All;
  • Caption = 'Log Interaction';
  • ToolTip = 'Specifies if an interaction entry should be created for this customer.';
  • }
  • field(DisplayInLCYField; DisplayInLCY)
  • {
  • ApplicationArea = All;
  • Caption = 'Show Amounts in LCY';
  • ToolTip = 'Specifies if foreign currency amounts should be converted to local currency.';
  • }
  • }
  • }
  • }
  • actions
  • {
  • area(Processing)
  • {
  • action(ResetDefaults)
  • {
  • ApplicationArea = All;
  • Caption = 'Reset to Defaults';
  • Image = ResetStatus;
  • trigger OnAction()
  • begin
  • NoOfCopies := 0;
  • ShowInternalInfo := false;
  • LogInteraction := true;
  • DisplayInLCY := false;
  • end;
  • }
  • }
  • }
  • trigger OnOpenPage()
  • begin
  • if not SaveValuesLoaded then
  • InitDefaults();
  • end;
  • trigger OnQueryClosePage(CloseAction: Action): Boolean
  • begin
  • if CloseAction in [Action::OK, Action::LookupOK, Action::Preview] then begin
  • if (StartDate <> 0D) and (EndDate <> 0D) and (EndDate < StartDate) then
  • Error('End Date (%1) cannot be earlier than Start Date (%2).', EndDate, StartDate);
  • end;
  • exit(true);
  • end;
  • }
  • Request Page Lifecycle and Property Mechanics

SaveValues = true : When enabled, Business Central stores the user-entered values of request page controls and dataitem filters in the tenant database per user ID and object ID. When that same user runs the report again, the previous settings are preloaded automatically.

OnOpenPage : Trigger executed when the request page is instantiated in the client. Used to initialize default filter dates, lookup values, and dynamic control visibility.

OnQueryClosePage(CloseAction: Action): Boolean : Trigger executed when the user clicks Print , Preview , Schedule , or OK . It receives the CloseAction parameter. If validation logic finds invalid inputs (e.g., an illegal date range or missing required parameter), raising an Error() or returning false halts closure and prevents report dataset processing.

Programmatic Invocation and Parameter Passing

Reports can also be executed programmatically in AL without displaying the request page UI: // Execute report directly using stored filters or default parameters

Report.Run(Report::"Standard Sales - Invoice", false, false, SalesHeaderRec);

  • // Run request page programmatically to capture parameter XML
  • var
  • ParametersXml: Text;
  • begin
  • ParametersXml := Report.RunRequestPage(Report::"Sales Order Summary");
  • Report.Execute(Report::"Sales Order Summary", ParametersXml);
  • end;