Article : Printing Invoices to PDF from Dynamics NAV
Printing Invoices to PDF from Dynamics NAV
This is an example of how to use the PDF
Printer from Microsoft Dynamics NAV
(Navision). I will use the C/AL code to show you a couple of thing that you can
do from within NAV. These subjects are covered by the example.
- Printing multiple documents in a loop.
- Using a watermark with dynamic text.
- Printing on top of a PDF used as background or letterhead.
- Signing the PDF using a digital certificate.
- Merging the output with other existing PDF documents.
- Making the printing silent. No dialogs are shown.
- Error handling
Click
here to see a sample output file
PDF Printer version 10.2 or later is required to follow this example.
Printing Multiple Documents
One of the tricky aspects of printing multiple documents in a row is to
control the settings for each print job. The tricky part is that the RUNREPORT
function returns before the PDF is created. It returns control to your C/AL code
as soon as the print job is created and sent to the print spooler queue. The
Windows spooler decides when the job is sent to the printer where the actual PDF
creation takes place.
Before you run a report in your code, you must set the parameters for the
next print job. This controls things like output path, watermarks, and all the
other settings for the printer. When this file is saved using the call to the
WriteSettings method, you can run your report.
At this point, you have put a print job on the spooler queue. Now you should
wait in your code for the PDF creation to finish. There are different strategies
that can be used here. The obvious is to wait for the output PDF to appear in
the location where we expect it to be created. However, this relies on the fact
that every goes as expected. In case of an error the output file may never
appear in this location.
It is considered a better strategy to have the PDF Printer create a status
file and wait for that instead. The status file is also created in the event of
an error. Once the status file is created, you will know that you either have
your output as expected or an error to report. It is shown in the example how
you set the file name of the status file and how you check it for errors.
Watermarks
A PDF watermark is a simple text string that you can create in your C/AL
code. The content is dynamic, which means that you can change the text from one
PDF creation to the next. You can change the font, color, size, rotation, and
location of the watermark text. A watermark can be placed under or on top of the
printed content from the report that you run.
Use Another PDF as Background or Letterhead
One of the strong features of the PDF Printer is the ability to print on top
of another PDF document. This is often used when you have a PDF containing only
your company letterhead. Normally, the background is below the content of the
printed report. However, it is possible to use the other PDF as a stamp on top
of the printed content instead.
Signing the PDF
More and more companies require that the documents they receive are signed
using a digital certificate by the sender. This is used to validate the origin
and content of the document. A digital signature can tell if someone tampered
with the content of the document after it was signed.
Merging with other PDF Documents
Another nice feature is that you can merge your report output with other PDF
files. Sometime you have information in external PDF documents that you want to
merge with the output of your report. Typical use of this feature in ERP systems
is merging an invoice with technical information concerning the products on the
invoice. Another typical use is adding a PDF with terms and conditions.
Hiding Dialogs
When printing from Navision you often want to hide the normal user interface
of the PDF Printer. You make all the selections from your C/AL code and
therefore you want to bypass the printing dialogs. The example shows you how to
do that.
Error Handling
Handling errors are important to make sure your jobs runs smoothly. Here you
will see how errors are detected and error messages are retrieved from the
status file.
The Code// Export Invoices example// This example is based on PDF Printer 10.2 or later.// Please go to
www.bullzip.com to download the printer.// There is a counter that limits the number of invoices printed to PDF.// NOTE: You should change the paths to match the location of the files on your system.
CREATE(pdfSettings);
CREATE(pdfUtil);
IF header.FINDFIRST THEN BEGIN
baseFolder :='C:\ss2\Projects\PDFPrt\Examples\<span>Microsoft Dynamics NAV'</span>;// The status file is used to check for errors and determine when the PDF is ready.
statusFileName := baseFolder +'\temp\status.ini';// You can get a free test certificate at
http://www.pdfpowertool.com certificateFileName := baseFolder +'\ressources\certificate.pfx';
certificatePassword :='password';// Set file name of background PDF.// Performance can be increased if you use an EPS file for background instead of a PDF.// Letterhead-A4.eps is a sample EPS background.// Note that using EPS files as background requires the Expert edition of the PDF Printer.
backgroundFileName := baseFolder +'\ressources\letterhead-a4.pdf';
mergeBeforeFileName := baseFolder +'\ressources\Before.pdf';
mergeAfterFileName := baseFolder +'\ressources\After.pdf';
counter :=0;
REPEAT
// Set file name for output file.
pdfFileName := baseFolder +'\Output\Invoice '+ header."No."+'.pdf';// Delete old output file if it already exist.
IF EXISTS(pdfFileName) THEN ERASE(pdfFileName);// Multiple PDF printers could be installed.// Let the automation know which one to control.
pdfSettings.printerName := pdfUtil.DefaultPrinterName;// Set output file name
pdfSettings.SetValue('Output', pdfFileName);// Make sure no dialogs are shown during conversion.
pdfSettings.SetValue('ShowSaveAs','never');
pdfSettings.SetValue('ShowSettings','never');
pdfSettings.SetValue('ShowPDF','no');
pdfSettings.SetValue('ShowProgress','no');
pdfSettings.SetValue('ShowProgressFinished','no');
pdfSettings.SetValue('ConfirmOverwrite','no');// Set file name of status file to wait for.
pdfSettings.SetValue('StatusFile', statusFileName);// Add a text watermark.
pdfSettings.SetValue('WatermarkText','PDF EXAMPLE - invoice '+ header."no.");
pdfSettings.SetValue('WatermarkColor','#FF0000');
pdfSettings.SetValue('WatermarkVerticalPosition','top');
pdfSettings.SetValue('WatermarkHorizontalPosition','right');
pdfSettings.SetValue('WatermarkRotation','90');
pdfSettings.SetValue('WatermarkOutlineWidth','0.5');
pdfSettings.SetValue('WatermarkFontSize','20');
pdfSettings.SetValue('WatermarkVerticalAdjustment','5');
pdfSettings.SetValue('WatermarkHorizontalAdjustment','1');// Add a background.// If a professional or expert license is installed the quality of the// background will improve.
pdfSettings.SetValue('Superimpose', backgroundFileName);
pdfSettings.SetValue('SuperimposeLayer','bottom');// Merge with other PDF files.
pdfSettings.SetValue('MergeFile', mergeBeforeFileName +'|.|'+ mergeAfterFileName);// Sign with a digital certificate.
pdfSettings.SetValue('SignCertificate', certificateFileName);
pdfSettings.SetValue('SignPassword', certificatePassword);
pdfSettings.SetValue('ShowSignature','yes');// Do not show errors in PDF user interface.
pdfSettings.SetValue('SuppressErrors','yes');// You can see more features and settings at//
http://www.biopdf.com/guide/settings.php// Write settings to printer.// This writes a file name runonce.ini. It is a configuration that is used// for the next print job. The printer will delete the runonce.ini after it// is read.
pdfSettings.WriteSettings(TRUE);
IF EXISTS(statusFileName) THEN ERASE(statusFileName);
header2.COPY(header);
header2.SETRECFILTER;
REPORT.RUNMODAL(206, FALSE, FALSE, header2);
IF pdfUtil.WaitForFile(statusFileName,20000) THEN BEGIN// Check status file for errors.
IF pdfUtil.ReadIniString(statusFileName,'Status','Errors','')<>'0' THEN BEGIN
ERROR('Error creating PDF. '+ pdfUtil.ReadIniString(statusFileName,'Status','MessageText',''));END;END ELSE BEGIN// The timeout elapsed. Something is wrong.
ERROR('Error creating '+ pdfFileName)END;
counter := counter +1;
UNTIL (header.NEXT=0) OR (counter >=5);END;
Objects and C/AL Code
You can download a ZIP file with the code used in this example. Please change
the object number in the text file before you import it in your NAV database.
Otherwise, you may end up overwriting your own code.