Some time ago, we wrote an article on how to merge PDF product specifications to printed Purchase orders. Read the article >>
The solution presented in the above article is based on capability to merge PDF documents using Docentric Free Edition utilities. It enables you to view, email, archive or distribute a D365FO report merged with any PDF attachments. Report can be either Docentric- or SSRS- based, and report distribution covers all Docentric print destinations (Screen, Email, Print archive, File, Printer with the Print as PDF option turned on) except printing to network printers (Printer print destination).
We are now going to extend this solution to support printing of reports merged with PDF attachments to network printers in D365FO cloud environments. The only limitation that will remain is printing to network printers in on-premises environments.
The Coding Part - With Added Support for Printing to Network Printers
In the previous article, we provided the working code for merging the Purchase order report with PDF attachments fetched from the corresponding products (the Item records), assuming that these attachments are the product specifications related to the printing Purchase order lines. Of course, you can filter attachments on Items per Tags, Category, Attachment description, etc. The printing Purchase order report, after it's merged with the product specifications, is further regularly viewed, emailed, archived or distributed using Docentric print destinations.
We're now adding a new code - an additional event handler for the same delegate DocReportRunDelegates.generateReportContent(), to support also the printing of a Purchase order report merged with the product specifications (fetched as Attachments which are PDF documents) to the network printer that has been selected on the Print destination settings form > Docentric Printer print destination. Let's take a look.
using DOCFC = Docentric.AX.Framework.Collections;
using DOCDPC = Docentric.AX.Documents.Pdf.Conversion;
public class DocPrintPdfAttachmentsToPrinterAsEmf
/// After the PurchPurchaseOrder.Report has been generated, the delegate method prints additional PDF attachments. These attachments are converted from PDF to EMF images, which are supported by the DRA print service.
/// <param name = "_printReportSettings">Specifies the settings for printing the report.</param>
/// <param name = "_printedReport">Represents the printed report.</param>
/// <param name = "_result">The delegate result used to cancel the report print execution.</param>
[SubscribesTo(classStr(DocReportRunDelegates), delegateStr(DocReportRunDelegates, generateReportContent))]
public static void DocReportRunDelegates_generateReportContent(DocPrintReportSettings _printReportSettings, DocPrintedReport _printedReport, DocEventHandlerResult _result)
// Exit if we are printing anything else then PurchPurchaseOrder.Report
if (_printReportSettings.parmReportId() != ssrsReportStr(PurchPurchaseOrder, Report))
// Exit if we are not printing to printer print destination
if (_printReportSettings.parmPrintDestination() != DocPrintDestination::Printer)
// Exit if we are not printing in native printer format (EMF); Skip if "Print as PDF" is used.
if (_printedReport.outputFileFormat() != DocFileFormat::EMF)
// Define a new list of byte array for additional attachments and prepare the conversion options
DOCDPC.DocImageConversionOptions conversionOptions = new DOCDPC.DocImageConversionOptions(DocGlobalHelper::getDotNetEnumValueForXppEnumValue(imgFormat.GetType(), enumNum(DocFileFormat), DocFileFormat::EMF));
DOCFC.DocByteArrayList emfByteArrayList = new DOCFC.DocByteArrayList();
// The generated report EMF pages in list of byte array.
IList pages = _printedReport.getReportContentImageList();
// Get the PurchTable record, based on the VendPurchOrderJour information
purchTable = VendPurchOrderJour::findRecId(
// Or you can get it this way:
//purchTable = PurchTable::find(_printReportSettings.parmArchiveContract().parmSourceTableId());
// Loop through the products related to the purchase order lines.
// By doing this, we ensure that each product is included only once, even if it appears on multiple purchase order lines.
while select RecId, TableId, DisplayProductNumber from product
exists join inventTable where inventTable.Product == product.RecId
exists join purchLine where purchLine.ItemId == inventTable.ItemId &&
purchLine.PurchId == purchTable.PurchId
// Fetch attachments for the current product.
while select docuRef where
docuRef.RefTableId == product.TableId &&
docuRef.RefRecId == product.RecId
exists join docuType
where docuType.TypeId == docuRef.TypeId &&
(docutype.TypeGroup == DocuTypeGroup::File ||
docuType.TypeGroup == DocuTypeGroup::Image ||
docuType.TypeGroup == DocuTypeGroup::Document)
DocuValue docuValue = docuRef.docuValue();
// Only PDF attachments will be printed; other attachments will be ignored.
if (docuValue.FileType != 'pdf')
// Each PDF attachment is converted into a series of EMF images, which are then added to the list of EMF byte arrays.
info("Attachment for item id: " + product.DisplayProductNumber + " --> " + docuRef.Name);
using (System.IO.Stream docuRefStream = DocumentManagement::getAttachmentStream(docuRef))
// Convert PDF to EMF and add all the EMF pages to the list
DocGlobalHelper::handleClrException(funcName(), "Error occurred while adding the list of EMF byte arrays to the collection.");
DocGlobalHelper::handleException(funcName(), "An error occurred while adding the list of EMF byte arrays to the collection.");
// The report is printed as a collection of EMF images in byte array.
// If we have any additional pages to print we add then to the original list.
if (emfByteArrayList.Count > 0)
for (int i=0; i < emfByteArrayList.Count; i++)
Check the previous article: Append PDF Product Specifications to Printed Purchase Orders in D365FO >>