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:
- No option to logically route print to a particular printer. (For example, a specific kitchen based on item)
- No option to execute background print. (For example KOT against online order)
- 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:
- 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.
- 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.