title | description | ms.date | ms.topic | author |
---|---|---|---|---|
Creating a Printer Extension |
Describes how to create an extension that sets up cloud printers. |
04/01/2021 |
conceptual |
jswymer |
This article describes how to use the OnAfterSetupPrinters and OnAfterDocumentPrintReady events to set up different printers for reports.
This article uses a simplified printer extension example for sending reports to an email printer. The example creates a printer extension that sets up a single email printer. Users can then assign the printer to reports from the Printer Selections page in the client. In this article, you will:
- Create two codeunits, one that subscribes to the OnAfterSetupPrinters event and another that subscribes to the OnAfterDocumentPrintReady event.
- Use the SMTP Mail and Mail Management codeunits that are part of the base application for sending the report via email.
This section describes how to use the OnAfterSetupPrinters event to set up a printer. When completed, users can select the printer from on the Printer Selections page.
-
Create an AL project for the printer extension.
See Get Started with AL.
-
Create a codeunit to use for subscribing to the OnAfterSetupPrinters event.
-
Create a method that subscribes to the OnAfterSetupPrinters event.
At this point, your code would look something like this:
codeunit 50100 SetupPrinter { [EventSubscriber(ObjectType::Codeunit, Codeunit::"ReportManagement", 'OnAfterSetupPrinters', '', true, true)] procedure OnSetupPrinters(var Printers: Dictionary of [Text[250], JsonObject]) var begin end; }
For more information about subscribing to events, see Subscribing to Events.
-
Now you can start adding code to the event subscriber method to create the printer payloads.
In this example, you set up a printer named 'My Printer' that has two paper trays: A4 and Custom. There are two ways of setting values for a payload JSON object. You can add properties (key-value pairs) by using the Add method, as shown in the example. Or, you can use the ReadFrom method to read the JSON data from the string into a JsonObject variable (see Using ReadFrom to create the payload).
codeunit 50100 SetupPrinter { [EventSubscriber(ObjectType::Codeunit, Codeunit::"ReportManagement", 'OnAfterSetupPrinters', '', true, true)] procedure OnSetupPrinters(var Printers: Dictionary of [Text[250], JsonObject]) var Payload: JsonObject; PaperTrays: JsonArray; PaperTrayA4: JsonObject; PaperTrayCustom: JsonObject; begin // Step 1: Create the paper trays PaperTrayA4.Add('papersourcekind', 'Upper'); PaperTrayA4.Add('paperkind', 'A4'); PaperTrayCustom.Add('papersourcekind', 'Custom'); PaperTrayCustom.Add('paperkind', 'Custom'); PaperTrayCustom.Add('width', 236); PaperTrayCustom.Add('height', 322); PaperTrayCustom.Add('units', 'mm'); // Step 2: Add the paper trays to the list of paper trays PaperTrays.Add(PaperTrayA4); PaperTrays.Add(PaperTrayCustom); // Step 3: Add the required parameters for the payload Payload.Add('version', 1); Payload.Add('papertrays', PaperTrays); // Step 4: Add the printer to the dictionary Printers.Add('My Printer', Payload); end; }
-
At this point, you can compile your project, and publish/install the extension on the tenant to test the payload.
Open the Printer Selections page in the client. You should see My Printer as an option in the Printer Name field. If there are errors with payload, you'll get an error when you try to open the Printer Name field. For more information, see Troubleshooting Printer Payload Errors.
The event subscriber method has one parameter, which is a dictionary of printers. The key is a name of the printer. The value is a JSON object that is referred to as the payload. The payload specifies information about a specific printer. The payload includes several attributes in the following structure:
{
"version": 1,
"description":[default=""],
"duplex":[default=false],
"color":[default=false],
"defaultcopies":[default=1],
"papertrays":
[
{
"papersourcekind":'Upper' | 1,
"paperkind":'A4' | 9,
"units":[default='HI'],
"height":[default=0],
"width":[default=0],
"landscape":[default=false]
}
]
}
There are few required attributes, such as version
and papertrays
. The papertrays
attribute must contain at least one paper tray setup, which in turn must include the attributes papersourcekind
and paperkind
. For more information about the attributes, see Printer Payload.
The following example illustrates how to create a payload by using the ReadFrom method.
codeunit 50101 SetupPrinter2
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"ReportManagement", 'OnAfterSetupPrinters', '', true, true)]
procedure SetupPrinters(var Printers: Dictionary of [Text[250], JsonObject])
var
Payload: JsonObject;
begin
// Step 1: Read the payload from the text
Payload.ReadFrom('{"version":1,"papertrays":[{"papersourcekind":"Upper","paperkind":"A4"},{"papersourcekind":"Custom","paperkind":"Custom","width":236,"height":322,"units":"mm"}]}');
// Step 2: Add the printer to the dictionary
Printers.Add('My Printer', Payload);
end;
}
A printer can have several paper trays. If a report doesn't specify which paper tray to use or the specified paper tray isn't present in the printer's setup, a default paper tray is used. The default paper tray is the first one defined in the papertrays
list.
You can change the paper tray for an existing report by subscribing to the OnAfterGetPaperTrayForReport
event and setting a value for a DefaultPage
parameter.
[EventSubscriber(ObjectType::Codeunit, Codeunit::"ReportManagement", 'OnAfterGetPaperTrayForReport', '', true, true)]
procedure GetPaperTrayForReport(ReportID: Integer; var FirstPage: Integer; var DefaultPage: Integer; var LastPage: Integer)
As an alternative, if you're creating a new report, you can set a paper tray by specifying PaperSourceDefaultPage property.
report 50103 MyReport
{
PaperSourceDefaultPage = Upper;
...
}
This section describes how to subscribe to the OnAfterDocumentPrintReady event. You subscribe to the OnAfterDocumentPrintReady event to define what happens when a user chooses to print a report. The event subscriber specifies how and where to send the report.
-
Create a codeunit to use for subscribing to the OnAfterDocumentPrintReady event.
-
Create a method that subscribes to OnAfterDocumentPrintReady event.
At this point, your code would look something like this:
codeunit 50102 HandlePrintAction { [EventSubscriber(ObjectType::Codeunit, Codeunit::ReportManagement, 'OnAfterDocumentPrintReady', '', true, true)] procedure OnDocumentPrintReady(ObjectType: Option "Report","Page"; ObjectId: Integer; ObjectPayload: JsonObject; DocumentStream: InStream; var Success: Boolean) var begin end; }
For more information about subscribing to events, see Subscribing to Events.
-
Now you can start adding code to the event subscriber method to handle the report payload and send the report.
The following code sends a report by email to the printer that is named 'My Printer'. In this example, the printer's email address is 'myprinterb@businesscentral.onmicrosoft.com'.
codeunit 50101 SendReportByEmail { [EventSubscriber(ObjectType::Codeunit, Codeunit::ReportManagement, 'OnAfterDocumentPrintReady', '', true, true)] procedure OnDocumentPrintReady(ObjectType: Option "Report","Page"; ObjectId: Integer; ObjectPayload: JsonObject; DocumentStream: InStream; var Success: Boolean) var SMTPMail: Codeunit "SMTP Mail"; PrinterNameToken: JsonToken; PrinterName: Text; ObjectNameToken: JsonToken; ObjectName: Text; DocumentTypeToken: JsonToken; DocumentTypeParts: List of [Text]; FileExtension: Text; MailManagement: Codeunit "Mail Management"; SendFrom: Text; FileName: Text; Recipients: List of [Text]; begin begin // Step 1: Before doing anything, it is important to check the current Success value if Success then exit; // Step 2: Make sure code only runs for reports if ObjectType = ObjectType::Report then begin // Step 3: Get report object payload information ObjectPayload.Get('printername', PrinterNameToken); PrinterName := PrinterNameToken.AsValue().AsText(); if PrinterName = 'My Printer' then begin ObjectPayload.Get('objectname', ObjectNameToken); ObjectName := ObjectNameToken.AsValue().AsText(); ObjectPayload.Get('documenttype', DocumentTypeToken); // Step 4: Build the email message DocumentTypeParts := DocumentTypeToken.AsValue().AsText().Split('/'); FileExtension := DocumentTypeParts.Get(DocumentTypeParts.Count); Recipients.Add('myprinterb@businesscentral.onmicrosoft.com'); SendFrom := MailManagement.GetSenderEmailAddress(); SMTPMail.CreateMessage('Sender', SendFrom, Recipients, 'Hello this is your report', 'Please take a look'); SMTPMail.AddAttachmentStream(DocumentStream, ObjectName + '.' + FileExtension); // Step 5: Send the email for print SMTPMail.Send; Success := true; exit; end; end; end; end; }
-
At this point, you can compile and publish/install the extension on a tenant to test.
First, make sure that SMTP email is set up on the tenant (see Set Up Email in the Application Help).
Then, on the Printer Selections page, set a report to use 'My Printer', and then run and print the report.
The event subscriber receives the printer payload and combines it with the report metadata, like the report's ID. This combination is the report payload. The content of the report itself is received as a stream object. You add code to define how and where to send the report payload for printing. In this example, it's sent as an email.
The report object payload is a JSON object that includes several parameters and values arranged in a specific structure, as shown in the following example
{
"filterviews":
[
{"name":"Header","tableid":112,"view":"VERSION(1) SORTING(Field3) WHERE(Field3=1(103027))"},
{"name":"Line","tableid":113,"view":"VERSION(1) SORTING(Field3,Field4) WHERE(Field4=1(0..10000))"},
{"name":"ShipmentLine","tableid":7190,"view":"VERSION(1) SORTING(Field1,Field2,Field3) WHERE(Field2=1(10000))"}
],
"version":1,
"objectname":"Standard Sales - Invoice",
"objectid":1306,
"documenttype":"application/pdf",
"invokedby":"00000000-0000-0000-0000-000000000001",
"invokeddatetime":"2020-01-17T15:33:52.48+01:00",
"companyname":"CRONUS International Ltd.",
"printername":"My Printer",
"duplex":false,
"color":false,
"defaultcopies":1,
"papertray":
{
"papersourcekind":257,
"paperkind":0,
"landscape":false,
"units":0,
"height":1268,
"width":929
}
}
The parameters can be read but not modified at runtime. For more information about the report payload, see Report Payload.
Working With and Troubleshooting Payloads
Developing Printer Extensions Overview
Events in AL
Publishing Events
Raising Events
Subscribing to Events