An idea: create a developer safe zone in each source file

The algorithms for patching source code can be fuzzy; they can patch near to the original line numbers if surrounding text matches correctly.

If all Frappe and ERPNext DocType *.py and *.js included a safe zone near the top of the code, end-user developers would suffer far fewer patch failures.

Using Sales Invoice for example:

erpdev@loso:~/frappe-bench-DELS$ ll apps/erpnext/erpnext/accounts/doctype/sales_invoice
total 484
drwxr-xr-x   5 erpdev erpdev  4096 Mar  4 18:31 ./
drwxr-xr-x 149 erpdev erpdev 12288 Mar  2 00:00 ../
-rw-r--r--   1 erpdev erpdev    40 Mar  1 23:58 __init__.py
drwxr-xr-x   2 erpdev erpdev  4096 Mar  4 18:32 __pycache__/
   :      :      :      :      
-rw-r--r--   1 erpdev erpdev 33968 Mar  4 16:47 sales_invoice.js
-rw-r--r--   1 erpdev erpdev   222 Mar  4 16:46 sales_invoice_dc.js
   :      :      :      :      
-rw-r--r--   1 erpdev erpdev 75707 Mar  4 18:31 sales_invoice.py
-rw-r--r--   1 erpdev erpdev   321 Mar  2 00:28 sales_invoice_dc.py
   :      :      :      :      

So, sales_invoice_dc.js and sales_invoice_dc.py would be null files, always imported by sales_invoice.js and sales_invoice.py respectively.

Like:

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# -------------------------- User protected zone -------------------->>>

from . import sales_invoice_dc  # developer customization

# ------------------------------- End of zone -----------------------<<<
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

A further possibility: a base class and an implementation class:

  1. Rename sales_invoice.js to sales_invoice_base.js
  2. Change the line …
erpnext.accounts.SalesInvoiceController = 
         erpnext.selling.SellingController.extend({

… to read …

erpnext.accounts.SalesInvoiceControllerBase =
         erpnext.selling.SellingController.extend({
  1. Create a new sales_invoice.js with:
erpnext.accounts.SalesInvoiceController = 
         erpnext.accounts.SalesInvoiceControllerBase.extend({
	setup: function(doc) {
		this._super(doc);
	},
	company: function() {
		this._super();
	},
	onload: function() {
		var me = this;
		this._super();
	},
	refresh: function(doc, dt, dn) {
		const me = this;
		this._super();
	},
         :          :          :          :          : 

Customization would then simply replace sales_invoice.js with a developer modified version having code added after any of the this._super() lines.

Opinions? Dissent?

If there’s serious consensus, I’d write up a GitHub feature request issue.

1 Like

Thanks for posting @MartinHBramwell. Can you say a bit more about the advantages you see for this above and beyond the override_doctype_class hook?

1 Like

Oh jeez. There probably isn’t any advantage.

That is exactly what I have been looking for: Best strategy to avoid failed patches from new releases?

I shall begin working with that right away.

Great! It’s an extremely helpful new feature. Exciting to see the direction v13 is headed towards more sustainable custom deployments.