We are adding some domain specific features to default POS in ERPNext. We were able to do it by extending the POS Controller Class implemented [here]. (erpnext/erpnext/selling/page/point_of_sale/pos_controller.js at develop · frappe/erpnext · GitHub). We want to extend the existing POS from a custom optional app.
Some common question you may have and quick answers to it:
Q1) Why not raise a PR in existing POS.
A) We are implementing domain specific features that only people of that domain will benefit from. Adding it for all only will add unnecessary complexity for even those who have zero value from it.
Q2) Why not create a new POS independent from default POS?
A) Recreating a POS for implementing some domain specific features made no sense to us. Especially as almost all POS features are required. Extending existing POS via a domain specific custom optional frappe app, seemed to be the most effective way forward.
What has been done so far?
We have been able to extend POS by initiating in another Frappe page. We initiated a POS using the similar code as it is implemented in the original POS page, using frappe.provide
:
frappe.provide('erpnext.PointOfSale');
For this, we first created a new Frappe Page. Then we then initiated the Frappe Point of Sale
class, after extending it. See the code below:
frappe.provide('erpnext.PointOfSale');
frappe.pages['rest-pos'].on_page_load = function (wrapper) {
var page = frappe.ui.make_app_page({
parent: wrapper,
title: 'REST POS',
single_column: true
});
frappe.require('point-of-sale.bundle.js', function () {
erpnext.PointOfSale.Controller = class MyPosController extends erpnext.PointOfSale.Controller {
constructor(wrapper) {
super(wrapper);
}
prepare_menu() {
this.page.clear_menu();
this.page.add_menu_item(("Open Form View"), this.open_form_view.bind(this), false, 'Ctrl+F');
this.page.add_menu_item(("Toggle Recent Orders"), this.toggle_recent_order.bind(this), false, 'Ctrl+O');
this.page.add_menu_item(("Save as Draft"), this.save_draft_invoice.bind(this), false, 'Ctrl+S');
this.page.add_menu_item(('New Menu POS'), this.close_pos.bind(this), false, 'Shift+Ctrl+C');
this.page.add_menu_item(__('Close the POS'), this.close_pos.bind(this), false, 'Shift+Ctrl+C');
}
};
wrapper.pos = new erpnext.PointOfSale.Controller(wrapper);
window.cur_pos = wrapper.pos;
});
};
You can see the original POS page code here.
See the screenshot of POS with new menu added below:
While the above solution works, we trying to figure out the following:
-
The current approach works by extending the POS & doesn’t require change to core POS code. However we end up having the enhanced POS in another route. In this case at
/rest-pos
. Only way to override core POS via this method is by creating a redirect script. -
If a custom app can load a JS that extends the existing POS in ERPNext implemented by POS controller it will be great. Is there any way we can load a JS file that extends the POS before it is used by ERPNext?