Developing a Custom Report Render
APPLIES TO: Business Central 2022 release wave 1 and later
This article describes the concept of a custom report render. The custom report render manages the rendering of a generated report dataset with a layout type specified by an extension. The actual rendering will take place in the application by using the OnCustomDocumentMergerEx
event provided by the ReportManagement
codeunit. The layout must be specified in the rendering
section in the report definition.
History and context
The custom render feature is a substitute for the business events that were used in the OnDocumentMerge
event provided by the DocumentManagement
codeunit for rendering Word documents in the application. When using the custom render logic, the report can support multiple layouts and the event code won't have dependencies to standard Word layout processing in the platform or application. The layout files that are provided in the extension are imported without any further processing, whereas the Word documents are aligned with the platform requirements for that format.
Layout declaration for a custom render
report 50000 "Standard Report Layout"
{
DefaultRenderingLayout = CustomLayout;
...
rendering
{
layout(CustomLayout)
{
Type = Custom;
LayoutFile = './StandardReportLayout.custom';
Caption = 'First custom layout';
Summary = 'First custom layout summary';
MimeType = 'Application/Report/MyExtension';
}
}
}
Sample AL code
The simplest possible custom document render can be implemented as in the following sample. The example will use the existing application logic to render XML datasets into Microsoft Word or PDF documents using a given template (Word template).
[EventSubscriber(ObjectType::Codeunit, Codeunit::ReportManagement, 'OnCustomDocumentMergerEx', '', true, true)]
local procedure OnCustomDocumentMergerEx(ObjectID: Integer; ReportAction: Option SaveAsPdf,SaveAsWord,SaveAsExcel,Preview,Print,SaveAsHtml; ObjectPayload: JsonObject; XmlData: InStream; LayoutData: InStream; var DocumentStream: OutStream; var IsHandled: Boolean)
var
DocumentReportMgt: Codeunit "Document Report Mgt.";
TempBlob: Codeunit "Temp Blob";
DataInStream: InStream;
DataOutStream: OutStream;
ObjectName: JsonToken;
DocumentTypeParts: List of [Text];
DocumentType: JsonToken;
Extension: Text;
Token: JsonToken;
MimeType: Text;
LayoutName: Text;
LayoutModel: Text;
JsonText: Text;
JsonFile: File;
begin
if IsHandled then
exit;
Init();
// Sample code to persist the json object to disk
ObjectPayload.WriteTo(JsonText);
JsonFile.TextMode := true;
JsonFile.Create(TempFolderPath + 'OnCustomDocumentMergerEx.json', TextEncoding::UTF8);
JsonFile.Write(JsonText);
JsonFile.Close();
// Get report options from the json object
ObjectPayload.Get('objectname', ObjectName);
ObjectPayload.Get('documenttype', DocumentType);
ObjectPayload.Get('layoutmimetype', Token);
MimeType := Token.AsValue().AsText();
ObjectPayload.Get('layoutname', Token);
LayoutName := Token.AsValue().AsText();
ObjectPayload.Get('layoutmodel', Token);
LayoutModel := Token.AsValue().AsText();
DocumentTypeParts := DocumentType.AsValue().AsText().Split('/');
// Notice that the Extension below have to be remapped to a standard file extension based on the document mimetype.
Extension := DocumentTypeParts.Get(DocumentTypeParts.Count);
TempBlob.CreateOutStream(DataOutStream);
// The
case ReportAction of
ReportAction::SaveAsPdf, ReportAction::Preview, ReportAction::Print:
begin
if not DocumentReportMgt.TryXmlMergeWordDocument(LayoutData, XmlData, DataOutStream) then
error('Unable to handle custom document merge');
DocumentReportMgt.ConvertWordToPdf(TempBlob, ObjectID);
TempBlob.CreateInStream(DataInStream);
CopyStream(DocumentStream, DataInStream);
IsHandled := true;
end;
ReportAction::SaveAsHtml:
begin
if not DocumentReportMgt.TryXmlMergeWordDocument(LayoutData, XmlData, DataOutStream) then
error('Unable to handle custom document merge');
DocumentReportMgt.ConvertWordToHtml(TempBlob);
TempBlob.CreateInStream(DataInStream);
CopyStream(DocumentStream, DataInStream);
IsHandled := true;
end;
ReportAction::SaveAsWord:
begin
if not DocumentReportMgt.TryXmlMergeWordDocument(LayoutData, XmlData, DocumentStream) then
error('Unable to handle custom document merge');
IsHandled := true;
end;
else
error('Unsupported report action %0', ReportAction);
end;
end;
See Also
Working With and Troubleshooting Payloads
OnCustomDocumentMergerEx Event
Events in AL
Publishing Events
Raising Events
Subscribing to Events