Table of Contents

Grouping Print Jobs

If a printer is used by more than a single user, you may run into situations where print jobs from different users are mixed in the output bin. Pages that belong to the same print job are printed together without being mixed, but the jobs themselves may come out in a mixed order.

This problem becomes even worse if you have multiple print services or instances of print services. In this case, you cannot be sure that multiple jobs from the same user will be printed in a predictable order. The jobs are printed in the order they are handed to the Windows spooler process by the different instances of the service.

In most use cases, this is not a problem, but you may have situations where it is important to ensure that the order of reports and pages is consistent. Let's say that you are in a warehouse where you ship orders. You are printing an invoice and a shipping list to put in a box with the items to be shipped. Here, the invoice and the shipping list must follow each other and not be mixed up with other orders and shipping lists.

The solution to the print sequence problem described above is to create a direct printer definition and set the initial job status to On Hold.

On-hold printer

When this printer is used, jobs are written to the print queue and have the status On Hold.

On-hold printer

The user's session ID is also written to the print queue. Session IDs are later used to group jobs, helping us find the jobs that belong together.

Collect the print jobs

When the last print job in the group is in the print queue, it is time to collect all the jobs and mark them ready for printing.

Jobs are collected by calling the GroupSessionPrintJobs function on the queue table.

var
    DirPrtQueue: Record "ForNAV DirPrt Queue";
begin
    DirPrtQueue.GroupSessionPrintJobs(true);
end;

All jobs with the current session ID are collected, and the result is placed as a new entry on the print queue with the type set to Collection. Collected jobs are marked as finished, and the latest job is marked as ready.

The GroupSessionPrintJobs function takes a parameter that tells the print service how to handle the collection of jobs. The print service can print the jobs individually or merge them before printing them. Regular print jobs are stored as PDFs on the print queue, and combining the separate PDF documents into one PDF before printing will ensure that the printers handle all the documents as one print job. This prevents other service instances from inserting print jobs between the jobs in the collection.

Only jobs based on PDF documents are supported for merging before print. Zebra ZPL jobs do not support this.

Group by a custom filter

When you call GroupSessionPrintJobs, your jobs are grouped by the user session. If you need to group by another criteria, you can use the more generic GroupJobs function.

procedure GroupJobs(var DirPrtQueue: Record "ForNAV DirPrt Queue"; MergeCollection: Boolean)

Your jobs will be grouped based on the filter on the DirPrtQueue record parameter.

When to collect

You decide when to call the function to collect the On Hold jobs. If your documents are printed by a user action on a page, it would make sense to subscribe to the OnAfterActionEvent and then call the GroupSessionPrintJobs function from there. If you don't have access to the page code, this could be done in a page extension.

Here is an example of the code. Remember to modify it to fit your scenario.

[EventSubscriber(ObjectType::Page, Page::"ForNAV Reports", 'OnAfterActionEvent', 'Run', true, true)]
local procedure MyOnAfterActionEvent()
var
    DirPrtQueue: Record "ForNAV DirPrt Queue";
begin
    DirPrtQueue.GroupSessionPrintJobs(true);
end;

Multiple printers

Print jobs are grouped per printer. This means that if you have jobs on hold for multiple printers in your session, the system will create a collection for each printer in the job queue.

Client-print

You can combine document grouping from both client-print and service-print. The methods described earlier apply to service-print. For grouping print jobs with client-print, use the DownloadPrintJobs function in the print queue table. This function groups and downloads jobs based on a specified filter. You can find more details on grouping client-print jobs here:

Print multiple documents with client-print

Handling Mixed Print Jobs

If you need to process multiple reports where some use service-print and others use client-print, follow this approach:

  1. Configure Direct Printers for Client-Print

    • Set them to queue jobs.
    • Ensure the initial status is set to on-hold.
  2. Tagging Client Printers

    • Add a tag to client printers to identify them as client printers.
    • This tag is transferred to the print queue during print operations.
    • You may need to display the tag field on the direct printer page, as it is hidden by default.
  3. Processing Print Jobs

    • First, collect client-print jobs by applying a filter to the print queue using session information and the assigned tag.
    • Download the jobs.
  4. Handling Remaining Service-Print Jobs

    • Once all client-print jobs for your session are processed, the remaining jobs will be service-print jobs.
    • Use the GroupSessionPrintJobs function in the print queue to collect these.

Below is an example of the implementation for this process:

trigger OnAction()
var
    LocalPrinter: Record "ForNAV Local Printer";
    DirPrtQueue: Record "ForNAV DirPrt Queue";
    i: Integer;
    merge: Boolean;
    printerNameService, printerNameClient : Text;
begin
    // Create direct service printer
    printerNameService := 'Service - Sequence Printer';
    LocalPrinter.SetRange("Cloud Printer Name", printerNameService);
    LocalPrinter.DeleteAll();
    LocalPrinter.Init();
    LocalPrinter."Cloud Printer Name" := printerNameService;
    LocalPrinter."Local Printer Name" := 'ForNAV PDF Network Printer';
    LocalPrinter.IsPrintService := true;
    LocalPrinter."Initial Job Status" := LocalPrinter."Initial Job Status"::OnHold;
    LocalPrinter.Insert(true);

    // Create direct client printer
    printerNameClient := 'Client - Sequence Printer';
    LocalPrinter.SetRange("Cloud Printer Name", printerNameClient);
    LocalPrinter.DeleteAll();
    LocalPrinter.Init();
    LocalPrinter."Cloud Printer Name" := printerNameClient;
    LocalPrinter."Local Printer Name" := 'DEFAULT';
    LocalPrinter.IsPrintService := true;
    LocalPrinter.Tag := 'Client Print';
    LocalPrinter."Initial Job Status" := LocalPrinter."Initial Job Status"::OnHold;
    LocalPrinter.Insert(true);

    // Create service print jobs
    for i := 1 to 2 do
        Report.Print(Report::"ForNAV Customer - List", '', printerNameService);

    // Create client print jobs
    for i := 1 to 2 do
        Report.Print(Report::"ForNAV Customer - List", '', printerNameClient);

    // Ask if we should merge the service print jobs
    merge := Confirm('Merge print jobs?');

    // Download client print jobs from this session
    // Use the tag from the printer to filter the print jobs
    Clear(DirPrtQueue);
    DirPrtQueue.SetRange("Session ID", Database.SessionId());
    DirPrtQueue.SetRange(Status, DirPrtQueue.Status::OnHold);
    DirPrtQueue.SetRange(Tag, 'Client Print');
    DirPrtQueue.DownloadPrintJobs(DirPrtQueue);

    // Download service print jobs from this session
    DirPrtQueue.GroupSessionPrintJobs(merge);

    Commit();
    Page.RunModal(Page::"ForNAV DirPrt Queue");
end;
Note

The tag field on the direct printers was added in version 8.0.0.1.

Note

Grouping of printjobs are available since extension version 7.4.0.3 and binaries version 7.4.0.2576.