bioPDF writer

I have been using PDFCreator to create PDF documents from my NAV client.  I am also using it with NAS (Nav Application Server) on my Windows 2003 32bit server.  I needed to get this up an running on a 64bit Windows 2008 server and I ran into problems.

I could easily create the PDF documents from my client.  I saw the pdf file appear in my file system and attached it to my record.  But, when NAS was running the same job no files where created and the job failed.  I unsuccessfully tried a few tricks but nothing changed.  I decided to find another path and looked at bioPDF writer.

The result is a new single instance codeunit to handle the print of any report to a pdf file.  Lets say that the user would like to be able to print and open a sales invoice in pdf format.  Copy the function PrintRecords to PrintRecordsToPDF for table no. 112, Sales Invoice Header.  Add two lines and you are done.

[code htmlscript=”false”]WITH SalesInvHeader DO BEGIN
COPY(Rec);
FIND(‘-‘);
ReportSelection.SETRANGE(Usage,ReportSelection.Usage::"S.Invoice");
ReportSelection.SETFILTER("Report ID",'<>0’);
ReportSelection.FIND(‘-‘);
REPEAT
bioPDFMgt.BeforeReportPrint(ReportSelection."Report ID"); // Dynamics.is
REPORT.RUNMODAL(ReportSelection."Report ID",ShowRequestForm,FALSE,SalesInvHeader);
HYPERLINK(bioPDFMgt.AfterReportPrintGetFileName(ReportSelection."Report ID")); // Dynamics.is
UNTIL ReportSelection.NEXT = 0;
END;[/code]

Where bioPDFMgt is a local variable for the BioPDF Management Codeunit.

The BioPDF Management Codeunit needs to be added to global variable in Codeunit 1, ApplicationManagement.  Add to the FindPrinter function.

[code htmlscript=”false”]FindPrinter(ReportID : Integer) : Text[250]
// Dynamics.is start
IF bioPDFMgt.PrinterBufferExists(ReportID) THEN
EXIT(bioPDFMgt.GetPrinterName);
// Dynamics.is end

CLEAR(PrinterSelection);

IF NOT PrinterSelection.GET(USERID,ReportID) THEN
IF NOT PrinterSelection.GET(”,ReportID) THEN
IF NOT PrinterSelection.GET(USERID,0) THEN
IF PrinterSelection.GET(”,0) THEN;

// Dynamics.is start
bioPDFMgt.SaveLastPrinter(PrinterSelection."Printer Name");
// Dynamics.is end

EXIT(PrinterSelection."Printer Name");[/code]

The BioPDF Management Codeunit includes these functions:

Name Description
BeforeReportPrint Setup PDF printer and printer selection
AfterReportPrintGetBLOB Copy the PDF file to a tempBLOB record
AfterReportPrintGetFileName Return the PDF file name
CleanUp Clear PDF automation objects
ConfirmFileExists Return an error if file does not exist
FileExists Return a boolean value for given file name
FileRename Rename a file (copy and delete combined)
FileErase Delete a file
FileCopy Copy a file
ClearPrinterBuffer Clear the printer selection buffer
CreatePrinterBuffer Adds a report and a printer name to the printer selection buffer
PrinterBufferExists Check if a printer selection buffer exists for given report
GetPrinterName Get the printer name from the printer selection buffer
SaveLastPrinter Save the name of the last printer used
GetLastPrinter Get the name of the last printer used

BioPDF Management Codeunit (2009 R2)

BioPDF Management Codeunit (5 SP1)

FindPrinter function in Codeunit 1

There is sometime a mixup in printer names between Netbios Names and DNS Names.  Also, you might want to have certain reports printed to certain printers only.  I installed a code after
[code htmlscript=”false”]IF NOT PrinterSelection.GET(USERID,ReportID) THEN
IF NOT PrinterSelection.GET(”,ReportID) THEN
IF NOT PrinterSelection.GET(USERID,0) THEN
IF PrinterSelection.GET(”,0) THEN;[/code]
to search for printers using both Netbios Names and DNS Names.
[code htmlscript=”false”]IF (PrinterSelection."Printer Name" <> ”) AND
NOT Printer.GET(PrinterSelection."Printer Name") AND
(COPYSTR(PrinterSelection."Printer Name",1,2) = ‘\\’) THEN BEGIN
IF UPPERCASE(COPYSTR(PrinterSelection."Printer Name",1,26)) =
‘\\PRINTSERVER.DYNAMICS.IS\’ THEN BEGIN
LookupPrinterName :=
‘\\PRINTSERVER\’ + COPYSTR(PrinterSelection."Printer Name",27);
PrinterFound := Printer.GET(LookupPrinterName);
END
ELSE
IF UPPERCASE(COPYSTR(PrinterSelection."Printer Name",1,14)) =
‘\\PRINTSERVER\’ THEN BEGIN
LookupPrinterName :=
‘\\PRINTSERVER.DYNAMICS.IS\’ +
COPYSTR(PrinterSelection."Printer Name",15);
PrinterFound := Printer.GET(LookupPrinterName);
END;
IF PrinterFound THEN
PrinterSelection."Printer Name" := Printer.Name
ELSE BEGIN
IF ISCLEAR(SystemNetwork) THEN
CREATE(SystemNetwork,TRUE,TRUE);
SystemNetwork.AddWindowsPrinterConnection(
PrinterSelection."Printer Name");
IF NOT Printer.GET(PrinterSelection."Printer Name") THEN
ERROR(Text50000,PrinterSelection."Printer Name");
END;
END;[/code]
Where
[code htmlscript=”false”]Text50000 =
"Printer for this report is not found: %1, restart NAV and try again.
If still unsuccesful please contact IT department."[/code]
and

Name DataType Subtype Length
PrinterSelection Record Printer Selection
Printer Record Printer
SystemNetwork Automation ‘Windows Script Host Object Model’.WshNetwork
LookupPrinterName Text 250
PrinterFound Boolean

The line SystemNetwork.AddWindowsPrinterConnection connects the computer to the network printer if so a restart of the NAV client should be enough to get things working.

 

Printer Selection by Location Code

I recently was asked to redirect a invoice printout to different printers depending on a code variable on the sales invoice header.  The solution was created and I would like to share it with the example of using printers by location.

After installing this solution you will be able to select a invoice printer for each location.  If non is selected then the default printer from Printer Selection table will be used according to standard Dynamics NAV functionality.

PrinterByLocationCode