Cloud Hosted ERPNext & Local Printers(USB/Network) [WIP]

This is a documentation post of an ongoing research we are executing to implement a mechanism to manage and use multiple printers across multiple locations. The setup needs to work with an ERPNext instance that is hosted on the cloud.

Intention:
The intention of this post is to document our journey, potential solutions we come up with and possible issues we face. We also hope to get inputs and feedbacks from others in the community who have nailed this with lesser firepower. As many of you, we too at times over-engineer.

THIS POST IS A WORK IN PROGRESS, WE WILL UPDATE IT AS WE MOVE AHEAD

We had previously discussed about a quick hack that worked for us in a scenario that was less complex in a conference talk.

Our current use-case is for a restaurant chain, with multiple branches. In each location, we will be having multiple POS machines & mobile phone which will initiate actions that send prints to multiple printers.

Some of it will be network printers. Currently in ERPNext, we can easily print invoices, bills etcā€¦ via browsers print option, as long as the printers are available in it. However this only works for user initiated printing. The limitations are:

  1. No option to logically route print to a particular printer. (For example, a specific kitchen based on item)
  2. No option to execute background print. (For example KOT against online order)
  3. No option to execute multiple prints. (Bill at counter & KOT at kitchen)

Though 3rd point was partially solved in the video shared above, it doesnā€™t really work in a multi-branch scenario.

Before we go into various solutions we explored, I recommend you look at how it was done in a single location with the help of flask in the link provided.

On top of all this, we also canā€™t pick a solution that charge per ip, location or printers. There are some paid solutions that solves some of our challenges.

Scenario 1:
Best possible outcome would have been ERPNext/Frappe directly sending prints to prescribed printers as shown in the diagram below. Let us call this Scenario 1. While this is technically possible with most printers that support IPP, in real-world it is almost impossible to achieve without some proxy servers in between.

Challenges for scenario 1

  • Requires a dedicated-ip or domain via which we can connect to the printer. Port also need to be forwarded. While many ISP does give this, it is not something we can expect in every QSR branch. And this definitely is not a complete solution if it involves talking to ISP.
  • Solutions like no-ip doesnā€™t work in most ISPs as ports are not forwarded by default. You need to raise a request with the ISP to see if it works for you.
  • Even if you get a dedicated-ip and the port. Our setup will still fail, in case we use a mobile hotspot for internet due to an outage. Almost all our clients, do fallback to mobile network few times a month.

THIS POST IS A WORK IN PROGRESS, WE WILL UPDATE IT AS WE MOVE AHEAD

Scenario 2:
The next best possible solution is to proxy all print requests initiated on ERPNext to a client system at the local network and let that machine push it to the printer.

Here, the printer & client connection part is trivial. However, finding a way for server to let the client know when a print job is created is the tricky part.

We figured out two ways to get this done:

  1. Expose a flask/node app via a tunnel using some solution as ngrok. That way the issue of ip is resolved. Then that flask application can initiate the print just as we did in the video linked in this post before.
  2. Make use of Frappeā€™s realtime support using web-socket. We were able to send print request via web-socket to POS & other relevant front-ends this way. Then the front-end as in the KOT solution in the video above, will make a request to the flask app running locally.

If we can somehow connect to Frappe via web-socket directly from the flask application, then we can avoid having to use the POS or other front-end page to be the means to receive prints. Relying on front-end page will be error prone and is not very reliable. For example, you can loose prints if the user closes the tab or is refreshing the tab when a print comes.

There is a query on this in Discuss here. This is the python client library that we could potentially use to interface with Frappe/ERPNext web-socket server. Weā€™ll explore this when we get time.

Another backup plan is to, maybe have this run in a headless browser initiated via python and listen in to the socket from it.

A rough diagram of how the whole websocket based solution could work is outlined below:

In frappe, we plan to create few doc types such as:

  • Printer (add printers, location/branch, ip or domain, status)
  • Print Queue (print jobs are added here along with the destination printer info)

Any application that need to send a print to a printer without the user initiating it, needs to create a document in the queue along with the destination printer. Ideally we will need to get a feedback if the print succeeded and also have some mechanism to retry.

