If you’re new to Microsoft Dynamics 365 Business Central development, reports might seem confusing at first. Don’t worry! This guide will explain everything in simple terms, with easy-to-follow examples. By the end, you’ll understand how to work with report fields and how to customize existing reports.
What is a Report?
Think of a report as a document that shows business data – like an invoice, a customer list, or a sales summary. In Business Central, reports pull data from your database and display it in a nice format that users can read, print, or save.
Part 1: Understanding Report Fields
What Are Report Fields?
Report fields are like blank spaces on a form that get filled in with data. For example:
- Customer Name (gets filled with “John Smith”)
- Invoice Number (gets filled with “INV-001”)
- Total Amount (gets filled with “$1,500.00”)
Creating a Simple Report Field
Here’s what a basic report field looks like:
Al
Column (CustomerName; Customer.Name)
{
}
Let’s break this down:
- column = We’re creating a field
- CustomerName = The name we give to this field
- Customer.Name = Where the data comes from (the Customer table, Name field)
Important Field Properties (The Easy Ones)
1. Caption – Giving Your Field a Label
The Caption is like a label that tells users what the field shows.
Al
column (CustomerName; Customer.Name)
{
Caption = 'Customer Name';
}
Simple rule: Always give your fields clear, easy-to-read captions.
2. DecimalPlaces – Controlling Decimal Numbers
This controls how many numbers appear after the decimal point.
Al
Column (Price; Item."Unit Price")
{
DecimalPlaces = 2:2; // Shows exactly 2 decimals (like $10.50)
}
When to use:
- Money amounts: Use 2:2 (shows $10.50, not $10.5)
- Quantities: Use 0:2 (shows 5 or 5.25, but not 5.0000)
3. BlankZero – Hiding Zero Values
Sometimes you don’t want to show zero. This property hides zeros and shows blank instead.
Al
column (Discount; SalesLine."Discount %")
{
BlankZero = true; // If discount is 0%, shows nothing
}
Example:
- Without BlankZero: Shows “0%” even when there’s no discount
- With BlankZero: Shows nothing when there’s no discount (looks cleaner!)
Real Example: A Simple Invoice Report
Let’s create fields for a simple invoice:
Al
dataitem(SalesInvoice; "Sales Invoice Header")
{
// Invoice Number
column(InvoiceNo; "No.")
{
Caption = 'Invoice Number';
}
// Customer Name
column(CustomerName; "Sell-to Customer Name")
{
Caption = 'Customer';
}
// Invoice Date
column(InvoiceDate; "Posting Date")
{
Caption = 'Date';
}
// Total Amount
Column (TotalAmount; "Amount Including VAT")
{
Caption = 'Total';
DecimalPlaces = 2:2;
}
}
What this does:
- Gets invoice data from the Sales Invoice table
- Shows the invoice number, customer name, date, and total
- Formats the total amount with 2 decimal places
Adding Calculations
You can also create fields that calculate values. Here’s a simple example:
Al
{
column(DiscountAmount; GetDiscountAmount())
Caption = 'Discount';
DecimalPlaces = 2:2;
}
// This function does the calculation
local procedure GetDiscountAmount(): Decimal
begin
exit(SalesInvoice.Amount * SalesInvoice."Discount %" / 100);
end;
What this does:
- Creates a field called DiscountAmount
- Calculates the discount by multiplying Amount × Discount %
- Shows the result with 2 decimal places
Part 2: Report Extensions (Customizing Existing Reports)
What Are Report Extensions?
Sometimes you need to add information to a report that already exists in Business Central. Instead of changing the original report (which could cause problems), you create an “extension” – think of it as adding extra pages to a book without changing the original pages.
Why Use Extensions?
The Problem:
- Business Central comes with standard reports (like invoices)
- You want to add your own fields (like “Account Manager”)
- You can’t change Microsoft’s reports directly
The Solution:
- Create a report extension
- Add your custom fields
- The original report stays safe, and you can upgrade Business Central without losing your changes
Creating Your First Report Extension
Here’s a simple example that adds a field to the Customer List report:
Al
reportextension 50100 "My Customer List Extension" extends "Customer - List"
{
dataset
{
add(Customer)
{
column(AccountManager; Customer."Salesperson Code")
{
Caption = 'Account Manager';
}
}
}
}
Let’s understand this step by step:
- reportextension 50100 = Creating an extension with ID 50100
- “My Customer List Extension” = Naming our extension
- extends “Customer – List” = Adding to the existing Customer List report
- add(Customer) = Adding to the Customer section
- column(AccountManager…) = Adding our new field
Result: The Customer List now shows an Account Manager column!
Adding Multiple Fields
Let’s add more information to a Sales Invoice:
Al
reportextension 50101 "Sales Invoice Extra Info" extends "Sales Invoice"
{
dataset
{
add(Header)
{
// Add shipping method
column(ShippingMethod; Header."Shipping Agent Code")
{
Caption = 'Shipping Method';
}
// Add payment terms
column(PaymentTerms; Header."Payment Terms Code")
{
Caption = 'Payment Terms';
}
// Add a custom field
column(ProjectCode; Header."Project Code")
{
Caption = 'Project';
}
}
}
}
What this does:
- Adds Shipping Method to the invoice
- Adds Payment Terms to the invoice
- Adds a Project Code field
- All without touching the original Sales Invoice report!
Adding Options to Reports
Sometimes you want to give users choices before running a report. Here’s how:
Al
reportextension 50102 "Customer List Options" extends "Customer - List"
{
requestpage
{
layout
{
addafter(Options)
{
// Add a checkbox
field(ShowInactive; ShowInactive)
{
ApplicationArea = All;
Caption = 'Show Inactive Customers';
}
// Add a number field
field(MinimumBalance; MinimumBalance)
{
ApplicationArea = All;
Caption = 'Minimum Balance to Show';
}
}
}
}
var
ShowInactive: Boolean;
MinimumBalance: Decimal;
}
What this does:
- Adds a checkbox: “Show Inactive Customers”
- Adds a number field: “Minimum Balance to Show”
- Users can check/uncheck or enter amounts before running the report
Calculating Values in Extensions
You can add calculated fields to existing reports:
Al
reportextension 50103 "Sales Order Calculations" extends "Sales Order"
{
dataset
{
add(Header)
{
// Add calculated field
column(DaysUntilDelivery; CalculateDaysUntilDelivery())
{
Caption = 'Days Until Delivery';
}
}
}
// The calculation
local procedure CalculateDaysUntilDelivery(): Integer
begin
if Header."Requested Delivery Date" <> 0D then
exit(Header."Requested Delivery Date" - Today)
else
exit(0);
end;
}
What this does:
- Adds a field showing days until delivery
- Calculates: Delivery Date minus Today’s Date
- Shows 0 if no delivery date is set
Simple Examples for Common Tasks
Example 1: Adding a Custom Message to an Invoice
Al
reportextension 50104 "Invoice Custom Message" extends "Sales Invoice"
{
dataset
{
add(Header)
{
column(ThankYouMessage; GetThankYouMessage())
{
Caption = 'Thank You Message';
}
}
}
local procedure GetThankYouMessage(): Text
begin
exit('Thank you for your business! We appreciate your order.');
end;
}
Example 2: Showing Customer’s Total Orders
al
reportextension 50105 "Customer Total Orders" extends "Customer - List"
{
dataset
{
add(Customer)
{
column(TotalOrders; CalculateTotalOrders())
{
Caption = 'Total Orders';
DecimalPlaces = 2:2;
}
}
}
local procedure CalculateTotalOrders(): Decimal
var
SalesInvoiceHeader: Record "Sales Invoice Header";
Total: Decimal;
begin
Total := 0;
SalesInvoiceHeader.SetRange("Sell-to Customer No.", Customer."No.");
if SalesInvoiceHeader.FindSet() then
repeat
Total := Total + SalesInvoiceHeader."Amount Including VAT";
until SalesInvoiceHeader.Next() = 0;
exit(Total);
end;
}
What this does:
- Finds all invoices for the customer
- Adds up all the invoice amounts
- Shows the total
Example 3: Color-Coding Based on Values
Al
reportextension 50106 "Customer Credit Status" extends "Customer - List"
{
dataset
{
add(Customer)
{
column(CreditStatus; GetCreditStatus())
{
Caption = 'Credit Status';
}
}
}
local procedure GetCreditStatus(): Text
begin
if Customer."Balance (LCY)" > Customer."Credit Limit (LCY)" then
exit('⚠️ OVER LIMIT')
else if Customer."Balance (LCY)" > (Customer."Credit Limit (LCY)" * 0.8) then
exit('⚡ NEAR LIMIT')
else
exit('✓ OK');
end;
}
What this does:
- Checks customer’s balance vs credit limit
- Shows warning symbols for customers near or over limit
- Makes it easy to spot credit issues
Tips for Beginners
Tip 1: Start Simple
Don’t try to do everything at once. Start with:
- Adding one field
- Test it
- Then add more
Tip 2: Use Good Names
Al
// BAD - Unclear names
column(X1; Customer.Name)
column(Amt; Amount)
// GOOD - Clear names
column(CustomerName; Customer.Name)
column(TotalAmount; Amount)
Tip 3: Always Add Captions
Al
// BAD - No caption
column(CustomerName; Customer.Name)
{
}
// GOOD - Has caption
column(CustomerName; Customer.Name)
{
Caption = 'Customer Name';
}
Tip 4: Format Money Properly
al
// For money, always use 2 decimal places
column(Price; Item."Unit Price")
{
DecimalPlaces = 2:2;
}
Tip 5: Test Your Reports
- Always run your report after making changes
- Check if the data looks correct
- Make sure calculations work properly
Common Mistakes to Avoid
Mistake 1: Forgetting DecimalPlaces
Al
// BAD - Might show $10.5000000
column(Price; Item."Unit Price")
{
}
// GOOD - Always shows $10.50
column(Price; Item."Unit Price")
{
DecimalPlaces = 2:2;
}
Mistake 2: Not Testing with Real Data
- Test your report with actual data
- Check what happens with zero values
- Try it with big numbers and small numbers
Mistake 3: Making Complex Calculations
Al
// BAD - Too complex, hard to debug
column(ComplexValue; ((Amount * Tax) + (Discount / 100)) - Fees)
// GOOD - Break it down
column(ComplexValue; CalculateComplexValue())
local procedure CalculateComplexValue(): Decimal
var
Step1: Decimal;
Step2: Decimal;
begin
Step1 := Amount * Tax;
Step2 := Discount / 100;
exit((Step1 + Step2) - Fees);
end;
Quick Reference Guide
For Report Fields
| Property | What It Does | Example |
| Caption | Labels the field | Caption = ‘Customer Name’; |
| DecimalPlaces | Controls decimals | DecimalPlaces = 2:2; |
| BlankZero | Hides zeros | BlankZero = true; |
For Report Extensions
| Action | Code Pattern | Use When |
| Add field | add(DataItem) { column(…) } | Adding new data |
| Add options | requestpage { layout { field(…) } } | User needs choices |
| Calculate | local procedure Name(): Decimal | Need to compute values |
Your First Complete Report Extension
Here’s everything together in one working example:
Al
reportextension 50107 "My First Extension" extends "Customer - List"
{
dataset
{
// Add new fields
add(Customer)
{
// Show account manager
column(AccountMgr; Customer."Salesperson Code")
{
Caption = 'Account Manager';
}
// Calculate and show customer value
column(CustomerValue; GetCustomerValue())
{
Caption = 'Total Customer Value';
DecimalPlaces = 2:2;
}
// Show credit status
column(Status; GetCreditStatus())
{
Caption = 'Status';
}
}
}
// Add user options
requestpage
{
layout
{
addafter(Options)
{
field(ShowDetails; ShowDetails)
{
ApplicationArea = All;
Caption = 'Show Detailed Information';
}
}
}
}
var
ShowDetails: Boolean;
// Calculate customer's total value
local procedure GetCustomerValue(): Decimal
var
SalesInvoiceHeader: Record "Sales Invoice Header";
TotalValue: Decimal;
begin
TotalValue := 0;
SalesInvoiceHeader.SetRange("Sell-to Customer No.", Customer."No.");
if SalesInvoiceHeader.FindSet() then
repeat
TotalValue := TotalValue + SalesInvoiceHeader."Amount Including VAT";
until SalesInvoiceHeader.Next() = 0;
exit(TotalValue);
end;
// Check credit status
local procedure GetCreditStatus(): Text
begin
if Customer."Balance (LCY)" > Customer."Credit Limit (LCY)" then
exit('Over Limit')
else
exit('OK');
end;
}
What this complete example does:
- Extends the Customer List report
- Adds Account Manager field
- Calculates total customer value from all invoices
- Shows credit status (OK or Over Limit)
- Adds a checkbox option for users
- Formats all money values properly
Next Steps
Now that you understand the basics:
- Practice: Try adding fields to existing reports
- Experiment: Create simple calculations
- Ask Questions: Join Business Central communities
- Learn More: Read Microsoft’s documentation as you get comfortable
Summary: Key Points to Remember
- Report Fields show data in your reports
- Captions make fields easy to understand
- DecimalPlaces format numbers properly (use 2:2 for money)
- BlankZero hides zero values when you don’t need them
- Report Extensions let you customize reports safely
- Add fields with add(DataItem) { column(…) }
- Add options with requestpage { layout {…} }
- Always test your changes with real data
Conclusion
Congratulations! You now know the basics of working with Business Central reports. Start small, practice often, and don’t be afraid to experiment. Every expert developer started exactly where you are now.
Remember: The best way to learn is by doing. Pick a simple report and try adding one field. Once that works, add another. Before you know it, you’ll be creating complex, professional reports!