Bulk document print slow

Hi all,

I tried to multi print 100 invoices via Actions > Print and it took 10mins to complete the PDFs. Anyone ever tried to speed up this process?

Thx

Uggh. Yes. But the solution we came up with was complicated.

Like you said, printing hundreds of PDFs can be slow. Many times, the browser timed out. :confused:

To avoid timeouts and browser performance, my goal was to relocate the PDF generation to the Background Workers, instead of the web server. With this solution, the Print Formats and PDF work would happen server-side. I could enqueue the job, and perform other work. Later, I could examine and see if it completed.

I could create 1 PDF per document. Or, create a single, unified PDF with 100 pages.

First Challenge:
The Frappe Framework creates the PDF’s through a function named 'download_multi_pdf()'. However, this function expects to be called by the browser. It also alters the HTTP response object. :slightly_frowning_face:

So, you cannot just 'frappe.enqueue()' the 'download_multi_pdf()'function.
It does not work.

What I did was make a copy of 'download_multi_pdf()'. Got rid of the portions I didn’t need, like altering HTTP responses. Rewrote other pieces, for simplicity. And now I had a standalone function, that wrote PDF documents to disk.

Without the browser dependencies, this new PDF function -could- be enqueued. :partying_face:

Second Challenge:
Where to save all these PDFs?

Normally when you create PDFs from Print Formats, a new web page/tab opens in your browser. You can either view the PDF, print it, or save it. However, my code all happened server-side. How would I retrieve and view these PDFs, once they were created?

For this challenge, I solved by saving the PDFs within the File Manager document (SQL table = tabFile). I created a new Folder to group them together. I taught my custom download_multi_pdf() to add new documents every time it executed.

Third Challenge:
How to select invoices and enqueue them?

The was solved by creating a new Button on a List Page using JS code:

  • Button opens a dialog.
  • Dialog asks for invoice Start Date and End Date.
  • Dialog asks which ‘Print Format’ to use for PDF generation.
  • When you click “Ok” on the dialog, your dialog choices are passed to a Python function.
  • Python function uses the Date Range to find all the Invoices. Then takes their ID’s ('name') and passes to the PDF generation function. Along with the chosen Print Format.

Click the button, finish the dialog, then go do other things. Eventually the PDFs are created. You can add an Alert or Email notification, so the User knows when it finishes.

Conclusion:

  • It’s a little faster, because it’s running server-side, instead of the browser.
  • You can work on other things, or even close your browser, without interrupting the process.
  • In theory, you don’t even need the ERPNext UI. You could trigger this from a RPC API call.

It works great, but took a lot of thought. :thinking:

4 Likes

Hi @brian_pond thx for sharing your solution

“A little faster” - how many percent speedup that you got by moving pdf generation to background worker?