Some other observation:

  • Configuring different printers on the system is often tricky and vary from printer to printer. We have found using network printer along with IPP to be the best option if you plan to maintain a consistent solution without having to deal with proprietary drivers and their headaches.
  • Using CUPs for connecting to printer can help streamline this process. We where able to use cups via docker in windows based machine as well.

Do let us know if you have solved any issue as this. Or if you have any suggestions.

Updates:

  • We had success using network printing suggested by @mujeerhashmi along with cloudflares tunnel. We had to use tunnel to reach to local branches that doesnā€™t have a static ip or port forwarding.
  • We are also checking https://qz.io/ based solution that @ankush suggested over telegram.
4 Likes

Network Printers are already supported in ERPNext. Check this out (https://docs.erpnext.com/docs/v14/user/manual/en/setting-up/print/print-settings#3-network-printer-print-server). I have not tested it though.

1 Like

We have an implementation in the wild like this. It is a CUPS server thatā€™s on prem, the Frappe server is in the cloud. Some development on the Network Printer Settings doctype was required, but this allowed us to print barcode labels with the click of a button.

3 Likes

This is a very good topic about network printing, and in fact, there are many similar practices in China. For example, Taobao and Pinduoduo, these giant e-commerce companies, need to print a lot of logistics waybills during the process of conducting e-commerce business. They use the service layer ā†’ middleware service ā†’ printer architecture that you mentioned. The middleware service is important and usually requires the installation of a guardian process. It is generally installed on Windows and serves as a client for WebSocket.

A similar middleware can be referenced here: GitHub - dandanhuiyi/printer: 굋čƕ web é”µé¢č°ƒē”Ø 菜éøŸę‰“印ē»„件 和 Lodopę‰“å°ē»„件

For this business scenario, there are actually two design approaches:

  1. The middleware service needs to be developed as a client by Frappe. This is usually done for the Windows version. However, I donā€™t recommend using WebSocket, but I highly recommend using Socket.IO. Socket.IO and Frappeā€™s Socket.IO are two different forms of socket connections, and I suggest using Socket.IO + Frappeā€™s Socket.IO.
  2. The second approach is to use some public middleware services. For Frappe or ERPNext, Lodop or other printing components can be used. You need to send PDF or HTML to these ws://192.168.8.1/xx endpoints.

Iā€™m really looking forward to seeing Frappeā€™s improvement in this area.

1 Like

@esafwan Iā€™m shortly before introducing the ERPNext and looking also very intensive for a proper cloud-print solution and didnā€™t find until now.
I know from other ERP solutions a comparable simple, robust and reliable solution:

Raspberry Pi with cups and a little webserver application which connects via API to the ERP instance and listen if a print job is open. I donā€™t understand why ERPNext is not having such a little ā€œhelperā€ software.

Latest updates on use of local printers with respect to our project(URY):

The project we were working on is now in alpha and is accessible at ury.app & Github. It is deployed across 7 outlets and processes 1000s of invoices & kitchen order tickets per day.

  1. We switched to a Kitchen Display System over printed KOT in all counters except 1 or 2. This is challenging for outlets that have a high volume of sales from aggregators like Swiggy and Zomato.

  2. In locations where we still have KOT prints, we are mostly relying on QZ Tray.

  3. When using QZ Tray / KDS for kitchen order, we used the regular browser print option for bill printing.

  4. In outlets where we are unable to stabilize internet connectivity, we have a local version of ERPNext set up, which handles Invoicing, Printing, etc. The offline data is synced at regular intervals to the central cloud-based ERP. There is some level of conflict resolution logic for customer data and some restrictions imposed on the local version. So far this is working well in all outlets where we have implemented this.

  5. In the absence of a static IP, we had initially tried to rely on solutions like Reverse SSH tunnels, ngrok, Cloudflareā€™s Tunnel etc which proved to be either unreliable or expensive. In some cases, both.

Though print-related headaches and issues may seem never-ending and create a sense of hopelessness, once you have a solution for these, we almost never have to look back. It just works.

1 Like