Merge pull request #25254 from CaseSolvedUK/taxdetail-v13

feat: Tax Detail Report
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..c820d23
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,12 @@
+# Since version 2.23 (released in August 2019), git-blame has a feature
+# to ignore or bypass certain commits.
+#
+# This file contains a list of commits that are not likely what you
+# are looking for in a blame, such as mass reformatting or renaming.
+# You can set this file as a default ignore file for blame by running
+# the following command.
+#
+# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
+
+# Replace use of Class.extend with native JS class
+1fe891b287a1b3f225d29ee3d07e7b1824aba9e7
diff --git a/.gitignore b/.gitignore
index 652fbdc..63c51c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
 .wnf-lang-status
 *.egg-info
 dist/
+erpnext/public/dist
 erpnext/docs/current
 *.swp
 *.swo
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 6775398..ad971e2 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '13.2.1'
+__version__ = '13.3.0'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index e1276e7..781f94e 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -7,26 +7,30 @@
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "auto_accounting_for_stock",
-  "acc_frozen_upto",
-  "frozen_accounts_modifier",
-  "determine_address_tax_category_from",
+  "accounts_transactions_settings_section",
   "over_billing_allowance",
   "role_allowed_to_over_bill",
-  "column_break_4",
-  "credit_controller",
-  "check_supplier_invoice_uniqueness",
   "make_payment_via_journal_entry",
+  "column_break_11",
+  "check_supplier_invoice_uniqueness",
   "unlink_payment_on_cancellation_of_invoice",
-  "unlink_advance_payment_on_cancelation_of_order",
-  "book_asset_depreciation_entry_automatically",
-  "add_taxes_from_item_tax_template",
   "automatically_fetch_payment_terms",
   "delete_linked_ledger_entries",
+  "book_asset_depreciation_entry_automatically",
+  "unlink_advance_payment_on_cancelation_of_order",
+  "tax_settings_section",
+  "determine_address_tax_category_from",
+  "column_break_19",
+  "add_taxes_from_item_tax_template",
+  "period_closing_settings_section",
+  "acc_frozen_upto",
+  "frozen_accounts_modifier",
+  "column_break_4",
+  "credit_controller",
   "deferred_accounting_settings_section",
-  "automatically_process_deferred_accounting_entry",
   "book_deferred_entries_based_on",
   "column_break_18",
+  "automatically_process_deferred_accounting_entry",
   "book_deferred_entries_via_journal_entry",
   "submit_journal_entries",
   "print_settings",
@@ -41,15 +45,6 @@
  ],
  "fields": [
   {
-   "default": "1",
-   "description": "If enabled, the system will post accounting entries for inventory automatically",
-   "fieldname": "auto_accounting_for_stock",
-   "fieldtype": "Check",
-   "hidden": 1,
-   "in_list_view": 1,
-   "label": "Make Accounting Entry For Every Stock Movement"
-  },
-  {
    "description": "Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below",
    "fieldname": "acc_frozen_upto",
    "fieldtype": "Date",
@@ -94,6 +89,7 @@
    "default": "0",
    "fieldname": "make_payment_via_journal_entry",
    "fieldtype": "Check",
+   "hidden": 1,
    "label": "Make Payment via Journal Entry"
   },
   {
@@ -234,6 +230,29 @@
    "fieldtype": "Link",
    "label": "Role Allowed to Over Bill ",
    "options": "Role"
+  },
+  {
+   "fieldname": "period_closing_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Period Closing Settings"
+  },
+  {
+   "fieldname": "accounts_transactions_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Transactions Settings"
+  },
+  {
+   "fieldname": "column_break_11",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "tax_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Tax Settings"
+  },
+  {
+   "fieldname": "column_break_19",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "icon-cog",
@@ -241,7 +260,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-03-11 18:52:05.601996",
+ "modified": "2021-04-30 15:25:10.381008",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
index f7d471b..78e7ff6 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -15,7 +15,7 @@
 	},
 
 	refresh: function (frm) {
-		frappe.require("assets/js/bank-reconciliation-tool.min.js", () =>
+		frappe.require("bank-reconciliation-tool.bundle.js", () =>
 			frm.trigger("make_reconciliation_tool")
 		);
 		frm.upload_statement_button = frm.page.set_secondary_action(
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
index 3dbd605..0a2e0bc 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -239,6 +239,7 @@
 					"withdrawal",
 					"description",
 					"reference_number",
+					"bank_account"
 				],
 			},
 		});
@@ -319,7 +320,7 @@
 			return;
 		}
 
-		frappe.require("/assets/js/data_import_tools.min.js", () => {
+		frappe.require("data_import_tools.bundle.js", () => {
 			frm.import_preview = new frappe.data_import.ImportPreview({
 				wrapper: frm.get_field("import_preview").$wrapper,
 				doctype: frm.doc.reference_doctype,
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
index 5e913cc..7ffff02 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -146,7 +146,7 @@
   },
   {
    "depends_on": "eval:!doc.__islocal && !doc.import_file\n",
-   "description": "Must be a publicly accessible Google Sheets URL",
+   "description": "Must be a publicly accessible Google Sheets URL and adding Bank Account column is necessary for importing via Google Sheets",
    "fieldname": "google_sheets_url",
    "fieldtype": "Data",
    "label": "Import from Google Sheets"
@@ -202,7 +202,7 @@
  ],
  "hide_toolbar": 1,
  "links": [],
- "modified": "2021-02-10 19:29:59.027325",
+ "modified": "2021-05-12 14:17:37.777246",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Statement Import",
@@ -224,4 +224,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
index 9f41b13..5f110e2 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -47,6 +47,13 @@
 
 	def start_import(self):
 
+		preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template(
+			self.import_file, self.google_sheets_url
+		)
+
+		if 'Bank Account' not in json.dumps(preview):
+			frappe.throw(_("Please add the Bank Account column"))
+
 		from frappe.core.page.background_jobs.background_jobs import get_info
 		from frappe.utils.scheduler import is_scheduler_inactive
 
@@ -67,6 +74,7 @@
 				data_import=self.name,
 				bank_account=self.bank_account,
 				import_file_path=self.import_file,
+				google_sheets_url=self.google_sheets_url,
 				bank=self.bank,
 				template_options=self.template_options,
 				now=frappe.conf.developer_mode or frappe.flags.in_test,
@@ -90,18 +98,20 @@
 	data_import = frappe.get_doc("Bank Statement Import", data_import_name)
 	data_import.export_errored_rows()
 
-def start_import(data_import, bank_account, import_file_path, bank, template_options):
+def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options):
 	"""This method runs in background job"""
 
 	update_mapping_db(bank, template_options)
 
 	data_import = frappe.get_doc("Bank Statement Import", data_import)
+	file = import_file_path if import_file_path else google_sheets_url
 
-	import_file = ImportFile("Bank Transaction", file = import_file_path, import_type="Insert New Records")
+	import_file = ImportFile("Bank Transaction", file = file, import_type="Insert New Records")
 	data = import_file.raw_data
 
-	add_bank_account(data, bank_account)
-	write_files(import_file, data)
+	if import_file_path:
+		add_bank_account(data, bank_account)
+		write_files(import_file, data)
 
 	try:
 		i = Importer(data_import.reference_doctype, data_import=data_import)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index d76641d..957a50f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -194,19 +194,19 @@
 	refresh_field("accounts");
 }
 
-erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
-	onload: function() {
+erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Controller {
+	onload() {
 		this.load_defaults();
 		this.setup_queries();
 		this.setup_balance_formatter();
 		erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
-	},
+	}
 
-	onload_post_render: function() {
+	onload_post_render() {
 		cur_frm.get_field("accounts").grid.set_multiple_add("account");
-	},
+	}
 
-	load_defaults: function() {
+	load_defaults() {
 		//this.frm.show_print_first = true;
 		if(this.frm.doc.__islocal && this.frm.doc.company) {
 			frappe.model.set_default_values(this.frm.doc);
@@ -216,9 +216,9 @@
 			var posting_date = this.frm.doc.posting_date;
 			if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
 		}
-	},
+	}
 
-	setup_queries: function() {
+	setup_queries() {
 		var me = this;
 
 		me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
@@ -324,9 +324,9 @@
 		});
 
 
-	},
+	}
 
-	setup_balance_formatter: function() {
+	setup_balance_formatter() {
 		const formatter = function(value, df, options, doc) {
 			var currency = frappe.meta.get_field_currency(df, doc);
 			var dr_or_cr = value ? ('<label>' + (value > 0.0 ? __("Dr") : __("Cr")) + '</label>') : "";
@@ -337,9 +337,9 @@
 		};
 		this.frm.fields_dict.accounts.grid.update_docfield_property('balance', 'formatter', formatter);
 		this.frm.fields_dict.accounts.grid.update_docfield_property('party_balance', 'formatter', formatter);
-	},
+	}
 
-	reference_name: function(doc, cdt, cdn) {
+	reference_name(doc, cdt, cdn) {
 		var d = frappe.get_doc(cdt, cdn);
 
 		if(d.reference_name) {
@@ -351,9 +351,9 @@
 				this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
 			}
 		}
-	},
+	}
 
-	get_outstanding: function(doctype, docname, company, child, due_date) {
+	get_outstanding(doctype, docname, company, child, due_date) {
 		var me = this;
 		var args = {
 			"doctype": doctype,
@@ -375,9 +375,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	accounts_add: function(doc, cdt, cdn) {
+	accounts_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		$.each(doc.accounts, function(i, d) {
 			if(d.account && d.party && d.party_type) {
@@ -400,9 +400,9 @@
 		cur_frm.cscript.update_totals(doc);
 
 		erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
-	},
+	}
 
-});
+};
 
 cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
 
diff --git a/erpnext/accounts/doctype/party_account/party_account.json b/erpnext/accounts/doctype/party_account/party_account.json
index aa32d95..c9f15a6 100644
--- a/erpnext/accounts/doctype/party_account/party_account.json
+++ b/erpnext/accounts/doctype/party_account/party_account.json
@@ -1,87 +1,39 @@
 {
- "allow_copy": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2014-08-29 16:02:39.740505", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
+ "actions": [],
+ "creation": "2014-08-29 16:02:39.740505",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "field_order": [
+  "company",
+  "account"
+ ],
  "fields": [
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_list_view": 1, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "fieldname": "account", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_list_view": 1, 
-   "label": "Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Account",
+   "options": "Account"
   }
- ], 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
-
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2016-07-11 03:28:03.348246", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Party Account", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_seen": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-04-07 18:13:08.833822",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Party Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index d1523cd..8dcd1aa 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -34,8 +34,8 @@
 	}
 });
 
-erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.extend({
-	onload: function() {
+erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller {
+	onload() {
 		var me = this;
 
 		this.frm.set_query("party", function() {
@@ -84,18 +84,18 @@
 				frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title});
 			}
 		};
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		this.frm.disable_save();
 		this.toggle_primary_action();
-	},
+	}
 
-	onload_post_render: function() {
+	onload_post_render() {
 		this.toggle_primary_action();
-	},
+	}
 
-	party: function() {
+	party() {
 		var me = this
 		if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
 			return frappe.call({
@@ -112,9 +112,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	get_unreconciled_entries: function() {
+	get_unreconciled_entries() {
 		var me = this;
 		return this.frm.call({
 			doc: me.frm.doc,
@@ -125,9 +125,9 @@
 			}
 		});
 
-	},
+	}
 
-	reconcile: function() {
+	reconcile() {
 		var me = this;
 		var show_dialog = me.frm.doc.payments.filter(d => d.difference_amount && !d.difference_account);
 
@@ -209,9 +209,9 @@
 		} else {
 			this.reconcile_payment_entries();
 		}
-	},
+	}
 
-	reconcile_payment_entries: function() {
+	reconcile_payment_entries() {
 		var me = this;
 
 		return this.frm.call({
@@ -222,9 +222,9 @@
 				me.toggle_primary_action();
 			}
 		});
-	},
+	}
 
-	set_invoice_options: function() {
+	set_invoice_options() {
 		var me = this;
 		var invoices = [];
 
@@ -244,9 +244,9 @@
 		}
 
 		refresh_field("payments");
-	},
+	}
 
-	toggle_primary_action: function() {
+	toggle_primary_action() {
 		if ((this.frm.doc.payments || []).length) {
 			this.frm.fields_dict.reconcile.$input
 				&& this.frm.fields_dict.reconcile.$input.addClass("btn-primary");
@@ -260,6 +260,6 @@
 		}
 	}
 
-});
+};
 
 $.extend(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index cf6ec18..6635128 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -114,7 +114,7 @@
 				'party_type': self.party_type,
 				'voucher_type': voucher_type,
 				'account': self.receivable_payable_account
-			}, as_dict=1, debug=1)
+			}, as_dict=1)
 
 	def add_payment_entries(self, entries):
 		self.set('payments', [])
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 493bd44..72d587a 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -4,18 +4,18 @@
 {% include 'erpnext/selling/sales_common.js' %};
 frappe.provide("erpnext.accounts");
 
-erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
+erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnext.selling.SellingController {
 	setup(doc) {
 		this.setup_posting_date_time_check();
-		this._super(doc);
-	},
+		super.setup(doc);
+	}
 
-	company: function() {
+	company() {
 		erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
-	},
+	}
 
 	onload(doc) {
-		this._super();
+		super.onload();
 		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
 		if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
 			this.frm.script_manager.trigger("is_pos");
@@ -23,10 +23,10 @@
 		}
 
 		erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
-	},
+	}
 
 	refresh(doc) {
-		this._super();
+		super.refresh();
 		if (doc.docstatus == 1 && !doc.is_return) {
 			this.frm.add_custom_button(__('Return'), this.make_sales_return, __('Create'));
 			this.frm.page.set_inner_btn_group_as_primary(__('Create'));
@@ -36,13 +36,13 @@
 			this.frm.return_print_format = "Sales Invoice Return";
 			this.frm.set_value('consolidated_invoice', '');
 		}
-	},
+	}
 
-	is_pos: function() {
+	is_pos() {
 		this.set_pos_data();
-	},
+	}
 
-	set_pos_data: async function() {
+	async set_pos_data() {
 		if(this.frm.doc.is_pos) {
 			this.frm.set_value("allocate_advances_automatically", 0);
 			if(!this.frm.doc.company) {
@@ -69,7 +69,7 @@
 				}
 			}
 		}
-	},
+	}
 
 	customer() {
 		if (!this.frm.doc.customer) return
@@ -86,13 +86,13 @@
 			}, () => {
 				this.apply_pricing_rule();
 			});
-	},
+	}
 
-	amount: function(){
+	amount(){
 		this.write_off_outstanding_amount_automatically()
-	},
+	}
 
-	change_amount: function(){
+	change_amount(){
 		if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
 			this.calculate_write_off_amount();
 		}else {
@@ -101,16 +101,16 @@
 		}
 
 		this.frm.refresh_fields();
-	},
+	}
 
-	loyalty_amount: function(){
+	loyalty_amount(){
 		this.calculate_outstanding_amount();
 		this.frm.refresh_field("outstanding_amount");
 		this.frm.refresh_field("paid_amount");
 		this.frm.refresh_field("base_paid_amount");
-	},
+	}
 
-	write_off_outstanding_amount_automatically: function() {
+	write_off_outstanding_amount_automatically() {
 		if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
 			frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
 			// this will make outstanding amount 0
@@ -125,15 +125,15 @@
 
 		this.calculate_outstanding_amount(false);
 		this.frm.refresh_fields();
-	},
+	}
 
-	make_sales_return: function() {
+	make_sales_return() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.pos_invoice.pos_invoice.make_sales_return",
 			frm: cur_frm
 		})
-	},
-})
+	}
+}
 
 $.extend(cur_frm.cscript, new erpnext.selling.POSInvoiceController({ frm: cur_frm }))
 
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 1e6a3d1..473db56 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -461,7 +461,17 @@
 		order by posting_date desc, posting_time desc
 		limit 1""", (item_code, warehouse), as_dict=1)
 
-	pos_sales_qty = frappe.db.sql("""select sum(p_item.qty) as qty
+	pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
+
+	sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
+
+	if sle_qty and pos_sales_qty:
+		return sle_qty - pos_sales_qty
+	else:
+		return sle_qty
+
+def get_pos_reserved_qty(item_code, warehouse):
+	reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
 		from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
 		where p.name = p_item.parent
 		and p.consolidated_invoice is NULL
@@ -470,14 +480,8 @@
 		and p_item.item_code = %s
 		and p_item.warehouse = %s
 		""", (item_code, warehouse), as_dict=1)
-
-	sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
-	pos_sales_qty = pos_sales_qty[0].qty or 0 if pos_sales_qty else 0
-
-	if sle_qty and pos_sales_qty:
-		return sle_qty - pos_sales_qty
-	else:
-		return sle_qty
+	
+	return reserved_qty[0].qty or 0 if reserved_qty else 0
 
 @frappe.whitelist()
 def make_sales_return(source_name, target_doc=None):
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index f58c8f4..617b5b4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -4,10 +4,10 @@
 frappe.provide("erpnext.accounts");
 {% include 'erpnext/public/js/controllers/buying.js' %};
 
-erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
-	setup: function(doc) {
+erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.BuyingController {
+	setup(doc) {
 		this.setup_posting_date_time_check();
-		this._super(doc);
+		super.setup(doc);
 
 		// formatter for purchase invoice item
 		if(this.frm.doc.update_stock) {
@@ -25,14 +25,14 @@
 				}
 			};
 		});
-	},
+	}
 
-	company: function() {
+	company() {
 		erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
-	},
+	}
 
-	onload: function() {
-		this._super();
+	onload() {
+		super.onload();
 
 		if(!this.frm.doc.__islocal) {
 			// show credit_to in print format
@@ -48,11 +48,11 @@
 		}
 
 		erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
-	},
+	}
 
-	refresh: function(doc) {
+	refresh(doc) {
 		const me = this;
-		this._super();
+		super.refresh();
 
 		hide_fields(this.frm.doc);
 		// Show / Hide button
@@ -161,26 +161,26 @@
 		}
 
 		this.frm.set_df_property("tax_withholding_category", "hidden", doc.apply_tds ? 0 : 1);
-	},
+	}
 
-	unblock_invoice: function() {
+	unblock_invoice() {
 		const me = this;
 		frappe.call({
 			'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.unblock_invoice',
 			'args': {'name': me.frm.doc.name},
 			'callback': (r) => me.frm.reload_doc()
 		});
-	},
+	}
 
-	block_invoice: function() {
+	block_invoice() {
 		this.make_comment_dialog_and_block_invoice();
-	},
+	}
 
-	change_release_date: function() {
+	change_release_date() {
 		this.make_dialog_and_set_release_date();
-	},
+	}
 
-	can_change_release_date: function(date) {
+	can_change_release_date(date) {
 		const diff = frappe.datetime.get_diff(date, frappe.datetime.nowdate());
 		if (diff < 0) {
 			frappe.throw(__('New release date should be in the future'));
@@ -188,9 +188,9 @@
 		} else {
 			return true;
 		}
-	},
+	}
 
-	make_comment_dialog_and_block_invoice: function(){
+	make_comment_dialog_and_block_invoice(){
 		const me = this;
 
 		const title = __('Block Invoice');
@@ -232,9 +232,9 @@
 		});
 
 		this.dialog.show();
-	},
+	}
 
-	make_dialog_and_set_release_date: function() {
+	make_dialog_and_set_release_date() {
 		const me = this;
 
 		const title = __('Set New Release Date');
@@ -263,17 +263,17 @@
 		});
 
 		this.dialog.show();
-	},
+	}
 
-	set_release_date: function(data) {
+	set_release_date(data) {
 		return frappe.call({
 			'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.change_release_date',
 			'args': data,
 			'callback': (r) => this.frm.reload_doc()
 		});
-	},
+	}
 
-	supplier: function() {
+	supplier() {
 		var me = this;
 
 		// Do not update if inter company reference is there as the details will already be updated
@@ -295,9 +295,9 @@
 				me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
 				me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
 			})
-	},
+	}
 
-	apply_tds: function(frm) {
+	apply_tds(frm) {
 		var me = this;
 
 		if (!me.frm.doc.apply_tds) {
@@ -307,9 +307,9 @@
 			me.frm.set_value("tax_withholding_category", me.frm.supplier_tds);
 			me.frm.set_df_property("tax_withholding_category", "hidden", 0);
 		}
-	},
+	}
 
-	credit_to: function() {
+	credit_to() {
 		var me = this;
 		if(this.frm.doc.credit_to) {
 			me.frm.call({
@@ -327,16 +327,16 @@
 				}
 			});
 		}
-	},
+	}
 
-	make_inter_company_invoice: function(frm) {
+	make_inter_company_invoice(frm) {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_inter_company_sales_invoice",
 			frm: frm
 		});
-	},
+	}
 
-	is_paid: function() {
+	is_paid() {
 		hide_fields(this.frm.doc);
 		if(cint(this.frm.doc.is_paid)) {
 			this.frm.set_value("allocate_advances_automatically", 0);
@@ -347,44 +347,44 @@
 		}
 		this.calculate_outstanding_amount();
 		this.frm.refresh_fields();
-	},
+	}
 
-	write_off_amount: function() {
+	write_off_amount() {
 		this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
 		this.calculate_outstanding_amount();
 		this.frm.refresh_fields();
-	},
+	}
 
-	paid_amount: function() {
+	paid_amount() {
 		this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
 		this.write_off_amount();
 		this.frm.refresh_fields();
-	},
+	}
 
-	allocated_amount: function() {
+	allocated_amount() {
 		this.calculate_total_advance();
 		this.frm.refresh_fields();
-	},
+	}
 
-	items_add: function(doc, cdt, cdn) {
+	items_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		this.frm.script_manager.copy_from_first_row("items", row,
 			["expense_account", "cost_center", "project"]);
-	},
+	}
 
-	on_submit: function() {
+	on_submit() {
 		$.each(this.frm.doc["items"] || [], function(i, row) {
 			if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
 		})
-	},
+	}
 
-	make_debit_note: function() {
+	make_debit_note() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_debit_note",
 			frm: cur_frm
 		})
-	},
-});
+	}
+};
 
 cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 24e67fe..d3d3ffa 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1380,7 +1380,7 @@
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-03-30 22:45:58.334107",
+ "modified": "2021-04-30 22:45:58.334107",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 8a42d9e..b48db24 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -5,17 +5,17 @@
 frappe.provide("erpnext.accounts");
 
 
-erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({
-	setup: function(doc) {
+erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends erpnext.selling.SellingController {
+	setup(doc) {
 		this.setup_posting_date_time_check();
-		this._super(doc);
-	},
-	company: function() {
+		super.setup(doc);
+	}
+	company() {
 		erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
-	},
-	onload: function() {
+	}
+	onload() {
 		var me = this;
-		this._super();
+		super.onload();
 
 		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice'];
 		if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
@@ -35,11 +35,11 @@
 		}
 		erpnext.queries.setup_warehouse_query(this.frm);
 		erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
-	},
+	}
 
-	refresh: function(doc, dt, dn) {
+	refresh(doc, dt, dn) {
 		const me = this;
-		this._super();
+		super.refresh();
 		if(cur_frm.msgbox && cur_frm.msgbox.$wrapper.is(":visible")) {
 			// hide new msgbox
 			cur_frm.msgbox.hide();
@@ -138,16 +138,16 @@
 				}, __('Create'));
 			}
 		}
-	},
+	}
 
-	make_maintenance_schedule: function() {
+	make_maintenance_schedule() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
 			frm: cur_frm
 		})
-	},
+	}
 
-	on_submit: function(doc, dt, dn) {
+	on_submit(doc, dt, dn) {
 		var me = this;
 
 		if (frappe.get_route()[0] != 'Form') {
@@ -157,9 +157,9 @@
 		$.each(doc["items"], function(i, row) {
 			if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
 		})
-	},
+	}
 
-	set_default_print_format: function() {
+	set_default_print_format() {
 		// set default print format to POS type or Credit Note
 		if(cur_frm.doc.is_pos) {
 			if(cur_frm.pos_print_format) {
@@ -180,9 +180,9 @@
 				cur_frm.meta._default_print_format = null;
 			}
 		}
-	},
+	}
 
-	sales_order_btn: function() {
+	sales_order_btn() {
 		var me = this;
 		this.$sales_order_btn = this.frm.add_custom_button(__('Sales Order'),
 			function() {
@@ -201,9 +201,9 @@
 					}
 				})
 			}, __("Get Items From"));
-	},
+	}
 
-	quotation_btn: function() {
+	quotation_btn() {
 		var me = this;
 		this.$quotation_btn = this.frm.add_custom_button(__('Quotation'),
 			function() {
@@ -225,9 +225,9 @@
 					}
 				})
 			}, __("Get Items From"));
-	},
+	}
 
-	delivery_note_btn: function() {
+	delivery_note_btn() {
 		var me = this;
 		this.$delivery_note_btn = this.frm.add_custom_button(__('Delivery Note'),
 			function() {
@@ -253,12 +253,12 @@
 					}
 				});
 			}, __("Get Items From"));
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
-	customer: function() {
+	}
+	customer() {
 		if (this.frm.doc.is_pos){
 			var pos_profile = this.frm.doc.pos_profile;
 		}
@@ -289,16 +289,16 @@
 				}
 			});
 		}
-	},
+	}
 
-	make_inter_company_invoice: function() {
+	make_inter_company_invoice() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_inter_company_purchase_invoice",
 			frm: me.frm
 		});
-	},
+	}
 
-	debit_to: function() {
+	debit_to() {
 		var me = this;
 		if(this.frm.doc.debit_to) {
 			me.frm.call({
@@ -316,14 +316,14 @@
 				}
 			});
 		}
-	},
+	}
 
-	allocated_amount: function() {
+	allocated_amount() {
 		this.calculate_total_advance();
 		this.frm.refresh_fields();
-	},
+	}
 
-	write_off_outstanding_amount_automatically: function() {
+	write_off_outstanding_amount_automatically() {
 		if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
 			frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
 			// this will make outstanding amount 0
@@ -338,39 +338,39 @@
 
 		this.calculate_outstanding_amount(false);
 		this.frm.refresh_fields();
-	},
+	}
 
-	write_off_amount: function() {
+	write_off_amount() {
 		this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
 		this.write_off_outstanding_amount_automatically();
-	},
+	}
 
-	items_add: function(doc, cdt, cdn) {
+	items_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);
-	},
+	}
 
-	set_dynamic_labels: function() {
-		this._super();
+	set_dynamic_labels() {
+		super.set_dynamic_labels();
 		this.frm.events.hide_fields(this.frm)
-	},
+	}
 
-	items_on_form_rendered: function() {
-		erpnext.setup_serial_no();
-	},
+	items_on_form_rendered() {
+		erpnext.setup_serial_or_batch_no();
+	}
 
-	packed_items_on_form_rendered: function(doc, grid_row) {
-		erpnext.setup_serial_no();
-	},
+	packed_items_on_form_rendered(doc, grid_row) {
+		erpnext.setup_serial_or_batch_no();
+	}
 
-	make_sales_return: function() {
+	make_sales_return() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
 			frm: cur_frm
 		})
-	},
+	}
 
-	asset: function(frm, cdt, cdn) {
+	asset(frm, cdt, cdn) {
 		var row = locals[cdt][cdn];
 		if(row.asset) {
 			frappe.call({
@@ -384,18 +384,18 @@
 				}
 			})
 		}
-	},
+	}
 
-	is_pos: function(frm){
+	is_pos(frm){
 		this.set_pos_data();
-	},
+	}
 
-	pos_profile: function() {
+	pos_profile() {
 		this.frm.doc.taxes = []
 		this.set_pos_data();
-	},
+	}
 
-	set_pos_data: function() {
+	set_pos_data() {
 		if(this.frm.doc.is_pos) {
 			this.frm.set_value("allocate_advances_automatically", 0);
 			if(!this.frm.doc.company) {
@@ -425,13 +425,13 @@
 			}
 		}
 		else this.frm.trigger("refresh");
-	},
+	}
 
-	amount: function(){
+	amount(){
 		this.write_off_outstanding_amount_automatically()
-	},
+	}
 
-	change_amount: function(){
+	change_amount(){
 		if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
 			this.calculate_write_off_amount();
 		}else {
@@ -440,15 +440,15 @@
 		}
 
 		this.frm.refresh_fields();
-	},
+	}
 
-	loyalty_amount: function(){
+	loyalty_amount(){
 		this.calculate_outstanding_amount();
 		this.frm.refresh_field("outstanding_amount");
 		this.frm.refresh_field("paid_amount");
 		this.frm.refresh_field("base_paid_amount");
 	}
-});
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4461f29..bb74a02 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1111,7 +1111,7 @@
 			if not item.serial_no:
 				continue
 
-			for serial_no in item.serial_no.split("\n"):
+			for serial_no in get_serial_nos(item.serial_no):
 				if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
 					frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
 
@@ -1755,15 +1755,10 @@
 		item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
 
 def get_delivery_note_details(internal_reference):
-	so_item_map = {}
-
 	si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
 		filters={'parent': internal_reference})
 
-	for d in si_item_details:
-		so_item_map.setdefault(d.name, d.so_detail)
-
-	return so_item_map
+	return {d.name: d.so_detail for d in si_item_details if d.so_detail}
 
 def get_sales_invoice_details(internal_reference):
 	dn_item_map = {}
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 09db7fe..5c1cbaa 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -21,7 +21,10 @@
 	else:
 		party_type = 'Supplier'
 		party = inv.supplier
-	
+
+	if not party:
+		frappe.throw(_("Please select {0} first").format(party_type))
+
 	return party_type, party
 
 def get_party_tax_withholding_details(inv, tax_withholding_category=None):
@@ -324,7 +327,7 @@
 		net_total, ldc.certificate_limit
 	):
 		tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
-	
+
 	return tds_amount
 
 def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
diff --git a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
index bd7a126..4c7faf4 100644
--- a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
+++ b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
@@ -1,5 +1,6 @@
 {
  "attach_print": 0,
+ "channel": "Email",
  "condition": "doc.auto_created",
  "creation": "2018-04-25 14:19:05.440361",
  "days_in_advance": 0,
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 444b40e..db605f7 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -364,7 +364,7 @@
 		payment_terms_details = frappe.db.sql("""
 			select
 				si.name, si.party_account_currency, si.currency, si.conversion_rate,
-				ps.due_date, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
+				ps.due_date, ps.payment_term, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
 			from `tab{0}` si, `tabPayment Schedule` ps
 			where
 				si.name = ps.parent and
@@ -394,7 +394,7 @@
 			"due_date": d.due_date,
 			"invoiced": invoiced,
 			"invoice_grand_total": row.invoiced,
-			"payment_term": d.description,
+			"payment_term": d.description or d.payment_term,
 			"paid": d.paid_amount + d.discounted_amount,
 			"credit_note": 0.0,
 			"outstanding": invoiced - d.paid_amount - d.discounted_amount
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 1729abc..26bb44f 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -5,7 +5,8 @@
 import frappe
 from frappe import _
 from frappe.utils import flt, cint
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
+	get_filtered_list_for_consolidated_report)
 
 def execute(filters=None):
 	period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
@@ -132,6 +133,10 @@
 	if filters.get('accumulated_values'):
 		period_list = [period_list[-1]]
 
+	# from consolidated financial statement
+	if filters.get('accumulated_in_group_company'):
+		period_list = get_filtered_list_for_consolidated_report(filters, period_list)
+
 	for period in period_list:
 		key = period if consolidated else period.key
 		if asset:
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py
index cf0946b..3577457 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.py
+++ b/erpnext/accounts/report/cash_flow/cash_flow.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe import _
 from frappe.utils import cint, cstr
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data, get_filtered_list_for_consolidated_report)
 from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
 from erpnext.accounts.utils import get_fiscal_year
 from six import iteritems
@@ -67,9 +67,9 @@
 			section_data.append(account_data)
 
 		add_total_row_account(data, section_data, cash_flow_account['section_footer'],
-			period_list, company_currency, summary_data)
+			period_list, company_currency, summary_data, filters)
 
-	add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data)
+	add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data, filters)
 	columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
 
 	chart = get_chart_data(columns, data)
@@ -162,18 +162,26 @@
 
 	return start_date
 
-def add_total_row_account(out, data, label, period_list, currency, summary_data, consolidated = False):
+def add_total_row_account(out, data, label, period_list, currency, summary_data, filters, consolidated=False):
 	total_row = {
 		"account_name": "'" + _("{0}").format(label) + "'",
 		"account": "'" + _("{0}").format(label) + "'",
 		"currency": currency
 	}
+
+	summary_data[label] = 0
+
+	# from consolidated financial statement
+	if filters.get('accumulated_in_group_company'):
+		period_list = get_filtered_list_for_consolidated_report(filters, period_list)
+
 	for row in data:
 		if row.get("parent_account"):
 			for period in period_list:
 				key = period if consolidated else period['key']
 				total_row.setdefault(key, 0.0)
 				total_row[key] += row.get(key, 0.0)
+				summary_data[label] += row.get(key)
 
 			total_row.setdefault("total", 0.0)
 			total_row["total"] += row["total"]
@@ -181,7 +189,6 @@
 	out.append(total_row)
 	out.append({})
 
-	summary_data[label] = total_row["total"]
 
 def get_report_summary(summary_data, currency):
 	report_summary = []
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
index 0947922..1363b53 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
@@ -2,118 +2,128 @@
 // For license information, please see license.txt
 /* eslint-disable */
 
-frappe.query_reports["Consolidated Financial Statement"] = {
-	"filters": [
-		{
-			"fieldname":"company",
-			"label": __("Company"),
-			"fieldtype": "Link",
-			"options": "Company",
-			"default": frappe.defaults.get_user_default("Company"),
-			"reqd": 1
-		},
-		{
-			"fieldname":"filter_based_on",
-			"label": __("Filter Based On"),
-			"fieldtype": "Select",
-			"options": ["Fiscal Year", "Date Range"],
-			"default": ["Fiscal Year"],
-			"reqd": 1,
-			on_change: function() {
-				let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
-				frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
-				frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
-				frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
-				frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
+frappe.require("assets/erpnext/js/financial_statements.js", function() {
+	frappe.query_reports["Consolidated Financial Statement"] = {
+		"filters": [
+			{
+				"fieldname":"company",
+				"label": __("Company"),
+				"fieldtype": "Link",
+				"options": "Company",
+				"default": frappe.defaults.get_user_default("Company"),
+				"reqd": 1
+			},
+			{
+				"fieldname":"filter_based_on",
+				"label": __("Filter Based On"),
+				"fieldtype": "Select",
+				"options": ["Fiscal Year", "Date Range"],
+				"default": ["Fiscal Year"],
+				"reqd": 1,
+				on_change: function() {
+					let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
+					frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
+					frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
+					frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
+					frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
 
-				frappe.query_report.refresh();
+					frappe.query_report.refresh();
+				}
+			},
+			{
+				"fieldname":"period_start_date",
+				"label": __("Start Date"),
+				"fieldtype": "Date",
+				"hidden": 1,
+				"reqd": 1
+			},
+			{
+				"fieldname":"period_end_date",
+				"label": __("End Date"),
+				"fieldtype": "Date",
+				"hidden": 1,
+				"reqd": 1
+			},
+			{
+				"fieldname":"from_fiscal_year",
+				"label": __("Start Year"),
+				"fieldtype": "Link",
+				"options": "Fiscal Year",
+				"default": frappe.defaults.get_user_default("fiscal_year"),
+				"reqd": 1
+			},
+			{
+				"fieldname":"to_fiscal_year",
+				"label": __("End Year"),
+				"fieldtype": "Link",
+				"options": "Fiscal Year",
+				"default": frappe.defaults.get_user_default("fiscal_year"),
+				"reqd": 1
+			},
+			{
+				"fieldname":"finance_book",
+				"label": __("Finance Book"),
+				"fieldtype": "Link",
+				"options": "Finance Book"
+			},
+			{
+				"fieldname":"report",
+				"label": __("Report"),
+				"fieldtype": "Select",
+				"options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
+				"default": "Balance Sheet",
+				"reqd": 1
+			},
+			{
+				"fieldname": "presentation_currency",
+				"label": __("Currency"),
+				"fieldtype": "Select",
+				"options": erpnext.get_presentation_currency_list(),
+				"default": frappe.defaults.get_user_default("Currency")
+			},
+			{
+				"fieldname":"accumulated_in_group_company",
+				"label": __("Accumulated Values in Group Company"),
+				"fieldtype": "Check",
+				"default": 0
+			},
+			{
+				"fieldname": "include_default_book_entries",
+				"label": __("Include Default Book Entries"),
+				"fieldtype": "Check",
+				"default": 1
 			}
-		},
-		{
-			"fieldname":"period_start_date",
-			"label": __("Start Date"),
-			"fieldtype": "Date",
-			"hidden": 1,
-			"reqd": 1
-		},
-		{
-			"fieldname":"period_end_date",
-			"label": __("End Date"),
-			"fieldtype": "Date",
-			"hidden": 1,
-			"reqd": 1
-		},
-		{
-			"fieldname":"from_fiscal_year",
-			"label": __("Start Year"),
-			"fieldtype": "Link",
-			"options": "Fiscal Year",
-			"default": frappe.defaults.get_user_default("fiscal_year"),
-			"reqd": 1
-		},
-		{
-			"fieldname":"to_fiscal_year",
-			"label": __("End Year"),
-			"fieldtype": "Link",
-			"options": "Fiscal Year",
-			"default": frappe.defaults.get_user_default("fiscal_year"),
-			"reqd": 1
-		},
-		{
-			"fieldname":"finance_book",
-			"label": __("Finance Book"),
-			"fieldtype": "Link",
-			"options": "Finance Book"
-		},
-		{
-			"fieldname":"report",
-			"label": __("Report"),
-			"fieldtype": "Select",
-			"options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
-			"default": "Balance Sheet",
-			"reqd": 1
-		},
-		{
-			"fieldname": "presentation_currency",
-			"label": __("Currency"),
-			"fieldtype": "Select",
-			"options": erpnext.get_presentation_currency_list(),
-			"default": frappe.defaults.get_user_default("Currency")
-		},
-		{
-			"fieldname":"accumulated_in_group_company",
-			"label": __("Accumulated Values in Group Company"),
-			"fieldtype": "Check",
-			"default": 0
-		},
-		{
-			"fieldname": "include_default_book_entries",
-			"label": __("Include Default Book Entries"),
-			"fieldtype": "Check",
-			"default": 1
-		}
-	],
-	"formatter": function(value, row, column, data, default_formatter) {
-		value = default_formatter(value, row, column, data);
+		],
+		"formatter": function(value, row, column, data, default_formatter) {			
+			if (data && column.fieldname=="account") {
+				value = data.account_name || value;
+				
+				column.link_onclick =
+				"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
+				column.is_tree = true;
+			}
 
-		if (!data.parent_account) {
-			value = $(`<span>${value}</span>`);
+			value = default_formatter(value, row, column, data);
 
-			var $value = $(value).css("font-weight", "bold");
+			if (!data.parent_account) {
+				value = $(`<span>${value}</span>`);
 
-			value = $value.wrap("<p></p>").parent().html();
-		}
-		return value;
-	},
-	onload: function() {
-		let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
+				var $value = $(value).css("font-weight", "bold");
 
-		frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
-			var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
-			frappe.query_report.set_filter_value({
-				period_start_date: fy.year_start_date,
-				period_end_date: fy.year_end_date
+				value = $value.wrap("<p></p>").parent().html();
+			}
+			return value;
+		},
+		onload: function() {
+			let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
+
+			frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
+				var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
+				frappe.query_report.set_filter_value({
+					period_start_date: fy.year_start_date,
+					period_end_date: fy.year_end_date
+				});
 			});
-		});
+		}
 	}
-}
+});
\ No newline at end of file
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 0c4a422..7793af7 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -94,7 +94,7 @@
 
 	chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
 
-	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
+	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, filters, True)
 
 	return data, None, chart, report_summary
 
@@ -149,9 +149,9 @@
 			section_data.append(account_data)
 
 		add_total_row_account(data, section_data, cash_flow_account['section_footer'],
-			companies, company_currency, summary_data, True)
+			companies, company_currency, summary_data, filters, True)
 
-	add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, True)
+	add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, filters, True)
 
 	report_summary = get_cash_flow_summary(summary_data, company_currency)
 
@@ -329,8 +329,9 @@
 		has_value = False
 		total = 0
 		row = frappe._dict({
-			"account_name": _(d.account_name),
-			"account": _(d.account_name),
+			"account_name": ('%s - %s' %(_(d.account_number), _(d.account_name))
+				if d.account_number else _(d.account_name)),
+			"account": _(d.name),
 			"parent_account": _(d.parent_account),
 			"indent": flt(d.indent),
 			"year_start_date": start_date,
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 14efa1f..d20ddbd 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -119,10 +119,10 @@
 
 def validate_dates(from_date, to_date):
 	if not from_date or not to_date:
-		frappe.throw("From Date and To Date are mandatory")
+		frappe.throw(_("From Date and To Date are mandatory"))
 
 	if to_date < from_date:
-		frappe.throw("To Date cannot be less than From Date")
+		frappe.throw(_("To Date cannot be less than From Date"))
 
 def get_months(start_date, end_date):
 	diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month)
@@ -522,4 +522,12 @@
 				"width": 150
 			})
 
-	return columns
\ No newline at end of file
+	return columns
+
+def get_filtered_list_for_consolidated_report(filters, period_list):
+	filtered_summary_list = []
+	for period in period_list:
+		if period == filters.get('company'):
+			filtered_summary_list.append(period)
+
+	return filtered_summary_list
diff --git a/erpnext/accounts/report/pos_register/pos_register.py b/erpnext/accounts/report/pos_register/pos_register.py
index 52f7fe2..cfbd7fd 100644
--- a/erpnext/accounts/report/pos_register/pos_register.py
+++ b/erpnext/accounts/report/pos_register/pos_register.py
@@ -116,22 +116,19 @@
 		frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
 
 def get_conditions(filters):
-	conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s".format(
-		company=filters.get("company"),
-		from_date=filters.get("from_date"),
-		to_date=filters.get("to_date"))
+	conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s"
 
 	if filters.get("pos_profile"):
-		conditions += " AND pos_profile = %(pos_profile)s".format(pos_profile=filters.get("pos_profile"))
+		conditions += " AND pos_profile = %(pos_profile)s"
 	
 	if filters.get("owner"):
-		conditions += " AND owner = %(owner)s".format(owner=filters.get("owner"))
+		conditions += " AND owner = %(owner)s"
 	
 	if filters.get("customer"):
-		conditions += " AND customer = %(customer)s".format(customer=filters.get("customer"))
+		conditions += " AND customer = %(customer)s"
 	
 	if filters.get("is_return"):
-		conditions += " AND is_return = %(is_return)s".format(is_return=filters.get("is_return"))
+		conditions += " AND is_return = %(is_return)s"
 	
 	if filters.get("mode_of_payment"):
 		conditions += """
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
index fe261b3..5d04824 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
@@ -5,7 +5,8 @@
 import frappe
 from frappe import _
 from frappe.utils import flt
-from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
+from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
+	get_filtered_list_for_consolidated_report)
 
 def execute(filters=None):
 	period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
@@ -33,13 +34,17 @@
 	chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
 
 	currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")
-	report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency)
+	report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters)
 
 	return columns, data, None, chart, report_summary
 
-def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, consolidated=False):
+def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, filters, consolidated=False):
 	net_income, net_expense, net_profit = 0.0, 0.0, 0.0
 
+	# from consolidated financial statement
+	if filters.get('accumulated_in_group_company'):
+		period_list = get_filtered_list_for_consolidated_report(filters, period_list)
+
 	for period in period_list:
 		key = period if consolidated else period.key
 		if income:
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 9aff144..8799275 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -195,8 +195,7 @@
 				# If depreciation is already completed (for double declining balance)
 				if skip_row: continue
 
-				depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
-					d.total_number_of_depreciations, d)
+				depreciation_amount = get_depreciation_amount(self, value_after_depreciation, d)
 
 				if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
 					schedule_date = add_months(d.depreciation_start_date,
@@ -208,7 +207,7 @@
 
 				# For first row
 				if has_pro_rata and n==0:
-					depreciation_amount, days, months = get_pro_rata_amt(d, depreciation_amount,
+					depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
 						self.available_for_use_date, d.depreciation_start_date)
 
 					# For first depr schedule date will be the start date
@@ -220,7 +219,7 @@
 					to_date = add_months(self.available_for_use_date,
 						n * cint(d.frequency_of_depreciation))
 
-					depreciation_amount, days, months = get_pro_rata_amt(d,
+					depreciation_amount, days, months = self.get_pro_rata_amt(d,
 						depreciation_amount, schedule_date, to_date)
 
 					monthly_schedule_date = add_months(schedule_date, 1)
@@ -365,24 +364,6 @@
 	def get_value_after_depreciation(self, idx):
 		return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
 
-	def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
-		precision = self.precision("gross_purchase_amount")
-
-		if row.depreciation_method in ("Straight Line", "Manual"):
-			depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
-
-			if not depreciation_left:
-				frappe.msgprint(_("All the depreciations has been booked"))
-				depreciation_amount = flt(row.expected_value_after_useful_life)
-				return depreciation_amount
-
-			depreciation_amount = (flt(row.value_after_depreciation) -
-				flt(row.expected_value_after_useful_life)) / depreciation_left
-		else:
-			depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
-
-		return depreciation_amount
-
 	def validate_expected_value_after_useful_life(self):
 		for row in self.get('finance_books'):
 			accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
@@ -575,6 +556,13 @@
 
 			return 100 * (1 - flt(depreciation_rate, float_precision))
 
+	def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
+		days = date_diff(to_date, from_date)
+		months = month_diff(to_date, from_date)
+		total_days = get_total_days(to_date, row.frequency_of_depreciation)
+
+		return (depreciation_amount * flt(days)) / flt(total_days), days, months
+
 def update_maintenance_status():
 	assets = frappe.get_all(
 		"Asset", filters={"docstatus": 1, "maintenance_required": 1}
@@ -758,15 +746,20 @@
 def is_cwip_accounting_enabled(asset_category):
 	return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
 
-def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
-	days = date_diff(to_date, from_date)
-	months = month_diff(to_date, from_date)
-	total_days = get_total_days(to_date, row.frequency_of_depreciation)
-
-	return (depreciation_amount * flt(days)) / flt(total_days), days, months
-
 def get_total_days(date, frequency):
 	period_start_date = add_months(date,
 		cint(frequency) * -1)
 
 	return date_diff(date, period_start_date)
+
+@erpnext.allow_regional
+def get_depreciation_amount(asset, depreciable_value, row):
+	depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+	if row.depreciation_method in ("Straight Line", "Manual"):
+		depreciation_amount = (flt(row.value_after_depreciation) -
+			flt(row.expected_value_after_useful_life)) / depreciation_left
+	else:
+		depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
+
+	return depreciation_amount
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index f12a33d..3cd4b80 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -635,6 +635,45 @@
 		frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
 		frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc)
 
+	def test_discounted_wdv_depreciation_rate_for_indian_region(self):
+		# set indian company
+		company_flag = frappe.flags.company
+		frappe.flags.company = "_Test Company"
+
+		pr = make_purchase_receipt(item_code="Macbook Pro",
+			qty=1, rate=8000.0, location="Test Location")
+
+		asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
+		asset = frappe.get_doc('Asset', asset_name)
+		asset.calculate_depreciation = 1
+		asset.available_for_use_date = '2030-06-12'
+		asset.purchase_date = '2030-01-01'
+		asset.append("finance_books", {
+			"expected_value_after_useful_life": 1000,
+			"depreciation_method": "Written Down Value",
+			"total_number_of_depreciations": 3,
+			"frequency_of_depreciation": 12,
+			"depreciation_start_date": "2030-12-31"
+		})
+		asset.save(ignore_permissions=True)
+
+		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+		expected_schedules = [
+			["2030-12-31", 1106.85, 1106.85],
+			["2031-12-31", 3446.58, 4553.43],
+			["2032-12-31", 1723.29, 6276.72],
+			["2033-06-12", 723.28, 7000.00]
+		]
+
+		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+		# reset indian company
+		frappe.flags.company = company_flag
+
 def create_asset_data():
 	if not frappe.db.exists("Asset Category", "Computers"):
 		create_asset_category()
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index 74963c2..51ce157 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -4,7 +4,7 @@
 frappe.ui.form.on('Asset Category', {
 	onload: function(frm) {
 		frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account');
-		frm.add_fetch('company_name', 'depreciation_expense_account', 'accumulated_depreciation_account');
+		frm.add_fetch('company_name', 'depreciation_expense_account', 'depreciation_expense_account');
 
 		frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) {
 			var d  = locals[cdt][cdn];
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index dd0f065..c0e19e9 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -61,8 +61,8 @@
 	}
 });
 
-erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
-	setup: function() {
+erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends erpnext.buying.BuyingController {
+	setup() {
 		this.frm.custom_make_buttons = {
 			'Purchase Receipt': 'Purchase Receipt',
 			'Purchase Invoice': 'Purchase Invoice',
@@ -70,13 +70,13 @@
 			'Payment Entry': 'Payment',
 		}
 
-		this._super();
+		super.setup();
 
-	},
+	}
 
-	refresh: function(doc, cdt, cdn) {
+	refresh(doc, cdt, cdn) {
 		var me = this;
-		this._super();
+		super.refresh();
 		var allow_receipt = false;
 		var is_drop_ship = false;
 
@@ -182,9 +182,9 @@
 		} else if(doc.docstatus===0) {
 			cur_frm.cscript.add_from_mappers();
 		}
-	},
+	}
 
-	get_items_from_open_material_requests: function() {
+	get_items_from_open_material_requests() {
 		erpnext.utils.map_current_doc({
 			method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
 			args: {
@@ -202,17 +202,17 @@
 			},
 			get_query_method: "erpnext.stock.doctype.material_request.material_request.get_material_requests_based_on_supplier"
 		});
-	},
+	}
 
-	validate: function() {
+	validate() {
 		set_schedule_date(this.frm);
-	},
+	}
 
-	has_unsupplied_items: function() {
+	has_unsupplied_items() {
 		return this.frm.doc['supplied_items'].some(item => item.required_qty != item.supplied_qty)
-	},
+	}
 
-	make_stock_entry: function() {
+	make_stock_entry() {
 		var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
 		var me = this;
 
@@ -326,9 +326,9 @@
 			me.dialog.hide();
 		});
 
-	},
+	}
 
-	_make_rm_stock_entry: function(rm_items) {
+	_make_rm_stock_entry(rm_items) {
 		frappe.call({
 			method:"erpnext.buying.doctype.purchase_order.purchase_order.make_rm_stock_entry",
 			args: {
@@ -341,31 +341,31 @@
 				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
 			}
 		});
-	},
+	}
 
-	make_inter_company_order: function(frm) {
+	make_inter_company_order(frm) {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
 			frm: frm
 		});
-	},
+	}
 
-	make_purchase_receipt: function() {
+	make_purchase_receipt() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
 			frm: cur_frm,
 			freeze_message: __("Creating Purchase Receipt ...")
 		})
-	},
+	}
 
-	make_purchase_invoice: function() {
+	make_purchase_invoice() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
 			frm: cur_frm
 		})
-	},
+	}
 
-	add_from_mappers: function() {
+	add_from_mappers() {
 		var me = this;
 		this.frm.add_custom_button(__('Material Request'),
 			function() {
@@ -471,13 +471,13 @@
 				}
 			});
 		}, __("Tools"));
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	items_add: function(doc, cdt, cdn) {
+	items_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		if(doc.schedule_date) {
 			row.schedule_date = doc.schedule_date;
@@ -485,13 +485,13 @@
 		} else {
 			this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
 		}
-	},
+	}
 
-	unhold_purchase_order: function(){
+	unhold_purchase_order(){
 		cur_frm.cscript.update_status("Resume", "Draft")
-	},
+	}
 
-	hold_purchase_order: function(){
+	hold_purchase_order(){
 		var me = this;
 		var d = new frappe.ui.Dialog({
 			title: __('Reason for Hold'),
@@ -523,28 +523,28 @@
 			}
 		});
 		d.show();
-	},
+	}
 
-	unclose_purchase_order: function(){
+	unclose_purchase_order(){
 		cur_frm.cscript.update_status('Re-open', 'Submitted')
-	},
+	}
 
-	close_purchase_order: function(){
+	close_purchase_order(){
 		cur_frm.cscript.update_status('Close', 'Closed')
-	},
+	}
 
-	delivered_by_supplier: function(){
+	delivered_by_supplier(){
 		cur_frm.cscript.update_status('Deliver', 'Delivered')
-	},
+	}
 
-	items_on_form_rendered: function() {
-		set_schedule_date(this.frm);
-	},
-
-	schedule_date: function() {
+	items_on_form_rendered() {
 		set_schedule_date(this.frm);
 	}
-});
+
+	schedule_date() {
+		set_schedule_date(this.frm);
+	}
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index b76c378..ee0e1ef 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -205,10 +205,10 @@
 
 })
 
-erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
-	refresh: function() {
+erpnext.buying.RequestforQuotationController = class RequestforQuotationController extends erpnext.buying.BuyingController {
+	refresh() {
 		var me = this;
-		this._super();
+		super.refresh();
 		if (this.frm.doc.docstatus===0) {
 			this.frm.add_custom_button(__('Material Request'),
 				function() {
@@ -302,17 +302,17 @@
 					me.get_suppliers_button(me.frm);
 				}, __("Tools"));
 		}
-	},
+	}
 
-	calculate_taxes_and_totals: function() {
+	calculate_taxes_and_totals() {
 		return;
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	get_suppliers_button: function (frm) {
+	get_suppliers_button (frm) {
 		var doc = frm.doc;
 		var dialog = new frappe.ui.Dialog({
 			title: __("Get Suppliers"),
@@ -410,8 +410,8 @@
 		});
 
 		dialog.show();
-	},
-});
+	}
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm}));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index a0187b0..a3ba52e 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -4,19 +4,19 @@
 // attach required files
 {% include 'erpnext/public/js/controllers/buying.js' %};
 
-erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
-	setup: function() {
+erpnext.buying.SupplierQuotationController = class SupplierQuotationController extends erpnext.buying.BuyingController {
+	setup() {
 		this.frm.custom_make_buttons = {
 			'Purchase Order': 'Purchase Order',
 			'Quotation': 'Quotation'
 		}
 
-		this._super();
-	},
+		super.setup();
+	}
 
-	refresh: function() {
+	refresh() {
 		var me = this;
-		this._super();
+		super.refresh();
 
 		if (this.frm.doc.__islocal && !this.frm.doc.valid_till) {
 			this.frm.set_value('valid_till', frappe.datetime.add_months(this.frm.doc.transaction_date, 1));
@@ -77,22 +77,22 @@
 				})
 			}, __("Get Items From"));
 		}
-	},
+	}
 
-	make_purchase_order: function() {
+	make_purchase_order() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
 			frm: cur_frm
 		})
-	},
-	make_quotation: function() {
+	}
+	make_quotation() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_quotation",
 			frm: cur_frm
 		})
 
 	}
-});
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.SupplierQuotationController({frm: cur_frm}));
diff --git a/erpnext/change_log/v13/v13.0.2.md b/erpnext/change_log/v13/v13_0_2.md
similarity index 100%
rename from erpnext/change_log/v13/v13.0.2.md
rename to erpnext/change_log/v13/v13_0_2.md
diff --git a/erpnext/change_log/v13/v13_3_0.md b/erpnext/change_log/v13/v13_3_0.md
new file mode 100644
index 0000000..016dbb0
--- /dev/null
+++ b/erpnext/change_log/v13/v13_3_0.md
@@ -0,0 +1,73 @@
+# Version 13.3.0 Release Notes
+
+### Features & Enhancements
+
+- Purchase receipt creation from purchase invoice ([#25126](https://github.com/frappe/erpnext/pull/25126))
+- New Document Transaction Deletion ([#25354](https://github.com/frappe/erpnext/pull/25354))
+- Employee Referral ([#24997](https://github.com/frappe/erpnext/pull/24997))
+- Add Create Expense Claim button in Delivery Trip ([#25526](https://github.com/frappe/erpnext/pull/25526))
+- Reduced rate of asset depreciation as per IT Act ([#25648](https://github.com/frappe/erpnext/pull/25648))
+- Improve DATEV export ([#25238](https://github.com/frappe/erpnext/pull/25238))
+- Add pick batch button ([#25413](https://github.com/frappe/erpnext/pull/25413))
+- Enable custom field search on POS ([#25421](https://github.com/frappe/erpnext/pull/25421))
+- New check field in subscriptions for (not) submitting invoices ([#25394](https://github.com/frappe/erpnext/pull/25394))
+- Show POS reserved stock in stock projected qty report ([#25593](https://github.com/frappe/erpnext/pull/25593))
+- e-way bill validity field ([#25555](https://github.com/frappe/erpnext/pull/25555))
+- Significant reduction in time taken to save sales documents ([#25475](https://github.com/frappe/erpnext/pull/25475))
+
+### Fixes
+
+- Bank statement import via google sheet ([#25677](https://github.com/frappe/erpnext/pull/25677))
+- Invoices not getting fetched during payment reconciliation ([#25598](https://github.com/frappe/erpnext/pull/25598))
+- Error on applying TDS without party ([#25632](https://github.com/frappe/erpnext/pull/25632))
+- Allow to cancel loan with cancelled repayment entry ([#25507](https://github.com/frappe/erpnext/pull/25507))
+- Can't open general ledger from consolidated financial report ([#25542](https://github.com/frappe/erpnext/pull/25542))
+- Add 'Partially Received' to Status drop-down list in Material Request ([#24857](https://github.com/frappe/erpnext/pull/24857))
+- Updated item filters for material request ([#25531](https://github.com/frappe/erpnext/pull/25531))
+- Added validation in stock entry to check duplicate serial nos ([#25611](https://github.com/frappe/erpnext/pull/25611))
+- Update shopify api version ([#25600](https://github.com/frappe/erpnext/pull/25600))
+- Dialog variable assignment after definition in POS ([#25680](https://github.com/frappe/erpnext/pull/25680))
+- Added tax_types list ([#25587](https://github.com/frappe/erpnext/pull/25587))
+- Include search fields in Project Link field query ([#25505](https://github.com/frappe/erpnext/pull/25505))
+- Item stock levels displaying inconsistently ([#25506](https://github.com/frappe/erpnext/pull/25506))
+- Change today to now to get data for reposting ([#25703](https://github.com/frappe/erpnext/pull/25703))
+- Parameter for get_filtered_list_for_consolidated_report in consolidated balance sheet ([#25700](https://github.com/frappe/erpnext/pull/25700))
+- Minor fixes in loan ([#25546](https://github.com/frappe/erpnext/pull/25546))
+- Fieldname when updating docfield property ([#25516](https://github.com/frappe/erpnext/pull/25516))
+- Use get_serial_nos for splitting ([#25590](https://github.com/frappe/erpnext/pull/25590))
+- Show item's full name on hover over item in POS ([#25554](https://github.com/frappe/erpnext/pull/25554))
+- Stock ledger entry created against draft stock entry ([#25540](https://github.com/frappe/erpnext/pull/25540))
+- Incorrect expense account set in pos invoice ([#25543](https://github.com/frappe/erpnext/pull/25543))
+- Stock balance and batch-wise balance history report showing different closing stock ([#25575](https://github.com/frappe/erpnext/pull/25575))
+- Make strings translatable ([#25521](https://github.com/frappe/erpnext/pull/25521))
+- Serial no changed after saving stock reconciliation ([#25541](https://github.com/frappe/erpnext/pull/25541))
+- Ignore fraction difference while making round off gl entry ([#25438](https://github.com/frappe/erpnext/pull/25438))
+- Sync shopify customer addresses ([#25481](https://github.com/frappe/erpnext/pull/25481))
+- Total stock summary report not working ([#25551](https://github.com/frappe/erpnext/pull/25551))
+- Rename field has not updated value of deposit and withdrawal fields ([#25545](https://github.com/frappe/erpnext/pull/25545))
+- Unexpected keyword argument 'merge_logs' ([#25489](https://github.com/frappe/erpnext/pull/25489))
+- Validation message of quality inspection in purchase receipt ([#25667](https://github.com/frappe/erpnext/pull/25667))
+- Added is_stock_item filter ([#25530](https://github.com/frappe/erpnext/pull/25530))
+- Fetch total stock at company in PO ([#25532](https://github.com/frappe/erpnext/pull/25532))
+- Updated filters for process statement of accounts ([#25384](https://github.com/frappe/erpnext/pull/25384))
+- Incorrect expense account set in pos invoice ([#25571](https://github.com/frappe/erpnext/pull/25571))
+- Client script breaking while settings tax labels ([#25653](https://github.com/frappe/erpnext/pull/25653))
+- Empty payment term column in accounts receivable report ([#25556](https://github.com/frappe/erpnext/pull/25556))
+- Designation insufficient permission on lead doctype. ([#25331](https://github.com/frappe/erpnext/pull/25331))
+- Force https for shopify webhook registration ([#25630](https://github.com/frappe/erpnext/pull/25630))
+- Patch regional fields for old companies ([#25673](https://github.com/frappe/erpnext/pull/25673))
+- Woocommerce order sync issue ([#25692](https://github.com/frappe/erpnext/pull/25692))
+- Allow to receive same serial numbers multiple times ([#25471](https://github.com/frappe/erpnext/pull/25471))
+- Update Allocated amount after Paid Amount is changed in PE ([#25515](https://github.com/frappe/erpnext/pull/25515))
+- Updating Standard Notification's channel field ([#25564](https://github.com/frappe/erpnext/pull/25564))
+- Report summary showing inflated values when values are accumulated in Group Company ([#25577](https://github.com/frappe/erpnext/pull/25577))
+- UI fixes related to overflowing payment section ([#25652](https://github.com/frappe/erpnext/pull/25652))
+- List invoices in Payment Reconciliation Payment ([#25524](https://github.com/frappe/erpnext/pull/25524))
+- Ageing errors in PSOA ([#25490](https://github.com/frappe/erpnext/pull/25490))
+- Prevent spurious defaults for items when making prec from dnote ([#25559](https://github.com/frappe/erpnext/pull/25559))
+- Stock reconciliation getting time out error during submission ([#25557](https://github.com/frappe/erpnext/pull/25557))
+- Timesheet filter date exclusive issue ([#25626](https://github.com/frappe/erpnext/pull/25626))
+- Update cost center in the item table fetched from POS Profile ([#25609](https://github.com/frappe/erpnext/pull/25609))
+- Updated modified time in purchase invoice to pull new fields ([#25678](https://github.com/frappe/erpnext/pull/25678))
+- Stock and Accounts Settings form refactor ([#25534](https://github.com/frappe/erpnext/pull/25534))
+- Payment amount showing in foreign currency ([#25292](https://github.com/frappe/erpnext/pull/25292))
\ No newline at end of file
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index b686dc0..3f2d339 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -838,9 +838,10 @@
 		if not self.get("items"):
 			return
 
-		earliest_schedule_date = min([d.schedule_date for d in self.get("items")])
-		if earliest_schedule_date:
-			self.schedule_date = earliest_schedule_date
+		if any(d.schedule_date for d in self.get("items")):
+			# Select earliest schedule_date.
+			self.schedule_date = min(d.schedule_date for d in self.get("items")
+							if d.schedule_date is not None)
 
 		if self.schedule_date:
 			for d in self.get('items'):
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index bc1ac5e..b31724f 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -292,11 +292,14 @@
 		cond = """(`tabProject`.customer = %s or
 			ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer")))
 
-	fields = get_fields("Project", ["name"])
+	fields = get_fields("Project", ["name", "project_name"])
+	searchfields = frappe.get_meta("Project").get_search_fields()
+	searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
 
 	return frappe.db.sql("""select {fields} from `tabProject`
-		where `tabProject`.status not in ("Completed", "Cancelled")
-			and {cond} `tabProject`.name like %(txt)s {match_cond}
+		where
+			`tabProject`.status not in ("Completed", "Cancelled")
+			and {cond} {match_cond} {scond}
 		order by
 			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
 			idx desc,
@@ -304,6 +307,7 @@
 		limit {start}, {page_len}""".format(
 			fields=", ".join(['`tabProject`.{0}'.format(f) for f in fields]),
 			cond=cond,
+			scond=searchfields,
 			match_cond=get_match_cond(doctype),
 			start=start,
 			page_len=page_len), {
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 4bb6138..ed3aee5 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -100,6 +100,10 @@
 		["Queued", "eval:self.status == 'Queued'"],
 		["Failed", "eval:self.status == 'Failed'"],
 		["Cancelled", "eval:self.docstatus == 2"],
+	],
+	"Transaction Deletion Record": [
+		["Draft", None],
+		["Completed", "eval:self.docstatus == 1"],
 	]
 }
 
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index b14c274..41ca404 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -379,8 +379,7 @@
 					link = frappe.utils.get_link_to_form('Quality Inspection', d.quality_inspection)
 					frappe.throw(_("Quality Inspection: {0} is not submitted for the item: {1} in row {2}").format(link, d.item_code, d.idx), QualityInspectionNotSubmittedError)
 
-				qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
-				if qa_failed:
+				if qa_doc.status != 'Accepted':
 					frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
 						.format(d.idx, d.item_code), QualityInspectionRejectedError)
 			elif qa_required :
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 0c88d28..8dfee1d 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -4,8 +4,8 @@
 frappe.provide("erpnext");
 cur_frm.email_field = "email_id";
 
-erpnext.LeadController = frappe.ui.form.Controller.extend({
-	setup: function () {
+erpnext.LeadController = class LeadController extends frappe.ui.form.Controller {
+	setup () {
 		this.frm.make_methods = {
 			'Customer': this.make_customer,
 			'Quotation': this.make_quotation,
@@ -13,9 +13,9 @@
 		};
 
 		this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
-	},
+	}
 
-	onload: function () {
+	onload () {
 		this.frm.set_query("customer", function (doc, cdt, cdn) {
 			return { query: "erpnext.controllers.queries.customer_query" }
 		});
@@ -27,9 +27,9 @@
 		this.frm.set_query("contact_by", function (doc, cdt, cdn) {
 			return { query: "frappe.core.doctype.user.user.user_query" }
 		});
-	},
+	}
 
-	refresh: function () {
+	refresh () {
 		let doc = this.frm.doc;
 		erpnext.toggle_naming_series();
 		frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' }
@@ -45,47 +45,47 @@
 		} else {
 			frappe.contacts.clear_address_and_contact(this.frm);
 		}
-	},
+	}
 
-	make_customer: function () {
+	make_customer () {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.lead.lead.make_customer",
 			frm: cur_frm
 		})
-	},
+	}
 
-	make_opportunity: function () {
+	make_opportunity () {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.lead.lead.make_opportunity",
 			frm: cur_frm
 		})
-	},
+	}
 
-	make_quotation: function () {
+	make_quotation () {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.lead.lead.make_quotation",
 			frm: cur_frm
 		})
-	},
+	}
 
-	organization_lead: function () {
+	organization_lead () {
 		this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
 		this.frm.toggle_reqd("company_name", this.frm.doc.organization_lead);
-	},
+	}
 
-	company_name: function () {
+	company_name () {
 		if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) {
 			this.frm.set_value("lead_name", this.frm.doc.company_name);
 		}
-	},
+	}
 
-	contact_date: function () {
+	contact_date () {
 		if (this.frm.doc.contact_date) {
 			let d = moment(this.frm.doc.contact_date);
 			d.add(1, "day");
 			this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat));
 		}
 	}
-});
+};
 
 $.extend(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm }));
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index ac374a9..925c30b 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -145,8 +145,8 @@
 })
 
 // TODO commonify this code
-erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
-	onload: function() {
+erpnext.crm.Opportunity = class Opportunity extends frappe.ui.form.Controller {
+	onload() {
 
 		if(!this.frm.doc.status) {
 			frm.set_value('status', 'Open');
@@ -159,9 +159,9 @@
 		}
 
 		this.setup_queries();
-	},
+	}
 
-	setup_queries: function() {
+	setup_queries() {
 		var me = this;
 
 		if(this.frm.fields_dict.contact_by.df.options.match(/^User/)) {
@@ -185,15 +185,15 @@
 		else if (me.frm.doc.opportunity_from == "Customer") {
 			me.frm.set_query('party_name', erpnext.queries['customer']);
 		}
-	},
+	}
 
-	create_quotation: function() {
+	create_quotation() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.opportunity.opportunity.make_quotation",
 			frm: cur_frm
 		})
 	}
-});
+};
 
 $.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
 
diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
index b59d848..68e7780 100644
--- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
+++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js
@@ -72,8 +72,8 @@
 });
 
 
-education.StudentsEditor = Class.extend({
-	init: function(frm, wrapper, students) {
+education.StudentsEditor = class StudentsEditor {
+	constructor(frm, wrapper, students) {
 		this.wrapper = wrapper;
 		this.frm = frm;
 		if(students.length > 0) {
@@ -81,8 +81,8 @@
 		} else {
 			this.show_empty_state();
 		}
-	},
-	make: function(frm, students) {
+	}
+	make(frm, students) {
 		var me = this;
 
 		$(this.wrapper).empty();
@@ -173,13 +173,13 @@
 		});
 
 		$(htmls.join("")).appendTo(me.wrapper);
-	},
+	}
 
-	show_empty_state: function() {
+	show_empty_state() {
 		$(this.wrapper).html(
 			`<div class="text-center text-muted" style="line-height: 100px;">
 				${__("No Students in")} ${this.frm.doc.student_group}
 			</div>`
 		);
 	}
-});
+};
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index f0a05ed..5d5b2e1 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -335,13 +335,13 @@
 
 	if not last_order_id:
 		if shopify_settings.sync_based_on == 'Date':
-			url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
+			url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&created_at_min={0}&since_id=0".format(
 				get_datetime(shopify_settings.from_date)), shopify_settings)
 		else:
-			url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
+			url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(
 				shopify_settings.from_order_id), shopify_settings)
 	else:
-		url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
+		url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
 
 	return url
 
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
index 6dedaa8..a505ee0 100644
--- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
+++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
@@ -1,6 +1,7 @@
 
 from __future__ import unicode_literals
 import frappe, base64, hashlib, hmac, json
+from frappe.utils import cstr
 from frappe import _
 
 def verify_request():
@@ -146,22 +147,19 @@
 
 def link_items(items_list, woocommerce_settings, sys_lang):
 	for item_data in items_list:
-		item_woo_com_id = item_data.get("product_id")
+		item_woo_com_id = cstr(item_data.get("product_id"))
 
-		if frappe.get_value("Item", {"woocommerce_id": item_woo_com_id}):
-			#Edit Item
-			item = frappe.get_doc("Item", {"woocommerce_id": item_woo_com_id})
-		else:
+		if not frappe.db.get_value("Item", {"woocommerce_id": item_woo_com_id}, 'name'):
 			#Create Item
 			item = frappe.new_doc("Item")
+			item.item_code = _("woocommerce - {0}", sys_lang).format(item_woo_com_id)
+			item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang)
+			item.item_group = _("WooCommerce Products", sys_lang)
 
-		item.item_name = item_data.get("name")
-		item.item_code = _("woocommerce - {0}", sys_lang).format(item_data.get("product_id"))
-		item.woocommerce_id = item_data.get("product_id")
-		item.item_group = _("WooCommerce Products", sys_lang)
-		item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang)
-		item.flags.ignore_mandatory = True
-		item.save()
+			item.item_name = item_data.get("name")
+			item.woocommerce_id = item_woo_com_id
+			item.flags.ignore_mandatory = True
+			item.save()
 
 def create_sales_order(order, woocommerce_settings, customer_name, sys_lang):
 	new_sales_order = frappe.new_doc("Sales Order")
@@ -194,12 +192,12 @@
 
 	for item in order.get("line_items"):
 		woocomm_item_id = item.get("product_id")
-		found_item = frappe.get_doc("Item", {"woocommerce_id": woocomm_item_id})
+		found_item = frappe.get_doc("Item", {"woocommerce_id": cstr(woocomm_item_id)})
 
 		ordered_items_tax = item.get("total_tax")
 
-		new_sales_order.append("items",{
-			"item_code": found_item.item_code,
+		new_sales_order.append("items", {
+			"item_code": found_item.name,
 			"item_name": found_item.item_name,
 			"description": found_item.item_name,
 			"delivery_date": new_sales_order.delivery_date,
@@ -207,7 +205,7 @@
 			"qty": item.get("quantity"),
 			"rate": item.get("price"),
 			"warehouse": woocommerce_settings.warehouse or default_warehouse
-			})
+		})
 
 		add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account)
 
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index cbdf906..381c5e5 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -30,14 +30,14 @@
 		webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
 		# url = get_shopify_url('admin/webhooks.json', self)
 		created_webhooks = [d.method for d in self.webhooks]
-		url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
+		url = get_shopify_url('admin/api/2021-04/webhooks.json', self)
 		for method in webhooks:
 			session = get_request_session()
 			try:
 				res = session.post(url, data=json.dumps({
 					"webhook": {
 						"topic": method,
-						"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'),
+						"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data', force_https=True),
 						"format": "json"
 						}
 					}), headers=get_header(self))
@@ -56,7 +56,7 @@
 		deleted_webhooks = []
 
 		for d in self.webhooks:
-			url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
+			url = get_shopify_url('admin/api/2021-04/webhooks/{0}.json'.format(d.webhook_id), self)
 			try:
 				res = session.delete(url, headers=get_header(self))
 				res.raise_for_status()
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
index 7866fde..2af57f4 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
@@ -32,10 +32,12 @@
 		raise e
 
 def create_customer_address(customer, shopify_customer):
-	if not shopify_customer.get("addresses"):
-		return
+	addresses = shopify_customer.get("addresses", [])
 
-	for i, address in enumerate(shopify_customer.get("addresses")):
+	if not addresses and "default_address" in shopify_customer:
+		addresses.append(shopify_customer["default_address"])
+
+	for i, address in enumerate(addresses):
 		address_title, address_type = get_address_title_and_type(customer.customer_name, i)
 		try :
 			frappe.get_doc({
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
index f9f0bb3..16efb6c 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
@@ -8,7 +8,7 @@
 shopify_variants_attr_list = ["option1", "option2", "option3"]
 
 def sync_item_from_shopify(shopify_settings, item):
-	url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
+	url = get_shopify_url("admin/api/2021-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
 	session = get_request_session()
 
 	try:
diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py
index 362f6cf..3840e78 100644
--- a/erpnext/erpnext_integrations/utils.py
+++ b/erpnext/erpnext_integrations/utils.py
@@ -28,7 +28,7 @@
 
 	return innerfn
 
-def get_webhook_address(connector_name, method, exclude_uri=False):
+def get_webhook_address(connector_name, method, exclude_uri=False, force_https=False):
 	endpoint = "erpnext.erpnext_integrations.connectors.{0}.{1}".format(connector_name, method)
 
 	if exclude_uri:
@@ -39,7 +39,11 @@
 	except RuntimeError:
 		url = "http://localhost:8000"
 
-	server_url = '{uri.scheme}://{uri.netloc}/api/method/{endpoint}'.format(uri=urlparse(url), endpoint=endpoint)
+	url_data = urlparse(url)
+	scheme = "https" if force_https else url_data.scheme
+	netloc = url_data.netloc
+
+	server_url = f"{scheme}://{netloc}/api/method/{endpoint}"
 
 	return server_url
 
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.js b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
index b49b00e..0614604 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.js
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
@@ -9,14 +9,14 @@
 	}
 });
 
-erpnext.ExerciseEditor = Class.extend({
-	init: function(frm, wrapper) {
+erpnext.ExerciseEditor = class ExerciseEditor {
+	constructor(frm, wrapper) {
 		this.wrapper = wrapper;
 		this.frm = frm;
 		this.make(frm, wrapper);
-	},
+	}
 
-	make: function(frm, wrapper) {
+	make(frm, wrapper) {
 		$(this.wrapper).empty();
 
 		this.exercise_toolbar = $('<p>\
@@ -38,9 +38,9 @@
 			this.make_cards(frm);
 			this.make_buttons(frm);
 		}
-	},
+	}
 
-	make_cards: function(frm) {
+	make_cards(frm) {
 		var me = this;
 		$(me.exercise_cards).empty();
 
@@ -60,9 +60,9 @@
 					</div>
 			</div>`, {image_src: step.image, title: step.title, description: step.description, col_id: "col-"+i, card_id: "card-"+i, id: i})).appendTo(me.row);
 		});
-	},
+	}
 
-	make_buttons: function(frm) {
+	make_buttons(frm) {
 		let me = this;
 		$('.btn-edit').on('click', function() {
 			let id = $(this).attr('data-id');
@@ -82,9 +82,9 @@
 				frm.dirty();
 			}, 300);
 		});
-	},
+	}
 
-	show_add_card_dialog: function(frm) {
+	show_add_card_dialog(frm) {
 		let me = this;
 		let d = new frappe.ui.Dialog({
 			title: __('Add Exercise Step'),
@@ -137,9 +137,9 @@
 			primary_action_label: __('Add')
 		});
 		d.show();
-	},
+	}
 
-	show_edit_card_dialog: function(frm, id) {
+	show_edit_card_dialog(frm, id) {
 		let new_dialog = new frappe.ui.Dialog({
 			title: __("Edit Exercise Step"),
 			fields: [
@@ -183,4 +183,4 @@
 		});
 		new_dialog.show();
 	}
-});
+};
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index bb6cd8b..3024819 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -15,10 +15,11 @@
 
 develop_version = '13.x.x-develop'
 
-app_include_js = "/assets/js/erpnext.min.js"
-app_include_css = "/assets/css/erpnext.css"
-web_include_js = "/assets/js/erpnext-web.min.js"
-web_include_css = "/assets/css/erpnext-web.css"
+app_include_js = "erpnext.bundle.js"
+app_include_css = "erpnext.bundle.css"
+web_include_js = "erpnext-web.bundle.js"
+web_include_css = "erpnext-web.bundle.css"
+email_css = "email.bundle.css"
 
 doctype_js = {
 	"Address": "public/js/address.js",
@@ -426,7 +427,8 @@
 		'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
 		'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
 		'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
-		'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields'
+		'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
+		'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
 	},
 	'United Arab Emirates': {
 		'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
diff --git a/erpnext/hr/doctype/designation/designation.json b/erpnext/hr/doctype/designation/designation.json
index 4c3888b..bab6b90 100644
--- a/erpnext/hr/doctype/designation/designation.json
+++ b/erpnext/hr/doctype/designation/designation.json
@@ -182,6 +182,10 @@
    "share": 1,
    "submit": 0,
    "write": 1
+  },
+  {
+   "read": 1,
+   "role": "Sales User"
   }
  ],
  "quick_entry": 1,
@@ -191,4 +195,4 @@
  "track_changes": 0,
  "track_seen": 0,
  "track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index c21d4b8..5639cc9 100755
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -2,8 +2,8 @@
 // License: GNU General Public License v3. See license.txt
 
 frappe.provide("erpnext.hr");
-erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
-	setup: function() {
+erpnext.hr.EmployeeController = class EmployeeController extends frappe.ui.form.Controller {
+	setup() {
 		this.frm.fields_dict.user_id.get_query = function(doc, cdt, cdn) {
 			return {
 				query: "frappe.core.doctype.user.user.user_query",
@@ -12,30 +12,30 @@
 		}
 		this.frm.fields_dict.reports_to.get_query = function(doc, cdt, cdn) {
 			return { query: "erpnext.controllers.queries.employee_query"} }
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		var me = this;
 		erpnext.toggle_naming_series();
-	},
+	}
 
-	date_of_birth: function() {
+	date_of_birth() {
 		return cur_frm.call({
 			method: "get_retirement_date",
 			args: {date_of_birth: this.frm.doc.date_of_birth}
 		});
-	},
+	}
 
-	salutation: function() {
+	salutation() {
 		if(this.frm.doc.salutation) {
 			this.frm.set_value("gender", {
 				"Mr": "Male",
 				"Ms": "Female"
 			}[this.frm.doc.salutation]);
 		}
-	},
+	}
 
-});
+};
 frappe.ui.form.on('Employee',{
 	setup: function(frm) {
 		frm.set_query("leave_policy", function() {
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
index 3205a92..ab965d5 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
@@ -68,13 +68,13 @@
 	}
 }
 
-erpnext.MarkedEmployee = Class.extend({
-	init: function(frm, wrapper, employee) {
+erpnext.MarkedEmployee = class MarkedEmployee {
+	constructor(frm, wrapper, employee) {
 		this.wrapper = wrapper;
 		this.frm = frm;
 		this.make(frm, employee);
-	},
-	make: function(frm, employee) {
+	}
+	make(frm, employee) {
 		var me = this;
 		$(this.wrapper).empty();
 
@@ -104,16 +104,16 @@
 				})).appendTo(row);
 		});
 	}
-});
+};
 
 
-erpnext.EmployeeSelector = Class.extend({
-	init: function(frm, wrapper, employee) {
+erpnext.EmployeeSelector = class EmployeeSelector {
+	constructor(frm, wrapper, employee) {
 		this.wrapper = wrapper;
 		this.frm = frm;
 		this.make(frm, employee);
-	},
-	make: function(frm, employee) {
+	}
+	make(frm, employee) {
 		var me = this;
 
 		$(this.wrapper).empty();
@@ -266,6 +266,6 @@
 
 		mark_employee_toolbar.appendTo($(this.wrapper));
 	}
-});
+};
 
 
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index e3e6e80..a268c15 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -14,6 +14,7 @@
   "column_break_5",
   "expense_approver",
   "approval_status",
+  "delivery_trip",
   "is_paid",
   "expense_details",
   "expenses",
@@ -365,13 +366,20 @@
    "label": "Total Taxes and Charges",
    "options": "Company:company:default_currency",
    "read_only": 1
+  },
+  {
+   "depends_on": "eval: doc.delivery_trip",
+   "fieldname": "delivery_trip",
+   "fieldtype": "Link",
+   "label": "Delivery Trip",
+   "options": "Delivery Trip"
   }
  ],
  "icon": "fa fa-money",
  "idx": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-09-18 17:26:09.703215",
+ "modified": "2021-05-04 05:35:12.040199",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Expense Claim",
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.js b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
index 29aa854..bbafc82 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.js
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
@@ -5,19 +5,19 @@
 
 frappe.provide("erpnext.hr");
 
-erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
-	onload: function() {
+erpnext.hr.AttendanceControlPanel = class AttendanceControlPanel extends frappe.ui.form.Controller {
+	onload() {
 		this.frm.set_value("att_fr_date", frappe.datetime.get_today());
 		this.frm.set_value("att_to_date", frappe.datetime.get_today());
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		this.frm.disable_save();
 		this.show_upload();
 		this.setup_import_progress();
-	},
+	}
 
-	get_template:function() {
+	get_template() {
 		if(!this.frm.doc.att_fr_date || !this.frm.doc.att_to_date) {
 			frappe.msgprint(__("Attendance From Date and Attendance To Date is mandatory"));
 			return;
@@ -28,7 +28,7 @@
 			from_date: this.frm.doc.att_fr_date,
 			to_date: this.frm.doc.att_to_date,
 		});
-	},
+	}
 
 	show_upload() {
 		var $wrapper = $(cur_frm.fields_dict.upload_html.wrapper).empty();
@@ -36,7 +36,7 @@
 			wrapper: $wrapper,
 			method: 'erpnext.hr.doctype.upload_attendance.upload_attendance.upload'
 		});
-	},
+	}
 
 	setup_import_progress() {
 		var $log_wrapper = $(this.frm.fields_dict.import_log.wrapper).empty();
@@ -64,6 +64,6 @@
 			}
 		});
 	}
-})
+}
 
 cur_frm.cscript = new erpnext.hr.AttendanceControlPanel({frm: cur_frm});
diff --git a/erpnext/hr/notification/training_feedback/training_feedback.json b/erpnext/hr/notification/training_feedback/training_feedback.json
index 2cc064f..92b68a9 100644
--- a/erpnext/hr/notification/training_feedback/training_feedback.json
+++ b/erpnext/hr/notification/training_feedback/training_feedback.json
@@ -1,5 +1,6 @@
 {
  "attach_print": 0,
+ "channel": "Email",
  "creation": "2017-08-11 03:17:11.769210",
  "days_in_advance": 0,
  "docstatus": 0,
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index ddbcdfd..2adfaf4 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -45,8 +45,8 @@
 })
 
 // TODO commonify this code
-erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
-	refresh: function() {
+erpnext.maintenance.MaintenanceSchedule = class MaintenanceSchedule extends frappe.ui.form.Controller {
+	refresh() {
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
 
 		var me = this;
@@ -76,21 +76,21 @@
 				});
 			}, __('Create'));
 		}
-	},
+	}
 
-	start_date: function(doc, cdt, cdn) {
+	start_date(doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
-	},
+	}
 
-	end_date: function(doc, cdt, cdn) {
+	end_date(doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
-	},
+	}
 
-	periodicity: function(doc, cdt, cdn) {
+	periodicity(doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
-	},
+	}
 
-	set_no_of_visits: function(doc, cdt, cdn) {
+	set_no_of_visits(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 
 		if (item.start_date && item.end_date && item.periodicity) {
@@ -112,8 +112,8 @@
 			var no_of_visits = cint(date_diff / days_in_period[item.periodicity]);
 			frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits);
 		}
-	},
-});
+	}
+};
 
 $.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
 
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 4cbb02a..12dc59c 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -41,8 +41,8 @@
 })
 
 // TODO commonify this code
-erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
-	refresh: function() {
+erpnext.maintenance.MaintenanceVisit = class MaintenanceVisit extends frappe.ui.form.Controller {
+	refresh() {
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
 
 		var me = this;
@@ -96,7 +96,7 @@
 					})
 				}, __("Get Items From"));
 		}
-	},
-});
+	}
+};
 
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
\ No newline at end of file
+$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index fbfd801..b32b96a 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -29,7 +29,10 @@
 
 		frm.set_query("item", function() {
 			return {
-				query: "erpnext.manufacturing.doctype.bom.bom.item_query"
+				query: "erpnext.manufacturing.doctype.bom.bom.item_query",
+				filters: {
+					"is_stock_item": 1
+				}
 			};
 		});
 
@@ -357,16 +360,16 @@
 	}
 });
 
-erpnext.bom.BomController = erpnext.TransactionController.extend({
-	conversion_rate: function(doc) {
+erpnext.bom.BomController = class BomController extends erpnext.TransactionController {
+	conversion_rate(doc) {
 		if(this.frm.doc.currency === this.get_company_currency()) {
 			this.frm.set_value("conversion_rate", 1.0);
 		} else {
 			erpnext.bom.update_cost(doc);
 		}
-	},
+	}
 
-	item_code: function(doc, cdt, cdn){
+	item_code(doc, cdt, cdn){
 		var scrap_items = false;
 		var child = locals[cdt][cdn];
 		if (child.doctype == 'BOM Scrap Item') {
@@ -378,19 +381,19 @@
 		}
 
 		get_bom_material_detail(doc, cdt, cdn, scrap_items);
-	},
+	}
 
-	buying_price_list: function(doc) {
+	buying_price_list(doc) {
 		this.apply_price_list();
-	},
+	}
 
-	plc_conversion_rate: function(doc) {
+	plc_conversion_rate(doc) {
 		if (!this.in_apply_price_list) {
 			this.apply_price_list(null, true);
 		}
-	},
+	}
 
-	conversion_factor: function(doc, cdt, cdn) {
+	conversion_factor(doc, cdt, cdn) {
 		if (frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
 			var item = frappe.get_doc(cdt, cdn);
 			frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
@@ -399,8 +402,8 @@
 			this.toggle_conversion_factor(item);
 			this.frm.events.update_cost(this.frm);
 		}
-	},
-});
+	}
+};
 
 $.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
 
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 979f7ca..d1f6385 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -973,6 +973,9 @@
 		if not has_variants:
 			query_filters["has_variants"] = 0
 
+	if filters and filters.get("is_stock_item"):
+		query_filters["is_stock_item"] = 1
+		
 	return frappe.get_all("Item",
 		fields = fields, filters=query_filters,
 		or_filters = or_cond_filters, order_by=order_by,
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 9ef949c..82d223c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -774,4 +774,7 @@
 erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
 erpnext.patches.v13_0.update_shipment_status
 erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
+erpnext.patches.v12_0.add_ewaybill_validity_field
+erpnext.patches.v13_0.germany_make_custom_fields
+erpnext.patches.v13_0.germany_fill_debtor_creditor_number
 erpnext.patches.v13_0.set_pos_closing_as_failed
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
new file mode 100644
index 0000000..87d98f1
--- /dev/null
+++ b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
@@ -0,0 +1,16 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	custom_fields = {
+		'Sales Invoice': [
+			dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
+				depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
+		]
+	}
+	create_custom_fields(custom_fields, update=True)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 06331d7..a6471eb 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -44,9 +44,11 @@
 		# make current item's tax map
 		item_tax_map = {}
 		for d in old_item_taxes[item_code]:
-			item_tax_map[d.tax_type] = d.tax_rate
+			if d.tax_type not in item_tax_map:
+				item_tax_map[d.tax_type] = d.tax_rate
 
-		item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code)
+		tax_types = []
+		item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code, tax_types=tax_types)
 
 		# update the item tax table
 		frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
@@ -68,7 +70,7 @@
 								and item_tax_template is NULL""".format(dt), as_dict=1):
 			item_tax_map = json.loads(d.item_tax_rate)
 			item_tax_template_name = get_item_tax_template(item_tax_templates,
-				item_tax_map, d.item_code, d.parenttype, d.parent)
+				item_tax_map, d.item_code, d.parenttype, d.parent, tax_types=tax_types)
 			frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template_name)
 
 	frappe.db.auto_commit_on_many_writes = False
@@ -78,7 +80,7 @@
 	settings.determine_address_tax_category_from = "Billing Address"
 	settings.save()
 
-def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None):
+def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None, tax_types=None):
 	# search for previously created item tax template by comparing tax maps
 	for template, item_tax_template_map in iteritems(item_tax_templates):
 		if item_tax_map == item_tax_template_map:
@@ -126,7 +128,9 @@
 		account_type = frappe.get_cached_value("Account", tax_type, "account_type")
 
 		if tax_type and account_type in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'):
-			item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
+			if tax_type not in tax_types:
+				item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
+				tax_types.append(tax_type)
 			item_tax_templates.setdefault(item_tax_template.title, {})
 			item_tax_templates[item_tax_template.title][tax_type] = tax_rate
 	if item_tax_template.get("taxes"):
diff --git a/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
new file mode 100644
index 0000000..11e1e9b
--- /dev/null
+++ b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+
+
+def execute():
+	"""Move account number into the new custom field debtor_creditor_number.
+
+	German companies used to use a dedicated payable/receivable account for
+	every party to mimick party accounts in the external accounting software
+	"DATEV". This is no longer necessary. The reference ID for DATEV will be
+	stored in a new custom field "debtor_creditor_number". 
+	"""
+	company_list = frappe.get_all('Company', filters={'country': 'Germany'})
+
+	for company in company_list:
+		party_account_list = frappe.get_all('Party Account', filters={'company': company.name}, fields=['name', 'account', 'debtor_creditor_number'])
+		for party_account in party_account_list:
+			if (not party_account.account) or party_account.debtor_creditor_number:
+				# account empty or debtor_creditor_number already filled
+				continue
+
+			account_number = frappe.db.get_value('Account', party_account.account, 'account_number')
+			if not account_number:
+				continue
+
+			frappe.db.set_value('Party Account', party_account.name, 'debtor_creditor_number', account_number)
+			frappe.db.set_value('Party Account', party_account.name, 'account', '')
diff --git a/erpnext/patches/v13_0/germany_make_custom_fields.py b/erpnext/patches/v13_0/germany_make_custom_fields.py
new file mode 100644
index 0000000..41ab945
--- /dev/null
+++ b/erpnext/patches/v13_0/germany_make_custom_fields.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from erpnext.regional.germany.setup import make_custom_fields
+
+
+def execute():
+	"""Execute the make_custom_fields method for german companies.
+
+	It is usually run once at setup of a new company. Since it's new, run it
+	once for existing companies as well.
+	"""
+	company_list = frappe.get_all('Company', filters = {'country': 'Germany'})
+	if not company_list:
+		return
+
+	make_custom_fields()
diff --git a/erpnext/payroll/notification/retention_bonus/retention_bonus.json b/erpnext/payroll/notification/retention_bonus/retention_bonus.json
index 50db033..37381fa 100644
--- a/erpnext/payroll/notification/retention_bonus/retention_bonus.json
+++ b/erpnext/payroll/notification/retention_bonus/retention_bonus.json
@@ -1,5 +1,6 @@
 {
  "attach_print": 0,
+ "channel": "Email",
  "condition": "doc.docstatus==1",
  "creation": "2018-05-15 18:52:36.362838",
  "date_changed": "bonus_payment_date",
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 3cdfcb2..2570df7 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -458,7 +458,7 @@
  "index_web_pages_for_search": 1,
  "links": [],
  "max_attachments": 4,
- "modified": "2020-09-02 11:54:01.223620",
+ "modified": "2021-04-28 16:36:11.654632",
  "modified_by": "Administrator",
  "module": "Projects",
  "name": "Project",
@@ -495,11 +495,11 @@
   }
  ],
  "quick_entry": 1,
- "search_fields": "customer, status, priority, is_active",
+ "search_fields": "project_name,customer, status, priority, is_active",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
  "timeline_field": "customer",
  "title_field": "project_name",
  "track_seen": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index ed02f79..8d99b48 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -209,7 +209,7 @@
 	if parent:
 		condition = "AND parent = %(parent)s"
 	if from_time and to_time:
-		condition += "AND from_time BETWEEN %(from_time)s AND %(to_time)s"
+		condition += "AND CAST(from_time as DATE) BETWEEN %(from_time)s AND %(to_time)s"
 
 	return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
 			from `tabTimesheet Detail` where parenttype = 'Timesheet' and docstatus=1 and project = %(project)s {0} and billable = 1
diff --git a/erpnext/projects/report/project_profitability/project_profitability.py b/erpnext/projects/report/project_profitability/project_profitability.py
index 5ad2d85..9139d84 100644
--- a/erpnext/projects/report/project_profitability/project_profitability.py
+++ b/erpnext/projects/report/project_profitability/project_profitability.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
+from frappe.utils import flt
 
 def execute(filters=None):
 	columns, data = [], []
@@ -52,8 +53,8 @@
 
 def calculate_cost_and_profit(data):
 	for row in data:
-		row.fractional_cost = row.base_gross_pay * row.utilization
-		row.profit = row.base_grand_total - row.base_gross_pay * row.utilization
+		row.fractional_cost = flt(row.base_gross_pay) * flt(row.utilization)
+		row.profit = flt(row.base_grand_total) - flt(row.base_gross_pay) * flt(row.utilization)
 	return data
 
 def get_conditions(filters):
diff --git a/erpnext/public/css/email.css b/erpnext/public/css/email.css
deleted file mode 100644
index 8cf1a31..0000000
--- a/erpnext/public/css/email.css
+++ /dev/null
@@ -1,29 +0,0 @@
-.panel-header {
-  background-color: #fafbfc;
-  border: 1px solid #d1d8dd;
-  border-radius: 3px 3px 0 0;
-}
-.panel-body {
-  background-color: #fff;
-  border: 1px solid #d1d8dd;
-  border-top: none;
-  border-radius: 0 0 3px 3px;
-  overflow-wrap: break-word;
-}
-.sender-avatar {
-  width: 24px;
-  height: 24px;
-  border-radius: 3px;
-  vertical-align: middle;
-}
-.sender-avatar-placeholder {
-  width: 24px;
-  height: 24px;
-  border-radius: 3px;
-  vertical-align: middle;
-  line-height: 24px;
-  text-align: center;
-  color: #d1d8dd;
-  border: 1px solid #d1d8dd;
-  background-color: #fff;
-}
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
deleted file mode 100644
index 6e4efcb..0000000
--- a/erpnext/public/css/erpnext.css
+++ /dev/null
@@ -1,408 +0,0 @@
-.erpnext-footer {
-  margin: 11px auto;
-  text-align: center;
-}
-.show-all-reports {
-  margin-top: 5px;
-  font-size: 11px;
-}
-/* toolbar */
-.toolbar-splash {
-  width: 32px;
-  height: 32px;
-  margin: -10px auto;
-}
-.erpnext-icon {
-  width: 24px;
-  margin-right: 0px;
-  margin-top: -3px;
-}
-.dashboard-list-item {
-  background-color: inherit;
-  padding: 5px 0px;
-  border-bottom: 1px solid #d1d8dd;
-}
-#page-stock-balance .dashboard-list-item {
-  padding: 5px 15px;
-}
-.dashboard-list-item:last-child {
-  border-bottom: none;
-}
-.frappe-control[data-fieldname='result_html'] {
-  overflow: scroll;
-}
-.assessment-result-tool {
-  table-layout: fixed;
-}
-.assessment-result-tool input {
-  width: 100%;
-  border: 0;
-  outline: none;
-  text-align: right;
-}
-.assessment-result-tool th {
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-.assessment-result-tool .total-score,
-.assessment-result-tool .grade,
-.assessment-result-tool .score {
-  text-align: right;
-}
-/* pos */
-body[data-route="pos"] .pos-bill-toolbar {
-  padding: 10px 0px;
-  height: 51px;
-}
-body[data-route="pos"] .pos-bill-item:hover,
-body[data-route="pos"] .list-customers-table > .pos-list-row:hover {
-  background-color: #f5f7fa;
-  cursor: pointer;
-}
-body[data-route="pos"] .pos-item-qty {
-  display: inline-block;
-}
-body[data-route="pos"] .pos-qty-row > div {
-  padding: 5px 0px;
-}
-body[data-route="pos"] .pos-qty-btn {
-  margin-top: 3px;
-  cursor: pointer;
-  font-size: 120%;
-}
-body[data-route="pos"] .search-area .form-group {
-  max-width: 100% !important;
-}
-body[data-route="pos"] .tax-table {
-  margin-bottom: 10px;
-}
-body[data-route="pos"] .discount-field-col {
-  padding-left: 24px;
-}
-body[data-route="pos"] .discount-amount-area .input-group:first-child {
-  margin-bottom: 2px;
-}
-body[data-route="pos"] .payment-toolbar .row {
-  width: 323px;
-  margin: 0 auto;
-}
-body[data-route="pos"] .payment-mode {
-  cursor: pointer;
-  font-family: sans-serif;
-  font-size: 15px;
-}
-body[data-route="pos"] .pos-payment-row .col-xs-6 {
-  padding: 15px;
-}
-body[data-route="pos"] .pos-payment-row {
-  border-bottom: 1px solid #d1d8dd;
-  margin: 2px 0px 5px 0px;
-  height: 60px;
-  margin-top: 0px;
-  margin-bottom: 0px;
-}
-body[data-route="pos"] .pos-payment-row:hover,
-body[data-route="pos"] .pos-keyboard-key:hover {
-  background-color: #fafbfc;
-  cursor: pointer;
-}
-body[data-route="pos"] .pos-keyboard-key,
-body[data-route="pos"] .delete-btn {
-  border: 1px solid #d1d8dd;
-  height: 85px;
-  width: 85px;
-  margin: 10px 10px;
-  font-size: 24px;
-  font-weight: 200;
-  background-color: #FDFDFD;
-  border-color: #e8e8e8;
-}
-body[data-route="pos"] .numeric-keypad {
-  border: 1px solid #d1d8dd;
-  height: 69px;
-  width: 69px;
-  font-size: 20px;
-  font-weight: 200;
-  background-color: #FDFDFD;
-  border-color: #e8e8e8;
-  margin-left: -4px;
-}
-body[data-route="pos"] .pos-pay {
-  height: 69px;
-  width: 69px;
-  font-size: 17px;
-  font-weight: 200;
-  margin-left: -4px;
-}
-body[data-route="pos"] .numeric-keypad {
-  height: 60px;
-  width: 60px;
-  font-size: 20px;
-  font-weight: 200;
-  border-radius: 0;
-  background-color: #fff;
-  margin-left: -4px;
-}
-@media (max-width: 1199px) {
-  body[data-route="pos"] .numeric-keypad {
-    height: 45px;
-    width: 45px;
-    font-size: 14px;
-  }
-}
-@media (max-width: 991px) {
-  body[data-route="pos"] .numeric-keypad {
-    height: 40px;
-    width: 40px;
-  }
-}
-body[data-route="pos"] .numeric_keypad {
-  margin-left: -15px;
-}
-body[data-route="pos"] .numeric_keypad > .row > button {
-  border: none;
-  border-right: 1px solid #d1d8dd;
-  border-bottom: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .numeric_keypad > .row > button:first-child {
-  border-left: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .numeric_keypad > .row:first-child > button {
-  border-top: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .pos-pay {
-  background-color: #5E64FF;
-  border: none;
-}
-body[data-route="pos"] .multimode-payments {
-  padding-left: 30px;
-}
-body[data-route="pos"] .payment-toolbar {
-  padding-right: 30px;
-}
-body[data-route="pos"] .list-row-head.pos-invoice-list {
-  border-top: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .modal-dialog {
-  width: 750px;
-}
-@media (max-width: 767px) {
-  body[data-route="pos"] .modal-dialog {
-    width: auto;
-  }
-  body[data-route="pos"] .modal-dialog .modal-content {
-    height: auto;
-  }
-}
-@media (max-width: 767px) {
-  body[data-route="pos"] .amount-row h3 {
-    font-size: 15px;
-  }
-  body[data-route="pos"] .pos-keyboard-key,
-  body[data-route="pos"] .delete-btn {
-    height: 50px;
-  }
-  body[data-route="pos"] .multimode-payments {
-    padding-left: 15px;
-  }
-  body[data-route="pos"] .payment-toolbar {
-    padding-right: 15px;
-  }
-}
-body[data-route="pos"] .amount-label {
-  font-size: 16px;
-}
-body[data-route="pos"] .selected-payment-mode {
-  background-color: #fafbfc;
-  cursor: pointer;
-}
-body[data-route="pos"] .pos-invoice-list {
-  padding: 15px 10px;
-}
-body[data-route="pos"] .write_off_amount,
-body[data-route="pos"] .change_amount {
-  margin: 15px;
-  width: 130px;
-}
-body[data-route="pos"] .pos-list-row {
-  display: table;
-  table-layout: fixed;
-  width: 100%;
-  padding: 9px 15px;
-  font-size: 12px;
-  margin: 0px;
-  border-bottom: 1px solid #d1d8dd;
-}
-body[data-route="pos"] .pos-list-row .cell {
-  display: table-cell;
-  vertical-align: middle;
-}
-body[data-route="pos"] .pos-list-row .cell.price-cell {
-  width: 50%;
-}
-body[data-route="pos"] .pos-list-row .subject {
-  width: 40%;
-}
-body[data-route="pos"] .pos-list-row .list-row-checkbox,
-body[data-route="pos"] .pos-list-row .list-select-all {
-  margin-right: 7px;
-}
-body[data-route="pos"] .pos-bill-header {
-  background-color: #f5f7fa;
-  border: 1px solid #d1d8dd;
-  padding: 13px 15px;
-}
-body[data-route="pos"] .pos-list-row.active {
-  background-color: #fffce7;
-}
-body[data-route="pos"] .totals-area {
-  border-right: 1px solid #d1d8dd;
-  border-left: 1px solid #d1d8dd;
-  margin-bottom: 15px;
-}
-body[data-route="pos"] .tax-area .pos-list-row {
-  border: none;
-}
-body[data-route="pos"] .item-cart-items {
-  height: calc(100vh - 526px);
-  overflow: auto;
-  border: 1px solid #d1d8dd;
-  border-top: none;
-}
-@media (max-width: 767px) {
-  body[data-route="pos"] .item-cart-items {
-    height: 30vh;
-  }
-}
-body[data-route="pos"] .no-items-message {
-  min-height: 200px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  height: 100%;
-}
-body[data-route="pos"] .pos-list-row:last-child {
-  border-bottom: none;
-}
-body[data-route="pos"] .form-section-heading {
-  padding: 0;
-}
-body[data-route="pos"] .item-list {
-  border: 1px solid #d1d8dd;
-  border-top: none;
-  max-height: calc(100vh - 190px);
-  overflow: auto;
-}
-@media (max-width: 767px) {
-  body[data-route="pos"] .item-list {
-    max-height: initial;
-  }
-}
-body[data-route="pos"] .item-list .image-field {
-  height: 140px;
-}
-body[data-route="pos"] .item-list .image-field .placeholder-text {
-  font-size: 50px;
-}
-body[data-route="pos"] .item-list .pos-item-wrapper {
-  position: relative;
-}
-body[data-route="pos"] .pos-bill-toolbar {
-  margin-top: 10px;
-}
-body[data-route="pos"] .search-item .form-group {
-  margin: 0;
-}
-body[data-route="pos"] .item-list-area .pos-bill-header {
-  padding: 5px;
-  padding-left: 15px;
-}
-body[data-route="pos"] .pos-selected-item-action .pos-list-row:first-child {
-  padding-top: 0;
-}
-body[data-route="pos"] .pos-selected-item-action > .pos-list-row {
-  border: none;
-}
-@media (max-width: 1199px) {
-  body[data-route="pos"] .pos-selected-item-action > .pos-list-row {
-    padding: 5px 15px;
-  }
-}
-body[data-route="pos"] .edit-customer-btn {
-  position: absolute;
-  right: 57px;
-  top: 15px;
-  z-index: 100;
-}
-body[data-route="pos"] .btn-more {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  cursor: pointer;
-  background-color: #fafbfc;
-  min-height: 200px;
-}
-body[data-route="pos"] .collapse-btn {
-  cursor: pointer;
-}
-@media (max-width: 767px) {
-  body[data-route="pos"] .page-actions {
-    max-width: 110px;
-  }
-}
-.price-info {
-  position: absolute;
-  left: 0;
-  bottom: 0;
-  margin: 0 0 15px 15px;
-  background-color: rgba(141, 153, 166, 0.6);
-  padding: 5px 9px;
-  border-radius: 3px;
-  color: #fff;
-}
-.leaderboard .result {
-  border-top: 1px solid #d1d8dd;
-}
-.leaderboard .list-item {
-  padding-left: 45px;
-}
-.leaderboard .list-item_content {
-  padding-right: 45px;
-}
-.exercise-card {
-	box-shadow: 0 1px 3px rgba(0,0,0,0.30);
-	border-radius: 2px;
-	padding: 6px 6px 6px 8px;
-	margin-top: 10px;
-	height: 100% !important;
-}
-.exercise-card .card-img-top {
-	width: 100%;
-	height: 15vw;
-	object-fit: cover;
-}
-.exercise-card .btn-edit {
-	position: absolute;
-	bottom: 10px;
-	left: 20px;
-}
-.exercise-card .btn-del {
-	position: absolute;
-	bottom: 10px;
-	left: 50px;
-}
-.exercise-card .card-body {
-		margin-bottom: 10px;
-}
-.exercise-card .card-footer {
-		padding: 10px;
-}
-.exercise-row {
-	height: 100% !important;
-	display: flex;
-	flex-wrap: wrap;
-}
-.exercise-col {
-	padding: 10px;
-}
diff --git a/erpnext/public/css/leaflet/leaflet.css b/erpnext/public/css/leaflet/leaflet.css
deleted file mode 100755
index 979a8bd..0000000
--- a/erpnext/public/css/leaflet/leaflet.css
+++ /dev/null
@@ -1,611 +0,0 @@
-/* required styles */

-

-.leaflet-pane,

-.leaflet-tile,

-.leaflet-marker-icon,

-.leaflet-marker-shadow,

-.leaflet-tile-container,

-.leaflet-map-pane svg,

-.leaflet-map-pane canvas,

-.leaflet-zoom-box,

-.leaflet-image-layer,

-.leaflet-layer {

-    position: absolute;

-    left: 0;

-    top: 0;

-}

-

-.leaflet-container {

-    overflow: hidden;

-    -ms-touch-action: none;

-    touch-action: none;

-}

-

-.leaflet-tile,

-.leaflet-marker-icon,

-.leaflet-marker-shadow {

-    -webkit-user-select: none;

-    -moz-user-select: none;

-    user-select: none;

-    -webkit-user-drag: none;

-}

-

-

-/* Safari renders non-retina tile on retina better with this, but Chrome is worse */

-

-.leaflet-safari .leaflet-tile {

-    image-rendering: -webkit-optimize-contrast;

-}

-

-

-/* hack that prevents hw layers "stretching" when loading new tiles */

-

-.leaflet-safari .leaflet-tile-container {

-    width: 1600px;

-    height: 1600px;

-    -webkit-transform-origin: 0 0;

-}

-

-.leaflet-marker-icon,

-.leaflet-marker-shadow {

-    display: block;

-}

-

-

-/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */

-

-

-/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */

-

-.leaflet-container .leaflet-overlay-pane svg,

-.leaflet-container .leaflet-marker-pane img,

-.leaflet-container .leaflet-tile-pane img,

-.leaflet-container img.leaflet-image-layer {

-    max-width: none !important;

-}

-

-.leaflet-tile {

-    filter: inherit;

-    visibility: hidden;

-}

-

-.leaflet-tile-loaded {

-    visibility: inherit;

-}

-

-.leaflet-zoom-box {

-    width: 0;

-    height: 0;

-    -moz-box-sizing: border-box;

-    box-sizing: border-box;

-    z-index: 800;

-}

-

-

-/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */

-

-.leaflet-overlay-pane svg {

-    -moz-user-select: none;

-}

-

-.leaflet-pane {

-    z-index: 400;

-}

-

-.leaflet-tile-pane {

-    z-index: 200;

-}

-

-.leaflet-overlay-pane {

-    z-index: 400;

-}

-

-.leaflet-shadow-pane {

-    z-index: 500;

-}

-

-.leaflet-marker-pane {

-    z-index: 600;

-}

-

-.leaflet-popup-pane {

-    z-index: 700;

-}

-

-.leaflet-map-pane canvas {

-    z-index: 100;

-}

-

-.leaflet-map-pane svg {

-    z-index: 200;

-}

-

-.leaflet-vml-shape {

-    width: 1px;

-    height: 1px;

-}

-

-.lvml {

-    behavior: url(#default#VML);

-    display: inline-block;

-    position: absolute;

-}

-

-

-/* control positioning */

-

-.leaflet-control {

-    position: relative;

-    z-index: 800;

-    pointer-events: auto;

-}

-

-.leaflet-top,

-.leaflet-bottom {

-    position: absolute;

-    z-index: 1000;

-    pointer-events: none;

-}

-

-.leaflet-top {

-    top: 0;

-}

-

-.leaflet-right {

-    right: 0;

-}

-

-.leaflet-bottom {

-    bottom: 0;

-}

-

-.leaflet-left {

-    left: 0;

-}

-

-.leaflet-control {

-    float: left;

-    clear: both;

-}

-

-.leaflet-right .leaflet-control {

-    float: right;

-}

-

-.leaflet-top .leaflet-control {

-    margin-top: 10px;

-}

-

-.leaflet-bottom .leaflet-control {

-    margin-bottom: 10px;

-}

-

-.leaflet-left .leaflet-control {

-    margin-left: 10px;

-}

-

-.leaflet-right .leaflet-control {

-    margin-right: 10px;

-}

-

-

-/* zoom and fade animations */

-

-.leaflet-fade-anim .leaflet-tile {

-    will-change: opacity;

-}

-

-.leaflet-fade-anim .leaflet-popup {

-    opacity: 0;

-    -webkit-transition: opacity 0.2s linear;

-    -moz-transition: opacity 0.2s linear;

-    -o-transition: opacity 0.2s linear;

-    transition: opacity 0.2s linear;

-}

-

-.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {

-    opacity: 1;

-}

-

-.leaflet-zoom-animated {

-    -webkit-transform-origin: 0 0;

-    -ms-transform-origin: 0 0;

-    transform-origin: 0 0;

-}

-

-.leaflet-zoom-anim .leaflet-zoom-animated {

-    will-change: transform;

-}

-

-.leaflet-zoom-anim .leaflet-zoom-animated {

-    -webkit-transition: -webkit-transform 0.25s cubic-bezier(0, 0, 0.25, 1);

-    -moz-transition: -moz-transform 0.25s cubic-bezier(0, 0, 0.25, 1);

-    -o-transition: -o-transform 0.25s cubic-bezier(0, 0, 0.25, 1);

-    transition: transform 0.25s cubic-bezier(0, 0, 0.25, 1);

-}

-

-.leaflet-zoom-anim .leaflet-tile,

-.leaflet-pan-anim .leaflet-tile {

-    -webkit-transition: none;

-    -moz-transition: none;

-    -o-transition: none;

-    transition: none;

-}

-

-.leaflet-zoom-anim .leaflet-zoom-hide {

-    visibility: hidden;

-}

-

-

-/* cursors */

-

-.leaflet-interactive {

-    cursor: pointer;

-}

-

-.leaflet-grab {

-    cursor: -webkit-grab;

-    cursor: -moz-grab;

-}

-

-.leaflet-crosshair,

-.leaflet-crosshair .leaflet-interactive {

-    cursor: crosshair;

-}

-

-.leaflet-popup-pane,

-.leaflet-control {

-    cursor: auto;

-}

-

-.leaflet-dragging .leaflet-grab,

-.leaflet-dragging .leaflet-grab .leaflet-interactive,

-.leaflet-dragging .leaflet-marker-draggable {

-    cursor: move;

-    cursor: -webkit-grabbing;

-    cursor: -moz-grabbing;

-}

-

-

-/* visual tweaks */

-

-.leaflet-container {

-    background: #ddd;

-    outline: 0;

-}

-

-.leaflet-container a {

-    color: #0078A8;

-}

-

-.leaflet-container a.leaflet-active {

-    outline: 2px solid orange;

-}

-

-.leaflet-zoom-box {

-    border: 2px dotted #38f;

-    background: rgba(255, 255, 255, 0.5);

-}

-

-

-/* general typography */

-

-.leaflet-container {

-    font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;

-}

-

-

-/* general toolbar styles */

-

-.leaflet-bar {

-    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);

-    border-radius: 4px;

-}

-

-.leaflet-bar a,

-.leaflet-bar a:hover {

-    background-color: #fff;

-    border-bottom: 1px solid #ccc;

-    width: 26px;

-    height: 26px;

-    line-height: 26px;

-    display: block;

-    text-align: center;

-    text-decoration: none;

-    color: black;

-}

-

-.leaflet-bar a,

-.leaflet-control-layers-toggle {

-    background-position: 50% 50%;

-    background-repeat: no-repeat;

-    display: block;

-}

-

-.leaflet-bar a:hover {

-    background-color: #f4f4f4;

-}

-

-.leaflet-bar a:first-child {

-    border-top-left-radius: 4px;

-    border-top-right-radius: 4px;

-}

-

-.leaflet-bar a:last-child {

-    border-bottom-left-radius: 4px;

-    border-bottom-right-radius: 4px;

-    border-bottom: none;

-}

-

-.leaflet-bar a.leaflet-disabled {

-    cursor: default;

-    background-color: #f4f4f4;

-    color: #bbb;

-}

-

-.leaflet-touch .leaflet-bar a {

-    width: 30px;

-    height: 30px;

-    line-height: 30px;

-}

-

-

-/* zoom control */

-

-.leaflet-control-zoom-in,

-.leaflet-control-zoom-out {

-    font: bold 18px 'Lucida Console', Monaco, monospace;

-    text-indent: 1px;

-}

-

-.leaflet-control-zoom-out {

-    font-size: 20px;

-}

-

-.leaflet-touch .leaflet-control-zoom-in {

-    font-size: 22px;

-}

-

-.leaflet-touch .leaflet-control-zoom-out {

-    font-size: 24px;

-}

-

-

-/* layers control */

-

-.leaflet-control-layers {

-    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);

-    background: #fff;

-    border-radius: 5px;

-}

-

-.leaflet-control-layers-toggle {

-    background-image: url('assets/erpnext/images/leaflet/layers.png');

-    width: 36px;

-    height: 36px;

-}

-

-.leaflet-retina .leaflet-control-layers-toggle {

-    background-image: url('assets/erpnext/images/leaflet/layers-2x.png');

-    background-size: 26px 26px;

-}

-

-.leaflet-touch .leaflet-control-layers-toggle {

-    width: 44px;

-    height: 44px;

-}

-

-.leaflet-control-layers .leaflet-control-layers-list,

-.leaflet-control-layers-expanded .leaflet-control-layers-toggle {

-    display: none;

-}

-

-.leaflet-control-layers-expanded .leaflet-control-layers-list {

-    display: block;

-    position: relative;

-}

-

-.leaflet-control-layers-expanded {

-    padding: 6px 10px 6px 6px;

-    color: #333;

-    background: #fff;

-}

-

-.leaflet-control-layers-scrollbar {

-    overflow-y: scroll;

-    padding-right: 5px;

-}

-

-.leaflet-control-layers-selector {

-    margin-top: 2px;

-    position: relative;

-    top: 1px;

-}

-

-.leaflet-control-layers label {

-    display: block;

-}

-

-.leaflet-control-layers-separator {

-    height: 0;

-    border-top: 1px solid #ddd;

-    margin: 5px -10px 5px -6px;

-}

-

-

-/* attribution and scale controls */

-

-.leaflet-container .leaflet-control-attribution {

-    background: #fff;

-    background: rgba(255, 255, 255, 0.7);

-    margin: 0;

-}

-

-.leaflet-control-attribution,

-.leaflet-control-scale-line {

-    padding: 0 5px;

-    color: #333;

-}

-

-.leaflet-control-attribution a {

-    text-decoration: none;

-}

-

-.leaflet-control-attribution a:hover {

-    text-decoration: underline;

-}

-

-.leaflet-container .leaflet-control-attribution,

-.leaflet-container .leaflet-control-scale {

-    font-size: 11px;

-}

-

-.leaflet-left .leaflet-control-scale {

-    margin-left: 5px;

-}

-

-.leaflet-bottom .leaflet-control-scale {

-    margin-bottom: 5px;

-}

-

-.leaflet-control-scale-line {

-    border: 2px solid #777;

-    border-top: none;

-    line-height: 1.1;

-    padding: 2px 5px 1px;

-    font-size: 11px;

-    white-space: nowrap;

-    overflow: hidden;

-    -moz-box-sizing: border-box;

-    box-sizing: border-box;

-    background: #fff;

-    background: rgba(255, 255, 255, 0.5);

-}

-

-.leaflet-control-scale-line:not(:first-child) {

-    border-top: 2px solid #777;

-    border-bottom: none;

-    margin-top: -2px;

-}

-

-.leaflet-control-scale-line:not(:first-child):not(:last-child) {

-    border-bottom: 2px solid #777;

-}

-

-.leaflet-touch .leaflet-control-attribution,

-.leaflet-touch .leaflet-control-layers,

-.leaflet-touch .leaflet-bar {

-    box-shadow: none;

-}

-

-.leaflet-touch .leaflet-control-layers,

-.leaflet-touch .leaflet-bar {

-    border: 2px solid rgba(0, 0, 0, 0.2);

-    background-clip: padding-box;

-}

-

-

-/* popup */

-

-.leaflet-popup {

-    position: absolute;

-    text-align: center;

-}

-

-.leaflet-popup-content-wrapper {

-    padding: 1px;

-    text-align: left;

-    border-radius: 12px;

-}

-

-.leaflet-popup-content {

-    margin: 13px 19px;

-    line-height: 1.4;

-}

-

-.leaflet-popup-content p {

-    margin: 18px 0;

-}

-

-.leaflet-popup-tip-container {

-    margin: 0 auto;

-    width: 40px;

-    height: 20px;

-    position: relative;

-    overflow: hidden;

-}

-

-.leaflet-popup-tip {

-    width: 17px;

-    height: 17px;

-    padding: 1px;

-    margin: -10px auto 0;

-    -webkit-transform: rotate(45deg);

-    -moz-transform: rotate(45deg);

-    -ms-transform: rotate(45deg);

-    -o-transform: rotate(45deg);

-    transform: rotate(45deg);

-}

-

-.leaflet-popup-content-wrapper,

-.leaflet-popup-tip {

-    background: white;

-    color: #333;

-    box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);

-}

-

-.leaflet-container a.leaflet-popup-close-button {

-    position: absolute;

-    top: 0;

-    right: 0;

-    padding: 4px 4px 0 0;

-    border: none;

-    text-align: center;

-    width: 18px;

-    height: 14px;

-    font: 16px/14px Tahoma, Verdana, sans-serif;

-    color: #c3c3c3;

-    text-decoration: none;

-    font-weight: bold;

-    background: transparent;

-}

-

-.leaflet-container a.leaflet-popup-close-button:hover {

-    color: #999;

-}

-

-.leaflet-popup-scrolled {

-    overflow: auto;

-    border-bottom: 1px solid #ddd;

-    border-top: 1px solid #ddd;

-}

-

-.leaflet-oldie .leaflet-popup-content-wrapper {

-    zoom: 1;

-}

-

-.leaflet-oldie .leaflet-popup-tip {

-    width: 24px;

-    margin: 0 auto;

-    -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";

-    filter: progid: DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);

-}

-

-.leaflet-oldie .leaflet-popup-tip-container {

-    margin-top: -1px;

-}

-

-.leaflet-oldie .leaflet-control-zoom,

-.leaflet-oldie .leaflet-control-layers,

-.leaflet-oldie .leaflet-popup-content-wrapper,

-.leaflet-oldie .leaflet-popup-tip {

-    border: 1px solid #999;

-}

-

-

-/* div icon */

-

-.leaflet-div-icon {

-    background: #fff;

-    border: 1px solid #666;

-}
\ No newline at end of file
diff --git a/erpnext/public/css/leaflet/leaflet.draw.css b/erpnext/public/css/leaflet/leaflet.draw.css
deleted file mode 100755
index 6fb7db0..0000000
--- a/erpnext/public/css/leaflet/leaflet.draw.css
+++ /dev/null
@@ -1,316 +0,0 @@
-/* ================================================================== */
-
-
-/* Toolbars
-/* ================================================================== */
-
-.leaflet-draw-section {
-    position: relative;
-}
-
-.leaflet-draw-toolbar {
-    margin-top: 12px;
-}
-
-.leaflet-draw-toolbar-top {
-    margin-top: 0;
-}
-
-.leaflet-draw-toolbar-notop a:first-child {
-    border-top-right-radius: 0;
-}
-
-.leaflet-draw-toolbar-nobottom a:last-child {
-    border-bottom-right-radius: 0;
-}
-
-.leaflet-draw-toolbar a {
-    background-image: url('assets/erpnext/images/leaflet/spritesheet.png');
-    background-repeat: no-repeat;
-}
-
-.leaflet-retina .leaflet-draw-toolbar a {
-    background-image: url('assets/erpnext/images/leaflet/spritesheet-2x.png');
-    background-size: 270px 30px;
-}
-
-.leaflet-draw a {
-    display: block;
-    text-align: center;
-    text-decoration: none;
-}
-
-
-/* ================================================================== */
-
-
-/* Toolbar actions menu
-/* ================================================================== */
-
-.leaflet-draw-actions {
-    display: none;
-    list-style: none;
-    margin: 0;
-    padding: 0;
-    position: absolute;
-    left: 26px;
-    /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */
-    top: 0;
-    white-space: nowrap;
-}
-
-.leaflet-right .leaflet-draw-actions {
-    right: 26px;
-    left: auto;
-}
-
-.leaflet-draw-actions li {
-    display: inline-block;
-}
-
-.leaflet-draw-actions li:first-child a {
-    border-left: none;
-}
-
-.leaflet-draw-actions li:last-child a {
-    -webkit-border-radius: 0 4px 4px 0;
-    border-radius: 0 4px 4px 0;
-}
-
-.leaflet-right .leaflet-draw-actions li:last-child a {
-    -webkit-border-radius: 0;
-    border-radius: 0;
-}
-
-.leaflet-right .leaflet-draw-actions li:first-child a {
-    -webkit-border-radius: 4px 0 0 4px;
-    border-radius: 4px 0 0 4px;
-}
-
-.leaflet-draw-actions a {
-    background-color: #919187;
-    border-left: 1px solid #AAA;
-    color: #FFF;
-    font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
-    line-height: 28px;
-    text-decoration: none;
-    padding-left: 10px;
-    padding-right: 10px;
-    height: 28px;
-}
-
-.leaflet-draw-actions-bottom {
-    margin-top: 0;
-}
-
-.leaflet-draw-actions-top {
-    margin-top: 1px;
-}
-
-.leaflet-draw-actions-top a,
-.leaflet-draw-actions-bottom a {
-    height: 27px;
-    line-height: 27px;
-}
-
-.leaflet-draw-actions a:hover {
-    background-color: #A0A098;
-}
-
-.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
-    height: 26px;
-    line-height: 26px;
-}
-
-
-/* ================================================================== */
-
-
-/* Draw toolbar
-/* ================================================================== */
-
-.leaflet-draw-toolbar .leaflet-draw-draw-polyline {
-    background-position: -2px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-polygon {
-    background-position: -31px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
-    background-position: -62px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-circle {
-    background-position: -92px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-draw-marker {
-    background-position: -122px -2px;
-}
-
-
-/* ================================================================== */
-
-
-/* Edit toolbar
-/* ================================================================== */
-
-.leaflet-draw-toolbar .leaflet-draw-edit-edit {
-    background-position: -152px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-remove {
-    background-position: -182px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
-    background-position: -212px -2px;
-}
-
-.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
-    background-position: -242px -2px;
-}
-
-
-/* ================================================================== */
-
-
-/* Drawing styles
-/* ================================================================== */
-
-.leaflet-mouse-marker {
-    background-color: #fff;
-    cursor: crosshair;
-}
-
-.leaflet-draw-tooltip {
-    background: rgb(54, 54, 54);
-    background: rgba(0, 0, 0, 0.5);
-    border: 1px solid transparent;
-    -webkit-border-radius: 4px;
-    border-radius: 4px;
-    color: #fff;
-    font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
-    margin-left: 20px;
-    margin-top: -21px;
-    padding: 4px 8px;
-    position: absolute;
-    visibility: hidden;
-    white-space: nowrap;
-    z-index: 6;
-}
-
-.leaflet-draw-tooltip:before {
-    border-right: 6px solid black;
-    border-right-color: rgba(0, 0, 0, 0.5);
-    border-top: 6px solid transparent;
-    border-bottom: 6px solid transparent;
-    content: "";
-    position: absolute;
-    top: 7px;
-    left: -7px;
-}
-
-.leaflet-error-draw-tooltip {
-    background-color: #F2DEDE;
-    border: 1px solid #E6B6BD;
-    color: #B94A48;
-}
-
-.leaflet-error-draw-tooltip:before {
-    border-right-color: #E6B6BD;
-}
-
-.leaflet-draw-tooltip-single {
-    margin-top: -12px
-}
-
-.leaflet-draw-tooltip-subtext {
-    color: #f8d5e4;
-}
-
-.leaflet-draw-guide-dash {
-    font-size: 1%;
-    opacity: 0.6;
-    position: absolute;
-    width: 5px;
-    height: 5px;
-}
-
-
-/* ================================================================== */
-
-
-/* Edit styles
-/* ================================================================== */
-
-.leaflet-edit-marker-selected {
-    background: rgba(254, 87, 161, 0.1);
-    border: 4px dashed rgba(254, 87, 161, 0.6);
-    -webkit-border-radius: 4px;
-    border-radius: 4px;
-}
-
-.leaflet-edit-move {
-    cursor: move;
-}
-
-.leaflet-edit-resize {
-    cursor: pointer;
-}
-
-
-/* ================================================================== */
-
-
-/* Old IE styles
-/* ================================================================== */
-
-.leaflet-oldie .leaflet-draw-toolbar {
-    border: 3px solid #999;
-}
-
-.leaflet-oldie .leaflet-draw-toolbar a {
-    background-color: #eee;
-}
-
-.leaflet-oldie .leaflet-draw-toolbar a:hover {
-    background-color: #fff;
-}
-
-.leaflet-oldie .leaflet-draw-actions {
-    left: 32px;
-    margin-top: 3px;
-}
-
-.leaflet-oldie .leaflet-draw-actions li {
-    display: inline;
-    zoom: 1;
-}
-
-.leaflet-oldie .leaflet-edit-marker-selected {
-    border: 4px dashed #fe93c2;
-}
-
-.leaflet-oldie .leaflet-draw-actions a {
-    background-color: #999;
-}
-
-.leaflet-oldie .leaflet-draw-actions a:hover {
-    background-color: #a5a5a5;
-}
-
-.leaflet-oldie .leaflet-draw-actions-top a {
-    margin-top: 1px;
-}
-
-.leaflet-oldie .leaflet-draw-actions-bottom a {
-    height: 28px;
-    line-height: 28px;
-}
-
-.leaflet-oldie .leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
-    height: 27px;
-    line-height: 27px;
-}
\ No newline at end of file
diff --git a/erpnext/public/js/account_tree_grid.js b/erpnext/public/js/account_tree_grid.js
index 757f33e..413a5ee 100644
--- a/erpnext/public/js/account_tree_grid.js
+++ b/erpnext/public/js/account_tree_grid.js
@@ -14,9 +14,9 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.	If not, see <http://www.gnu.org/licenses/>.
 
-erpnext.AccountTreeGrid = frappe.views.TreeGridReport.extend({
-	init: function(wrapper, title) {
-		this._super({
+erpnext.AccountTreeGrid = class AccountTreeGrid extends frappe.views.TreeGridReport {
+	constructor(wrapper, title) {
+		super({
 			title: title,
 			parent: $(wrapper).find('.layout-main'),
 			page: wrapper.page,
@@ -33,8 +33,24 @@
 				}
 			},
 		});
-	},
-	setup_columns: function() {
+
+		this.filters = [
+			{fieldtype: "Select", label: __("Company"), link:"Company", fieldname: "company",
+				default_value: __("Select Company..."),
+				filter: function(val, item, opts, me) {
+					if (item.company == val || val == opts.default_value) {
+						return me.apply_zero_filter(val, item, opts, me);
+					}
+					return false;
+				}},
+			{fieldtype: "Select", label: "Fiscal Year", link:"Fiscal Year", fieldname: "fiscal_year",
+				default_value: __("Select Fiscal Year...")},
+			{fieldtype: "Date", label: __("From Date"), fieldname: "from_date"},
+			{fieldtype: "Label", label: __("To")},
+			{fieldtype: "Date", label: __("To Date"), fieldname: "to_date"}
+		]
+	}
+	setup_columns() {
 		this.columns = [
 			{id: "name", name: __("Account"), field: "name", width: 300, cssClass: "cell-title"},
 			{id: "opening_dr", name: __("Opening (Dr)"), field: "opening_dr", width: 100,
@@ -50,25 +66,10 @@
 			{id: "closing_cr", name: __("Closing (Cr)"), field: "closing_cr", width: 100,
 				formatter: this.currency_formatter}
 		];
+	}
 
-	},
-	filters: [
-		{fieldtype: "Select", label: __("Company"), link:"Company", fieldname: "company",
-			default_value: __("Select Company..."),
-			filter: function(val, item, opts, me) {
-				if (item.company == val || val == opts.default_value) {
-					return me.apply_zero_filter(val, item, opts, me);
-				}
-				return false;
-			}},
-		{fieldtype: "Select", label: "Fiscal Year", link:"Fiscal Year", fieldname: "fiscal_year",
-			default_value: __("Select Fiscal Year...")},
-		{fieldtype: "Date", label: __("From Date"), fieldname: "from_date"},
-		{fieldtype: "Label", label: __("To")},
-		{fieldtype: "Date", label: __("To Date"), fieldname: "to_date"}
-	],
-	setup_filters: function() {
-		this._super();
+	setup_filters() {
+		super.setup_filters();
 		var me = this;
 		// default filters
 		this.filter_inputs.fiscal_year.change(function() {
@@ -83,8 +84,8 @@
 		});
 		me.show_zero_check()
 		if(me.ignore_closing_entry) me.ignore_closing_entry();
-	},
-	prepare_data: function() {
+	}
+	prepare_data() {
 		var me = this;
 		if(!this.primary_data) {
 			// make accounts list
@@ -113,12 +114,12 @@
 		this.set_indent();
 		this.prepare_balances();
 
-	},
-	init_account: function(d) {
+	}
+	init_account(d) {
 		this.reset_item_values(d);
-	},
+	}
 
-	prepare_balances: function() {
+	prepare_balances() {
 		var gl = frappe.report_dump.data['GL Entry'];
 		var me = this;
 
@@ -139,8 +140,8 @@
 		});
 
 		this.update_groups();
-	},
-	update_balances: function(account, posting_date, v) {
+	}
+	update_balances(account, posting_date, v) {
 		// opening
 		if (posting_date < this.opening_date || v.is_opening === "Yes") {
 			if (account.report_type === "Profit and Loss" &&
@@ -161,8 +162,8 @@
 		var closing_bal = flt(account.opening_dr) - flt(account.opening_cr) +
 			flt(account.debit) - flt(account.credit);
 		this.set_debit_or_credit(account, "closing", closing_bal);
-	},
-	set_debit_or_credit: function(account, field, balance) {
+	}
+	set_debit_or_credit(account, field, balance) {
 		if(balance > 0) {
 			account[field+"_dr"] = balance;
 			account[field+"_cr"] = 0;
@@ -170,8 +171,8 @@
 			account[field+"_cr"] = Math.abs(balance);
 			account[field+"_dr"] = 0;
 		}
-	},
-	update_groups: function() {
+	}
+	update_groups() {
 		// update groups
 		var me= this;
 		$.each(this.data, function(i, account) {
@@ -202,9 +203,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	set_fiscal_year: function() {
+	set_fiscal_year() {
 		if (this.opening_date > this.closing_date) {
 			frappe.msgprint(__("Opening Date should be before Closing Date"));
 			return;
@@ -223,9 +224,9 @@
 			frappe.msgprint(__("Opening Date and Closing Date should be within same Fiscal Year"));
 			return;
 		}
-	},
+	}
 
-	show_general_ledger: function(account) {
+	show_general_ledger(account) {
 		frappe.route_options = {
 			account: account,
 			company: this.company,
@@ -234,4 +235,4 @@
 		};
 		frappe.set_route("query-report", "General Ledger");
 	}
-});
+};
diff --git a/erpnext/public/js/bank-reconciliation-tool.bundle.js b/erpnext/public/js/bank-reconciliation-tool.bundle.js
new file mode 100644
index 0000000..636ef18
--- /dev/null
+++ b/erpnext/public/js/bank-reconciliation-tool.bundle.js
@@ -0,0 +1,3 @@
+import "./bank_reconciliation_tool/data_table_manager";
+import "./bank_reconciliation_tool/number_card";
+import "./bank_reconciliation_tool/dialog_manager";
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cdfd909..8b4a497 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -9,14 +9,14 @@
 
 cur_frm.email_field = "contact_email";
 
-erpnext.buying.BuyingController = erpnext.TransactionController.extend({
-	setup: function() {
-		this._super();
-	},
+erpnext.buying.BuyingController = class BuyingController extends erpnext.TransactionController {
+	setup() {
+		super.setup();
+	}
 
-	onload: function(doc, cdt, cdn) {
+	onload(doc, cdt, cdn) {
 		this.setup_queries(doc, cdt, cdn);
-		this._super();
+		super.onload();
 
 		this.frm.set_query('shipping_rule', function() {
 			return {
@@ -48,9 +48,9 @@
 			});
 		}
 		/* eslint-enable */
-	},
+	}
 
-	setup_queries: function(doc, cdt, cdn) {
+	setup_queries(doc, cdt, cdn) {
 		var me = this;
 
 		if(this.frm.fields_dict.buying_price_list) {
@@ -109,9 +109,9 @@
 				return me.set_query_for_item_tax_template(doc, cdt, cdn)
 			});
 		}
-	},
+	}
 
-	refresh: function(doc) {
+	refresh(doc) {
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier'};
 
 		this.frm.toggle_display("supplier_name",
@@ -122,38 +122,38 @@
 			this.set_from_product_bundle();
 		}
 
-		this._super();
-	},
+		super.refresh();
+	}
 
-	supplier: function() {
+	supplier() {
 		var me = this;
 		erpnext.utils.get_party_details(this.frm, null, null, function(){
 			me.apply_price_list();
 		});
-	},
+	}
 
-	supplier_address: function() {
+	supplier_address() {
 		erpnext.utils.get_address_display(this.frm);
 		erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address");
-	},
+	}
 
-	buying_price_list: function() {
+	buying_price_list() {
 		this.apply_price_list();
-	},
+	}
 
-	discount_percentage: function(doc, cdt, cdn) {
+	discount_percentage(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		item.discount_amount = 0.0;
 		this.price_list_rate(doc, cdt, cdn);
-	},
+	}
 
-	discount_amount: function(doc, cdt, cdn) {
+	discount_amount(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		item.discount_percentage = 0.0;
 		this.price_list_rate(doc, cdt, cdn);
-	},
+	}
 
-	qty: function(doc, cdt, cdn) {
+	qty(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && (doc.update_stock || doc.is_return))) {
 			frappe.model.round_floats_in(item, ["qty", "received_qty"]);
@@ -168,22 +168,22 @@
 			item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
 			item.received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(item.received_qty);
 		}
-		this._super(doc, cdt, cdn);
-	},
+		super.qty(doc, cdt, cdn);
+	}
 
-	batch_no: function(doc, cdt, cdn) {
-		this._super(doc, cdt, cdn);
-	},
+	batch_no(doc, cdt, cdn) {
+		super.batch_no(doc, cdt, cdn);
+	}
 
-	received_qty: function(doc, cdt, cdn) {
+	received_qty(doc, cdt, cdn) {
 		this.calculate_accepted_qty(doc, cdt, cdn)
-	},
+	}
 
-	rejected_qty: function(doc, cdt, cdn) {
+	rejected_qty(doc, cdt, cdn) {
 		this.calculate_accepted_qty(doc, cdt, cdn)
-	},
+	}
 
-	calculate_accepted_qty: function(doc, cdt, cdn){
+	calculate_accepted_qty(doc, cdt, cdn){
 		var item = frappe.get_doc(cdt, cdn);
 		frappe.model.round_floats_in(item, ["received_qty", "rejected_qty"]);
 
@@ -191,9 +191,9 @@
 
 		item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item));
 		this.qty(doc, cdt, cdn);
-	},
+	}
 
-	validate_negative_quantity: function(cdt, cdn, item, fieldnames){
+	validate_negative_quantity(cdt, cdn, item, fieldnames){
 		if(!item || !fieldnames) { return }
 
 		var is_negative_qty = false;
@@ -206,9 +206,9 @@
 		}
 
 		return is_negative_qty
-	},
+	}
 
-	warehouse: function(doc, cdt, cdn) {
+	warehouse(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		if(item.item_code && item.warehouse) {
 			return this.frm.call({
@@ -221,9 +221,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	project: function(doc, cdt, cdn) {
+	project(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		if(item.project) {
 			$.each(this.frm.doc["items"] || [],
@@ -234,48 +234,48 @@
 					}
 				});
 		}
-	},
+	}
 
-	rejected_warehouse: function(doc, cdt) {
+	rejected_warehouse(doc, cdt) {
 		// trigger autofill_warehouse only if parent rejected_warehouse field is triggered
 		if (["Purchase Invoice", "Purchase Receipt"].includes(cdt)) {
 			this.autofill_warehouse(doc.items, "rejected_warehouse", doc.rejected_warehouse);
 		}
-	},
+	}
 
-	category: function(doc, cdt, cdn) {
+	category(doc, cdt, cdn) {
 		// should be the category field of tax table
 		if(cdt != doc.doctype) {
 			this.calculate_taxes_and_totals();
 		}
-	},
-	add_deduct_tax: function(doc, cdt, cdn) {
+	}
+	add_deduct_tax(doc, cdt, cdn) {
 		this.calculate_taxes_and_totals();
-	},
+	}
 
-	set_from_product_bundle: function() {
+	set_from_product_bundle() {
 		var me = this;
 		this.frm.add_custom_button(__("Product Bundle"), function() {
 			erpnext.buying.get_items_from_product_bundle(me.frm);
 		}, __("Get Items From"));
-	},
+	}
 
-	shipping_address: function(){
+	shipping_address(){
 		var me = this;
 		erpnext.utils.get_address_display(this.frm, "shipping_address",
 			"shipping_address_display", true);
-	},
+	}
 
-	billing_address: function() {
+	billing_address() {
 		erpnext.utils.get_address_display(this.frm, "billing_address",
 			"billing_address_display", true);
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	update_auto_repeat_reference: function(doc) {
+	update_auto_repeat_reference(doc) {
 		if (doc.auto_repeat) {
 			frappe.call({
 				method:"frappe.automation.doctype.auto_repeat.auto_repeat.update_reference",
@@ -292,9 +292,9 @@
 				}
 			})
 		}
-	},
+	}
 
-	manufacturer: function(doc, cdt, cdn) {
+	manufacturer(doc, cdt, cdn) {
 		const row = locals[cdt][cdn];
 
 		if(row.manufacturer) {
@@ -311,9 +311,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	manufacturer_part_no: function(doc, cdt, cdn) {
+	manufacturer_part_no(doc, cdt, cdn) {
 		const row = locals[cdt][cdn];
 
 		if (row.manufacturer_part_no) {
@@ -336,7 +336,7 @@
 
 			}
 		}
-});
+};
 
 cur_frm.add_fetch('project', 'cost_center', 'cost_center');
 
@@ -497,4 +497,4 @@
 	});
 
 	dialog.show();
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 87b21b7..d346357 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -3,22 +3,22 @@
 
 frappe.provide("erpnext.stock");
 
-erpnext.stock.StockController = frappe.ui.form.Controller.extend({
-	onload: function() {
+erpnext.stock.StockController = class StockController extends frappe.ui.form.Controller {
+	onload() {
 		// warehouse query if company
 		if (this.frm.fields_dict.company) {
 			this.setup_warehouse_query();
 		}
-	},
+	}
 
-	setup_warehouse_query: function() {
+	setup_warehouse_query() {
 		var me = this;
 		erpnext.queries.setup_queries(this.frm, "Warehouse", function() {
 			return erpnext.queries.warehouse(me.frm.doc);
 		});
-	},
+	}
 
-	setup_posting_date_time_check: function() {
+	setup_posting_date_time_check() {
 		// make posting date default and read only unless explictly checked
 		frappe.ui.form.on(this.frm.doctype, 'set_posting_date_and_time_read_only', function(frm) {
 			if(frm.doc.docstatus == 0 && frm.doc.set_posting_time) {
@@ -46,9 +46,9 @@
 				frm.trigger('set_posting_date_and_time_read_only');
 			}
 		});
-	},
+	}
 
-	show_stock_ledger: function() {
+	show_stock_ledger() {
 		var me = this;
 		if(this.frm.doc.docstatus > 0) {
 			cur_frm.add_custom_button(__("Stock Ledger"), function() {
@@ -63,9 +63,9 @@
 			}, __("View"));
 		}
 
-	},
+	}
 
-	show_general_ledger: function() {
+	show_general_ledger() {
 		var me = this;
 		if(this.frm.doc.docstatus > 0) {
 			cur_frm.add_custom_button(__('Accounting Ledger'), function() {
@@ -81,4 +81,4 @@
 			}, __("View"));
 		}
 	}
-});
+};
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 2e133be..31410da 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -1,12 +1,12 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-erpnext.taxes_and_totals = erpnext.payments.extend({
-	setup: function() {
+erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
+	setup() {
 		this.fetch_round_off_accounts();
-	},
+	}
 
-	apply_pricing_rule_on_item: function(item) {
+	apply_pricing_rule_on_item(item) {
 		let effective_item_rate = item.price_list_rate;
 		let item_rate = item.rate;
 		if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
@@ -32,9 +32,9 @@
 		}
 
 		frappe.model.set_value(item.doctype, item.name, "rate", item_rate);
-	},
+	}
 
-	calculate_taxes_and_totals: function(update_paid_amount) {
+	calculate_taxes_and_totals(update_paid_amount) {
 		this.discount_amount_applied = false;
 		this._calculate_taxes_and_totals();
 		this.calculate_discount_amount();
@@ -63,16 +63,16 @@
 		}
 
 		this.frm.refresh_fields();
-	},
+	}
 
-	calculate_discount_amount: function(){
+	calculate_discount_amount(){
 		if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
 			this.set_discount_amount();
 			this.apply_discount_amount();
 		}
-	},
+	}
 
-	_calculate_taxes_and_totals: function() {
+	_calculate_taxes_and_totals() {
 		this.validate_conversion_rate();
 		this.calculate_item_values();
 		this.initialize_taxes();
@@ -82,9 +82,9 @@
 		this.manipulate_grand_total_for_inclusive_tax();
 		this.calculate_totals();
 		this._cleanup();
-	},
+	}
 
-	validate_conversion_rate: function() {
+	validate_conversion_rate() {
 		this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, (cur_frm) ? precision("conversion_rate") : 9);
 		var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate",
 			this.frm.doc.name);
@@ -99,9 +99,9 @@
 				frappe.throw(err_message);
 			}
 		}
-	},
+	}
 
-	calculate_item_values: function() {
+	calculate_item_values() {
 		var me = this;
 		if (!this.discount_amount_applied) {
 			$.each(this.frm.doc["items"] || [], function(i, item) {
@@ -121,16 +121,16 @@
 				me.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]);
 			});
 		}
-	},
+	}
 
-	set_in_company_currency: function(doc, fields) {
+	set_in_company_currency(doc, fields) {
 		var me = this;
 		$.each(fields, function(i, f) {
 			doc["base_"+f] = flt(flt(doc[f], precision(f, doc)) * me.frm.doc.conversion_rate, precision("base_" + f, doc));
 		});
-	},
+	}
 
-	initialize_taxes: function() {
+	initialize_taxes() {
 		var me = this;
 
 		$.each(this.frm.doc["taxes"] || [], function(i, tax) {
@@ -152,9 +152,9 @@
 			}
 			frappe.model.round_floats_in(tax);
 		});
-	},
+	}
 
-	fetch_round_off_accounts: function() {
+	fetch_round_off_accounts() {
 		let me = this;
 		frappe.flags.round_off_applicable_accounts = [];
 
@@ -165,14 +165,14 @@
 					"company": me.frm.doc.company,
 					"account_list": frappe.flags.round_off_applicable_accounts
 				},
-				callback: function(r) {
+				callback(r) {
 					frappe.flags.round_off_applicable_accounts.push(...r.message);
 				}
 			});
 		}
-	},
+	}
 
-	determine_exclusive_rate: function() {
+	determine_exclusive_rate() {
 		var me = this;
 
 		var has_inclusive_tax = false;
@@ -210,9 +210,9 @@
 				me.set_in_company_currency(item, ["net_rate", "net_amount"]);
 			}
 		});
-	},
+	}
 
-	get_current_tax_fraction: function(tax, item_tax_map) {
+	get_current_tax_fraction(tax, item_tax_map) {
 		// Get tax fraction for calculating tax exclusive amount
 		// from tax inclusive amount
 		var current_tax_fraction = 0.0;
@@ -241,14 +241,14 @@
 			inclusive_tax_amount_per_qty *= -1;
 		}
 		return [current_tax_fraction, inclusive_tax_amount_per_qty];
-	},
+	}
 
-	_get_tax_rate: function(tax, item_tax_map) {
+	_get_tax_rate(tax, item_tax_map) {
 		return (Object.keys(item_tax_map).indexOf(tax.account_head) != -1) ?
 			flt(item_tax_map[tax.account_head], precision("rate", tax)) : tax.rate;
-	},
+	}
 
-	calculate_net_total: function() {
+	calculate_net_total() {
 		var me = this;
 		this.frm.doc.total_qty = this.frm.doc.total = this.frm.doc.base_total = this.frm.doc.net_total = this.frm.doc.base_net_total = 0.0;
 
@@ -261,9 +261,9 @@
 			});
 
 		frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
-	},
+	}
 
-	calculate_taxes: function() {
+	calculate_taxes() {
 		var me = this;
 		this.frm.doc.rounding_adjustment = 0;
 		var actual_tax_dict = {};
@@ -342,9 +342,9 @@
 				}
 			});
 		});
-	},
+	}
 
-	set_cumulative_total: function(row_idx, tax) {
+	set_cumulative_total(row_idx, tax) {
 		var tax_amount = tax.tax_amount_after_discount_amount;
 		if (tax.category == 'Valuation') {
 			tax_amount = 0;
@@ -357,13 +357,13 @@
 		} else {
 			tax.total = flt(this.frm.doc["taxes"][row_idx-1].total + tax_amount, precision("total", tax));
 		}
-	},
+	}
 
-	_load_item_tax_rate: function(item_tax_rate) {
+	_load_item_tax_rate(item_tax_rate) {
 		return item_tax_rate ? JSON.parse(item_tax_rate) : {};
-	},
+	}
 
-	get_current_tax_amount: function(item, tax, item_tax_map) {
+	get_current_tax_amount(item, tax, item_tax_map) {
 		var tax_rate = this._get_tax_rate(tax, item_tax_map);
 		var current_tax_amount = 0.0;
 
@@ -399,9 +399,9 @@
 		this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
 
 		return current_tax_amount;
-	},
+	}
 
-	set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
+	set_item_wise_tax(item, tax, tax_rate, current_tax_amount) {
 		// store tax breakup for each item
 		let tax_detail = tax.item_wise_tax_detail;
 		let key = item.item_code || item.item_name;
@@ -411,9 +411,9 @@
 			item_wise_tax_amount += tax_detail[key][1];
 
 		tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
-	},
+	}
 
-	round_off_totals: function(tax) {
+	round_off_totals(tax) {
 		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
 			tax.tax_amount= Math.round(tax.tax_amount);
 			tax.tax_amount_after_discount_amount = Math.round(tax.tax_amount_after_discount_amount);
@@ -421,16 +421,16 @@
 
 		tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
 		tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax));
-	},
+	}
 
-	round_off_base_values: function(tax) {
+	round_off_base_values(tax) {
 		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
 			tax.base_tax_amount= Math.round(tax.base_tax_amount);
 			tax.base_tax_amount_after_discount_amount = Math.round(tax.base_tax_amount_after_discount_amount);
 		}
-	},
+	}
 
-	manipulate_grand_total_for_inclusive_tax: function() {
+	manipulate_grand_total_for_inclusive_tax() {
 		var me = this;
 		// if fully inclusive taxes and diff
 		if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
@@ -461,9 +461,9 @@
 				}
 			}
 		}
-	},
+	}
 
-	calculate_totals: function() {
+	calculate_totals() {
 		// Changing sequence can cause rounding_adjustmentng issue and on-screen discrepency
 		var me = this;
 		var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
@@ -509,9 +509,9 @@
 
 		// rounded totals
 		this.set_rounded_total();
-	},
+	}
 
-	set_rounded_total: function() {
+	set_rounded_total() {
 		var disable_rounded_total = 0;
 		if(frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total", this.frm.doc.name)) {
 			disable_rounded_total = this.frm.doc.disable_rounded_total;
@@ -533,9 +533,9 @@
 
 			this.set_in_company_currency(this.frm.doc, ["rounding_adjustment", "rounded_total"]);
 		}
-	},
+	}
 
-	_cleanup: function() {
+	_cleanup() {
 		this.frm.doc.base_in_words = this.frm.doc.in_words = "";
 
 		if(this.frm.doc["items"] && this.frm.doc["items"].length) {
@@ -562,16 +562,16 @@
 				tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
 			});
 		}
-	},
+	}
 
-	set_discount_amount: function() {
+	set_discount_amount() {
 		if(this.frm.doc.additional_discount_percentage) {
 			this.frm.doc.discount_amount = flt(flt(this.frm.doc[frappe.scrub(this.frm.doc.apply_discount_on)])
 				* this.frm.doc.additional_discount_percentage / 100, precision("discount_amount"));
 		}
-	},
+	}
 
-	apply_discount_amount: function() {
+	apply_discount_amount() {
 		var me = this;
 		var distributed_amount = 0.0;
 		this.frm.doc.base_discount_amount = 0.0;
@@ -609,9 +609,9 @@
 				this._calculate_taxes_and_totals();
 			}
 		}
-	},
+	}
 
-	get_total_for_discount_amount: function() {
+	get_total_for_discount_amount() {
 		if(this.frm.doc.apply_discount_on == "Net Total") {
 			return this.frm.doc.net_total;
 		} else {
@@ -635,27 +635,27 @@
 
 			return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
 		}
-	},
+	}
 
-	calculate_total_advance: function(update_paid_amount) {
+	calculate_total_advance(update_paid_amount) {
 		var total_allocated_amount = frappe.utils.sum($.map(this.frm.doc["advances"] || [], function(adv) {
 			return flt(adv.allocated_amount, precision("allocated_amount", adv));
 		}));
 		this.frm.doc.total_advance = flt(total_allocated_amount, precision("total_advance"));
 
 		this.calculate_outstanding_amount(update_paid_amount);
-	},
+	}
 
-	is_internal_invoice: function() {
+	is_internal_invoice() {
 		if (['Sales Invoice', 'Purchase Invoice'].includes(this.frm.doc.doctype)) {
 			if (this.frm.doc.company === this.frm.doc.represents_company) {
 				return true;
 			}
 		}
 		return false;
-	},
+	}
 
-	calculate_outstanding_amount: function(update_paid_amount) {
+	calculate_outstanding_amount(update_paid_amount) {
 		// NOTE:
 		// paid_amount and write_off_amount is only for POS/Loyalty Point Redemption Invoice
 		// total_advance is only for non POS Invoice
@@ -703,9 +703,9 @@
 			this.frm.doc.outstanding_amount =  flt(total_amount_to_pay - flt(paid_amount) +
 				flt(this.frm.doc.change_amount * this.frm.doc.conversion_rate), precision("outstanding_amount"));
 		}
-	},
+	}
 
-	update_paid_amount_for_return: function() {
+	update_paid_amount_for_return() {
 		var grand_total = this.frm.doc.rounded_total || this.frm.doc.grand_total;
 
 		if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
@@ -729,9 +729,9 @@
 		this.frm.refresh_fields();
 
 		this.calculate_paid_amount();
-	},
+	}
 
-	set_default_payment: function(total_amount_to_pay, update_paid_amount) {
+	set_default_payment(total_amount_to_pay, update_paid_amount) {
 		var me = this;
 		var payment_status = true;
 		if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) {
@@ -747,9 +747,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	calculate_paid_amount: function() {
+	calculate_paid_amount() {
 		var me = this;
 		var paid_amount = 0.0;
 		var base_paid_amount = 0.0;
@@ -769,9 +769,9 @@
 
 		this.frm.set_value('paid_amount', flt(paid_amount, precision("paid_amount")));
 		this.frm.set_value('base_paid_amount', flt(base_paid_amount, precision("base_paid_amount")));
-	},
+	}
 
-	calculate_change_amount: function(){
+	calculate_change_amount(){
 		this.frm.doc.change_amount = 0.0;
 		this.frm.doc.base_change_amount = 0.0;
 		if(in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype)
@@ -790,9 +790,9 @@
 					precision("base_change_amount"));
 			}
 		}
-	},
+	}
 
-	calculate_write_off_amount: function(){
+	calculate_write_off_amount(){
 		if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
 			this.frm.doc.write_off_amount = flt(this.frm.doc.grand_total - this.frm.doc.paid_amount
 				+ this.frm.doc.change_amount, precision("write_off_amount"));
@@ -804,4 +804,4 @@
 		}
 		this.calculate_outstanding_amount(false);
 	}
-});
+};
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 0af8da7..b533746 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -3,8 +3,8 @@
 
 frappe.provide('erpnext.accounts.dimensions');
 
-erpnext.TransactionController = erpnext.taxes_and_totals.extend({
-	setup: function() {
+erpnext.TransactionController = class TransactionController extends erpnext.taxes_and_totals {
+	setup() {
 		this._super();
 		frappe.flags.hide_serial_batch_dialog = true;
 		frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
@@ -222,8 +222,8 @@
 			});
 		}
 
-	},
-	onload: function() {
+	}
+	onload() {
 		var me = this;
 
 		if(this.frm.doc.__islocal) {
@@ -249,15 +249,15 @@
 				}
 			]);
 		}
-	},
+	}
 
-	is_return: function() {
+	is_return() {
 		if(!this.frm.doc.is_return && this.frm.doc.return_against) {
 			this.frm.set_value('return_against', '');
 		}
-	},
+	}
 
-	setup_quality_inspection: function() {
+	setup_quality_inspection() {
 		if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) {
 			return;
 		}
@@ -290,9 +290,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	make_payment_request: function() {
+	make_payment_request() {
 		var me = this;
 		const payment_request_type = (in_list(['Sales Order', 'Sales Invoice'], this.frm.doc.doctype))
 			? "Inward" : "Outward";
@@ -314,9 +314,9 @@
 				}
 			}
 		})
-	},
+	}
 
-	onload_post_render: function() {
+	onload_post_render() {
 		if(this.frm.doc.__islocal && !(this.frm.doc.taxes || []).length
 			&& !(this.frm.doc.__onload ? this.frm.doc.__onload.load_after_mapping : false)) {
 			frappe.after_ajax(() => this.apply_default_taxes());
@@ -328,9 +328,9 @@
 			this.setup_item_selector();
 			this.frm.get_field("items").grid.set_multiple_add("item_code", "qty");
 		}
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		erpnext.toggle_naming_series();
 		erpnext.hide_company();
 		this.set_dynamic_labels();
@@ -360,9 +360,9 @@
 					.appendTo($input_group);
 			}
 		}
-	},
+	}
 
-	scan_barcode: function() {
+	scan_barcode() {
 		let scan_barcode_field = this.frm.fields_dict["scan_barcode"];
 
 		let show_description = function(idx, exist = null) {
@@ -434,9 +434,9 @@
 			});
 		}
 		return false;
-	},
+	}
 
-	apply_default_taxes: function() {
+	apply_default_taxes() {
 		var me = this;
 		var taxes_and_charges_field = frappe.meta.get_docfield(me.frm.doc.doctype, "taxes_and_charges",
 			me.frm.doc.name);
@@ -475,22 +475,22 @@
 				}
 			});
 		}
-	},
+	}
 
-	setup_sms: function() {
+	setup_sms() {
 		var me = this;
 		let blacklist = ['Purchase Invoice', 'BOM'];
 		if(this.frm.doc.docstatus===1 && !in_list(["Lost", "Stopped", "Closed"], this.frm.doc.status)
 			&& !blacklist.includes(this.frm.doctype)) {
 			this.frm.page.add_menu_item(__('Send SMS'), function() { me.send_sms(); });
 		}
-	},
+	}
 
-	send_sms: function() {
+	send_sms() {
 		var sms_man = new erpnext.SMSManager(this.frm.doc);
-	},
+	}
 
-	barcode: function(doc, cdt, cdn) {
+	barcode(doc, cdt, cdn) {
 		var d = locals[cdt][cdn];
 		if(d.barcode=="" || d.barcode==null) {
 			// barcode cleared, remove item
@@ -499,9 +499,9 @@
 
 		this.frm.from_barcode = this.frm.from_barcode ? this.frm.from_barcode + 1 : 1;
 		this.item_code(doc, cdt, cdn);
-	},
+	}
 
-	item_code: function(doc, cdt, cdn) {
+	item_code(doc, cdt, cdn) {
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 		var update_stock = 0, show_batch_dialog = 0;
@@ -651,9 +651,9 @@
 				});
 			}
 		}
-	},
+	}
 
-	price_list_rate: function(doc, cdt, cdn) {
+	price_list_rate(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
 
@@ -665,17 +665,17 @@
 				precision("rate", item));
 
 		this.calculate_taxes_and_totals();
-	},
+	}
 
-	margin_rate_or_amount: function(doc, cdt, cdn) {
+	margin_rate_or_amount(doc, cdt, cdn) {
 		// calculated the revised total margin and rate on margin rate changes
 		let item = frappe.get_doc(cdt, cdn);
 		this.apply_pricing_rule_on_item(item);
 		this.calculate_taxes_and_totals();
 		cur_frm.refresh_fields();
-	},
+	}
 
-	margin_type: function(doc, cdt, cdn) {
+	margin_type(doc, cdt, cdn) {
 		// calculate the revised total margin and rate on margin type changes
 		let item = frappe.get_doc(cdt, cdn);
 		if (!item.margin_type) {
@@ -685,9 +685,9 @@
 			this.calculate_taxes_and_totals();
 			cur_frm.refresh_fields();
 		}
-	},
+	}
 
-	get_incoming_rate: function(item, posting_date, posting_time, voucher_type, company) {
+	get_incoming_rate(item, posting_date, posting_time, voucher_type, company) {
 
 		let item_args = {
 			'item_code': item.item_code,
@@ -710,9 +710,9 @@
 				frappe.model.set_value(item.doctype, item.name, 'rate', r.message * item.conversion_factor);
 			}
 		});
-	},
+	}
 
-	add_taxes_from_item_tax_template: function(item_tax_map) {
+	add_taxes_from_item_tax_template(item_tax_map) {
 		let me = this;
 
 		if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) {
@@ -730,9 +730,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	serial_no: function(doc, cdt, cdn) {
+	serial_no(doc, cdt, cdn) {
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 
@@ -752,9 +752,9 @@
 				}
 			}
 		}
-	},
+	}
 
-	update_qty: function(cdt, cdn) {
+	update_qty(cdt, cdn) {
 		var valid_serial_nos = [];
 		var serialnos = [];
 		var item = frappe.get_doc(cdt, cdn);
@@ -767,17 +767,17 @@
 		frappe.model.set_value(item.doctype, item.name,
 			"qty", valid_serial_nos.length / item.conversion_factor);
 		frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
-	},
+	}
 
-	validate: function() {
+	validate() {
 		this.calculate_taxes_and_totals(false);
-	},
+	}
 
-	update_stock: function() {
+	update_stock() {
 		this.frm.trigger('set_default_internal_warehouse');
-	},
+	}
 
-	set_default_internal_warehouse: function() {
+	set_default_internal_warehouse() {
 		let me = this;
 		if ((this.frm.doc.doctype === 'Sales Invoice' && me.frm.doc.update_stock)
 			|| this.frm.doc.doctype == 'Delivery Note') {
@@ -796,9 +796,9 @@
 				});
 			}
 		}
-	},
+	}
 
-	company: function() {
+	company() {
 		var me = this;
 		var set_pricing = function() {
 			if(me.frm.doc.company && me.frm.fields_dict.currency) {
@@ -905,16 +905,16 @@
 		if(this.frm.doc.company) {
 			erpnext.last_selected_company = this.frm.doc.company;
 		}
-	},
+	}
 
-	transaction_date: function() {
+	transaction_date() {
 		if (this.frm.doc.transaction_date) {
 			this.frm.transaction_date = this.frm.doc.transaction_date;
 			frappe.ui.form.trigger(this.frm.doc.doctype, "currency");
 		}
-	},
+	}
 
-	posting_date: function() {
+	posting_date() {
 		var me = this;
 		if (this.frm.doc.posting_date) {
 			this.frm.posting_date = this.frm.doc.posting_date;
@@ -943,9 +943,9 @@
 				frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
 			}
 		}
-	},
+	}
 
-	due_date: function() {
+	due_date() {
 		// due_date is to be changed, payment terms template and/or payment schedule must
 		// be removed as due_date is automatically changed based on payment terms
 		if (this.frm.doc.due_date && !this.frm.updating_party_details && !this.frm.doc.is_pos) {
@@ -968,13 +968,13 @@
 				frappe.msgprint(final_message);
 			}
 		}
-	},
+	}
 
-	bill_date: function() {
+	bill_date() {
 		this.posting_date();
-	},
+	}
 
-	recalculate_terms: function() {
+	recalculate_terms() {
 		const doc = this.frm.doc;
 		if (doc.payment_terms_template) {
 			this.payment_terms_template();
@@ -993,17 +993,17 @@
 				}
 			);
 		}
-	},
+	}
 
-	get_company_currency: function() {
+	get_company_currency() {
 		return erpnext.get_currency(this.frm.doc.company);
-	},
+	}
 
-	contact_person: function() {
+	contact_person() {
 		erpnext.utils.get_contact_details(this.frm);
-	},
+	}
 
-	currency: function() {
+	currency() {
 		/* manqala 19/09/2016: let the translation date be whichever of the transaction_date or posting_date is available */
 		var transaction_date = this.frm.doc.transaction_date || this.frm.doc.posting_date;
 		/* end manqala */
@@ -1025,9 +1025,9 @@
 		} else {
 			this.conversion_rate();
 		}
-	},
+	}
 
-	conversion_rate: function() {
+	conversion_rate() {
 		const me = this.frm;
 		if(this.frm.doc.currency === this.get_company_currency()) {
 			this.frm.set_value("conversion_rate", 1.0);
@@ -1047,9 +1047,9 @@
 		}
 		// Make read only if Accounts Settings doesn't allow stale rates
 		this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
-	},
+	}
 
-	shipping_rule: function() {
+	shipping_rule() {
 		var me = this;
 		if(this.frm.doc.shipping_rule) {
 			return this.frm.call({
@@ -1065,9 +1065,9 @@
 		else {
 			me.calculate_taxes_and_totals();
 		}
-	},
+	}
 
-	set_margin_amount_based_on_currency: function(exchange_rate) {
+	set_margin_amount_based_on_currency(exchange_rate) {
 		if (in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "Purchase Invoice", "Purchase Order", "Purchase Receipt"]), this.frm.doc.doctype) {
 			var me = this;
 			$.each(this.frm.doc.items || [], function(i, d) {
@@ -1077,9 +1077,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	set_actual_charges_based_on_currency: function(exchange_rate) {
+	set_actual_charges_based_on_currency(exchange_rate) {
 		var me = this;
 		$.each(this.frm.doc.taxes || [], function(i, d) {
 			if(d.charge_type == "Actual") {
@@ -1087,9 +1087,9 @@
 					flt(d.tax_amount) / flt(exchange_rate));
 			}
 		});
-	},
+	}
 
-	get_exchange_rate: function(transaction_date, from_currency, to_currency, callback) {
+	get_exchange_rate(transaction_date, from_currency, to_currency, callback) {
 		var args;
 		if (["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"].includes(this.frm.doctype)) {
 			args = "for_selling";
@@ -1113,9 +1113,9 @@
 				callback(flt(r.message));
 			}
 		});
-	},
+	}
 
-	price_list_currency: function() {
+	price_list_currency() {
 		var me=this;
 		this.set_dynamic_labels();
 
@@ -1129,9 +1129,9 @@
 		} else {
 			this.plc_conversion_rate();
 		}
-	},
+	}
 
-	plc_conversion_rate: function() {
+	plc_conversion_rate() {
 		if(this.frm.doc.price_list_currency === this.get_company_currency()) {
 			this.frm.set_value("plc_conversion_rate", 1.0);
 		} else if(this.frm.doc.price_list_currency === this.frm.doc.currency
@@ -1143,9 +1143,9 @@
 		if(!this.in_apply_price_list) {
 			this.apply_price_list(null, true);
 		}
-	},
+	}
 
-	uom: function(doc, cdt, cdn) {
+	uom(doc, cdt, cdn) {
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 		if(item.item_code && item.uom) {
@@ -1163,9 +1163,9 @@
 			});
 		}
 		me.calculate_stock_uom_rate(doc, cdt, cdn);
-	},
+	}
 
-	conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
+	conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) {
 		if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
 			var item = frappe.get_doc(cdt, cdn);
 			frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
@@ -1190,35 +1190,35 @@
 			}
 			this.calculate_stock_uom_rate(doc, cdt, cdn);
 		}
-	},
+	}
 
-	batch_no: function(doc, cdt, cdn) {
+	batch_no(doc, cdt, cdn) {
 		let item = frappe.get_doc(cdt, cdn);
 		this.apply_price_list(item, true);
-	},
+	}
 
-	toggle_conversion_factor: function(item) {
+	toggle_conversion_factor(item) {
 		// toggle read only property for conversion factor field if the uom and stock uom are same
 		if(this.frm.get_field('items').grid.fields_map.conversion_factor) {
 			this.frm.fields_dict.items.grid.toggle_enable("conversion_factor",
 				((item.uom != item.stock_uom) && !frappe.meta.get_docfield(cur_frm.fields_dict.items.grid.doctype, "conversion_factor").read_only)? true: false);
 		}
 
-	},
+	}
 
-	qty: function(doc, cdt, cdn) {
+	qty(doc, cdt, cdn) {
 		let item = frappe.get_doc(cdt, cdn);
 		this.conversion_factor(doc, cdt, cdn, true);
 		this.calculate_stock_uom_rate(doc, cdt, cdn);
 		this.apply_pricing_rule(item, true);
-	},
+	}
 
-	calculate_stock_uom_rate: function(doc, cdt, cdn) {
+	calculate_stock_uom_rate(doc, cdt, cdn) {
 		let item = frappe.get_doc(cdt, cdn);
 		item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
 		refresh_field("stock_uom_rate", item.name, item.parentfield);
-	},
-	service_stop_date: function(frm, cdt, cdn) {
+	}
+	service_stop_date(frm, cdt, cdn) {
 		var child = locals[cdt][cdn];
 
 		if(child.service_stop_date) {
@@ -1234,9 +1234,9 @@
 				frappe.throw(__("Service Stop Date cannot be after Service End Date"));
 			}
 		}
-	},
+	}
 
-	service_start_date: function(frm, cdt, cdn) {
+	service_start_date(frm, cdt, cdn) {
 		var child = locals[cdt][cdn];
 
 		if(child.service_start_date) {
@@ -1248,9 +1248,9 @@
 				}
 			})
 		}
-	},
+	}
 
-	calculate_net_weight: function(){
+	calculate_net_weight(){
 		/* Calculate Total Net Weight then further applied shipping rule to calculate shipping charges.*/
 		var me = this;
 		this.frm.doc.total_net_weight= 0.0;
@@ -1260,9 +1260,9 @@
 		});
 		refresh_field("total_net_weight");
 		this.shipping_rule();
-	},
+	}
 
-	set_dynamic_labels: function() {
+	set_dynamic_labels() {
 		// What TODO? should we make price list system non-mandatory?
 		this.frm.toggle_reqd("plc_conversion_rate",
 			!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
@@ -1271,9 +1271,9 @@
 		this.change_form_labels(company_currency);
 		this.change_grid_labels(company_currency);
 		this.frm.refresh_fields();
-	},
+	}
 
-	change_form_labels: function(company_currency) {
+	change_form_labels(company_currency) {
 		var me = this;
 
 		this.frm.set_currency_labels(["base_total", "base_net_total", "base_total_taxes_and_charges",
@@ -1320,16 +1320,16 @@
 		if(frappe.meta.get_docfield(cur_frm.doctype, "base_net_total"))
 			cur_frm.toggle_display("base_net_total", (show && (me.frm.doc.currency != company_currency)));
 
-	},
+	}
 
-	change_grid_labels: function(company_currency) {
+	change_grid_labels(company_currency) {
 		var me = this;
 
 		this.update_item_grid_labels(company_currency);
 
 		this.toggle_item_grid_columns(company_currency);
 
-		if(this.frm.fields_dict["operations"]) {
+		if (this.frm.doc.operations && this.frm.doc.operations.length > 0) {
 			this.frm.set_currency_labels(["operating_cost", "hour_rate"], this.frm.doc.currency, "operations");
 			this.frm.set_currency_labels(["base_operating_cost", "base_hour_rate"], company_currency, "operations");
 
@@ -1340,7 +1340,7 @@
 			});
 		}
 
-		if(this.frm.fields_dict["scrap_items"]) {
+		if (this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) {
 			this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items");
 			this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items");
 
@@ -1351,21 +1351,21 @@
 			});
 		}
 
-		if(this.frm.fields_dict["taxes"]) {
+		if (this.frm.doc.taxes && this.frm.doc.taxes.length > 0) {
 			this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
 
 			this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
 		}
 
-		if(this.frm.fields_dict["advances"]) {
+		if (this.frm.doc.advances && this.frm.doc.advances.length > 0) {
 			this.frm.set_currency_labels(["advance_amount", "allocated_amount"],
 				this.frm.doc.party_account_currency, "advances");
 		}
 
 		this.update_payment_schedule_grid_labels(company_currency);
-	},
+	}
 
-	update_item_grid_labels: function(company_currency) {
+	update_item_grid_labels(company_currency) {
 		this.frm.set_currency_labels([
 			"base_rate", "base_net_rate", "base_price_list_rate",
 			"base_amount", "base_net_amount", "base_rate_with_margin"
@@ -1375,9 +1375,9 @@
 			"rate", "net_rate", "price_list_rate", "amount",
 			"net_amount", "stock_uom_rate", "rate_with_margin"
 		], this.frm.doc.currency, "items");
-	},
+	}
 
-	update_payment_schedule_grid_labels: function(company_currency) {
+	update_payment_schedule_grid_labels(company_currency) {
 		const me = this;
 		if (this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length > 0) {
 			this.frm.set_currency_labels(["base_payment_amount", "base_outstanding", "base_paid_amount"],
@@ -1391,9 +1391,9 @@
 					schedule_grid.set_column_disp(fname, me.frm.doc.currency != company_currency);
 			});
 		}
-	},
+	}
 
-	toggle_item_grid_columns: function(company_currency) {
+	toggle_item_grid_columns(company_currency) {
 		const me = this;
 		// toggle columns
 		var item_grid = this.frm.fields_dict["items"].grid;
@@ -1414,21 +1414,21 @@
 			if(frappe.meta.get_docfield(item_grid.doctype, fname))
 				item_grid.set_column_disp(fname, (show && (me.frm.doc.currency != company_currency)));
 		});
-	},
+	}
 
-	recalculate: function() {
+	recalculate() {
 		this.calculate_taxes_and_totals();
-	},
+	}
 
-	recalculate_values: function() {
+	recalculate_values() {
 		this.calculate_taxes_and_totals();
-	},
+	}
 
-	calculate_charges: function() {
+	calculate_charges() {
 		this.calculate_taxes_and_totals();
-	},
+	}
 
-	ignore_pricing_rule: function() {
+	ignore_pricing_rule() {
 		if(this.frm.doc.ignore_pricing_rule) {
 			var me = this;
 			var item_list = [];
@@ -1462,9 +1462,9 @@
 		} else {
 			this.apply_pricing_rule();
 		}
-	},
+	}
 
-	apply_pricing_rule: function(item, calculate_taxes_and_totals) {
+	apply_pricing_rule(item, calculate_taxes_and_totals) {
 		var me = this;
 		var args = this._get_args(item);
 		if (!(args.items && args.items.length)) {
@@ -1483,9 +1483,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	_get_args: function(item) {
+	_get_args(item) {
 		var me = this;
 		return {
 			"items": this._get_item_list(item),
@@ -1513,9 +1513,9 @@
 			"pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '',
 			"coupon_code": me.frm.doc.coupon_code
 		};
-	},
+	}
 
-	_get_item_list: function(item) {
+	_get_item_list(item) {
 		var item_list = [];
 		var append_item = function(d) {
 			if (d.item_code) {
@@ -1556,9 +1556,9 @@
 			});
 		}
 		return item_list;
-	},
+	}
 
-	_set_values_for_item_list: function(children) {
+	_set_values_for_item_list(children) {
 		var me = this;
 		var price_list_rate_changed = false;
 		var items_rule_dict = {};
@@ -1598,9 +1598,9 @@
 		me.apply_rule_on_other_items(items_rule_dict);
 
 		if(!price_list_rate_changed) me.calculate_taxes_and_totals();
-	},
+	}
 
-	apply_rule_on_other_items: function(args) {
+	apply_rule_on_other_items(args) {
 		const me = this;
 		const fields = ["discount_percentage", "pricing_rules", "discount_amount", "rate"];
 
@@ -1619,9 +1619,9 @@
 				});
 			}
 		}
-	},
+	}
 
-	apply_product_discount: function(args) {
+	apply_product_discount(args) {
 		const items = this.frm.doc.items.filter(d => (d.is_free_item)) || [];
 
 		const exist_items = items.map(row => (row.item_code, row.pricing_rules));
@@ -1646,9 +1646,9 @@
 		// free_item_data is a temporary variable
 		args.free_item_data = '';
 		refresh_field('items');
-	},
+	}
 
-	apply_price_list: function(item, reset_plc_conversion) {
+	apply_price_list(item, reset_plc_conversion) {
 		// We need to reset plc_conversion_rate sometimes because the call to
 		// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
 		if (!reset_plc_conversion) {
@@ -1687,9 +1687,9 @@
 		}).always(() => {
 			me.in_apply_price_list = false;
 		});
-	},
+	}
 
-	remove_pricing_rule: function(item) {
+	remove_pricing_rule(item) {
 		let me = this;
 		const fields = ["discount_percentage",
 			"discount_amount", "margin_rate_or_amount", "rate_with_margin"];
@@ -1723,18 +1723,18 @@
 
 			me.trigger_price_list_rate();
 		}
-	},
+	}
 
-	trigger_price_list_rate: function() {
+	trigger_price_list_rate() {
 		var me  = this;
 
 		this.frm.doc.items.forEach(child_row => {
 			me.frm.script_manager.trigger("price_list_rate",
 				child_row.doctype, child_row.name);
 		})
-	},
+	}
 
-	validate_company_and_party: function() {
+	validate_company_and_party() {
 		var me = this;
 		var valid = true;
 
@@ -1749,9 +1749,9 @@
 			}
 		});
 		return valid;
-	},
+	}
 
-	get_terms: function() {
+	get_terms() {
 		var me = this;
 
 		erpnext.utils.get_terms(this.frm.doc.tc_name, this.frm.doc, function(r) {
@@ -1759,9 +1759,9 @@
 				me.frm.set_value("terms", r.message);
 			}
 		});
-	},
+	}
 
-	taxes_and_charges: function() {
+	taxes_and_charges() {
 		var me = this;
 		if(this.frm.doc.taxes_and_charges) {
 			return this.frm.call({
@@ -1787,9 +1787,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	tax_category: function() {
+	tax_category() {
 		var me = this;
 		if(me.frm.updating_party_details) return;
 
@@ -1797,9 +1797,9 @@
 			() => this.update_item_tax_map(),
 			() => erpnext.utils.set_taxes(this.frm, "tax_category"),
 		]);
-	},
+	}
 
-	item_tax_template: function(doc, cdt, cdn) {
+	item_tax_template(doc, cdt, cdn) {
 		var me = this;
 		if(me.frm.updating_party_details) return;
 
@@ -1825,9 +1825,9 @@
 			item.item_tax_rate = "{}";
 			me.calculate_taxes_and_totals();
 		}
-	},
+	}
 
-	update_item_tax_map: function() {
+	update_item_tax_map() {
 		var me = this;
 		var item_codes = [];
 		$.each(this.frm.doc.items || [], function(i, item) {
@@ -1863,9 +1863,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	is_recurring: function() {
+	is_recurring() {
 		// set default values for recurring documents
 		if(this.frm.doc.is_recurring && this.frm.doc.__islocal) {
 			frappe.msgprint(__("Please set recurring after saving"));
@@ -1888,9 +1888,9 @@
 		}
 
 		refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
-	},
+	}
 
-	from_date: function() {
+	from_date() {
 		// set to_date
 		if(this.frm.doc.from_date) {
 			var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
@@ -1904,25 +1904,25 @@
 				refresh_field('to_date');
 			}
 		}
-	},
+	}
 
-	set_gross_profit: function(item) {
+	set_gross_profit(item) {
 		if (["Sales Order", "Quotation"].includes(this.frm.doc.doctype) && item.valuation_rate) {
 			var rate = flt(item.rate) * flt(this.frm.doc.conversion_rate || 1);
 			item.gross_profit = flt(((rate - item.valuation_rate) * item.stock_qty), precision("amount", item));
 		}
-	},
+	}
 
-	setup_item_selector: function() {
+	setup_item_selector() {
 		// TODO: remove item selector
 
 		return;
 		// if(!this.item_selector) {
 		// 	this.item_selector = new erpnext.ItemSelector({frm: this.frm});
 		// }
-	},
+	}
 
-	get_advances: function() {
+	get_advances() {
 		if(!this.frm.is_return) {
 			return this.frm.call({
 				method: "set_advances",
@@ -1932,9 +1932,9 @@
 				}
 			})
 		}
-	},
+	}
 
-	make_payment_entry: function() {
+	make_payment_entry() {
 		return frappe.call({
 			method: cur_frm.cscript.get_method_for_payment(),
 			args: {
@@ -1947,9 +1947,9 @@
 				// cur_frm.refresh_fields()
 			}
 		});
-	},
+	}
 
-	get_method_for_payment: function(){
+	get_method_for_payment(){
 		var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
 		if(cur_frm.doc.__onload && cur_frm.doc.__onload.make_payment_via_journal_entry){
 			if(in_list(['Sales Invoice', 'Purchase Invoice'],  cur_frm.doc.doctype)){
@@ -1960,9 +1960,9 @@
 		}
 
 		return method
-	},
+	}
 
-	set_query_for_batch: function(doc, cdt, cdn) {
+	set_query_for_batch(doc, cdt, cdn) {
 		// Show item's batches in the dropdown of batch no
 
 		var me = this;
@@ -1992,9 +1992,9 @@
 				filters: filters
 			}
 		}
-	},
+	}
 
-	set_query_for_item_tax_template: function(doc, cdt, cdn) {
+	set_query_for_item_tax_template(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		if(!item.item_code) {
 			return doc.company ? {filters: {company: doc.company}} : {};
@@ -2014,9 +2014,9 @@
 				filters: filters
 			}
 		}
-	},
+	}
 
-	payment_terms_template: function() {
+	payment_terms_template() {
 		var me = this;
 		const doc = this.frm.doc;
 		if(doc.payment_terms_template && doc.doctype !== 'Delivery Note') {
@@ -2039,9 +2039,9 @@
 				}
 			})
 		}
-	},
+	}
 
-	payment_term: function(doc, cdt, cdn) {
+	payment_term(doc, cdt, cdn) {
 		const me = this;
 		var row = locals[cdt][cdn];
 		if(row.payment_term) {
@@ -2065,17 +2065,17 @@
 				}
 			})
 		}
-	},
+	}
 
-	against_blanket_order: function(doc, cdt, cdn) {
+	against_blanket_order(doc, cdt, cdn) {
 		var item = locals[cdt][cdn];
 		if(!item.against_blanket_order) {
 			frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order", null);
 			frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order_rate", 0.00);
 		}
-	},
+	}
 
-	blanket_order: function(doc, cdt, cdn) {
+	blanket_order(doc, cdt, cdn) {
 		var me = this;
 		var item = locals[cdt][cdn];
 		if (item.blanket_order && (item.parenttype=="Sales Order" || item.parenttype=="Purchase Order")) {
@@ -2103,34 +2103,34 @@
 				}
 			})
 		}
-	},
+	}
 
-	set_reserve_warehouse: function() {
+	set_reserve_warehouse() {
 		this.autofill_warehouse(this.frm.doc.supplied_items, "reserve_warehouse", this.frm.doc.set_reserve_warehouse);
-	},
+	}
 
-	set_warehouse: function() {
+	set_warehouse() {
 		this.autofill_warehouse(this.frm.doc.items, "warehouse", this.frm.doc.set_warehouse);
-	},
+	}
 
-	set_target_warehouse: function() {
+	set_target_warehouse() {
 		this.autofill_warehouse(this.frm.doc.items, "target_warehouse", this.frm.doc.set_target_warehouse);
-	},
+	}
 
-	set_from_warehouse: function() {
+	set_from_warehouse() {
 		this.autofill_warehouse(this.frm.doc.items, "from_warehouse", this.frm.doc.set_from_warehouse);
-	},
+	}
 
-	autofill_warehouse : function (child_table, warehouse_field, warehouse) {
+	autofill_warehouse(child_table, warehouse_field, warehouse) {
 		if (warehouse && child_table && child_table.length) {
 			let doctype = child_table[0].doctype;
 			$.each(child_table || [], function(i, item) {
 				frappe.model.set_value(doctype, item.name, warehouse_field, warehouse);
 			});
 		}
-	},
+	}
 
-	coupon_code: function() {
+	coupon_code() {
 		var me = this;
 		frappe.run_serially([
 			() => this.frm.doc.ignore_pricing_rule=1,
@@ -2139,7 +2139,7 @@
 			() => me.apply_pricing_rule()
 		]);
 	}
-});
+};
 
 erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_dialog) {
 	let warehouse, receiving_stock, existing_stock;
diff --git a/erpnext/public/js/erpnext-web.bundle.js b/erpnext/public/js/erpnext-web.bundle.js
new file mode 100644
index 0000000..7db6967
--- /dev/null
+++ b/erpnext/public/js/erpnext-web.bundle.js
@@ -0,0 +1,2 @@
+import "./website_utils";
+import "./shopping_cart";
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
new file mode 100644
index 0000000..519cfca
--- /dev/null
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -0,0 +1,27 @@
+import "./conf";
+import "./utils";
+import "./queries";
+import "./sms_manager";
+import "./utils/party";
+import "./controllers/stock_controller";
+import "./payment/payments";
+import "./controllers/taxes_and_totals";
+import "./controllers/transaction";
+import "./templates/item_selector.html";
+import "./templates/employees_to_mark_attendance.html";
+import "./utils/item_selector";
+import "./help_links";
+import "./agriculture/ternary_plot";
+import "./templates/item_quick_entry.html";
+import "./utils/item_quick_entry";
+import "./utils/customer_quick_entry";
+import "./education/student_button.html";
+import "./education/assessment_result_tool.html";
+import "./hub/hub_factory";
+import "./call_popup/call_popup";
+import "./utils/dimension_tree_filter";
+import "./telephony";
+import "./templates/call_link.html";
+
+// import { sum } from 'frappe/public/utils/util.js'
+
diff --git a/erpnext/public/js/hub/hub_factory.js b/erpnext/public/js/hub/hub_factory.js
index 8dab2d6..9c67c1c 100644
--- a/erpnext/public/js/hub/hub_factory.js
+++ b/erpnext/public/js/hub/hub_factory.js
@@ -19,11 +19,7 @@
 	}
 
 	make(page_name) {
-		const assets = [
-			'/assets/js/marketplace.min.js'
-		];
-
-		frappe.require(assets, () => {
+		frappe.require('marketplace.bundle.js', () => {
 			erpnext.hub.marketplace = new erpnext.hub.Marketplace({
 				parent: this.make_page(true, page_name)
 			});
diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.bundle.js
similarity index 100%
rename from erpnext/public/js/hub/marketplace.js
rename to erpnext/public/js/hub/marketplace.bundle.js
diff --git a/erpnext/public/js/item-dashboard.bundle.js b/erpnext/public/js/item-dashboard.bundle.js
new file mode 100644
index 0000000..2d329e2
--- /dev/null
+++ b/erpnext/public/js/item-dashboard.bundle.js
@@ -0,0 +1,5 @@
+import "../../stock/dashboard/item_dashboard.html";
+import "../../stock/dashboard/item_dashboard_list.html";
+import "../../stock/dashboard/item_dashboard.js";
+import "../../stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html";
+import "../../stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html";
diff --git a/erpnext/public/js/payment/payments.js b/erpnext/public/js/payment/payments.js
index 0d656bc..7df976c 100644
--- a/erpnext/public/js/payment/payments.js
+++ b/erpnext/public/js/payment/payments.js
@@ -1,31 +1,31 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-erpnext.payments = erpnext.stock.StockController.extend({
-	make_payment: function() {
+erpnext.payments = class payments extends erpnext.stock.StockController {
+	make_payment() {
 		var me = this;
 
 		this.dialog = new frappe.ui.Dialog({
 			title: 'Payment'
 		});
-	
+
 		this.dialog.show();
 		this.$body = this.dialog.body;
 		this.set_payment_primary_action();
 		this.make_keyboard();
 		this.select_text()
-	},
+	}
 
-	select_text: function(){
+	select_text(){
 		var me = this;
 		$(this.$body).find('.form-control').click(function(){
 			$(this).select();
 		})
-	},
+	}
 
-	set_payment_primary_action: function(){
+	set_payment_primary_action(){
 		var me = this;
-	
+
 		this.dialog.set_primary_action(__("Submit"), function() {
 			// Allow no ZERO payment
 			$.each(me.frm.doc.payments, function (index, data) {
@@ -36,18 +36,18 @@
 				}
 			});
 		})
-	},
+	}
 
-	make_keyboard: function(){
+	make_keyboard(){
 		var me = this;
 		$(this.$body).empty();
 		$(this.$body).html(frappe.render_template('pos_payment', this.frm.doc))
 		this.show_payment_details();
 		this.bind_keyboard_event()
 		this.clear_amount()
-	},
+	}
 
-	make_multimode_payment: function(){
+	make_multimode_payment(){
 		var me = this;
 
 		if(this.frm.doc.change_amount > 0){
@@ -57,9 +57,9 @@
 		this.payments = frappe.model.add_child(this.frm.doc, 'Multi Mode Payment', "payments");
 		this.payments.mode_of_payment = this.dialog.fields_dict.mode_of_payment.get_value();
 		this.payments.amount = flt(this.payment_val);
-	},
+	}
 
-	show_payment_details: function(){
+	show_payment_details(){
 		var me = this;
 		var multimode_payments = $(this.$body).find('.multimode-payments').empty();
 		if(this.frm.doc.payments.length){
@@ -82,9 +82,9 @@
 		}else{
 			$("<p>No payment mode selected in pos profile</p>").appendTo(multimode_payments)
 		}
-	},
+	}
 
-	set_outstanding_amount: function(){
+	set_outstanding_amount(){
 		this.selected_mode = $(this.$body).find(repl("input[idx='%(idx)s']",{'idx': this.idx}));
 		this.highlight_selected_row()
 		this.payment_val = 0.0
@@ -99,47 +99,47 @@
 		}
 		this.selected_mode.select()
 		this.bind_amount_change_event();
-	},
-	
-	bind_keyboard_event: function(){
+	}
+
+	bind_keyboard_event(){
 		var me = this;
 		this.payment_val = '';
 		this.bind_form_control_event();
 		this.bind_numeric_keys_event();
-	},
+	}
 
-	bind_form_control_event: function(){
+	bind_form_control_event(){
 		var me = this;
 		$(this.$body).find('.pos-payment-row').click(function(){
 			me.idx = $(this).attr("idx");
 			me.set_outstanding_amount()
 		})
-		
+
 		$(this.$body).find('.form-control').click(function(){
 			me.idx = $(this).attr("idx");
 			me.set_outstanding_amount();
 			me.update_paid_amount(true);
 		})
-		
+
 		$(this.$body).find('.write_off_amount').change(function(){
 			me.write_off_amount(flt($(this).val()), precision("write_off_amount"));
 		})
-		
+
 		$(this.$body).find('.change_amount').change(function(){
 			me.change_amount(flt($(this).val()), precision("change_amount"));
 		})
-	},
+	}
 
-	highlight_selected_row: function(){
+	highlight_selected_row(){
 		var me = this;
 		var selected_row = $(this.$body).find(repl(".pos-payment-row[idx='%(idx)s']",{'idx': this.idx}));
 		$(this.$body).find('.pos-payment-row').removeClass('selected-payment-mode')
 		selected_row.addClass('selected-payment-mode')
 		$(this.$body).find('.amount').attr('disabled', true);
 		this.selected_mode.attr('disabled', false);
-	},
-	
-	bind_numeric_keys_event: function(){
+	}
+
+	bind_numeric_keys_event(){
 		var me = this;
 		$(this.$body).find('.pos-keyboard-key').click(function(){
 			me.payment_val += $(this).text();
@@ -147,7 +147,7 @@
 			me.idx = me.selected_mode.attr("idx")
 			me.update_paid_amount()
 		})
-		
+
 		$(this.$body).find('.delete-btn').click(function(){
 			me.payment_val =  cstr(flt(me.selected_mode.val())).slice(0, -1);
 			me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency));
@@ -155,9 +155,9 @@
 			me.update_paid_amount();
 		})
 
-	},
-	
-	bind_amount_change_event: function(){
+	}
+
+	bind_amount_change_event(){
 		var me = this;
 		this.selected_mode.change(function(){
 			me.payment_val =  flt($(this).val()) || 0.0;
@@ -165,9 +165,9 @@
 			me.idx = me.selected_mode.attr("idx")
 			me.update_payment_amount()
 		})
-	},
+	}
 
-	clear_amount: function() {
+	clear_amount() {
 		var me = this;
 		$(this.$body).find('.clr').click(function(e){
 			e.stopPropagation();
@@ -178,9 +178,9 @@
 			me.highlight_selected_row();
 			me.update_payment_amount();
 		})
-	},
+	}
 
-	write_off_amount: function(write_off_amount) {
+	write_off_amount(write_off_amount) {
 		var me = this;
 
 		this.frm.doc.write_off_amount = flt(write_off_amount, precision("write_off_amount"));
@@ -188,17 +188,17 @@
 			precision("base_write_off_amount"));
 		this.calculate_outstanding_amount(false)
 		this.show_amounts()
-	},
+	}
 
-	change_amount: function(change_amount) {
+	change_amount(change_amount) {
 		var me = this;
 
 		this.frm.doc.change_amount = flt(change_amount, precision("change_amount"));
 		this.calculate_write_off_amount()
 		this.show_amounts()
-	},
+	}
 
-	update_paid_amount: function(update_write_off) {
+	update_paid_amount(update_write_off) {
 		var me = this;
 		if(in_list(['change_amount', 'write_off_amount'], this.idx)){
 			var value = me.selected_mode.val();
@@ -213,9 +213,9 @@
 		}else{
 			this.update_payment_amount()
 		}
-	},
+	}
 
-	update_payment_amount: function(){
+	update_payment_amount(){
 		var me = this;
 
 		$.each(this.frm.doc.payments, function(index, data){
@@ -226,9 +226,9 @@
 
 		this.calculate_outstanding_amount(false);
 		this.show_amounts();
-	},
+	}
 
-	show_amounts: function(){
+	show_amounts(){
 		var me = this;
 		$(this.$body).find(".write_off_amount").val(format_currency(this.frm.doc.write_off_amount, this.frm.doc.currency));
 		$(this.$body).find('.paid_amount').text(format_currency(this.frm.doc.paid_amount, this.frm.doc.currency));
@@ -236,4 +236,4 @@
 		$(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, frappe.get_doc(":Company", this.frm.doc.company).default_currency))
 		this.update_invoice();
 	}
-})
\ No newline at end of file
+}
diff --git a/erpnext/public/js/point-of-sale.bundle.js b/erpnext/public/js/point-of-sale.bundle.js
new file mode 100644
index 0000000..fbc4bbb
--- /dev/null
+++ b/erpnext/public/js/point-of-sale.bundle.js
@@ -0,0 +1,8 @@
+import "../../selling/page/point_of_sale/pos_item_selector.js";
+import "../../selling/page/point_of_sale/pos_item_cart.js";
+import "../../selling/page/point_of_sale/pos_item_details.js";
+import "../../selling/page/point_of_sale/pos_number_pad.js";
+import "../../selling/page/point_of_sale/pos_payment.js";
+import "../../selling/page/point_of_sale/pos_past_order_list.js";
+import "../../selling/page/point_of_sale/pos_past_order_summary.js";
+import "../../selling/page/point_of_sale/pos_controller.js";
diff --git a/erpnext/public/js/stock_analytics.js b/erpnext/public/js/stock_analytics.js
index 140c9dc..dfe2c88 100644
--- a/erpnext/public/js/stock_analytics.js
+++ b/erpnext/public/js/stock_analytics.js
@@ -2,8 +2,8 @@
 // License: GNU General Public License v3. See license.txt
 
 
-erpnext.StockAnalytics = erpnext.StockGridReport.extend({
-	init: function(wrapper, opts) {
+erpnext.StockAnalytics = class StockAnalytics extends erpnext.StockGridReport {
+	constructor(wrapper, opts) {
 		var args = {
 			title: __("Stock Analytics"),
 			parent: $(wrapper).find('.layout-main'),
@@ -30,9 +30,33 @@
 
 		if(opts) $.extend(args, opts);
 
-		this._super(args);
-	},
-	setup_columns: function() {
+		super(args);
+
+		this.filters = [
+			{fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty",
+				options:[{label:__("Value"), value:"Value"}, {label:__("Quantity"), value:"Quantity"}],
+				filter: function(val, item, opts, me) {
+					return me.apply_zero_filter(val, item, opts, me);
+				}},
+			{fieldtype:"Select", label: __("Brand"), link:"Brand", fieldname: "brand",
+				default_value: __("Select Brand..."), filter: function(val, item, opts) {
+					return val == opts.default_value || item.brand == val || item._show;
+				}, link_formatter: {filter_input: "brand"}},
+			{fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", fieldname: "warehouse",
+				default_value: __("Select Warehouse...")},
+			{fieldtype:"Date", label: __("From Date"), fieldname: "from_date"},
+			{fieldtype:"Date", label: __("To Date"), fieldname: "to_date"},
+			{fieldtype:"Select", label: __("Range"), fieldname: "range",
+				options:[
+					{label:__("Daily"), value:"Daily"},
+					{label:__("Weekly"), value:"Weekly"},
+					{label:__("Monthly"), value:"Monthly"},
+					{label:__("Quarterly"), value:"Quarterly"},
+					{label:__("Yearly"), value:"Yearly"},
+				]}
+		];
+	}
+	setup_columns() {
 		var std_columns = [
 			{id: "name", name: __("Item"), field: "name", width: 300},
 			{id: "brand", name: __("Brand"), field: "brand", width: 100},
@@ -43,43 +67,21 @@
 
 		this.make_date_range_columns();
 		this.columns = std_columns.concat(this.columns);
-	},
-	filters: [
-		{fieldtype:"Select", label: __("Value or Qty"), fieldname: "value_or_qty",
-			options:[{label:__("Value"), value:"Value"}, {label:__("Quantity"), value:"Quantity"}],
-			filter: function(val, item, opts, me) {
-				return me.apply_zero_filter(val, item, opts, me);
-			}},
-		{fieldtype:"Select", label: __("Brand"), link:"Brand", fieldname: "brand",
-			default_value: __("Select Brand..."), filter: function(val, item, opts) {
-				return val == opts.default_value || item.brand == val || item._show;
-			}, link_formatter: {filter_input: "brand"}},
-		{fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", fieldname: "warehouse",
-			default_value: __("Select Warehouse...")},
-		{fieldtype:"Date", label: __("From Date"), fieldname: "from_date"},
-		{fieldtype:"Date", label: __("To Date"), fieldname: "to_date"},
-		{fieldtype:"Select", label: __("Range"), fieldname: "range",
-			options:[
-				{label:__("Daily"), value:"Daily"},
-				{label:__("Weekly"), value:"Weekly"},
-				{label:__("Monthly"), value:"Monthly"},
-				{label:__("Quarterly"), value:"Quarterly"},
-				{label:__("Yearly"), value:"Yearly"},
-			]}
-	],
-	setup_filters: function() {
+	}
+
+	setup_filters() {
 		var me = this;
-		this._super();
+		super.setup_filters();
 
 		this.trigger_refresh_on_change(["value_or_qty", "brand", "warehouse", "range"]);
 
 		this.show_zero_check();
-	},
-	init_filter_values: function() {
-		this._super();
+	}
+	init_filter_values() {
+		super.init_filter_values();
 		this.filter_inputs.range && this.filter_inputs.range.val('Monthly');
-	},
-	prepare_data: function() {
+	}
+	prepare_data() {
 		var me = this;
 
 		if(!this.data) {
@@ -112,8 +114,8 @@
 		this.prepare_balances();
 		this.update_groups();
 
-	},
-	prepare_balances: function() {
+	}
+	prepare_balances() {
 		var me = this;
 		var from_date = frappe.datetime.str_to_obj(this.from_date);
 		var to_date = frappe.datetime.str_to_obj(this.to_date);
@@ -164,8 +166,8 @@
 				item.closing_qty_value += diff;
 			}
 		}
-	},
-	update_groups: function() {
+	}
+	update_groups() {
 		var me = this;
 		$.each(this.data, function(i, item) {
 			// update groups
@@ -192,8 +194,8 @@
 				}
 			}
 		});
-	},
-	show_stock_ledger: function(item_code) {
+	}
+	show_stock_ledger(item_code) {
 		frappe.route_options = {
 			item_code: item_code,
 			from_date: this.from_date,
@@ -201,5 +203,5 @@
 		};
 		frappe.set_route("query-report", "Stock Ledger");
 	}
-});
+};
 
diff --git a/erpnext/public/js/stock_grid_report.js b/erpnext/public/js/stock_grid_report.js
index 832fd3e..752fafd 100644
--- a/erpnext/public/js/stock_grid_report.js
+++ b/erpnext/public/js/stock_grid_report.js
@@ -1,16 +1,16 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-erpnext.StockGridReport = frappe.views.TreeGridReport.extend({
-	get_item_warehouse: function(warehouse, item) {
+erpnext.StockGridReport = class StockGridReport extends frappe.views.TreeGridReport {
+	get_item_warehouse(warehouse, item) {
 		if(!this.item_warehouse[item]) this.item_warehouse[item] = {};
 		if(!this.item_warehouse[item][warehouse]) this.item_warehouse[item][warehouse] = {
 			balance_qty: 0.0, balance_value: 0.0, fifo_stack: []
 		};
 		return this.item_warehouse[item][warehouse];
-	},
+	}
 
-	get_value_diff: function(wh, sl, is_fifo) {
+	get_value_diff(wh, sl, is_fifo) {
 		// value
 		if(sl.qty > 0) {
 			// incoming - rate is given
@@ -59,8 +59,8 @@
 		wh.balance_qty += sl.qty;
 		wh.balance_value += value_diff;
 		return value_diff;
-	},
-	get_fifo_value_diff: function(wh, sl) {
+	}
+	get_fifo_value_diff(wh, sl) {
 		// get exact rate from fifo stack
 		var fifo_stack = (wh.fifo_stack || []).reverse();
 		var fifo_value_diff = 0.0;
@@ -89,9 +89,9 @@
 		// reset the updated stack
 		wh.fifo_stack = fifo_stack.reverse();
 		return -fifo_value_diff;
-	},
+	}
 
-	get_serialized_value_diff: function(sl) {
+	get_serialized_value_diff(sl) {
 		var me = this;
 
 		var value_diff = 0.0;
@@ -103,9 +103,9 @@
 		});
 
 		return value_diff;
-	},
+	}
 
-	get_serialized_buying_rates: function() {
+	get_serialized_buying_rates() {
 		var serialized_buying_rates = {};
 
 		if (frappe.report_dump.data["Serial No"]) {
@@ -115,5 +115,5 @@
 		}
 
 		return serialized_buying_rates;
-	},
-});
+	}
+};
diff --git a/erpnext/public/js/telephony.js b/erpnext/public/js/telephony.js
index 9548d6c..1c3e314 100644
--- a/erpnext/public/js/telephony.js
+++ b/erpnext/public/js/telephony.js
@@ -1,19 +1,19 @@
-frappe.ui.form.ControlData = frappe.ui.form.ControlData.extend( {
+frappe.ui.form.ControlData = class ControlData extends frappe.ui.form.ControlData  {
 	make_input() {
-		this._super();
+		super.make_input();
 		if (this.df.options == 'Phone') {
 			this.setup_phone();
 		}
 		if (this.frm && this.frm.fields_dict) {
 			Object.values(this.frm.fields_dict).forEach(function(field) {
-				if (field.df.read_only === 1 && field.df.options === 'Phone' 
+				if (field.df.read_only === 1 && field.df.options === 'Phone'
 					&& field.disp_area.style[0] != 'display' && !field.has_icon) {
 					field.setup_phone();
 					field.has_icon = true;
 				}
 			});
 		}
-	},
+	}
 	setup_phone() {
 		if (frappe.phone_call.handler) {
 			let control = this.df.read_only ? '.control-value' : '.control-input';
@@ -30,4 +30,4 @@
 				});
 		}
 	}
-});
+};
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 19c9073..472746a 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -48,31 +48,24 @@
 		return cint(frappe.boot.sysdefaults.allow_stale);
 	},
 
-	setup_serial_no: function() {
-		var grid_row = cur_frm.open_grid_row();
-		if(!grid_row || !grid_row.grid_form.fields_dict.serial_no ||
-			grid_row.grid_form.fields_dict.serial_no.get_status()!=="Write") return;
+	setup_serial_or_batch_no: function() {
+		let grid_row = cur_frm.open_grid_row();
+		if (!grid_row || !grid_row.grid_form.fields_dict.serial_no ||
+			grid_row.grid_form.fields_dict.serial_no.get_status() !== "Write") return;
 
-		var $btn = $('<button class="btn btn-sm btn-default">'+__("Add Serial No")+'</button>')
-			.appendTo($("<div>")
-				.css({"margin-bottom": "10px", "margin-top": "10px"})
-				.appendTo(grid_row.grid_form.fields_dict.serial_no.$wrapper));
+		frappe.model.get_value('Item', {'name': grid_row.doc.item_code},
+			['has_serial_no', 'has_batch_no'], ({has_serial_no, has_batch_no}) => {
+				Object.assign(grid_row.doc, {has_serial_no, has_batch_no});
 
-		var me = this;
-		$btn.on("click", function() {
-			let callback = '';
-			let on_close = '';
-
-			frappe.model.get_value('Item', {'name':grid_row.doc.item_code}, 'has_serial_no',
-				(data) => {
-					if(data) {
-						grid_row.doc.has_serial_no = data.has_serial_no;
-						me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
-							callback, on_close, true);
-					}
+				if (has_serial_no) {
+					attach_selector_button(__("Add Serial No"),
+						grid_row.grid_form.fields_dict.serial_no.$wrapper, this, grid_row);
+				} else if (has_batch_no) {
+					attach_selector_button(__("Pick Batch No"),
+						grid_row.grid_form.fields_dict.batch_no.$wrapper, this, grid_row);
 				}
-			);
-		});
+			}
+		);
 	},
 
 	route_to_adjustment_jv: (args) => {
@@ -743,3 +736,14 @@
 		});
 	}
 });
+
+function attach_selector_button(inner_text, append_loction, context, grid_row) {
+	let $btn_div = $("<div>").css({"margin-bottom": "10px", "margin-top": "10px"})
+		.appendTo(append_loction);
+	let $btn = $(`<button class="btn btn-sm btn-default">${inner_text}</button>`)
+		.appendTo($btn_div);
+
+	$btn.on("click", function() {
+		context.show_serial_batch_selector(grid_row.frm, grid_row.doc, "", "", true);
+	});
+}
diff --git a/erpnext/public/js/utils/customer_quick_entry.js b/erpnext/public/js/utils/customer_quick_entry.js
index ebe6cd9..efb8dd9 100644
--- a/erpnext/public/js/utils/customer_quick_entry.js
+++ b/erpnext/public/js/utils/customer_quick_entry.js
@@ -1,17 +1,17 @@
 frappe.provide('frappe.ui.form');
 
-frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
-	init: function(doctype, after_insert) {
+frappe.ui.form.CustomerQuickEntryForm = class CustomerQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+	constructor(doctype, after_insert) {
+		super(doctype, after_insert);
 		this.skip_redirect_on_error = true;
-		this._super(doctype, after_insert);
-	},
+	}
 
-	render_dialog: function() {
+	render_dialog() {
 		this.mandatory = this.mandatory.concat(this.get_variant_fields());
-		this._super();
-	},
+		super.render_dialog();
+	}
 
-	get_variant_fields: function() {
+	get_variant_fields() {
 		var variant_fields = [{
 			fieldtype: "Section Break",
 			label: __("Primary Contact Details"),
@@ -77,5 +77,5 @@
 		}];
 
 		return variant_fields;
-	},
-})
\ No newline at end of file
+	}
+}
diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js
index 27ef107..7e0198d 100644
--- a/erpnext/public/js/utils/item_quick_entry.js
+++ b/erpnext/public/js/utils/item_quick_entry.js
@@ -1,27 +1,27 @@
 frappe.provide('frappe.ui.form');
 
-frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
-	init: function(doctype, after_insert) {
-		this._super(doctype, after_insert);
-	},
+frappe.ui.form.ItemQuickEntryForm = class ItemQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+	constructor(doctype, after_insert) {
+		super(doctype, after_insert);
+	}
 
-	render_dialog: function() {
+	render_dialog() {
 		this.mandatory = this.get_variant_fields().concat(this.mandatory);
 		this.mandatory = this.mandatory.concat(this.get_attributes_fields());
 		this.check_naming_series_based_on();
-		this._super();
+		super.render_dialog();
 		this.init_post_render_dialog_operations();
 		this.preset_fields_for_template();
 		this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.'))
-	},
+	}
 
-	check_naming_series_based_on: function() {
+	check_naming_series_based_on() {
 		if (frappe.defaults.get_default("item_naming_by") === "Naming Series") {
 			this.mandatory = this.mandatory.filter(d => d.fieldname !== "item_code");
 		}
-	},
+	}
 
-	init_post_render_dialog_operations: function() {
+	init_post_render_dialog_operations() {
 		this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry"));
 		this.init_for_create_variant_trigger();
 		this.init_for_item_template_trigger();
@@ -29,9 +29,9 @@
 		this.toggle_manufacturer_fields();
 		this.dialog.get_field("item_template").df.hidden = 1;
 		this.dialog.get_field("item_template").refresh();
-	},
+	}
 
-	register_primary_action: function() {
+	register_primary_action() {
 		var me = this;
 		this.dialog.set_primary_action(__('Save'), function() {
 			if (me.dialog.working) return;
@@ -59,9 +59,9 @@
 				me.insert(variant_values);
 			}
 		});
-	},
+	}
 
-	insert: function(variant_values) {
+	insert(variant_values) {
 		let me = this;
 		return new Promise(resolve => {
 			frappe.call({
@@ -94,9 +94,9 @@
 				freeze: true
 			});
 		});
-	},
+	}
 
-	open_doc: function() {
+	open_doc() {
 		this.dialog.hide();
 		this.update_doc();
 		if (this.dialog.fields_dict.create_variant.$input.prop("checked")) {
@@ -106,9 +106,9 @@
 		} else {
 			frappe.set_route('Form', this.doctype, this.doc.name);
 		}
-	},
+	}
 
-	get_variant_fields: function() {
+	get_variant_fields() {
 		var variant_fields = [{
 			fieldname: "create_variant",
 			fieldtype: "Check",
@@ -130,9 +130,9 @@
 		}];
 
 		return variant_fields;
-	},
+	}
 
-	get_manufacturing_fields: function() {
+	get_manufacturing_fields() {
 		this.manufacturer_fields = [{
 			fieldtype: 'Link',
 			options: 'Manufacturer',
@@ -148,9 +148,9 @@
 			reqd: 0
 		}];
 		return this.manufacturer_fields;
-	},
+	}
 
-	get_attributes_fields: function() {
+	get_attributes_fields() {
 		var attribute_fields = [{
 			fieldname: 'attribute_html',
 			fieldtype: 'HTML'
@@ -158,18 +158,18 @@
 
 		attribute_fields = attribute_fields.concat(this.get_manufacturing_fields());
 		return attribute_fields;
-	},
+	}
 
-	init_for_create_variant_trigger: function() {
+	init_for_create_variant_trigger() {
 		var me = this;
 
 		this.dialog.fields_dict.create_variant.$input.on("click", function() {
 			me.preset_fields_for_template();
 			me.init_post_template_trigger_operations(false, [], true);
 		});
-	},
+	}
 
-	preset_fields_for_template: function() {
+	preset_fields_for_template() {
 		var for_variant = this.dialog.get_value('create_variant');
 
 		// setup template field, seen and mandatory if variant
@@ -195,9 +195,9 @@
 			f.refresh();
 		});
 
-	},
+	}
 
-	init_for_item_template_trigger: function() {
+	init_for_item_template_trigger() {
 		var me = this;
 
 		me.dialog.fields_dict["item_template"].df.onchange = () => {
@@ -228,9 +228,9 @@
 				me.init_post_template_trigger_operations(false, [], true);
 			}
 		}
-	},
+	}
 
-	init_post_template_trigger_operations: function(is_manufacturer, attributes, attributes_flag) {
+	init_post_template_trigger_operations(is_manufacturer, attributes, attributes_flag) {
 		this.attributes = attributes;
 		this.attribute_values = {};
 		this.attributes_count = attributes.length;
@@ -240,23 +240,23 @@
 		this.toggle_manufacturer_fields();
 		this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes").toggleClass("hide-control", attributes_flag);
 		this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes-header").toggleClass("hide-control", attributes_flag);
-	},
+	}
 
-	toggle_manufacturer_fields: function() {
+	toggle_manufacturer_fields() {
 		var me = this;
 		$.each(this.manufacturer_fields, function(i, dialog_field) {
 			me.dialog.get_field(dialog_field.fieldname).df.hidden = !me.is_manufacturer;
 			me.dialog.get_field(dialog_field.fieldname).df.reqd = dialog_field.fieldname == 'manufacturer' ? me.is_manufacturer : false;
 			me.dialog.get_field(dialog_field.fieldname).refresh();
 		});
-	},
+	}
 
-	initiate_render_attributes: function() {
+	initiate_render_attributes() {
 		this.dialog.fields_dict.attribute_html.$wrapper.find(".attributes").empty();
 		this.render_attributes(this.attributes);
-	},
+	}
 
-	render_attributes: function(attributes) {
+	render_attributes(attributes) {
 		var me = this;
 
 		this.dialog.get_field('attribute_html').toggle(true);
@@ -291,9 +291,9 @@
 				});
 			}
 		});
-	},
+	}
 
-	init_make_control: function(fieldtype, row) {
+	init_make_control(fieldtype, row) {
 		this[row.attribute] = frappe.ui.form.make_control({
 			df: {
 				"fieldtype": fieldtype,
@@ -305,9 +305,9 @@
 			only_input: false
 		});
 		this[row.attribute].make_input();
-	},
+	}
 
-	init_awesomplete_for_attribute: function(row) {
+	init_awesomplete_for_attribute(row) {
 		var me = this;
 
 		this[row.attribute].input.awesomplete = new Awesomplete(this[row.attribute].input, {
@@ -343,9 +343,9 @@
 			me.attribute_values[$(e.target).attr("data-fieldname")] = e.target.value;
 			$(e.target).closest(".frappe-control").toggleClass("has-error", e.target.value ? false : true);
 		});
-	},
+	}
 
-	get_variant_doc: function() {
+	get_variant_doc() {
 		var me = this;
 		var variant_doc = {};
 		var attribute = this.validate_mandatory_attributes();
@@ -381,9 +381,9 @@
 			})
 		}
 		return variant_doc;
-	},
+	}
 
-	validate_mandatory_attributes: function() {
+	validate_mandatory_attributes() {
 		var me = this;
 		var attribute = {};
 		var mandatory = [];
@@ -404,4 +404,4 @@
 		}
 		return attribute;
 	}
-});
\ No newline at end of file
+};
diff --git a/erpnext/public/js/utils/item_selector.js b/erpnext/public/js/utils/item_selector.js
index d04c488..9fc2640 100644
--- a/erpnext/public/js/utils/item_selector.js
+++ b/erpnext/public/js/utils/item_selector.js
@@ -1,5 +1,5 @@
-erpnext.ItemSelector = Class.extend({
-	init: function(opts) {
+erpnext.ItemSelector = class ItemSelector {
+	constructor(opts) {
 		$.extend(this, opts);
 
 		if (!this.item_field) {
@@ -12,9 +12,9 @@
 
 		this.grid = this.frm.get_field("items").grid;
 		this.setup();
-	},
+	}
 
-	setup: function() {
+	setup() {
 		var me = this;
 		if(!this.grid.add_items_button) {
 			this.grid.add_items_button = this.grid.add_custom_button(__('Add Items'), function() {
@@ -26,9 +26,9 @@
 				setTimeout(function() { me.dialog.input.focus(); }, 1000);
 			});
 		}
-	},
+	}
 
-	make_dialog: function() {
+	make_dialog() {
 		this.dialog = new frappe.ui.Dialog({
 			title: __('Add Items')
 		});
@@ -53,9 +53,9 @@
 				me.timeout_id = undefined;
 			}, 500);
 		});
-	},
+	}
 
-	add_item: function(item_code) {
+	add_item(item_code) {
 		// add row or update qty
 		var added = false;
 
@@ -82,9 +82,9 @@
 			]);
 		}
 
-	},
+	}
 
-	render_items: function() {
+	render_items() {
 		let args = {
 			query: this.item_query,
 			filters: {}
@@ -107,4 +107,4 @@
 			me.dialog.results.html(frappe.render_template('item_selector', {'data':r.values}));
 		});
 	}
-});
\ No newline at end of file
+};
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 3333d56..79b6220 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -1,6 +1,6 @@
 
-erpnext.SerialNoBatchSelector = Class.extend({
-	init: function(opts, show_dialog) {
+erpnext.SerialNoBatchSelector = class SerialNoBatchSelector {
+	constructor(opts, show_dialog) {
 		$.extend(this, opts);
 		this.show_dialog = show_dialog;
 		// frm, item, warehouse_details, has_batch, oldest
@@ -12,16 +12,16 @@
 		if(d && d.has_serial_no && !(this.show_dialog == false)) this.has_serial_no = 1;
 
 		this.setup();
-	},
+	}
 
-	setup: function() {
+	setup() {
 		this.item_code = this.item.item_code;
 		this.qty = this.item.qty;
 		this.make_dialog();
 		this.on_close_dialog();
-	},
+	}
 
-	make_dialog: function() {
+	make_dialog() {
 		var me = this;
 
 		this.data = this.oldest ? this.oldest : [];
@@ -176,15 +176,15 @@
 		}
 
 		this.dialog.show();
-	},
+	}
 
-	on_close_dialog: function() {
+	on_close_dialog() {
 		this.dialog.get_close_btn().on('click', () => {
 			this.on_close && this.on_close(this.item);
 		});
-	},
+	}
 
-	validate: function() {
+	validate() {
 		let values = this.values;
 		if(!values.warehouse) {
 			frappe.throw(__("Please select a warehouse"));
@@ -210,7 +210,7 @@
 			}
 			return true;
 		}
-	},
+	}
 
 	update_batch_items() {
 		// clones an items if muliple batches are selected.
@@ -233,14 +233,14 @@
 					'selected_qty', this.values.warehouse);
 			});
 		}
-	},
+	}
 
 	update_serial_no_item() {
 		// just updates serial no for the item
 		if(this.has_serial_no && !this.has_batch) {
 			this.map_row_values(this.item, this.values, 'serial_no', 'qty');
 		}
-	},
+	}
 
 	update_batch_serial_no_items() {
 		// if serial no selected is from different batches, adds new rows for each batch.
@@ -281,14 +281,14 @@
 				});
 			})
 		}
-	},
+	}
 
-	batch_exists: function(batch) {
+	batch_exists(batch) {
 		const batches = this.frm.doc.items.map(data => data.batch_no);
 		return (batches && in_list(batches, batch)) ? true : false;
-	},
+	}
 
-	map_row_values: function(row, values, number, qty_field, warehouse) {
+	map_row_values(row, values, number, qty_field, warehouse) {
 		row.qty = values[qty_field];
 		row.transfer_qty = flt(values[qty_field]) * flt(row.conversion_factor);
 		row[number] = values[number];
@@ -301,9 +301,9 @@
 		}
 
 		this.frm.dirty();
-	},
+	}
 
-	update_total_qty: function() {
+	update_total_qty() {
 		let qty_field = this.dialog.fields_dict.qty;
 		let total_qty = 0;
 
@@ -312,9 +312,9 @@
 		});
 
 		qty_field.set_input(total_qty);
-	},
+	}
 
-	get_batch_fields: function() {
+	get_batch_fields() {
 		var me = this;
 
 		return [
@@ -425,9 +425,9 @@
 				},
 			}
 		];
-	},
+	}
 
-	get_serial_no_fields: function() {
+	get_serial_no_fields() {
 		var me = this;
 		this.serial_list = [];
 
@@ -510,4 +510,4 @@
 			}
 		];
 	}
-});
+};
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
deleted file mode 100644
index 29deada..0000000
--- a/erpnext/public/less/hub.less
+++ /dev/null
@@ -1,375 +0,0 @@
-@import "variables.less";
-@import (reference) "desk.less";
-
-body[data-route*="marketplace"] {
-	.layout-side-section {
-		padding-top: 25px;
-		padding-left: 5px;
-		padding-right: 25px;
-	}
-
-	[data-route], [data-action] {
-		cursor: pointer;
-	}
-
-	.layout-main-section {
-		border: none;
-		font-size: @text-medium;
-		padding-top: 25px;
-
-		@media (max-width: @screen-xs) {
-			padding-left: 20px;
-			padding-right: 20px;
-		}
-	}
-
-	input, textarea {
-		font-size: @text-medium;
-	}
-
-	.hub-image {
-		height: 200px;
-	}
-
-	.hub-image-loading, .hub-image-broken {
-		content: " ";
-		position: absolute;
-		left: 0;
-		height: 100%;
-		width: 100%;
-		background-color: var(--bg-light-gray);
-		display: flex;
-		align-items: center;
-		justify-content: center;
-
-		span {
-			font-size: 32px;
-			color: @text-extra-muted;
-		}
-	}
-
-	.progress-bar {
-		background-color: #89da28;
-	}
-
-	.subpage-title.flex {
-		align-items: flex-start;
-		justify-content: space-between;
-	}
-
-	.hub-card {
-		margin-bottom: 25px;
-		position: relative;
-		border: 1px solid @border-color;
-		border-radius: 4px;
-		overflow: hidden;
-
-		&:hover .hub-card-overlay {
-			display: block;
-		}
-	}
-
-	.hub-card.is-local {
-		&.active {
-			.hub-card-header {
-				background-color: #f4ffe5;
-			}
-
-			.octicon-check {
-				display: inline;
-			}
-		}
-
-		.octicon-check {
-			display: none;
-			position: absolute;
-			font-size: 20px;
-			right: 15px;
-			top: 50%;
-			transform: translateY(-50%);
-		}
-	}
-
-	.hub-card-header {
-		position: relative;
-		padding: 12px 15px;
-		height: 60px;
-		border-bottom: 1px solid @border-color;
-	}
-
-	.hub-card-body {
-		position: relative;
-		height: 200px;
-	}
-
-	.hub-card-overlay {
-		display: none;
-		position: absolute;
-		top: 0;
-		width: 100%;
-		height: 100%;
-		background-color: rgba(0, 0, 0, 0.05);
-	}
-
-	.hub-card-overlay-body {
-		position: relative;
-		height: 100%;
-	}
-
-	.hub-card-overlay-button {
-		position: absolute;
-		right: 15px;
-		bottom: 15px;
-	}
-
-	.hub-card-image {
-		position: relative;
-		width: 100%;
-		height: 100%;
-		object-fit: contain;
-	}
-
-	.hub-search-container {
-		margin-bottom: 20px;
-
-		input {
-			height: 32px;
-		}
-	}
-
-	.hub-sidebar {
-		padding-top: 25px;
-		padding-right: 15px;
-	}
-
-	.hub-sidebar-group {
-		margin-bottom: 10px;
-	}
-
-	.hub-sidebar-item {
-		padding: 5px 8px;
-		margin-bottom: 3px;
-		border-radius: 4px;
-		border: 1px solid transparent;
-
-		&.active, &:hover:not(.is-title) {
-			border-color: @border-color;
-		}
-	}
-
-	.hub-item-image {
-		position: relative;
-		border: 1px solid @border-color;
-		border-radius: 4px;
-		overflow: hidden;
-		height: 200px;
-		width: 200px;
-		display: flex;
-		align-items: center;
-	}
-
-	.hub-item-skeleton-image {
-		border-radius: 4px;
-		background-color: @light-bg;
-		overflow: hidden;
-		height: 200px;
-		width: 200px;
-	}
-
-	.hub-skeleton {
-		background-color: @light-bg;
-		color: @light-bg;
-		max-width: 500px;
-	}
-
-	.hub-item-seller img {
-		width: 50px;
-		height: 50px;
-		border-radius: 4px;
-		border: 1px solid @border-color;
-	}
-
-	.register-title {
-		font-size: @text-regular;
-	}
-
-	.register-form {
-		border: 1px solid @border-color;
-		border-radius: 4px;
-		padding: 15px 25px;
-	}
-
-	.publish-area.filled {
-		.empty-items-container {
-			display: none;
-		}
-	}
-
-	.publish-area.empty {
-		.hub-items-container {
-			display: none;
-		}
-	}
-
-	.publish-area-head {
-		display: flex;
-		justify-content: space-between;
-		margin-bottom: 20px;
-	}
-
-	.hub-list-item {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		border: 1px solid @border-color;
-		margin-bottom: -1px;
-		overflow: hidden;
-	}
-
-	.hub-list-item:first-child {
-		border-top-left-radius: 4px;
-		border-top-right-radius: 4px;
-	}
-	.hub-list-item:last-child {
-		border-bottom-left-radius: 4px;
-		border-bottom-right-radius: 4px;
-	}
-
-	.hub-list-left {
-		display: flex;
-		align-items: center;
-		max-width: 90%;
-	}
-
-	.hub-list-right {
-		padding-right: 15px;
-	}
-
-	.hub-list-image {
-		position: relative;
-		width: 58px;
-		height: 58px;
-		border-right: 1px solid @border-color;
-
-		&::after {
-			font-size: 12px;
-		}
-	}
-
-	.hub-list-body {
-		padding: 12px 15px;
-	}
-
-	.hub-list-title {
-		font-weight: bold;
-	}
-
-	.hub-list-subtitle {
-		color: @text-muted;
-	}
-
-	.selling-item-message-card {
-		max-width: 500px;
-		margin-bottom: 15px;
-		border-radius: 3px;
-		border: 1px solid @border-color;
-		.selling-item-detail {
-			overflow: auto;
-			.item-image {
-				float: left;
-				height: 80px;
-				width: 80px;
-				object-fit: contain;
-				margin: 5px;
-			}
-			.item-name {
-				margin-left: 10px;
-			}
-		}
-		.received-message-container {
-			clear: left;
-			background-color: @light-bg;
-			.received-message {
-				border-top: 1px solid @border-color;
-				padding: 10px;
-			}
-			.frappe-timestamp {
-				float: right;
-			}
-		}
-	}
-
-	.form-container {
-		.frappe-control {
-			max-width: 100% !important;
-		}
-	}
-
-	.form-message {
-		padding-top: 0;
-		padding-bottom: 0;
-		border-bottom: none;
-	}
-
-	.hub-items-container {
-		.hub-items-header {
-			justify-content: space-between;
-			align-items: baseline;
-		}
-	}
-
-	.hub-item-container {
-		overflow: hidden;
-	}
-
-	.hub-item-review-container {
-		margin-top: calc(30vh);
-	}
-
-	.hub-item-dropdown {
-		margin-top: 20px;
-	}
-
-	/* messages page */
-
-	.message-list-item {
-		display: flex;
-		align-items: center;
-		padding: 8px 12px;
-
-		&:not(.active) {
-			filter: grayscale(1);
-			color: @text-muted;
-		}
-
-		&:hover {
-			background-color: @light-bg;
-		}
-
-		.list-item-left {
-			width: 30px;
-			border-radius: 4px;
-			overflow: hidden;
-			margin-right: 15px;
-		}
-
-		.list-item-body {
-			font-weight: bold;
-			padding-bottom: 1px;
-		}
-	}
-
-	.message-container {
-		display: flex;
-		flex-direction: column;
-		border: 1px solid @border-color;
-		border-radius: 3px;
-		height: calc(100vh - 300px);
-		justify-content: space-between;
-		padding: 15px;
-	}
-
-	.message-list {
-		overflow: scroll;
-	}
-}
diff --git a/erpnext/public/less/pos.less b/erpnext/public/less/pos.less
deleted file mode 100644
index b081ed4..0000000
--- a/erpnext/public/less/pos.less
+++ /dev/null
@@ -1,229 +0,0 @@
-@import "../../../../frappe/frappe/public/less/variables.less";
-
-[data-route="point-of-sale"] {
-	.layout-main-section-wrapper {
-		margin-bottom: 0;
-	}
-
-	.pos-items-wrapper {
-		max-height: ~"calc(100vh - 210px)";
-	}
-}
-
-.pos {
-	// display: flex;
-	padding: 15px;
-}
-
-.list-item {
-	min-height: 40px;
-	height: auto;
-}
-
-.cart-container {
-	padding: 0 15px;
-	// flex: 2;
-	display: inline-block;
-	width: 39%;
-	vertical-align: top;
-}
-
-.item-container {
-	padding: 0 15px;
-	// flex: 3;
-	display: inline-block;
-	width: 60%;
-	vertical-align: top;
-}
-
-.search-field {
-	width: 60%;
-
-	input::placeholder {
-		font-size: @text-medium;
-	}
-}
-
-.item-group-field {
-	width: 40%;
-	margin-left: 15px;
-}
-
-.cart-wrapper {
-	margin-bottom: 12px;
-	.list-item__content:not(:first-child) {
-		justify-content: flex-end;
-	}
-
-	.list-item--head .list-item__content:nth-child(2) {
-		flex: 1.5;
-	}
-}
-
-.cart-items {
-	height: 150px;
-	overflow: auto;
-
-	.list-item.current-item {
-		background-color: @light-yellow;
-	}
-
-	.list-item.current-item.qty input {
-		border: 1px solid @brand-primary;
-		font-weight: bold;
-	}
-
-	.list-item.current-item.disc .discount {
-		font-weight: bold;
-	}
-
-	.list-item.current-item.rate .rate {
-		font-weight: bold;
-	}
-
-	.list-item .quantity {
-		flex: 1.5;
-	}
-
-	input {
-		text-align: right;
-		height: 22px;
-		font-size: @text-medium;
-	}
-}
-
-.fields {
-	display: flex;
-}
-
-.pos-items-wrapper {
-	max-height: 480px;
-	overflow-y: auto;
-}
-
-.pos-items {
-	overflow: hidden;
-}
-
-.pos-item-wrapper {
-	display: flex;
-	flex-direction: column;
-	position: relative;
-	width: 25%;
-}
-
-.image-view-container {
-	display: block;
-}
-
-.image-view-container .image-field {
-	height: auto;
-}
-
-.empty-state {
-	height: 100%;
-	position: relative;
-
-	span {
-		position: absolute;
-		color: @text-muted;
-		font-size: @text-medium;
-		top: 50%;
-		left: 50%;
-		transform: translate(-50%, -50%);
-	}
-}
-
-@keyframes yellow-fade {
-	0% {background-color: @light-yellow;}
-	100% {background-color: transparent;}
-}
-
-.highlight {
-	animation: yellow-fade 1s ease-in 1;
-}
-
-input[type=number]::-webkit-inner-spin-button,
-input[type=number]::-webkit-outer-spin-button {
-	-webkit-appearance: none;
-	margin: 0;
-}
-
-// number pad
-
-.number-pad {
-	border-collapse: collapse;
-	cursor: pointer;
-	display: table;
-}
-.num-row {
-	display: table-row;
-}
-.num-col {
-	display: table-cell;
-	border: 1px solid @border-color;
-
-	& > div {
-		width: 50px;
-		height: 50px;
-		text-align: center;
-		line-height: 50px;
-	}
-
-	&.active {
-		background-color: @light-yellow;
-	}
-
-	&.brand-primary {
-		background-color: @brand-primary;
-		color: #ffffff;
-	}
-}
-
-// taxes, totals and discount area
-.discount-amount {
-	.discount-inputs {
-		display: flex;
-		flex-direction: column;
-		padding: 15px 0;
-	}
-
-	input:first-child {
-		margin-bottom: 10px;
-	}
-}
-
-.taxes-and-totals {
-	border-top: 1px solid @border-color;
-
-	.taxes {
-		display: flex;
-		flex-direction: column;
-		padding: 15px 0;
-		align-items: flex-end;
-
-		& > div:first-child {
-			margin-bottom: 10px;
-		}
-	}
-}
-
-.grand-total {
-	border-top: 1px solid @border-color;
-
-	.list-item {
-		height: 60px;
-	}
-
-	.grand-total-value {
-		font-size: 18px;
-	}
-}
-
-.rounded-total-value {
-  font-size: 18px;
-}
-
-.quantity-total {
-  font-size: 18px;
-}
\ No newline at end of file
diff --git a/erpnext/public/less/products.less b/erpnext/public/less/products.less
deleted file mode 100644
index 5e744ce..0000000
--- a/erpnext/public/less/products.less
+++ /dev/null
@@ -1,71 +0,0 @@
-@import "variables.less";
-
-.products-list .product-image {
-	display: inline-block;
-	width: 160px;
-	height: 160px;
-	object-fit: contain;
-	margin-right: 1rem;
-}
-
-.product-image.no-image {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	font-size: 3rem;
-	color: var(--gray);
-	background: var(--light);
-}
-
-.product-image a {
-	text-decoration: none;
-}
-
-.filter-options {
-	margin-left: -5px;
-	padding-left: 5px;
-	max-height: 300px;
-	overflow: auto;
-}
-
-.item-slideshow-image {
-	height: 3rem;
-	width: 3rem;
-	object-fit: contain;
-	padding: 0.5rem;
-	border: 1px solid @border-color;
-	border-radius: 4px;
-	cursor: pointer;
-
-	&:hover, &.active {
-		border-color: var(--primary);
-	}
-}
-
-.address-card {
-	cursor: pointer;
-	position: relative;
-
-	.check {
-		display: none;
-	}
-
-	&.active {
-		border-color: var(--primary);
-
-		.check {
-			display: inline-flex;
-		}
-	}
-}
-
-.check {
-	display: inline-flex;
-    padding: 0.25rem;
-    background: var(--primary);
-    color: white;
-    border-radius: 50%;
-	font-size: 12px;
-	width: 24px;
-	height: 24px;
-}
\ No newline at end of file
diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less
deleted file mode 100644
index ac878de..0000000
--- a/erpnext/public/less/website.less
+++ /dev/null
@@ -1,388 +0,0 @@
-@import "variables.less";
-
-.web-long-description {
-	font-size: 18px;
-	line-height: 200%;
-}
-
-.web-page-content {
-	margin-bottom: 30px;
-}
-
-.item-stock {
-	margin-bottom: 10px !important;
-}
-
-.product-link {
-	display: block;
-	text-align: center;
-}
-
-
-.product-image img {
-	max-height: 500px;
-	margin: 0 auto;
-}
-
-@media (max-width: 767px) {
-	.product-image {
-		height: 0px;
-		padding: 0px 0px 100%;
-		overflow: hidden;
-	}
-}
-
-.product-image-square {
-	width: 100%;
-	height: 0;
-	padding: 50% 0px;
-	background-size: cover;
-	background-repeat: no-repeat;
-	background-position: center top;
-}
-
-.product-image.missing-image {
-	.product-image-square;
-	position: relative;
-	background-color: @light-border-color;
-}
-
-.product-image.missing-image .octicon {
-	font-size: 32px;
-	color: @border-color;
-}
-
-.product-search {
-	margin-bottom: 15px;
-}
-
-
-@media (max-width: 767px) {
-	.product-search {
-		width: 100%;
-	}
-}
-
-.borderless td, .borderless th {
-  border-bottom: 1px solid @light-border-color;
-  padding-left:0px !important;
-  line-height: 1.8em !important;
-}
-
-.item-desc {
-	 border-top: 2px solid @light-border-color;
-	 padding-top:10px;
-}
-
-.featured-products {
-	border-top: 1px solid @light-border-color;
-}
-
-.transaction-list-item {
-	.indicator {
-		font-weight: inherit;
-		color: @text-muted;
-	}
-
-	.transaction-time {
-		margin-top: 5px;
-	}
-
-}
-
-// order.html
-.transaction-subheading {
-	.indicator {
-		font-weight: inherit;
-		color: @text-muted;
-	}
-}
-
-.order-container {
-	margin: 50px 0px;
-
-	.order-item-header .h6 {
-		padding: 7px 15px;
-	}
-
-	.order-items {
-		margin: 30px 0px 0px;
-	}
-
-	.order-item-table {
-		margin: 0px -15px;
-	}
-
-	.order-item-header {
-		border-bottom: 1px solid #d1d8dd;
-	}
-
-	.order-image-col {
-		padding-right: 0px;
-	}
-
-	.order-image {
-		max-width: 55px;
-		max-height: 55px;
-		margin-top: -5px;
-	}
-
-	.order-taxes {
-		margin-top: 30px;
-
-		.row {
-			margin-top: 15px;
-		}
-	}
-
-	.tax-grand-total-row {
-		padding-top: 15px;
-		padding-bottom: 30px;
-	}
-
-	.tax-grand-total {
-		display: inline-block;
-		font-size: 16px;
-		font-weight: bold;
-		margin-top: 5px;
-	}
-}
-
-.cart-container {
-	margin: 50px 0px;
-
-	.checkout {
-		margin-bottom:15px;
-	}
-
-	.cart-item-header .h6 {
-		padding: 7px 15px;
-	}
-
-	.cart-items {
-		margin: 30px 0px 0px;
-	}
-
-	.cart-item-table {
-		margin: 0px -15px;
-	}
-
-	.cart-item-header {
-		border-bottom: 1px solid #d1d8dd;
-	}
-
-	.cart-image-col {
-		padding-right: 0px;
-	}
-
-	.cart-image {
-		max-width: 55px;
-		max-height: 55px;
-		margin-top: -5px;
-	}
-
-	.cart-taxes {
-		margin-top: 30px;
-
-		.row {
-			margin-top: 15px;
-		}
-	}
-
-	.tax-grand-total-row {
-		border-top: 1px solid @border-color;
-		padding-top: 15px;
-	}
-
-	.cart-addresses {
-		margin-top: 50px;
-	}
-}
-
-.cart-items-dropdown .cart-dropdown,
-.item_name_dropdown {
-	display: none;
-
-}
-
-.cart-dropdown-container {
-	width: 400px;
-	padding: 15px;
-
-	.item-price {
-		display: block !important;
-		padding-bottom: 10px;
-	}
-
-	.cart-item-header {
-		border-bottom: 1px solid #d1d8dd;
-	}
-
-	.cart-items-dropdown {
-		max-height: 350px;
-	}
-
-	.cart-items-dropdown .cart-dropdown {
-		display:block;
-		margin-top:15px;
-	}
-
-	.item_name_dropdown {
-		display:block;
-	}
-
-	.item-description,
-	.cart-items .checkout,
-	.item_name_and_description {
-		display: none;
-	}
-
-	.checkout-btn {
-		padding-bottom:25px;
-	}
-	.col-name-description {
-		margin-bottom:8px;
-	}
-}
-
-// .number-spinner {
-// 	width:100px;
-// 	margin-top:5px;
-// }
-
-.cart-btn {
-	border-color: #ccc;
-}
-.cart-qty {
-	text-align:center;
-}
-
-.product-list-link {
-	.row {
-		border-bottom: 1px solid @light-border-color;
-	}
-
-	.row:hover {
-		background-color: @light-bg;
-	}
-
-	.row > div {
-		padding-top: 15px;
-		padding-bottom: 15px;
-	}
-}
-
-.product-list-link:first-child .row {
-	border-top: 1px solid @light-border-color;
-}
-
-.item-group-nav-buttons {
-	margin-top: 15px;
-}
-
-.footer-subscribe {
-	.btn-default {
-		background-color: transparent;
-		border: 1px solid @border-color;
-	}
-}
-
-@media (min-width: 992px) {
-	.footer-subscribe {
-		max-width: 350px;
-	}
-}
-
-.item-group-content {
-	margin-top: 30px;
-}
-
-.item-group-slideshow {
-	margin-bottom: 1rem;
-}
-
-.product-image-img {
-	border: 1px solid @light-border-color;
-	border-radius: 3px;
-}
-
-.product-text {
-	word-wrap: break-word;
-	height: 75px;
-	display: block; /* Fallback for non-webkit */
-	display: -webkit-box;
-	max-width: 100%;
-	margin: 0 auto;
-	-webkit-line-clamp: 3;
-	-webkit-box-orient: vertical;
-	overflow: hidden;
-	text-overflow: ellipsis;
-}
-
-.product-image-wrapper {
-	padding-bottom: 40px;
-}
-
-.duration-bar {
-  display: inline-block;
-  color: white;
-  background: #8FD288;
-  padding: 3px;
-}
-
-.duration-invisible {
-  visibility: hidden;
-}
-
-.duration-value {
-  float: right;
-}
-
-.bar-outer-text {
-  color: #8FD288;
-  background: none;
-  float: none;
-  border: none;
-}
-
-.bom-spec {
-	margin-bottom: 20px;
-}
-
-.modal-title {
-	margin-top: 5px;
-}
-
-.modal-header {
-	padding: 10px 15px;
-}
-// For Item Alternate Image
-.item-alternative-image {
-	padding: 5px;
-	margin-bottom: 5px;
-
-	&:hover {
-		border-color: @brand-primary;
-	}
-}
-
-.item-slideshow-image {
-	height: 3rem;
-	width: 3rem;
-	object-fit: contain;
-	padding: 0.5rem;
-	border: 1px solid @border-color;
-	border-radius: 4px;
-	cursor: pointer;
-
-	&:hover, &.active {
-		border-color: @brand-primary;
-	}
-}
-
-.section-products {
-	.card-img-top {
-		max-height: 300px;
-		object-fit: contain;
-	}
-}
\ No newline at end of file
diff --git a/erpnext/public/less/email.less b/erpnext/public/scss/email.bundle.scss
similarity index 60%
rename from erpnext/public/less/email.less
rename to erpnext/public/scss/email.bundle.scss
index 4077c49..3c0b918 100644
--- a/erpnext/public/less/email.less
+++ b/erpnext/public/scss/email.bundle.scss
@@ -1,14 +1,14 @@
-@import "../../../../frappe/frappe/public/less/variables.less";
+@import "frappe/public/scss/desk/variables";
 
 .panel-header {
-	background-color: @light-bg;
-	border: 1px solid @border-color;
+	background-color: var(--bg-color);
+	border: 1px solid $border-color;
 	border-radius: 3px 3px 0 0;
 }
 
 .panel-body {
 	background-color: #fff;
-	border: 1px solid @border-color;
+	border: 1px solid $border-color;
 	border-top: none;
 	border-radius: 0 0 3px 3px;
 	overflow-wrap: break-word;
@@ -22,11 +22,11 @@
 }
 
 .sender-avatar-placeholder {
-	.sender-avatar;
+	@extend .sender-avatar;
 
 	line-height: 24px;
 	text-align: center;
-	color: @border-color;
-	border: 1px solid @border-color;
+	color: $border-color;
+	border: 1px solid $border-color;
 	background-color: #fff;
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/scss/erpnext-web.bundle.scss b/erpnext/public/scss/erpnext-web.bundle.scss
new file mode 100644
index 0000000..6ef1892
--- /dev/null
+++ b/erpnext/public/scss/erpnext-web.bundle.scss
@@ -0,0 +1,2 @@
+@import "./shopping_cart";
+@import "./website";
diff --git a/erpnext/public/scss/erpnext.bundle.scss b/erpnext/public/scss/erpnext.bundle.scss
new file mode 100644
index 0000000..d3313c7
--- /dev/null
+++ b/erpnext/public/scss/erpnext.bundle.scss
@@ -0,0 +1,3 @@
+@import "./erpnext";
+@import "./call_popup";
+@import "./point-of-sale";
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/scss/erpnext.scss
similarity index 81%
rename from erpnext/public/less/erpnext.less
rename to erpnext/public/scss/erpnext.scss
index 4076ebe..0e61861 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/scss/erpnext.scss
@@ -1,4 +1,4 @@
-@import "variables.less";
+@import "frappe/public/scss/desk/variables";
 
 .erpnext-footer {
 	margin: 11px auto;
@@ -141,7 +141,7 @@
 	}
 
 	.pos-payment-row {
-		border-bottom:1px solid @border-color;
+		border-bottom:1px solid $border-color;
 		margin: 2px 0px 5px 0px;
 		height: 60px;
 		margin-top: 0px;
@@ -149,12 +149,12 @@
 	}
 
 	.pos-payment-row:hover, .pos-keyboard-key:hover{
-		background-color: @light-bg;
+		background-color: var(--bg-color);
 		cursor: pointer;
 	}
 
 	.pos-keyboard-key, .delete-btn {
-		border: 1px solid @border-color;
+		border: 1px solid $border-color;
 		height:85px;
 		width:85px;
 		margin:10px 10px;
@@ -165,7 +165,7 @@
 	}
 
 	.numeric-keypad {
-		border: 1px solid @border-color;
+		border: 1px solid $border-color;
 		height:69px;
 		width:69px;
 		font-size:20px;
@@ -192,13 +192,13 @@
 		background-color: #fff;
 		margin-left:-4px;
 
-		@media (max-width: @screen-md) {
+		@media (max-width: map-get($grid-breakpoints, "xl")) {
 			height: 45px;
 			width: 45px;
 			font-size: 14px;
 		}
 
-		@media (max-width: @screen-sm) {
+		@media (max-width: map-get($grid-breakpoints, "lg")) {
 			height: 40px;
 			width: 40px;
 		}
@@ -209,21 +209,21 @@
 
 		& > .row > button {
 			border: none;
-			border-right: 1px solid @border-color;
-			border-bottom: 1px solid @border-color;
+			border-right: 1px solid $border-color;
+			border-bottom: 1px solid $border-color;
 
 			&:first-child {
-				border-left: 1px solid @border-color;
+				border-left: 1px solid $border-color;
 			}
 		}
 
 		& > .row:first-child > button {
-			border-top: 1px solid @border-color;
+			border-top: 1px solid $border-color;
 		}
 	}
 
 	.pos-pay {
-		background-color: @brand-primary;
+		background-color: var(--primary);
 		border: none;
 	}
 
@@ -236,13 +236,13 @@
 	}
 
 	.list-row-head.pos-invoice-list {
-		border-top: 1px solid @border-color;
+		border-top: 1px solid $border-color;
 	}
 
 	.modal-dialog {
 		width: 750px;
 
-		@media (max-width: @screen-xs) {
+		@media (max-width: map-get($grid-breakpoints, 'md')) {
 			width: auto;
 
 			.modal-content {
@@ -251,7 +251,7 @@
 		}
 	}
 
-	@media (max-width: @screen-xs) {
+	@media (max-width: map-get($grid-breakpoints, 'md')) {
 		.amount-row h3 {
 			font-size: 15px;
 		}
@@ -271,7 +271,7 @@
 	}
 
 	.selected-payment-mode {
-		background-color: @light-bg;
+		background-color: var(--bg-color);
 		cursor: pointer;
 	}
 
@@ -291,7 +291,7 @@
 		padding: 9px 15px;
 		font-size: 12px;
 		margin: 0px;
-		border-bottom: 1px solid @border-color;
+		border-bottom: 1px solid $border-color;
 
 		.cell {
 			display: table-cell;
@@ -313,17 +313,17 @@
 
 	.pos-bill-header {
 		background-color: #f5f7fa;
-		border: 1px solid @border-color;
+		border: 1px solid $border-color;
 		padding: 13px 15px;
 	}
 
 	.pos-list-row.active {
-		background-color: @light-yellow;
+		background-color: var(--fg-hover-color);
 	}
 
 	.totals-area {
-		border-right: 1px solid @border-color;
-		border-left: 1px solid @border-color;
+		border-right: 1px solid $border-color;
+		border-left: 1px solid $border-color;
 		margin-bottom: 15px;
 	}
 
@@ -332,12 +332,12 @@
 	}
 
 	.item-cart-items {
-		height: ~"calc(100vh - 526px)";
+		height: calc(100vh - 526px);
 		overflow: auto;
-		border: 1px solid @border-color;
+		border: 1px solid $border-color;
 		border-top: none;
 
-		@media (max-width: @screen-xs) {
+		@media (max-width: map-get($grid-breakpoints, 'md')) {
 			height: 30vh;
 		}
 	}
@@ -359,12 +359,12 @@
 	}
 
 	.item-list {
-		border: 1px solid @border-color;
+		border: 1px solid $border-color;
 		border-top: none;
-		max-height: ~"calc(100vh - 190px)";
+		max-height: calc(100vh - 190px);
 		overflow: auto;
 
-		@media (max-width: @screen-xs) {
+		@media (max-width: map-get($grid-breakpoints, 'md')) {
 			max-height: initial;
 		}
 
@@ -402,7 +402,7 @@
 		&> .pos-list-row {
 			border: none;
 
-			@media (max-width: @screen-md) {
+			@media (max-width: map-get($grid-breakpoints, 'xl')) {
 				padding: 5px 15px;
 			}
 		}
@@ -420,7 +420,7 @@
 		justify-content: center;
 		align-items: center;
 		cursor: pointer;
-		background-color: @light-bg;
+		background-color: var(--bg-color);
 		min-height: 200px;
 	}
 
@@ -428,7 +428,7 @@
 		cursor: pointer;
 	}
 
-	@media (max-width: @screen-xs) {
+	@media (max-width: map-get($grid-breakpoints, 'md')) {
 		.page-actions {
 			max-width: 110px;
 		}
@@ -491,4 +491,4 @@
 
 .exercise-col {
 	padding: 10px;
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index 0bb8e68..9bdaa8d 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -129,11 +129,20 @@
 				@extend .pointer-no-select;
 				border-radius: var(--border-radius-md);
 				box-shadow: var(--shadow-base);
+				position: relative;
 
 				&:hover {
 					transform: scale(1.02, 1.02);
 				}
 
+				.item-qty-pill {
+					position: absolute;
+					display: flex;
+					margin: var(--margin-sm);
+					justify-content: flex-end;
+					right: 0px;
+				}
+
 				.item-display {
 					display: flex;
 					align-items: center;
@@ -766,9 +775,10 @@
 		> .payment-modes {
 			display: flex;
 			padding-bottom: var(--padding-sm);
-			margin-bottom: var(--margin-xs);
+			margin-bottom: var(--margin-sm);
 			overflow-x: scroll;
 			overflow-y: hidden;
+			flex-shrink: 0;
 
 			> .payment-mode-wrapper {
 				min-width: 40%;
@@ -825,9 +835,24 @@
 		> .fields-numpad-container {
 			display: flex;
 			flex: 1;
+			height: 100%;
+    		position: relative;
+			justify-content: flex-end;
 
 			> .fields-section {
 				flex: 1;
+				position: absolute;
+				display: flex;
+				flex-direction: column;
+				width: 50%;
+				height: 100%;
+				top: 0;
+				left: 0;
+				padding-bottom: var(--margin-md);
+
+				.invoice-fields {
+					overflow-y: scroll;
+				}
 			}
 
 			> .number-pad {
@@ -835,6 +860,7 @@
 				display: flex;
 				justify-content: flex-end;
 				align-items: flex-end;
+				max-width: 50%;
 
 				.numpad-container {
 					display: grid;
@@ -861,6 +887,7 @@
 			margin-bottom: var(--margin-sm);
 			justify-content: center;
 			flex-direction: column;
+			flex-shrink: 0;
 
 			> .totals {
 				display: flex;
diff --git a/erpnext/regional/germany/setup.py b/erpnext/regional/germany/setup.py
index ac1f543..c1fa6e4 100644
--- a/erpnext/regional/germany/setup.py
+++ b/erpnext/regional/germany/setup.py
@@ -1,11 +1,24 @@
 import os
 import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 
 
 def setup(company=None, patch=True):
+	make_custom_fields()
 	add_custom_roles_for_reports()
 
 
+def make_custom_fields():
+	custom_fields = {
+		'Party Account': [
+			dict(fieldname='debtor_creditor_number', label='Debtor/Creditor Number',
+			fieldtype='Data', insert_after='account', translatable=0)
+		]
+	}
+
+	create_custom_fields(custom_fields)
+
+
 def add_custom_roles_for_reports():
 	"""Add Access Control to UAE VAT 201."""
 	if not frappe.db.get_value('Custom Role', dict(report='DATEV')):
@@ -16,4 +29,4 @@
 				dict(role='Accounts User'),
 				dict(role='Accounts Manager')
 			]
-		)).insert()
\ No newline at end of file
+		)).insert()
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index f138a80..826d51f 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -56,10 +56,10 @@
 	)
 
 	if not six.PY2:
-		data = data.encode('latin_1')
+		data = data.encode('latin_1', errors='replace')
 
 	header = get_header(filters, csv_class)
-	header = ';'.join(header).encode('latin_1')
+	header = ';'.join(header).encode('latin_1', errors='replace')
 
 	# 1st Row: Header with meta data
 	# 2nd Row: Data heading (Überschrift der Nutzdaten), included in `data` here.
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 699441b..b4e7a88 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -71,13 +71,14 @@
 
 def raise_document_name_too_long_error():
 	title = _('Document ID Too Long')
-	msg = _('As you have E-Invoicing enabled, to be able to generate IRN for this invoice, ')
-	msg += _('document id {} exceed 16 letters. ').format(bold(_('should not')))
+	msg = _('As you have E-Invoicing enabled, to be able to generate IRN for this invoice')
+	msg += ', '
+	msg += _('document id {} exceed 16 letters.').format(bold(_('should not')))
 	msg += '<br><br>'
-	msg += _('You must {} your {} in order to have document id of {} length 16. ').format(
+	msg += _('You must {} your {} in order to have document id of {} length 16.').format(
 		bold(_('modify')), bold(_('naming series')), bold(_('maximum'))
 	)
-	msg += _('Please account for ammended documents too. ')
+	msg += _('Please account for ammended documents too.')
 	frappe.throw(msg, title=title)
 
 def read_json(name):
@@ -847,6 +848,7 @@
 			res = self.make_request('post', self.generate_ewaybill_url, headers, data)
 			if res.get('success'):
 				self.invoice.ewaybill = res.get('result').get('EwbNo')
+				self.invoice.eway_bill_validity = res.get('result').get('EwbValidTill')
 				self.invoice.eway_bill_cancelled = 0
 				self.invoice.update(args)
 				self.invoice.flags.updater_reference = {
@@ -944,6 +946,7 @@
 
 		self.invoice.irn = res.get('Irn')
 		self.invoice.ewaybill = res.get('EwbNo')
+		self.invoice.eway_bill_validity = res.get('EwbValidTill')
 		self.invoice.ack_no = res.get('AckNo')
 		self.invoice.ack_date = res.get('AckDt')
 		self.invoice.signed_einvoice = dec_signed_invoice
@@ -960,6 +963,7 @@
 			'label': _('IRN Generated')
 		}
 		self.update_invoice()
+
 	def attach_qrcode_image(self):
 		qrcode = self.invoice.signed_qr_code
 		doctype = self.invoice.doctype
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 9ded8da..b12e152 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -422,6 +422,9 @@
 		dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
 			depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
 
+		dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
+			depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
+
 		dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
 			depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
 
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 86de90f..dc2bb93 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -879,3 +879,24 @@
 	if total_charges != additional_taxes:
 		diff = additional_taxes - total_charges
 		doc.get('items')[item_count - 1].taxable_value += diff
+
+def get_depreciation_amount(asset, depreciable_value, row):
+	depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+	if row.depreciation_method in ("Straight Line", "Manual"):
+		depreciation_amount = (flt(row.value_after_depreciation) -
+			flt(row.expected_value_after_useful_life)) / depreciation_left
+	else:
+		rate_of_depreciation = row.rate_of_depreciation
+		# if its the first depreciation
+		if depreciable_value == asset.gross_purchase_amount:
+			# as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
+			diff = date_diff(asset.available_for_use_date, row.depreciation_start_date)
+			if diff <= 180:
+				rate_of_depreciation = rate_of_depreciation / 2
+				frappe.msgprint(
+					_('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
+
+		depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
+
+	return depreciation_amount
\ No newline at end of file
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index cbc9478..a5ca7ee 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -3,9 +3,9 @@
 Provide a report and downloadable CSV according to the German DATEV format.
 
 - Query report showing only the columns that contain data, formatted nicely for
-  dispay to the user.
+	dispay to the user.
 - CSV download functionality `download_datev_csv` that provides a CSV file with
-  all required columns. Used to import the data into the DATEV Software.
+	all required columns. Used to import the data into the DATEV Software.
 """
 from __future__ import unicode_literals
 
@@ -88,6 +88,32 @@
 		"fieldtype": "Dynamic Link",
 		"options": "Beleginfo - Art 2",
 		"width": 150
+	},
+	{
+		"label": "Beleginfo - Art 3",
+		"fieldname": "Beleginfo - Art 3",
+		"fieldtype": "Link",
+		"options": "DocType",
+		"width": 100
+	},
+	{
+		"label": "Beleginfo - Inhalt 3",
+		"fieldname": "Beleginfo - Inhalt 3",
+		"fieldtype": "Dynamic Link",
+		"options": "Beleginfo - Art 3",
+		"width": 150
+	},
+	{
+		"label": "Beleginfo - Art 4",
+		"fieldname": "Beleginfo - Art 4",
+		"fieldtype": "Data",
+		"width": 100
+	},
+	{
+		"label": "Beleginfo - Inhalt 4",
+		"fieldname": "Beleginfo - Inhalt 4",
+		"fieldtype": "Data",
+		"width": 150
 	}
 ]
 
@@ -120,10 +146,8 @@
 	validate_fiscal_year(from_date, to_date, company)
 
 	if not frappe.db.exists('DATEV Settings', filters.get('company')):
-		frappe.log_error(_('Please create {} for Company {}.').format(
-			'<a href="desk#List/DATEV%20Settings/List">{}</a>'.format(_('DATEV Settings')),
-			frappe.bold(filters.get('company'))
-		))
+		msg = 'Please create DATEV Settings for Company {}'.format(filters.get('company'))
+		frappe.log_error(msg, title='DATEV Settings missing')
 		return False
 
 	return True
@@ -169,7 +193,11 @@
 			gl.voucher_type as 'Beleginfo - Art 1',
 			gl.voucher_no as 'Beleginfo - Inhalt 1',
 			gl.against_voucher_type as 'Beleginfo - Art 2',
-			gl.against_voucher as 'Beleginfo - Inhalt 2'
+			gl.against_voucher as 'Beleginfo - Inhalt 2',
+			gl.party_type as 'Beleginfo - Art 3',
+			gl.party as 'Beleginfo - Inhalt 3',
+			case gl.party_type when 'Customer' then 'Debitorennummer' when 'Supplier' then 'Kreditorennummer' else NULL end as 'Beleginfo - Art 4',
+			par.debtor_creditor_number as 'Beleginfo - Inhalt 4'
 
 		FROM `tabGL Entry` gl
 
@@ -177,6 +205,19 @@
 			left join `tabAccount` acc 
 			on gl.account = acc.name
 
+			left join `tabCustomer` cus
+			on gl.party_type = 'Customer'
+			and gl.party = cus.name
+
+			left join `tabSupplier` sup
+			on gl.party_type = 'Supplier'
+			and gl.party = sup.name
+
+			left join `tabParty Account` par
+			on par.parent = gl.party
+			and par.parenttype = gl.party_type
+			and par.company = %(company)s
+
 		WHERE gl.company = %(company)s 
 		AND DATE(gl.posting_date) >= %(from_date)s
 		AND DATE(gl.posting_date) <= %(to_date)s
@@ -196,40 +237,56 @@
 	return frappe.db.sql("""
 		SELECT
 
-			acc.account_number as 'Konto',
-			CASE cus.customer_type WHEN 'Company' THEN cus.customer_name ELSE null END as 'Name (Adressatentyp Unternehmen)',
-			CASE cus.customer_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)',
-			CASE cus.customer_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)',
-			CASE cus.customer_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp',
+			par.debtor_creditor_number as 'Konto',
+			CASE cus.customer_type
+				WHEN 'Company' THEN cus.customer_name
+				ELSE null
+				END as 'Name (Adressatentyp Unternehmen)',
+			CASE cus.customer_type
+				WHEN 'Individual' THEN TRIM(SUBSTR(cus.customer_name, LOCATE(' ', cus.customer_name)))
+				ELSE null
+				END as 'Name (Adressatentyp natürl. Person)',
+			CASE cus.customer_type
+				WHEN 'Individual' THEN SUBSTRING_INDEX(SUBSTRING_INDEX(cus.customer_name, ' ', 1), ' ', -1)
+				ELSE null
+				END as 'Vorname (Adressatentyp natürl. Person)',
+			CASE cus.customer_type
+				WHEN 'Individual' THEN '1'
+				WHEN 'Company' THEN '2'
+				ELSE '0'
+				END as 'Adressatentyp',
 			adr.address_line1 as 'Straße',
 			adr.pincode as 'Postleitzahl',
 			adr.city as 'Ort',
 			UPPER(country.code) as 'Land',
 			adr.address_line2 as 'Adresszusatz',
-			con.email_id as 'E-Mail',
-			coalesce(con.mobile_no, con.phone) as 'Telefon',
+			adr.email_id as 'E-Mail',
+			adr.phone as 'Telefon',
+			adr.fax as 'Fax',
 			cus.website as 'Internet',
 			cus.tax_id as 'Steuernummer'
 
-		FROM `tabParty Account` par
+		FROM `tabCustomer` cus
 
-			left join `tabAccount` acc
-			on acc.name = par.account
+			left join `tabParty Account` par
+			on par.parent = cus.name
+			and par.parenttype = 'Customer'
+			and par.company = %(company)s
 
-			left join `tabCustomer` cus
-			on cus.name = par.parent
+			left join `tabDynamic Link` dyn_adr
+			on dyn_adr.link_name = cus.name
+			and dyn_adr.link_doctype = 'Customer'
+			and dyn_adr.parenttype = 'Address'
 
 			left join `tabAddress` adr
-			on adr.name = cus.customer_primary_address
+			on adr.name = dyn_adr.parent
+			and adr.is_primary_address = '1'
 
 			left join `tabCountry` country
 			on country.name = adr.country
 
-			left join `tabContact` con
-			on con.name = cus.customer_primary_contact
-
-		WHERE par.company = %(company)s
-		AND par.parenttype = 'Customer'""", filters, as_dict=1)
+		WHERE adr.is_primary_address = '1'
+		""", filters, as_dict=1)
 
 
 def get_suppliers(filters):
@@ -242,35 +299,48 @@
 	return frappe.db.sql("""
 		SELECT
 
-			acc.account_number as 'Konto',
-			CASE sup.supplier_type WHEN 'Company' THEN sup.supplier_name ELSE null END as 'Name (Adressatentyp Unternehmen)',
-			CASE sup.supplier_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)',
-			CASE sup.supplier_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)',
-			CASE sup.supplier_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp',
+			par.debtor_creditor_number as 'Konto',
+			CASE sup.supplier_type
+				WHEN 'Company' THEN sup.supplier_name
+				ELSE null
+				END as 'Name (Adressatentyp Unternehmen)',
+			CASE sup.supplier_type
+				WHEN 'Individual' THEN TRIM(SUBSTR(sup.supplier_name, LOCATE(' ', sup.supplier_name)))
+				ELSE null
+				END as 'Name (Adressatentyp natürl. Person)',
+			CASE sup.supplier_type
+				WHEN 'Individual' THEN SUBSTRING_INDEX(SUBSTRING_INDEX(sup.supplier_name, ' ', 1), ' ', -1)
+				ELSE null
+				END as 'Vorname (Adressatentyp natürl. Person)',
+			CASE sup.supplier_type
+				WHEN 'Individual' THEN '1'
+				WHEN 'Company' THEN '2'
+				ELSE '0'
+				END as 'Adressatentyp',
 			adr.address_line1 as 'Straße',
 			adr.pincode as 'Postleitzahl',
 			adr.city as 'Ort',
 			UPPER(country.code) as 'Land',
 			adr.address_line2 as 'Adresszusatz',
-			con.email_id as 'E-Mail',
-			coalesce(con.mobile_no, con.phone) as 'Telefon',
+			adr.email_id as 'E-Mail',
+			adr.phone as 'Telefon',
+			adr.fax as 'Fax',
 			sup.website as 'Internet',
 			sup.tax_id as 'Steuernummer',
 			case sup.on_hold when 1 then sup.release_date else null end as 'Zahlungssperre bis'
 
-		FROM `tabParty Account` par
+		FROM `tabSupplier` sup
 
-			left join `tabAccount` acc
-			on acc.name = par.account
-
-			left join `tabSupplier` sup
-			on sup.name = par.parent
+			left join `tabParty Account` par
+			on par.parent = sup.name
+			and par.parenttype = 'Supplier'
+			and par.company = %(company)s
 
 			left join `tabDynamic Link` dyn_adr
 			on dyn_adr.link_name = sup.name
 			and dyn_adr.link_doctype = 'Supplier'
 			and dyn_adr.parenttype = 'Address'
-			
+
 			left join `tabAddress` adr
 			on adr.name = dyn_adr.parent
 			and adr.is_primary_address = '1'
@@ -278,17 +348,8 @@
 			left join `tabCountry` country
 			on country.name = adr.country
 
-			left join `tabDynamic Link` dyn_con
-			on dyn_con.link_name = sup.name
-			and dyn_con.link_doctype = 'Supplier'
-			and dyn_con.parenttype = 'Contact'
-
-			left join `tabContact` con
-			on con.name = dyn_con.parent
-			and con.is_primary_contact = '1'
-
-		WHERE par.company = %(company)s
-		AND par.parenttype = 'Supplier'""", filters, as_dict=1)
+		WHERE adr.is_primary_address = '1'
+		""", filters, as_dict=1)
 
 
 def get_account_names(filters):
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 49ca942..51d86ff 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -490,7 +490,7 @@
 	outstanding_based_on_gle = flt(outstanding_based_on_gle[0][0]) if outstanding_based_on_gle else 0
 
 	# Outstanding based on Sales Order
-	outstanding_based_on_so = 0.0
+	outstanding_based_on_so = 0
 
 	# if credit limit check is bypassed at sales order level,
 	# we should not consider outstanding Sales Orders, when customer credit balance report is run
@@ -501,9 +501,11 @@
 			where customer=%s and docstatus = 1 and company=%s
 			and per_billed < 100 and status != 'Closed'""", (customer, company))
 
-		outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0.0
+		outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0
 
 	# Outstanding based on Delivery Note, which are not created against Sales Order
+	outstanding_based_on_dn = 0
+
 	unmarked_delivery_note_items = frappe.db.sql("""select
 			dn_item.name, dn_item.amount, dn.base_net_total, dn.base_grand_total
 		from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
@@ -515,15 +517,29 @@
 			and ifnull(dn_item.against_sales_invoice, '') = ''
 		""", (customer, company), as_dict=True)
 
-	outstanding_based_on_dn = 0.0
+	if not unmarked_delivery_note_items:
+		return outstanding_based_on_gle + outstanding_based_on_so
+
+	si_amounts = frappe.db.sql("""
+		SELECT
+			dn_detail, sum(amount) from `tabSales Invoice Item`
+		WHERE
+			docstatus = 1
+			and dn_detail in ({})
+		GROUP BY dn_detail""".format(", ".join(
+			frappe.db.escape(dn_item.name)
+			for dn_item in unmarked_delivery_note_items
+		))
+	)
+
+	si_amounts = {si_item[0]: si_item[1] for si_item in si_amounts}
 
 	for dn_item in unmarked_delivery_note_items:
-		si_amount = frappe.db.sql("""select sum(amount)
-			from `tabSales Invoice Item`
-			where dn_detail = %s and docstatus = 1""", dn_item.name)[0][0]
+		dn_amount = flt(dn_item.amount)
+		si_amount = flt(si_amounts.get(dn_item.name))
 
-		if flt(dn_item.amount) > flt(si_amount) and dn_item.base_net_total:
-			outstanding_based_on_dn += ((flt(dn_item.amount) - flt(si_amount)) \
+		if dn_amount > si_amount and dn_item.base_net_total:
+			outstanding_based_on_dn += ((dn_amount - si_amount)
 				/ dn_item.base_net_total) * dn_item.base_grand_total
 
 	return outstanding_based_on_gle + outstanding_based_on_so + outstanding_based_on_dn
diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js
index 7fd0877..ffa185b 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.js
+++ b/erpnext/selling/doctype/installation_note/installation_note.js
@@ -30,8 +30,8 @@
 frappe.provide("erpnext.selling");
 
 // TODO commonify this code
-erpnext.selling.InstallationNote = frappe.ui.form.Controller.extend({
-	refresh: function() {
+erpnext.selling.InstallationNote = class InstallationNote extends frappe.ui.form.Controller {
+	refresh() {
 		var me = this;
 		if (this.frm.doc.docstatus===0) {
 			this.frm.add_custom_button(__('From Delivery Note'),
@@ -54,7 +54,7 @@
 				}, "fa fa-download", "btn-default"
 			);
 		}
-	},
-});
+	}
+};
 
 $.extend(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm}));
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 5a0d9c9..10606bf 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -36,13 +36,13 @@
 	}
 });
 
-erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
-	onload: function(doc, dt, dn) {
+erpnext.selling.QuotationController = class QuotationController extends erpnext.selling.SellingController {
+	onload(doc, dt, dn) {
 		var me = this;
-		this._super(doc, dt, dn);
+		super.(doc, dt, dn);
 
-	},
-	party_name: function() {
+	}
+	party_name() {
 		var me = this;
 		erpnext.utils.get_party_details(this.frm, null, null, function() {
 			me.apply_price_list();
@@ -51,9 +51,9 @@
 		if(me.frm.doc.quotation_to=="Lead" && me.frm.doc.party_name) {
 			me.frm.trigger("get_lead_details");
 		}
-	},
-	refresh: function(doc, dt, dn) {
-		this._super(doc, dt, dn);
+	}
+	refresh(doc, dt, dn) {
+		super.refresh(doc, dt, dn);
 		doctype = doc.quotation_to == 'Customer' ? 'Customer':'Lead';
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'party_name', doctype: doctype}
 
@@ -121,9 +121,9 @@
 
 		this.toggle_reqd_lead_customer();
 
-	},
+	}
 
-	set_dynamic_field_label: function(){
+	set_dynamic_field_label(){
 		if (this.frm.doc.quotation_to == "Customer")
 		{
 			this.frm.set_df_property("party_name", "label", "Customer");
@@ -138,22 +138,22 @@
 				return{	query: "erpnext.controllers.queries.lead_query" }
 			}
 		}
-	},
+	}
 
-	toggle_reqd_lead_customer: function() {
+	toggle_reqd_lead_customer() {
 		var me = this;
 
 		// to overwrite the customer_filter trigger from queries.js
 		this.frm.toggle_reqd("party_name", this.frm.doc.quotation_to);
 		this.frm.set_query('customer_address', this.address_query);
 		this.frm.set_query('shipping_address_name', this.address_query);
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	address_query: function(doc) {
+	address_query(doc) {
 		return {
 			query: 'frappe.contacts.doctype.address.address.address_query',
 			filters: {
@@ -161,20 +161,20 @@
 				link_name: doc.party_name
 			}
 		};
-	},
+	}
 
-	validate_company_and_party: function(party_field) {
+	validate_company_and_party(party_field) {
 		if(!this.frm.doc.quotation_to) {
 			frappe.msgprint(__("Please select a value for {0} quotation_to {1}", [this.frm.doc.doctype, this.frm.doc.name]));
 			return false;
 		} else if (this.frm.doc.quotation_to == "Lead") {
 			return true;
 		} else {
-			return this._super(party_field);
+			return super.validate_company_and_party(party_field);
 		}
-	},
+	}
 
-	get_lead_details: function() {
+	get_lead_details() {
 		var me = this;
 		if(!this.frm.doc.quotation_to === "Lead") {
 			return;
@@ -198,7 +198,7 @@
 			}
 		})
 	}
-});
+};
 
 cur_frm.script_manager.make(erpnext.selling.QuotationController);
 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e3b41e6..d5ceca8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -102,14 +102,14 @@
 	}
 });
 
-erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
-	onload: function(doc, dt, dn) {
-		this._super();
-	},
+erpnext.selling.SalesOrderController = class SalesOrderController extends erpnext.selling.SellingController {
+	onload(doc, dt, dn) {
+		super.onload();
+	}
 
-	refresh: function(doc, dt, dn) {
+	refresh(doc, dt, dn) {
 		var me = this;
-		this._super();
+		super.refresh();
 		let allow_delivery = false;
 
 		if (doc.docstatus==1) {
@@ -241,14 +241,14 @@
 		}
 
 		this.order_type(doc);
-	},
+	}
 
 	create_pick_list() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.create_pick_list",
 			frm: this.frm
 		})
-	},
+	}
 
 	make_work_order() {
 		var me = this;
@@ -343,33 +343,33 @@
 				}
 			}
 		});
-	},
+	}
 
-	order_type: function() {
+	order_type() {
 		this.toggle_delivery_date();
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	make_material_request: function() {
+	make_material_request() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
 			frm: this.frm
 		})
-	},
+	}
 
-	skip_delivery_note: function() {
+	skip_delivery_note() {
 		this.toggle_delivery_date();
-	},
+	}
 
-	toggle_delivery_date: function() {
+	toggle_delivery_date() {
 		this.frm.fields_dict.items.grid.toggle_reqd("delivery_date",
 			(this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note));
-	},
+	}
 
-	make_raw_material_request: function() {
+	make_raw_material_request() {
 		var me = this;
 		this.frm.call({
 			doc: this.frm.doc,
@@ -390,9 +390,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	make_raw_material_request_dialog: function(r) {
+	make_raw_material_request_dialog(r) {
 		var fields = [
 			{fieldtype:'Check', fieldname:'include_exploded_items',
 				label: __('Include Exploded Items')},
@@ -447,9 +447,9 @@
 			primary_action_label: __('Create')
 		});
 		d.show();
-	},
+	}
 
-	make_delivery_note_based_on_delivery_date: function() {
+	make_delivery_note_based_on_delivery_date() {
 		var me = this;
 
 		var delivery_dates = [];
@@ -509,51 +509,51 @@
 		} else {
 			this.make_delivery_note();
 		}
-	},
+	}
 
-	make_delivery_note: function() {
+	make_delivery_note() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_sales_invoice: function() {
+	make_sales_invoice() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_maintenance_schedule: function() {
+	make_maintenance_schedule() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_project: function() {
+	make_project() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_project",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_inter_company_order: function() {
+	make_inter_company_order() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_inter_company_purchase_order",
 			frm: this.frm
 		});
-	},
+	}
 
-	make_maintenance_visit: function() {
+	make_maintenance_visit() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_purchase_order: function(){
+	make_purchase_order(){
 		let pending_items = this.frm.doc.items.some((item) =>{
 			let pending_qty = flt(item.stock_qty) - flt(item.ordered_qty);
 			return pending_qty > 0;
@@ -690,9 +690,9 @@
 		dialog.get_field("items_for_po").refresh();
 		dialog.wrapper.find('.grid-heading-row .grid-row-check').click();
 		dialog.show();
-	},
+	}
 
-	hold_sales_order: function(){
+	hold_sales_order(){
 		var me = this;
 		var d = new frappe.ui.Dialog({
 			title: __('Reason for Hold'),
@@ -724,11 +724,11 @@
 			}
 		});
 		d.show();
-	},
-	close_sales_order: function(){
+	}
+	close_sales_order(){
 		this.frm.cscript.update_status("Close", "Closed")
-	},
-	update_status: function(label, status){
+	}
+	update_status(label, status){
 		var doc = this.frm.doc;
 		var me = this;
 		frappe.ui.form.is_saving = true;
@@ -743,5 +743,5 @@
 			}
 		});
 	}
-});
+};
 $.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index e3405e0..6db4150 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -7,7 +7,7 @@
 		single_column: true
 	});
 
-	frappe.require('assets/js/point-of-sale.min.js', function() {
+	frappe.require('point-of-sale.bundle.js', function() {
 		wrapper.pos = new erpnext.PointOfSale.Controller(wrapper);
 		window.cur_pos = wrapper.pos;
 	});
@@ -19,4 +19,4 @@
 		wrapper.pos.wrapper.html("");
 		wrapper.pos.check_opening_entry();
 	}
-};
\ No newline at end of file
+};
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 8adf5bf..4f4f1b2 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -56,10 +56,6 @@
 				dialog.fields_dict.balance_details.grid.refresh();
 			});
 		}
-		const pos_profile_query = {
-			query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
-			filters: { company: frappe.defaults.get_default('company') }
-		}
 		const dialog = new frappe.ui.Dialog({
 			title: __('Create POS Opening Entry'),
 			static: true,
@@ -105,6 +101,10 @@
 			primary_action_label: __('Submit')
 		});
 		dialog.show();
+		const pos_profile_query = {
+			query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
+			filters: { company: dialog.fields_dict.company.get_value() }
+		};
 	}
 
 	async prepare_app_defaults(data) {
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index 709fe57..b8a82a9 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -81,13 +81,26 @@
 		const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
 		const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
 
+		let qty_to_display = actual_qty;
+
+		if (Math.round(qty_to_display) > 999) {
+			qty_to_display = Math.round(qty_to_display)/1000;
+			qty_to_display = qty_to_display.toFixed(1) + 'K';
+		}
+
 		function get_item_image_html() {
 			if (!me.hide_images && item_image) {
-				return `<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
+				return `<div class="item-qty-pill">
+							<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
+						</div>
+						<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
 							<img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
 						</div>`;
 			} else {
-				return `<div class="item-display abbr">${frappe.get_abbr(item.item_name)}</div>`;
+				return `<div class="item-qty-pill">
+							<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
+						</div>
+						<div class="item-display abbr">${frappe.get_abbr(item.item_name)}</div>`;
 			}
 		}
 
@@ -95,13 +108,12 @@
 			`<div class="item-wrapper"
 				data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
 				data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
-				title="Avaiable Qty: ${actual_qty}">
+				title="${item.item_name}">
 
 				${get_item_image_html()}
 
 				<div class="item-detail">
 					<div class="item-name">
-						<span class="indicator ${indicator_color}"></span>
 						${frappe.ellipsis(item.item_name, 18)}
 					</div>
 					<div class="item-rate">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
@@ -316,4 +328,4 @@
 	toggle_component(show) {
 		show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
 	}
-};
\ No newline at end of file
+};
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 0428573..eb02867 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -9,15 +9,15 @@
 cur_frm.email_field = "contact_email";
 
 frappe.provide("erpnext.selling");
-erpnext.selling.SellingController = erpnext.TransactionController.extend({
-	setup: function() {
-		this._super();
+erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController {
+	setup() {
+		super.setup();
 		this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
 		this.frm.add_fetch("sales_person", "commission_rate", "commission_rate");
-	},
+	}
 
-	onload: function() {
-		this._super();
+	onload() {
+		super.onload();
 		this.setup_queries();
 		this.frm.set_query('shipping_rule', function() {
 			return {
@@ -26,9 +26,9 @@
 				}
 			};
 		});
-	},
+	}
 
-	setup_queries: function() {
+	setup_queries() {
 		var me = this;
 
 		$.each([["customer", "customer"],
@@ -81,10 +81,10 @@
 			});
 		}
 
-	},
+	}
 
-	refresh: function() {
-		this._super();
+	refresh() {
+		super.refresh();
 
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
 
@@ -95,45 +95,45 @@
 			this.frm.toggle_display("packing_list", packing_list_exists ? true : false);
 		}
 		this.toggle_editable_price_list_rate();
-	},
+	}
 
-	customer: function() {
+	customer() {
 		var me = this;
 		erpnext.utils.get_party_details(this.frm, null, null, function() {
 			me.apply_price_list();
 		});
-	},
+	}
 
-	customer_address: function() {
+	customer_address() {
 		erpnext.utils.get_address_display(this.frm, "customer_address");
 		erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name");
-	},
+	}
 
-	shipping_address_name: function() {
+	shipping_address_name() {
 		erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address");
 		erpnext.utils.set_taxes_from_address(this.frm, "shipping_address_name", "customer_address", "shipping_address_name");
-	},
+	}
 
-	sales_partner: function() {
+	sales_partner() {
 		this.apply_pricing_rule();
-	},
+	}
 
-	campaign: function() {
+	campaign() {
 		this.apply_pricing_rule();
-	},
+	}
 
-	selling_price_list: function() {
+	selling_price_list() {
 		this.apply_price_list();
 		this.set_dynamic_labels();
-	},
+	}
 
-	discount_percentage: function(doc, cdt, cdn) {
+	discount_percentage(doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
 		item.discount_amount = 0.0;
 		this.apply_discount_on_item(doc, cdt, cdn, 'discount_percentage');
-	},
+	}
 
-	discount_amount: function(doc, cdt, cdn) {
+	discount_amount(doc, cdt, cdn) {
 
 		if(doc.name === cdn) {
 			return;
@@ -142,9 +142,9 @@
 		var item = frappe.get_doc(cdt, cdn);
 		item.discount_percentage = 0.0;
 		this.apply_discount_on_item(doc, cdt, cdn, 'discount_amount');
-	},
+	}
 
-	apply_discount_on_item: function(doc, cdt, cdn, field) {
+	apply_discount_on_item(doc, cdt, cdn, field) {
 		var item = frappe.get_doc(cdt, cdn);
 		if(!item.price_list_rate) {
 			item[field] = 0.0;
@@ -152,14 +152,14 @@
 			this.price_list_rate(doc, cdt, cdn);
 		}
 		this.set_gross_profit(item);
-	},
+	}
 
-	commission_rate: function() {
+	commission_rate() {
 		this.calculate_commission();
 		refresh_field("total_commission");
-	},
+	}
 
-	total_commission: function() {
+	total_commission() {
 		if(this.frm.doc.base_net_total) {
 			frappe.model.round_floats_in(this.frm.doc, ["base_net_total", "total_commission"]);
 
@@ -175,9 +175,9 @@
 			this.frm.set_value("commission_rate",
 				flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.base_net_total));
 		}
-	},
+	}
 
-	allocated_percentage: function(doc, cdt, cdn) {
+	allocated_percentage(doc, cdt, cdn) {
 		var sales_person = frappe.get_doc(cdt, cdn);
 		if(sales_person.allocated_percentage) {
 
@@ -193,15 +193,15 @@
 			refresh_field(["allocated_percentage", "allocated_amount", "commission_rate","incentives"], sales_person.name,
 				sales_person.parentfield);
 		}
-	},
+	}
 
-	sales_person: function(doc, cdt, cdn) {
+	sales_person(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		this.calculate_incentive(row);
 		refresh_field("incentives",row.name,row.parentfield);
-	},
+	}
 
-	warehouse: function(doc, cdt, cdn) {
+	warehouse(doc, cdt, cdn) {
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 
@@ -239,18 +239,18 @@
 				});
 			}
 		})
-	},
+	}
 
-	toggle_editable_price_list_rate: function() {
+	toggle_editable_price_list_rate() {
 		var df = frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "price_list_rate", this.frm.doc.name);
 		var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate"));
 
 		if(df && editable_price_list_rate) {
 			df.read_only = 0;
 		}
-	},
+	}
 
-	calculate_commission: function() {
+	calculate_commission() {
 		if(this.frm.fields_dict.commission_rate) {
 			if(this.frm.doc.commission_rate > 100) {
 				var msg = __(frappe.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) +
@@ -262,9 +262,9 @@
 			this.frm.doc.total_commission = flt(this.frm.doc.base_net_total * this.frm.doc.commission_rate / 100.0,
 				precision("total_commission"));
 		}
-	},
+	}
 
-	calculate_contribution: function() {
+	calculate_contribution() {
 		var me = this;
 		$.each(this.frm.doc.doctype.sales_team || [], function(i, sales_person) {
 			frappe.model.round_floats_in(sales_person);
@@ -274,18 +274,18 @@
 					precision("allocated_amount", sales_person));
 			}
 		});
-	},
+	}
 
-	calculate_incentive: function(row) {
+	calculate_incentive(row) {
 		if(row.allocated_amount)
 		{
 			row.incentives = flt(
 					row.allocated_amount * row.commission_rate / 100.0,
 					precision("incentives", row));
 		}
-	},
+	}
 
-	batch_no: function(doc, cdt, cdn) {
+	batch_no(doc, cdt, cdn) {
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 
@@ -312,14 +312,14 @@
 				});
 			}
 		})
-	},
+	}
 
-	set_dynamic_labels: function() {
-		this._super();
+	set_dynamic_labels() {
+		super.set_dynamic_labels();
 		this.set_product_bundle_help(this.frm.doc);
-	},
+	}
 
-	set_product_bundle_help: function(doc) {
+	set_product_bundle_help(doc) {
 		if(!cur_frm.fields_dict.packing_list) return;
 		if ((doc.packed_items || []).length) {
 			$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
@@ -337,9 +337,9 @@
 			}
 		}
 		refresh_field('product_bundle_help');
-	},
+	}
 
-	company_address: function() {
+	company_address() {
 		var me = this;
 		if(this.frm.doc.company_address) {
 			frappe.call({
@@ -354,42 +354,42 @@
 		} else {
 			this.frm.set_value("company_address_display", "");
 		}
-	},
+	}
 
-	conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
-	    this._super(doc, cdt, cdn, dont_fetch_price_list_rate);
+	conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) {
+	    super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate);
 		if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) &&
 			in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
 				if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
 				this.set_batch_number(cdt, cdn);
 			}
-	},
+	}
 
-	batch_no: function(doc, cdt, cdn) {
-		this._super(doc, cdt, cdn);
-	},
+	batch_no(doc, cdt, cdn) {
+		super.batch_no(doc, cdt, cdn);
+	}
 
-	qty: function(doc, cdt, cdn) {
-		this._super(doc, cdt, cdn);
+	qty(doc, cdt, cdn) {
+		super.qty(doc, cdt, cdn);
 
 		if(in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
 			if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
 			this.set_batch_number(cdt, cdn);
 		}
-	},
+	}
 
 	/* Determine appropriate batch number and set it in the form.
 	* @param {string} cdt - Document Doctype
 	* @param {string} cdn - Document name
 	*/
-	set_batch_number: function(cdt, cdn) {
+	set_batch_number(cdt, cdn) {
 		const doc = frappe.get_doc(cdt, cdn);
 		if (doc && doc.has_batch_no && doc.warehouse) {
 			this._set_batch_number(doc);
 		}
-	},
+	}
 
-	_set_batch_number: function(doc) {
+	_set_batch_number(doc) {
 		let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
 		if (doc.has_serial_no && doc.serial_no) {
 			args['serial_no'] = doc.serial_no
@@ -406,9 +406,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	update_auto_repeat_reference: function(doc) {
+	update_auto_repeat_reference(doc) {
 		if (doc.auto_repeat) {
 			frappe.call({
 				method:"frappe.automation.doctype.auto_repeat.auto_repeat.update_reference",
@@ -426,7 +426,7 @@
 			})
 		}
 	}
-});
+};
 
 frappe.ui.form.on(cur_frm.doctype,"project", function(frm) {
 	if(in_list(["Delivery Note", "Sales Invoice"], frm.doc.doctype)) {
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index c2b5e4f..9957aad 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -169,9 +169,9 @@
 					return;
 				}
 				frappe.call({
-					method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
+					method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
 					args: {
-						company_name: data.company_name
+						company: data.company_name
 					},
 					freeze: true,
 					callback: function(r, rt) {
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 64e027d..077538d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -613,4 +613,13 @@
 	if out:
 		return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0]
 	else:
-		return None
\ No newline at end of file
+		return None
+
+@frappe.whitelist()
+def create_transaction_deletion_request(company):
+	tdr = frappe.get_doc({
+		'doctype': 'Transaction Deletion Record',
+		'company': company
+	})
+	tdr.insert()
+	tdr.submit()
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
deleted file mode 100644
index 8367a25..0000000
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-from frappe.utils import cint
-from frappe import _
-from frappe.desk.notifications import clear_notifications
-
-import functools
-
-@frappe.whitelist()
-def delete_company_transactions(company_name):
-	frappe.only_for("System Manager")
-	doc = frappe.get_doc("Company", company_name)
-
-	if frappe.session.user != doc.owner and frappe.session.user != 'Administrator':
-		frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
-			frappe.PermissionError)
-
-	delete_bins(company_name)
-	delete_lead_addresses(company_name)
-
-	for doctype in frappe.db.sql_list("""select parent from
-		tabDocField where fieldtype='Link' and options='Company'"""):
-		if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
-			"Party Account", "Employee", "Sales Taxes and Charges Template",
-			"Purchase Taxes and Charges Template", "POS Profile", "BOM",
-			"Company", "Bank Account", "Item Tax Template", "Mode Of Payment", "Mode of Payment Account",
-			"Item Default", "Customer", "Supplier", "GST Account"):
-				delete_for_doctype(doctype, company_name)
-
-	# reset company values
-	doc.total_monthly_sales = 0
-	doc.sales_monthly_history = None
-	doc.save()
-	# Clear notification counts
-	clear_notifications()
-
-def delete_for_doctype(doctype, company_name):
-	meta = frappe.get_meta(doctype)
-	company_fieldname = meta.get("fields", {"fieldtype": "Link",
-		"options": "Company"})[0].fieldname
-
-	if not meta.issingle:
-		if not meta.istable:
-			# delete communication
-			delete_communications(doctype, company_name, company_fieldname)
-
-			# delete children
-			for df in meta.get_table_fields():
-				frappe.db.sql("""delete from `tab{0}` where parent in
-					(select name from `tab{1}` where `{2}`=%s)""".format(df.options,
-						doctype, company_fieldname), company_name)
-
-		#delete version log
-		frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
-			(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
-				company_fieldname), (doctype, company_name))
-
-		# delete parent
-		frappe.db.sql("""delete from `tab{0}`
-			where {1}= %s """.format(doctype, company_fieldname), company_name)
-
-		# reset series
-		naming_series = meta.get_field("naming_series")
-		if naming_series and naming_series.options:
-			prefixes = sorted(naming_series.options.split("\n"),
-				key=functools.cmp_to_key(lambda a, b: len(b) - len(a)))
-
-			for prefix in prefixes:
-				if prefix:
-					last = frappe.db.sql("""select max(name) from `tab{0}`
-						where name like %s""".format(doctype), prefix + "%")
-					if last and last[0][0]:
-						last = cint(last[0][0].replace(prefix, ""))
-					else:
-						last = 0
-
-					frappe.db.sql("""update tabSeries set current = %s
-						where name=%s""", (last, prefix))
-
-def delete_bins(company_name):
-	frappe.db.sql("""delete from tabBin where warehouse in
-			(select name from tabWarehouse where company=%s)""", company_name)
-
-def delete_lead_addresses(company_name):
-	"""Delete addresses to which leads are linked"""
-	leads = frappe.get_all("Lead", filters={"company": company_name})
-	leads = [ "'%s'"%row.get("name") for row in leads ]
-	addresses = []
-	if leads:
-		addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
-			in ({leads})""".format(leads=",".join(leads)))
-
-		if addresses:
-			addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
-
-			frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
-				name not in (select distinct dl1.parent from `tabDynamic Link` dl1
-				inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
-				and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
-
-			frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
-				and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
-
-		frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
-
-def delete_communications(doctype, company_name, company_fieldname):
-		reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
-		reference_doc_names = [r.name for r in reference_docs]
-
-		communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
-		communication_names = [c.name for c in communications]
-
-		frappe.delete_doc("Communication", communication_names, ignore_permissions=True)
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 29f6c37..e1c803a 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -86,15 +86,6 @@
 					self.delete_mode_of_payment(template)
 					frappe.delete_doc("Company", template)
 
-	def test_delete_communication(self):
-		from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
-		company = create_child_company()
-		lead = create_test_lead_in_company(company)
-		communication = create_company_communication("Lead", lead)
-		delete_communications("Lead", "Test Company", "company")
-		self.assertFalse(frappe.db.exists("Communcation", communication))
-		self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
-
 	def delete_mode_of_payment(self, company):
 		frappe.db.sql(""" delete from `tabMode of Payment Account`
 			where company =%s """, (company))
diff --git a/erpnext/setup/doctype/transaction_deletion_record/__init__.py b/erpnext/setup/doctype/transaction_deletion_record/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/__init__.py
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
new file mode 100644
index 0000000..bbe6836
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestTransactionDeletionRecord(unittest.TestCase):
+	def setUp(self):
+		create_company('Dunder Mifflin Paper Co')
+
+	def tearDown(self):
+		frappe.db.rollback()
+
+	def test_doctypes_contain_company_field(self):
+		tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		for doctype in tdr.doctypes:
+			contains_company = False
+			doctype_fields = frappe.get_meta(doctype.doctype_name).as_dict()['fields']
+			for doctype_field in doctype_fields:
+				if doctype_field['fieldtype'] == 'Link' and doctype_field['options'] == 'Company':
+					contains_company = True
+					break
+			self.assertTrue(contains_company)
+	
+	def test_no_of_docs_is_correct(self):
+		for i in range(5):
+			create_task('Dunder Mifflin Paper Co')
+		tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		for doctype in tdr.doctypes:
+			if doctype.doctype_name == 'Task':
+				self.assertEqual(doctype.no_of_docs, 5)
+
+	def test_deletion_is_successful(self):
+		create_task('Dunder Mifflin Paper Co')
+		create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		tasks_containing_company = frappe.get_all('Task',
+		filters = {
+			'company' : 'Dunder Mifflin Paper Co'
+		})
+		self.assertEqual(tasks_containing_company, [])
+		
+def create_company(company_name):
+	company = frappe.get_doc({
+		'doctype': 'Company',
+		'company_name': company_name,
+		'default_currency': 'INR'
+	})		
+	company.insert(ignore_if_duplicate = True)
+
+def create_transaction_deletion_request(company):
+	tdr = frappe.get_doc({
+		'doctype': 'Transaction Deletion Record',
+		'company': company
+	})
+	tdr.insert()
+	tdr.submit()
+	return tdr
+
+
+def create_task(company):
+	task = frappe.get_doc({
+		'doctype': 'Task',
+		'company': company,
+		'subject': 'Delete'
+	})
+	task.insert()
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
new file mode 100644
index 0000000..20caa15
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Transaction Deletion Record', {
+	onload: function(frm) {
+		if (frm.doc.docstatus == 0) {
+			let doctypes_to_be_ignored_array;	
+			frappe.call({
+				method: 'erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record.get_doctypes_to_be_ignored',
+				callback: function(r) {
+					doctypes_to_be_ignored_array = r.message;
+					populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm);
+					frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+					frm.refresh_field('doctypes_to_be_ignored');
+				}
+			});
+		}
+
+		frm.get_field('doctypes_to_be_ignored').grid.cannot_add_rows = true;
+		frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+		frm.refresh_field('doctypes_to_be_ignored');
+	},
+
+	refresh: function(frm) {
+		frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+		frm.refresh_field('doctypes_to_be_ignored');
+	}
+	
+});
+
+function populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm) {
+	if (!(frm.doc.doctypes_to_be_ignored)) {
+		var i;
+		for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {     
+			frm.add_child('doctypes_to_be_ignored', {
+				doctype_name: doctypes_to_be_ignored_array[i]					
+			});
+		}
+	}
+}
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
new file mode 100644
index 0000000..9313f95
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -0,0 +1,79 @@
+{
+ "actions": [],
+ "autoname": "TDL.####",
+ "creation": "2021-04-06 20:17:18.404716",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "doctypes",
+  "doctypes_to_be_ignored",
+  "amended_from",
+  "status"
+ ],
+ "fields": [
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
+  {
+   "fieldname": "doctypes",
+   "fieldtype": "Table",
+   "label": "Summary",
+   "options": "Transaction Deletion Record Item",
+   "read_only": 1
+  },
+  {
+   "fieldname": "doctypes_to_be_ignored",
+   "fieldtype": "Table",
+   "label": "Excluded DocTypes",
+   "options": "Transaction Deletion Record Item"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Transaction Deletion Record",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Status",
+   "options": "Draft\nCompleted"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:13:48.049879",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
new file mode 100644
index 0000000..38f8de7
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.utils import cint
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.desk.notifications import clear_notifications
+
+class TransactionDeletionRecord(Document):
+	def validate(self):
+		frappe.only_for('System Manager')
+		company_obj = frappe.get_doc('Company', self.company)
+		if frappe.session.user != company_obj.owner and frappe.session.user != 'Administrator':
+			frappe.throw(_('Transactions can only be deleted by the creator of the Company or the Administrator.'), 
+				frappe.PermissionError)
+		doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
+		for doctype in self.doctypes_to_be_ignored:
+			if doctype.doctype_name not in doctypes_to_be_ignored_list:
+				frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "), title=_("Not Allowed"))
+
+	def before_submit(self):
+		if not self.doctypes_to_be_ignored:
+			self.populate_doctypes_to_be_ignored_table()
+
+		self.delete_bins()
+		self.delete_lead_addresses()
+		
+		company_obj = frappe.get_doc('Company', self.company)
+		# reset company values
+		company_obj.total_monthly_sales = 0
+		company_obj.sales_monthly_history = None
+		company_obj.save()
+		# Clear notification counts
+		clear_notifications()
+
+		singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
+		tables = frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
+		doctypes_to_be_ignored_list = singles
+		for doctype in self.doctypes_to_be_ignored:
+			doctypes_to_be_ignored_list.append(doctype.doctype_name)
+
+		docfields = frappe.get_all('DocField', 
+			filters = {
+				'fieldtype': 'Link', 
+				'options': 'Company',
+				'parent': ['not in', doctypes_to_be_ignored_list]},
+			fields=['parent', 'fieldname'])
+	
+		for docfield in docfields:
+			if docfield['parent'] != self.doctype:
+				no_of_docs = frappe.db.count(docfield['parent'], {
+							docfield['fieldname'] : self.company
+						})
+
+				if no_of_docs > 0:
+					self.delete_version_log(docfield['parent'], docfield['fieldname'])
+					self.delete_communications(docfield['parent'], docfield['fieldname'])
+
+					# populate DocTypes table
+					if docfield['parent'] not in tables:
+						self.append('doctypes', {
+							'doctype_name' : docfield['parent'],
+							'no_of_docs' : no_of_docs
+						})
+
+					# delete the docs linked with the specified company
+					frappe.db.delete(docfield['parent'], {
+						docfield['fieldname'] : self.company
+					})
+
+					naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
+					if naming_series:
+						if '#' in naming_series:
+							self.update_naming_series(naming_series, docfield['parent'])	
+
+	def populate_doctypes_to_be_ignored_table(self):		
+		doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
+		for doctype in doctypes_to_be_ignored_list:
+			self.append('doctypes_to_be_ignored', {
+						'doctype_name' : doctype
+					})
+
+	def update_naming_series(self, naming_series, doctype_name):
+		if '.' in naming_series:
+			prefix, hashes = naming_series.rsplit('.', 1)
+		else:
+			prefix, hashes = naming_series.rsplit('{', 1)
+		last = frappe.db.sql("""select max(name) from `tab{0}`
+						where name like %s""".format(doctype_name), prefix + '%')
+		if last and last[0][0]:
+			last = cint(last[0][0].replace(prefix, ''))
+		else:
+			last = 0
+
+		frappe.db.sql("""update tabSeries set current = %s where name=%s""", (last, prefix))
+
+	def delete_version_log(self, doctype, company_fieldname):
+		frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
+			(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
+				company_fieldname), (doctype, self.company))
+
+	def delete_communications(self, doctype, company_fieldname):
+		reference_docs = frappe.get_all(doctype, filters={company_fieldname:self.company})
+		reference_doc_names = [r.name for r in reference_docs]
+
+		communications = frappe.get_all('Communication', filters={'reference_doctype':doctype,'reference_name':['in', reference_doc_names]})
+		communication_names = [c.name for c in communications]
+
+		frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
+
+	def delete_bins(self):
+		frappe.db.sql("""delete from tabBin where warehouse in
+				(select name from tabWarehouse where company=%s)""", self.company)
+
+	def delete_lead_addresses(self):
+		"""Delete addresses to which leads are linked"""
+		leads = frappe.get_all('Lead', filters={'company': self.company})
+		leads = ["'%s'" % row.get("name") for row in leads]
+		addresses = []
+		if leads:
+			addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
+				in ({leads})""".format(leads=",".join(leads)))
+
+			if addresses:
+				addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
+
+				frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
+					name not in (select distinct dl1.parent from `tabDynamic Link` dl1
+					inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
+					and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
+
+				frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
+					and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
+
+			frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
+
+@frappe.whitelist()
+def get_doctypes_to_be_ignored():
+	doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
+		'Party Account', 'Employee', 'Sales Taxes and Charges Template',
+		'Purchase Taxes and Charges Template', 'POS Profile', 'BOM',
+		'Company', 'Bank Account', 'Item Tax Template', 'Mode of Payment',
+		'Item Default', 'Customer', 'Supplier', 'GST Account']
+	return doctypes_to_be_ignored_list
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
new file mode 100644
index 0000000..d7175dd
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
@@ -0,0 +1,12 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.listview_settings['Transaction Deletion Record'] = {
+	get_indicator: function(doc) {
+		if (doc.docstatus == 0) {
+			return [__("Draft"), "red"];
+		} else {
+			return [__("Completed"), "green"];
+		}
+	}
+};
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py b/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
new file mode 100644
index 0000000..be0be94
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
@@ -0,0 +1,39 @@
+{
+ "actions": [],
+ "creation": "2021-04-07 07:34:00.124124",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "doctype_name",
+  "no_of_docs"
+ ],
+ "fields": [
+  {
+   "fieldname": "doctype_name",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "DocType",
+   "options": "DocType",
+   "reqd": 1
+  },
+  {
+   "fieldname": "no_of_docs",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Number of Docs"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:10:46.166744",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
new file mode 100644
index 0000000..2176cb1
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TransactionDeletionRecordItem(Document):
+	pass
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index f21d55f..7ae81d7 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -428,7 +428,6 @@
 	frappe.local.flags.ignore_update_nsm = True
 	make_records(records[1:])
 	frappe.local.flags.ignore_update_nsm = False
-	
 	rebuild_tree("Department", "parent_department")
 
 
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 933ca8a..dbf9901 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -1,11 +1,11 @@
 frappe.provide('erpnext.stock');
 
-erpnext.stock.ItemDashboard = Class.extend({
-	init: function (opts) {
+erpnext.stock.ItemDashboard = class ItemDashboard {
+	constructor(opts) {
 		$.extend(this, opts);
 		this.make();
-	},
-	make: function () {
+	}
+	make() {
 		var me = this;
 		this.start = 0;
 		if (!this.sort_by) {
@@ -79,9 +79,9 @@
 			me.refresh();
 		});
 
-	},
-	refresh: function () {
-		if (this.before_refresh) {
+	}
+	refresh() {
+		if(this.before_refresh) {
 			this.before_refresh();
 		}
 
@@ -104,9 +104,9 @@
 				me.render(r.message);
 			}
 		});
-	},
-	render: function (data) {
-		if (this.start === 0) {
+	}
+	render(data) {
+		if (this.start===0) {
 			this.max_count = 0;
 			this.result.empty();
 		}
@@ -141,11 +141,11 @@
 			$(`<div class='text-muted' style='margin: 20px 5px;'>
 				${message} </div>`).appendTo(this.result);
 		}
-	},
+	}
 
-	get_item_dashboard_data: function (data, max_count, show_item) {
-		if (!max_count) max_count = 0;
-		if (!data) data = [];
+	get_item_dashboard_data(data, max_count, show_item) {
+		if(!max_count) max_count = 0;
+		if(!data) data = [];
 
 		data.forEach(function (d) {
 			d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
@@ -170,9 +170,9 @@
 			can_write: can_write,
 			show_item: show_item || false
 		};
-	},
+	}
 
-	get_capacity_dashboard_data: function (data) {
+	get_capacity_dashboard_data(data) {
 		if (!data) data = [];
 
 		data.forEach(function (d) {
@@ -189,7 +189,7 @@
 			can_write: can_write,
 		};
 	}
-});
+};
 
 erpnext.stock.move_item = function (item, source, target, actual_qty, rate, callback) {
 	var dialog = new frappe.ui.Dialog({
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 334bdea..b736015 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -123,17 +123,17 @@
 	}
 });
 
-erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend({
-	setup: function(doc) {
+erpnext.stock.DeliveryNoteController = class DeliveryNoteController extends erpnext.selling.SellingController {
+	setup(doc) {
 		this.setup_posting_date_time_check();
-		this._super(doc);
+		super.setup(doc);
 		this.frm.make_methods = {
 			'Delivery Trip': this.make_delivery_trip,
 		};
-	},
-	refresh: function(doc, dt, dn) {
+	}
+	refresh(doc, dt, dn) {
 		var me = this;
-		this._super();
+		super.refresh();
 		if ((!doc.is_return) && (doc.status!="Closed" || this.frm.is_new())) {
 			if (this.frm.doc.docstatus===0) {
 				this.frm.add_custom_button(__('Sales Order'),
@@ -231,64 +231,64 @@
 				erpnext.utils.make_subscription(doc.doctype, doc.name)
 			}, __('Create'))
 		}
-	},
+	}
 
-	make_shipment: function() {
+	make_shipment() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_shipment",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_sales_invoice: function() {
+	make_sales_invoice() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_installation_note: function() {
+	make_installation_note() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_installation_note",
 			frm: this.frm
 		});
-	},
+	}
 
-	make_sales_return: function() {
+	make_sales_return() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_return",
 			frm: this.frm
 		})
-	},
+	}
 
-	make_delivery_trip: function() {
+	make_delivery_trip() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip",
 			frm: cur_frm
 		})
-	},
+	}
 
-	tc_name: function() {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	items_on_form_rendered: function(doc, grid_row) {
-		erpnext.setup_serial_no();
-	},
+	items_on_form_rendered(doc, grid_row) {
+		erpnext.setup_serial_or_batch_no();
+	}
 
-	packed_items_on_form_rendered: function(doc, grid_row) {
-		erpnext.setup_serial_no();
-	},
+	packed_items_on_form_rendered(doc, grid_row) {
+		erpnext.setup_serial_or_batch_no();
+	}
 
-	close_delivery_note: function(doc){
+	close_delivery_note(doc){
 		this.update_status("Closed")
-	},
+	}
 
-	reopen_delivery_note : function() {
+	reopen_delivery_note() {
 		this.update_status("Submitted")
-	},
+	}
 
-	update_status: function(status) {
+	update_status(status) {
 		var me = this;
 		frappe.ui.form.is_saving = true;
 		frappe.call({
@@ -302,8 +302,8 @@
 				frappe.ui.form.is_saving = false;
 			}
 		})
-	},
-});
+	}
+};
 
 $.extend(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
 
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index a6fbb66..68cba29 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -41,6 +41,15 @@
 	},
 
 	refresh: function (frm) {
+		if (frm.doc.docstatus == 1 && frm.doc.employee) {
+			frm.add_custom_button(__('Expense Claim'), function() {
+				frappe.model.open_mapped_doc({
+					method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.make_expense_claim',
+					frm: cur_frm,
+				});
+			}, __("Create"));
+		}
+
 		if (frm.doc.docstatus == 1 && frm.doc.delivery_stops.length > 0) {
 			frm.add_custom_button(__("Notify Customers via Email"), function () {
 				frm.trigger('notify_customers');
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
index 879901f..11b71c2 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
@@ -21,6 +21,7 @@
   "column_break_4",
   "vehicle",
   "departure_time",
+  "employee",
   "delivery_service_stops",
   "delivery_stops",
   "calculate_arrival_time",
@@ -176,11 +177,19 @@
    "fieldtype": "Data",
    "label": "Driver Email",
    "read_only": 1
+  },
+  {
+   "fetch_from": "driver.employee",
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "label": "Employee",
+   "options": "Employee",
+   "read_only": 1
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-01-26 22:37:14.824021",
+ "modified": "2021-04-30 21:21:36.610142",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Trip",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index de85bc3..81e7301 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -11,6 +11,7 @@
 from frappe.contacts.doctype.address.address import get_address_display
 from frappe.model.document import Document
 from frappe.utils import cint, get_datetime, get_link_to_form
+from frappe.model.mapper import get_mapped_doc
 
 
 class DeliveryTrip(Document):
@@ -394,3 +395,15 @@
 	employee = frappe.db.get_value("Driver", driver, "employee")
 	email = frappe.db.get_value("Employee", employee, "prefered_email")
 	return {"email": email}
+
+@frappe.whitelist()
+def make_expense_claim(source_name, target_doc=None):
+	doc = get_mapped_doc("Delivery Trip", source_name,
+		{"Delivery Trip": {
+			"doctype": "Expense Claim",
+			"field_map": {
+				"name" : "delivery_trip"
+			}
+		}}, target_doc)
+
+	return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
index eeea6da..1e71603 100644
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
@@ -7,7 +7,7 @@
 
 import erpnext
 import frappe
-from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers
+from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers, make_expense_claim
 from erpnext.tests.utils import create_test_contact_and_address
 from frappe.utils import add_days, flt, now_datetime, nowdate
 
@@ -28,6 +28,10 @@
 		frappe.db.sql("delete from `tabEmail Template`")
 		frappe.db.sql("delete from `tabDelivery Trip`")
 
+	def test_expense_claim_fields_are_fetched_properly(self):
+		expense_claim = make_expense_claim(self.delivery_trip.name)
+		self.assertEqual(self.delivery_trip.name, expense_claim.delivery_trip)
+
 	def test_delivery_trip_notify_customers(self):
 		notify_customers(delivery_trip=self.delivery_trip.name)
 		self.delivery_trip.load_from_db()
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 8aec893..45e3c21 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -380,7 +380,7 @@
 
 		// Show Stock Levels only if is_stock_item
 		if (frm.doc.is_stock_item) {
-			frappe.require('assets/js/item-dashboard.min.js', function() {
+			frappe.require('item-dashboard.bundle.js', function() {
 				const section = frm.dashboard.add_section('', __("Stock Levels"));
 				erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({
 					parent: section,
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index 1abbc35..433f78a 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -5,8 +5,8 @@
 
 frappe.provide("erpnext.stock");
 
-erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
-	setup: function() {
+erpnext.stock.LandedCostVoucher = class LandedCostVoucher extends erpnext.stock.StockController {
+	setup() {
 		var me = this;
 		this.frm.fields_dict.purchase_receipts.grid.get_field('receipt_document').get_query =
 			function (doc, cdt, cdn) {
@@ -30,9 +30,9 @@
 		this.frm.add_fetch("receipt_document", "supplier", "supplier");
 		this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
 		this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		var help_content =
 			`<br><br>
 			<table class="table table-bordered" style="background-color: #f9f9f9;">
@@ -67,9 +67,9 @@
 			let company_currency = frappe.get_doc(":Company", this.frm.doc.company).default_currency;
 			this.frm.set_currency_labels(["total_taxes_and_charges"], company_currency);
 		}
-	},
+	}
 
-	get_items_from_purchase_receipts: function() {
+	get_items_from_purchase_receipts() {
 		var me = this;
 		if(!this.frm.doc.purchase_receipts.length) {
 			frappe.msgprint(__("Please enter Purchase Receipt first"));
@@ -82,22 +82,22 @@
 				}
 			});
 		}
-	},
+	}
 
-	amount: function(frm) {
+	amount(frm) {
 		this.set_total_taxes_and_charges();
 		this.set_applicable_charges_for_item();
-	},
+	}
 
-	set_total_taxes_and_charges: function() {
+	set_total_taxes_and_charges() {
 		var total_taxes_and_charges = 0.0;
 		$.each(this.frm.doc.taxes || [], function(i, d) {
 			total_taxes_and_charges += flt(d.base_amount);
 		});
 		this.frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
-	},
+	}
 
-	set_applicable_charges_for_item: function() {
+	set_applicable_charges_for_item() {
 		var me = this;
 
 		if(this.frm.doc.taxes.length) {
@@ -123,15 +123,15 @@
 				refresh_field("items");
 			}
 		}
-	},
-	distribute_charges_based_on: function (frm) {
+	}
+	distribute_charges_based_on (frm) {
 		this.set_applicable_charges_for_item();
-	},
+	}
 
-	items_remove: () => {
+	items_remove() {
 		this.trigger('set_applicable_charges_for_item');
 	}
-});
+};
 
 cur_frm.script_manager.make(erpnext.stock.LandedCostVoucher);
 
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 92c8d21..f516e06 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -407,28 +407,28 @@
 	}
 });
 
-erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.extend({
-	tc_name: function() {
+erpnext.buying.MaterialRequestController = class MaterialRequestController extends erpnext.buying.BuyingController {
+	tc_name() {
 		this.get_terms();
-	},
+	}
 
-	item_code: function() {
+	item_code() {
 		// to override item code trigger from transaction.js
-	},
+	}
 
-	validate_company_and_party: function() {
+	validate_company_and_party() {
 		return true;
-	},
+	}
 
-	calculate_taxes_and_totals: function() {
+	calculate_taxes_and_totals() {
 		return;
-	},
+	}
 
-	validate: function() {
+	validate() {
 		set_schedule_date(this.frm);
-	},
+	}
 
-	onload: function(doc, cdt, cdn) {
+	onload(doc, cdt, cdn) {
 		this.frm.set_query("item_code", "items", function() {
 			if (doc.material_request_type == "Customer Provided") {
 				return{
@@ -450,9 +450,9 @@
 				}
 			}
 		});
-	},
+	}
 
-	items_add: function(doc, cdt, cdn) {
+	items_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		if(doc.schedule_date) {
 			row.schedule_date = doc.schedule_date;
@@ -460,16 +460,16 @@
 		} else {
 			this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
 		}
-	},
+	}
 
-	items_on_form_rendered: function() {
-		set_schedule_date(this.frm);
-	},
-
-	schedule_date: function() {
+	items_on_form_rendered() {
 		set_schedule_date(this.frm);
 	}
-});
+
+	schedule_date() {
+		set_schedule_date(this.frm);
+	}
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 8d7b238..4e2d9e6 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -181,7 +181,7 @@
    "no_copy": 1,
    "oldfieldname": "status",
    "oldfieldtype": "Select",
-   "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived",
+   "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nPartially Received\nOrdered\nIssued\nTransferred\nReceived",
    "print_hide": 1,
    "print_width": "100px",
    "read_only": 1,
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index befdad9..688ae1d 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -114,15 +114,15 @@
 	}
 });
 
-erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend({
-	setup: function(doc) {
+erpnext.stock.PurchaseReceiptController = class PurchaseReceiptController extends erpnext.buying.BuyingController {
+	setup(doc) {
 		this.setup_posting_date_time_check();
-		this._super(doc);
-	},
+		super.setup(doc);
+	}
 
-	refresh: function() {
+	refresh() {
 		var me = this;
-		this._super();
+		super.refresh();
 		if(this.frm.doc.docstatus > 0) {
 			this.show_stock_ledger();
 			//removed for temporary
@@ -201,31 +201,31 @@
 		}
 
 		this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
-	},
+	}
 
-	make_purchase_invoice: function() {
+	make_purchase_invoice() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
 			frm: cur_frm
 		})
-	},
+	}
 
-	make_purchase_return: function() {
+	make_purchase_return() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return",
 			frm: cur_frm
 		})
-	},
+	}
 
-	close_purchase_receipt: function() {
+	close_purchase_receipt() {
 		cur_frm.cscript.update_status("Closed");
-	},
+	}
 
-	reopen_purchase_receipt: function() {
+	reopen_purchase_receipt() {
 		cur_frm.cscript.update_status("Submitted");
-	},
+	}
 
-	make_retention_stock_entry: function() {
+	make_retention_stock_entry() {
 		frappe.call({
 			method: "erpnext.stock.doctype.stock_entry.stock_entry.move_sample_to_retention_warehouse",
 			args:{
@@ -242,13 +242,13 @@
 				}
 			}
 		});
-	},
+	}
 
-	apply_putaway_rule: function() {
+	apply_putaway_rule() {
 		if (this.frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(this.frm);
 	}
 
-});
+};
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.stock.PurchaseReceiptController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 868e553..5095a80 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -13,8 +13,9 @@
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
 from erpnext.stock.doctype.item.test_item import make_item
 from six import iteritems
+from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
 from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 
 class TestPurchaseReceipt(unittest.TestCase):
 	def setUp(self):
@@ -144,6 +145,62 @@
 		self.assertFalse(frappe.db.get_value('Batch', {'item': item.name, 'reference_name': pr.name}))
 		self.assertFalse(frappe.db.get_all('Serial No', {'batch_no': batch_no}))
 
+	def test_duplicate_serial_nos(self):
+		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+		item = frappe.db.exists("Item", {'item_name': 'Test Serialized Item 123'})
+		if not item:
+			item = create_item("Test Serialized Item 123")
+			item.has_serial_no = 1
+			item.serial_no_series = "TSI123-.####"
+			item.save()
+		else:
+			item = frappe.get_doc("Item", {'item_name': 'Test Serialized Item 123'})
+
+		# First make purchase receipt
+		pr = make_purchase_receipt(item_code=item.name, qty=2, rate=500)
+		pr.load_from_db()
+
+		serial_nos = frappe.db.get_value('Stock Ledger Entry',
+			{'voucher_type': 'Purchase Receipt', 'voucher_no': pr.name, 'item_code': item.name}, 'serial_no')
+
+		serial_nos = get_serial_nos(serial_nos)
+
+		self.assertEquals(get_serial_nos(pr.items[0].serial_no), serial_nos)
+
+		# Then tried to receive same serial nos in difference company
+		pr_different_company = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+			serial_no='\n'.join(serial_nos), company='_Test Company 1', do_not_submit=True,
+			warehouse = 'Stores - _TC1')
+
+		self.assertRaises(SerialNoDuplicateError, pr_different_company.submit)
+
+		# Then made delivery note to remove the serial nos from stock
+		dn = create_delivery_note(item_code=item.name, qty=2, rate = 1500, serial_no='\n'.join(serial_nos))
+		dn.load_from_db()
+		self.assertEquals(get_serial_nos(dn.items[0].serial_no), serial_nos)
+
+		posting_date = add_days(today(), -3)
+
+		# Try to receive same serial nos again in the same company with backdated.
+		pr1 = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+			posting_date=posting_date, serial_no='\n'.join(serial_nos), do_not_submit=True)
+
+		self.assertRaises(SerialNoExistsInFutureTransaction, pr1.submit)
+
+		# Try to receive same serial nos with different company with backdated.
+		pr2 = make_purchase_receipt(item_code=item.name, qty=2, rate=500,
+			posting_date=posting_date, serial_no='\n'.join(serial_nos), company='_Test Company 1', do_not_submit=True,
+			warehouse = 'Stores - _TC1')
+
+		self.assertRaises(SerialNoExistsInFutureTransaction, pr2.submit)
+
+		# Receive the same serial nos after the delivery note posting date and time
+		make_purchase_receipt(item_code=item.name, qty=2, rate=500, serial_no='\n'.join(serial_nos))
+
+		# Raise the error for backdated deliver note entry cancel
+		self.assertRaises(SerialNoExistsInFutureTransaction, dn.cancel)
+
 	def test_purchase_receipt_gl_entry(self):
 		pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
 			warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1",
@@ -565,30 +622,6 @@
 
 		new_pr_doc.cancel()
 
-	def test_not_accept_duplicate_serial_no(self):
-		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
-
-		item_code = frappe.db.get_value('Item', {'has_serial_no': 1, 'is_fixed_asset': 0, "has_batch_no": 0})
-		if not item_code:
-			item = make_item("Test Serial Item 1", dict(has_serial_no=1, has_batch_no=0))
-			item_code = item.name
-
-		serial_no = random_string(5)
-		pr1 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no)
-		dn = create_delivery_note(item_code=item_code, qty=1, serial_no=serial_no)
-
-		pr2 = make_purchase_receipt(item_code=item_code, qty=1, serial_no=serial_no, do_not_submit=True)
-		self.assertRaises(SerialNoDuplicateError, pr2.submit)
-
-		se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1,
-			serial_no=serial_no, basic_rate=100, do_not_submit=True)
-		se.submit()
-
-		se.cancel()
-		dn.cancel()
-		pr1.cancel()
-
 	def test_auto_asset_creation(self):
 		asset_item = "Test Asset Item"
 
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index a7dfc9e..56b046a 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -27,10 +27,11 @@
 		dn.reload()
 		self.assertRaises(QualityInspectionRejectedError, dn.submit)
 
-		frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
+		frappe.db.set_value("Quality Inspection", qa.name, "status", "Accepted")
 		dn.reload()
 		dn.submit()
 
+		qa.reload()
 		qa.cancel()
 		dn.reload()
 		dn.cancel()
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 3f83780..63c7189 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -5,7 +5,7 @@
 from __future__ import unicode_literals
 import frappe, erpnext
 from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, add_to_date, today
+from frappe.utils import cint, get_link_to_form, add_to_date, now, today
 from erpnext.stock.stock_ledger import repost_future_sle
 from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
 from frappe.utils.user import get_users_with_role
@@ -127,7 +127,7 @@
 		check_if_stock_and_account_balance_synced(today(), d.name)
 
 def get_repost_item_valuation_entries():
-	date = add_to_date(today(), hours=-3)
+	date = add_to_date(now(), hours=-3)
 
 	return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
 		WHERE status != 'Completed' and creation <= %s and docstatus = 1
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index c02dd2e..5ecc9f8 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -243,7 +243,7 @@
 				if frappe.db.exists("Serial No", serial_no):
 					sr = frappe.db.get_value("Serial No", serial_no, ["name", "item_code", "batch_no", "sales_order",
 						"delivery_document_no", "delivery_document_type", "warehouse", "purchase_document_type",
-						"purchase_document_no", "company"], as_dict=1)
+						"purchase_document_no", "company", "status"], as_dict=1)
 
 					if sr.item_code!=sle.item_code:
 						if not allow_serial_nos_with_different_item(serial_no, sle):
@@ -266,6 +266,9 @@
 							frappe.throw(_("Serial No {0} does not belong to Warehouse {1}").format(serial_no,
 								sle.warehouse), SerialNoWarehouseError)
 
+						if not sr.purchase_document_no:
+							frappe.throw(_("Serial No {0} not in stock").format(serial_no), SerialNoNotExistsError)
+
 						if sle.voucher_type in ("Delivery Note", "Sales Invoice"):
 
 							if sr.batch_no and sr.batch_no != sle.batch_no:
@@ -382,19 +385,6 @@
 	if sn.company != sle.company:
 		return False
 
-	status = False
-	if sn.purchase_document_no:
-		if (sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and
-			sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"]):
-			status = True
-
-		# If status is receipt then system will allow to in-ward the delivered serial no
-		if (status and sle.voucher_type == "Stock Entry" and frappe.db.get_value("Stock Entry",
-			sle.voucher_no, "purpose") in ("Material Receipt", "Material Transfer")):
-			status = False
-
-	return status
-
 def allow_serial_nos_with_different_item(sle_serial_no, sle):
 	"""
 		Allows same serial nos for raw materials and finished goods
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index ef7d54a..6afcd1f 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -783,8 +783,8 @@
 	}
 });
 
-erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
-	setup: function() {
+erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockController {
+	setup() {
 		var me = this;
 
 		this.setup_posting_date_time_check();
@@ -831,9 +831,9 @@
 
 		frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier' }
 		this.frm.set_query("supplier_address", erpnext.queries.address_query)
-	},
+	}
 
-	onload_post_render: function() {
+	onload_post_render() {
 		var me = this;
 		this.set_default_account(function() {
 			if(me.frm.doc.__islocal && me.frm.doc.company && !me.frm.doc.amended_from) {
@@ -842,9 +842,9 @@
 		});
 
 		this.frm.get_field("items").grid.set_multiple_add("item_code", "qty");
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		var me = this;
 		erpnext.toggle_naming_series();
 		this.toggle_related_fields(this.frm.doc);
@@ -855,22 +855,22 @@
 		}
 		erpnext.hide_company();
 		erpnext.utils.add_item(this.frm);
-	},
+	}
 
-	scan_barcode: function() {
+	scan_barcode() {
 		let transaction_controller= new erpnext.TransactionController({frm:this.frm});
 		transaction_controller.scan_barcode();
-	},
+	}
 
-	on_submit: function() {
+	on_submit() {
 		this.clean_up();
-	},
+	}
 
-	after_cancel: function() {
+	after_cancel() {
 		this.clean_up();
-	},
+	}
 
-	set_default_account: function(callback) {
+	set_default_account(callback) {
 		var me = this;
 
 		if(this.frm.doc.company && erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
@@ -890,9 +890,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	clean_up: function() {
+	clean_up() {
 		// Clear Work Order record from locals, because it is updated via Stock Entry
 		if(this.frm.doc.work_order &&
 			in_list(["Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"],
@@ -900,13 +900,13 @@
 			frappe.model.remove_from_locals("Work Order",
 				this.frm.doc.work_order);
 		}
-	},
+	}
 
-	fg_completed_qty: function() {
+	fg_completed_qty() {
 		this.get_items();
-	},
+	}
 
-	get_items: function() {
+	get_items() {
 		var me = this;
 		if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
 			frappe.throw(__("BOM and Manufacturing Quantity are required"));
@@ -922,9 +922,9 @@
 				}
 			});
 		}
-	},
+	}
 
-	work_order: function() {
+	work_order() {
 		var me = this;
 		this.toggle_enable_bom();
 		if(!me.frm.doc.work_order || me.frm.doc.job_card) {
@@ -957,13 +957,13 @@
 				}
 			}
 		});
-	},
+	}
 
-	toggle_enable_bom: function() {
+	toggle_enable_bom() {
 		this.frm.toggle_enable("bom_no", !!!this.frm.doc.work_order);
-	},
+	}
 
-	add_excise_button: function() {
+	add_excise_button() {
 		if(frappe.boot.sysdefaults.country === "India")
 			this.frm.add_custom_button(__("Excise Invoice"), function() {
 				var excise = frappe.model.make_new_doc_and_get_name('Journal Entry');
@@ -971,35 +971,35 @@
 				excise.voucher_type = 'Excise Entry';
 				frappe.set_route('Form', 'Journal Entry', excise.name);
 			}, __('Create'));
-	},
+	}
 
-	items_add: function(doc, cdt, cdn) {
+	items_add(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]);
 
 		if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse;
 		if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse;
-	},
+	}
 
-	from_warehouse: function(doc) {
+	from_warehouse(doc) {
 		this.frm.trigger('set_tansit_warehouse');
 		this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse);
-	},
+	}
 
-	to_warehouse: function(doc) {
+	to_warehouse(doc) {
 		this.set_warehouse_in_children(doc.items, "t_warehouse", doc.to_warehouse);
-	},
+	}
 
-	set_warehouse_in_children: function(child_table, warehouse_field, warehouse) {
+	set_warehouse_in_children(child_table, warehouse_field, warehouse) {
 		let transaction_controller = new erpnext.TransactionController();
 		transaction_controller.autofill_warehouse(child_table, warehouse_field, warehouse);
-	},
+	}
 
-	items_on_form_rendered: function(doc, grid_row) {
-		erpnext.setup_serial_no();
-	},
+	items_on_form_rendered(doc, grid_row) {
+		erpnext.setup_serial_or_batch_no();
+	}
 
-	toggle_related_fields: function(doc) {
+	toggle_related_fields(doc) {
 		this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
 		this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
 
@@ -1026,12 +1026,12 @@
 			doc.purpose!='Material Issue');
 
 		this.frm.fields_dict["items"].grid.set_column_disp("additional_cost", doc.purpose!='Material Issue');
-	},
+	}
 
-	supplier: function(doc) {
+	supplier(doc) {
 		erpnext.utils.get_party_details(this.frm, null, null, null);
 	}
-});
+};
 
 erpnext.stock.select_batch_and_serial_no = (frm, item) => {
 	let get_warehouse_type_and_name = (item) => {
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 48cfa51..2f76bc7 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -76,6 +76,7 @@
 		self.validate_difference_account()
 		self.set_job_card_data()
 		self.set_purpose_for_stock_entry()
+		self.validate_duplicate_serial_no()
 
 		if not self.from_bom:
 			self.fg_completed_qty = 0.0
@@ -587,6 +588,22 @@
 			self.purpose = frappe.get_cached_value('Stock Entry Type',
 				self.stock_entry_type, 'purpose')
 
+	def validate_duplicate_serial_no(self):
+		warehouse_wise_serial_nos = {}
+
+		# In case of repack the source and target serial nos could be same
+		for warehouse in ['s_warehouse', 't_warehouse']:
+			serial_nos = []
+			for row in self.items:
+				if not (row.serial_no and row.get(warehouse)): continue
+
+				for sn in get_serial_nos(row.serial_no):
+					if sn in serial_nos:
+						frappe.throw(_('The serial no {0} has added multiple times in the stock entry {1}')
+							.format(frappe.bold(sn), self.name))
+
+					serial_nos.append(sn)
+
 	def validate_purchase_order(self):
 		"""Throw exception if more raw material is transferred against Purchase Order than in
 		the raw materials supplied table"""
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index ac4ed5e..3badc7e 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -220,8 +220,8 @@
 
 });
 
-erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
-	setup: function() {
+erpnext.stock.StockReconciliation = class StockReconciliation extends erpnext.stock.StockController {
+	setup() {
 		var me = this;
 
 		this.setup_posting_date_time_check();
@@ -249,17 +249,17 @@
 				}
 			}
 		}
-	},
+	}
 
-	refresh: function() {
+	refresh() {
 		if(this.frm.doc.docstatus > 0) {
 			this.show_stock_ledger();
 			if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
 				this.show_general_ledger();
 			}
 		}
-	},
+	}
 
-});
+};
 
 cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm});
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 7c5f4ec..0278c96 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -72,7 +72,7 @@
 
 				if item_dict.get("serial_nos"):
 					item.current_serial_no = item_dict.get("serial_nos")
-					if self.purpose == "Stock Reconciliation":
+					if self.purpose == "Stock Reconciliation" and not item.serial_no:
 						item.serial_no = item.current_serial_no
 
 				item.current_qty = item_dict.get("qty")
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index f18eabc..cf5d98d 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -5,40 +5,44 @@
  "doctype": "DocType",
  "engine": "InnoDB",
  "field_order": [
+  "item_defaults_section",
   "item_naming_by",
   "item_group",
   "stock_uom",
   "default_warehouse",
-  "sample_retention_warehouse",
   "column_break_4",
   "valuation_method",
+  "sample_retention_warehouse",
+  "use_naming_series",
+  "naming_series_prefix",
+  "section_break_9",
   "over_delivery_receipt_allowance",
   "role_allowed_to_over_deliver_receive",
-  "action_if_quality_inspection_is_not_submitted",
-  "show_barcode_field",
-  "clean_description_html",
-  "disable_serial_no_and_batch_selector",
-  "section_break_7",
+  "column_break_12",
   "auto_insert_price_list_rate_if_missing",
   "allow_negative_stock",
-  "column_break_10",
+  "show_barcode_field",
+  "clean_description_html",
+  "action_if_quality_inspection_is_not_submitted",
+  "section_break_7",
   "automatically_set_serial_nos_based_on_fifo",
   "set_qty_in_transactions_based_on_serial_no_input",
+  "column_break_10",
+  "disable_serial_no_and_batch_selector",
   "auto_material_request",
   "auto_indent",
+  "column_break_27",
   "reorder_email_notify",
   "inter_warehouse_transfer_settings_section",
   "allow_from_dn",
+  "column_break_31",
   "allow_from_pr",
   "control_historical_stock_transactions_section",
-  "role_allowed_to_create_edit_back_dated_transactions",
-  "column_break_26",
   "stock_frozen_upto",
   "stock_frozen_upto_days",
-  "stock_auth_role",
-  "batch_id_sb",
-  "use_naming_series",
-  "naming_series_prefix"
+  "column_break_26",
+  "role_allowed_to_create_edit_back_dated_transactions",
+  "stock_auth_role"
  ],
  "fields": [
   {
@@ -102,23 +106,24 @@
    "default": "1",
    "fieldname": "show_barcode_field",
    "fieldtype": "Check",
-   "label": "Show Barcode Field"
+   "label": "Show Barcode Field in Stock Transactions"
   },
   {
    "default": "1",
    "fieldname": "clean_description_html",
    "fieldtype": "Check",
-   "label": "Convert Item Description to Clean HTML"
+   "label": "Convert Item Description to Clean HTML in Transactions"
   },
   {
    "fieldname": "section_break_7",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "label": "Serialised and Batch Setting"
   },
   {
    "default": "0",
    "fieldname": "auto_insert_price_list_rate_if_missing",
    "fieldtype": "Check",
-   "label": "Auto Insert Price List Rate If Missing"
+   "label": "Auto Insert Item Price If Missing"
   },
   {
    "default": "0",
@@ -180,15 +185,10 @@
    "options": "Role"
   },
   {
-   "fieldname": "batch_id_sb",
-   "fieldtype": "Section Break",
-   "label": "Batch Identification"
-  },
-  {
    "default": "0",
    "fieldname": "use_naming_series",
    "fieldtype": "Check",
-   "label": "Use Naming Series"
+   "label": "Have Default Naming Series for Batch ID?"
   },
   {
    "default": "BATCH-",
@@ -242,6 +242,28 @@
    "fieldtype": "Link",
    "label": "Role Allowed to Over Deliver/Receive",
    "options": "Role"
+  },
+  {
+   "fieldname": "item_defaults_section",
+   "fieldtype": "Section Break",
+   "label": "Item Defaults"
+  },
+  {
+   "fieldname": "section_break_9",
+   "fieldtype": "Section Break",
+   "label": "Stock Transactions Settings"
+  },
+  {
+   "fieldname": "column_break_12",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_27",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_31",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "icon-cog",
@@ -249,7 +271,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-03-11 18:48:14.513055",
+ "modified": "2021-04-30 17:27:42.709231",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Settings",
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 3fc1df7..d1dcdc2 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -79,7 +79,7 @@
 		get_price_list_rate(args, item, out)
 
 	if args.customer and cint(args.is_pos):
-		out.update(get_pos_profile_item_details(args.company, args))
+		out.update(get_pos_profile_item_details(args.company, args, update_data=True))
 
 	if (args.get("doctype") == "Material Request" and
 		args.get("material_request_type") == "Material Transfer"):
@@ -470,7 +470,9 @@
 			item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
 			item_group = item_group_doc.parent_item_group
 
-def _get_item_tax_template(args, taxes, out={}, for_validate=False):
+def _get_item_tax_template(args, taxes, out=None, for_validate=False):
+	if out is None:
+		out = {}
 	taxes_with_validity = []
 	taxes_with_no_validity = []
 
@@ -933,10 +935,10 @@
 	return bin_details
 
 def get_company_total_stock(item_code, company):
-	return frappe.db.sql("""SELECT sum(actual_qty) from 
-		(`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name) 
-		WHERE `tabWarehouse`.company = '{0}' and `tabBin`.item_code = '{1}'"""
-		.format(company, item_code))[0][0]
+	return frappe.db.sql("""SELECT sum(actual_qty) from
+		(`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name)
+		WHERE `tabWarehouse`.company = %s and `tabBin`.item_code = %s""",
+		(company, item_code))[0][0]
 
 @frappe.whitelist()
 def get_serial_no_details(item_code, warehouse, stock_qty, serial_no):
diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js
index bddffd4..f00dd3e 100644
--- a/erpnext/stock/page/stock_balance/stock_balance.js
+++ b/erpnext/stock/page/stock_balance/stock_balance.js
@@ -62,7 +62,7 @@
 
 	// page.sort_selector.wrapper.css({'margin-right': '15px', 'margin-top': '4px'});
 
-	frappe.require('assets/js/item-dashboard.min.js', function() {
+	frappe.require('item-dashboard.bundle.js', function() {
 		page.item_dashboard = new erpnext.stock.ItemDashboard({
 			parent: page.main,
 			page_length: 20,
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
index b610e7d..c0ffdc9 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
@@ -79,7 +79,7 @@
 		}
 	});
 
-	frappe.require('assets/js/item-dashboard.min.js', function() {
+	frappe.require('item-dashboard.bundle.js', function() {
 		$(frappe.render_template('warehouse_capacity_summary_header')).appendTo(page.main);
 
 		page.capacity_dashboard = new erpnext.stock.ItemDashboard({
@@ -117,4 +117,4 @@
 		setup_click('Item');
 		setup_click('Warehouse');
 	});
-};
\ No newline at end of file
+};
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 087c12e..01927c2 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -70,7 +70,7 @@
 	return frappe.db.sql("""
 		select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
 		from `tabStock Ledger Entry`
-		where docstatus < 2 and ifnull(batch_no, '') != '' %s
+		where is_cancelled = 0 and docstatus < 2 and ifnull(batch_no, '') != '' %s
 		group by voucher_no, batch_no, item_code, warehouse
 		order by item_code, warehouse""" %
 		conditions, as_dict=1)
diff --git a/erpnext/stock/report/serial_no_ledger/__init__.py b/erpnext/stock/report/serial_no_ledger/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/__init__.py
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js
new file mode 100644
index 0000000..616312e
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.js
@@ -0,0 +1,52 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Serial No Ledger"] = {
+	"filters": [
+		{
+			'label': __('Item Code'),
+			'fieldtype': 'Link',
+			'fieldname': 'item_code',
+			'reqd': 1,
+			'options': 'Item',
+			get_query: function() {
+				return {
+					filters: {
+						'has_serial_no': 1
+					}
+				}
+			}
+		},
+		{
+			'label': __('Serial No'),
+			'fieldtype': 'Link',
+			'fieldname': 'serial_no',
+			'options': 'Serial No',
+			'reqd': 1
+		},
+		{
+			'label': __('Warehouse'),
+			'fieldtype': 'Link',
+			'fieldname': 'warehouse',
+			'options': 'Warehouse',
+			get_query: function() {
+				let company = frappe.query_report.get_filter_value('company');
+
+				if (company) {
+					return {
+						filters: {
+							'company': company
+						}
+					}
+				}
+			}
+		},
+		{
+			'label': __('As On Date'),
+			'fieldtype': 'Date',
+			'fieldname': 'posting_date',
+			'default': frappe.datetime.get_today()
+		},
+	]
+};
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json
new file mode 100644
index 0000000..e20e74c
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.json
@@ -0,0 +1,33 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-04-20 13:32:41.523219",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "json": "{}",
+ "modified": "2021-04-20 13:33:19.015829",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Serial No Ledger",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Stock Ledger Entry",
+ "report_name": "Serial No Ledger",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Stock User"
+  },
+  {
+   "role": "Purchase User"
+  },
+  {
+   "role": "Sales User"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
new file mode 100644
index 0000000..c3339fd
--- /dev/null
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe import _
+from erpnext.stock.stock_ledger import get_stock_ledger_entries
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+def execute(filters=None):
+	columns = get_columns(filters)
+	data = get_data(filters)
+	return columns, data
+
+def get_columns(filters):
+	columns = [{
+		'label': _('Posting Date'),
+		'fieldtype': 'Date',
+		'fieldname': 'posting_date'
+	}, {
+		'label': _('Posting Time'),
+		'fieldtype': 'Time',
+		'fieldname': 'posting_time'
+	}, {
+		'label': _('Voucher Type'),
+		'fieldtype': 'Link',
+		'fieldname': 'voucher_type',
+		'options': 'DocType',
+		'width': 220
+	}, {
+		'label': _('Voucher No'),
+		'fieldtype': 'Dynamic Link',
+		'fieldname': 'voucher_no',
+		'options': 'voucher_type',
+		'width': 220
+	}, {
+		'label': _('Company'),
+		'fieldtype': 'Link',
+		'fieldname': 'company',
+		'options': 'Company',
+		'width': 220
+	}, {
+		'label': _('Warehouse'),
+		'fieldtype': 'Link',
+		'fieldname': 'warehouse',
+		'options': 'Warehouse',
+		'width': 220
+	}]
+
+	return columns
+
+def get_data(filters):
+	return get_stock_ledger_entries(filters, '<=', order="asc") or []
+
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 6dfede4..bbd73e9 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -165,7 +165,7 @@
 		select
 			sle.item_code, warehouse, sle.posting_date, sle.actual_qty, sle.valuation_rate,
 			sle.company, sle.voucher_type, sle.qty_after_transaction, sle.stock_value_difference,
-			sle.item_code as name, sle.voucher_no, sle.stock_value
+			sle.item_code as name, sle.voucher_no, sle.stock_value, sle.batch_no
 		from
 			`tabStock Ledger Entry` sle force index (posting_sort_index)
 		where sle.docstatus < 2 %s %s
@@ -193,7 +193,7 @@
 
 		qty_dict = iwb_map[(d.company, d.item_code, d.warehouse)]
 
-		if d.voucher_type == "Stock Reconciliation":
+		if d.voucher_type == "Stock Reconciliation" and not d.batch_no:
 			qty_diff = flt(d.qty_after_transaction) - flt(qty_dict.bal_qty)
 		else:
 			qty_diff = flt(d.actual_qty)
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
index babc6dc..cb109f8 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js
@@ -14,7 +14,14 @@
 			"fieldname":"warehouse",
 			"label": __("Warehouse"),
 			"fieldtype": "Link",
-			"options": "Warehouse"
+			"options": "Warehouse",
+			"get_query": () => {
+				return {
+					filters: {
+						company: frappe.query_report.get_filter_value('company')
+					}
+				}
+			}
 		},
 		{
 			"fieldname":"item_code",
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 1183e41..808d279 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -6,6 +6,7 @@
 from frappe import _
 from frappe.utils import flt, today
 from erpnext.stock.utils import update_included_uom_in_report, is_reposting_item_valuation_in_progress
+from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_pos_reserved_qty
 
 def execute(filters=None):
 	is_reposting_item_valuation_in_progress()
@@ -49,9 +50,13 @@
 		if (re_order_level or re_order_qty) and re_order_level > bin.projected_qty:
 			shortage_qty = re_order_level - flt(bin.projected_qty)
 
+		reserved_qty_for_pos = get_pos_reserved_qty(bin.item_code, bin.warehouse)
+		if reserved_qty_for_pos:
+			bin.projected_qty -= reserved_qty_for_pos
+
 		data.append([item.name, item.item_name, item.description, item.item_group, item.brand, bin.warehouse,
 			item.stock_uom, bin.actual_qty, bin.planned_qty, bin.indented_qty, bin.ordered_qty,
-			bin.reserved_qty, bin.reserved_qty_for_production, bin.reserved_qty_for_sub_contract,
+			bin.reserved_qty, bin.reserved_qty_for_production, bin.reserved_qty_for_sub_contract, reserved_qty_for_pos,
 			bin.projected_qty, re_order_level, re_order_qty, shortage_qty])
 
 		if include_uom:
@@ -74,9 +79,11 @@
 		{"label": _("Requested Qty"), "fieldname": "indented_qty", "fieldtype": "Float", "width": 110, "convertible": "qty"},
 		{"label": _("Ordered Qty"), "fieldname": "ordered_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
 		{"label": _("Reserved Qty"), "fieldname": "reserved_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
-		{"label": _("Reserved Qty for Production"), "fieldname": "reserved_qty_for_production", "fieldtype": "Float",
+		{"label": _("Reserved for Production"), "fieldname": "reserved_qty_for_production", "fieldtype": "Float",
 			"width": 100, "convertible": "qty"},
-		{"label": _("Reserved for sub contracting"), "fieldname": "reserved_qty_for_sub_contract", "fieldtype": "Float",
+		{"label": _("Reserved for Sub Contracting"), "fieldname": "reserved_qty_for_sub_contract", "fieldtype": "Float",
+			"width": 100, "convertible": "qty"},
+		{"label": _("Reserved for POS Transactions"), "fieldname": "reserved_qty_for_pos", "fieldtype": "Float",
 			"width": 100, "convertible": "qty"},
 		{"label": _("Projected Qty"), "fieldname": "projected_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
 		{"label": _("Reorder Level"), "fieldname": "re_order_level", "fieldtype": "Float", "width": 100, "convertible": "qty"},
diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.py b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
index ed52393..59c253c 100644
--- a/erpnext/stock/report/total_stock_summary/total_stock_summary.py
+++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
@@ -51,7 +51,7 @@
 			INNER JOIN `tabWarehouse` warehouse
 				ON warehouse.name = ledger.warehouse
 			WHERE
-				actual_qty != 0 %s""" % (columns, conditions))
+				ledger.actual_qty != 0 %s""" % (columns, conditions))
 
 def validate_filters(filters):
 	if filters.get("group_by") == 'Company' and \
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index bbfcb7a..9729987 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -2,9 +2,11 @@
 # License: GNU General Public License v3. See license.txt
 from __future__ import unicode_literals
 
-import frappe, erpnext
+import frappe
+import erpnext
+import copy
 from frappe import _
-from frappe.utils import cint, flt, cstr, now, now_datetime
+from frappe.utils import cint, flt, cstr, now, get_link_to_form
 from frappe.model.meta import get_field_precision
 from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
 from erpnext.stock.utils import get_bin
@@ -13,6 +15,8 @@
 
 # future reposting
 class NegativeStockError(frappe.ValidationError): pass
+class SerialNoExistsInFutureTransaction(frappe.ValidationError):
+	pass
 
 _exceptions = frappe.local('stockledger_exceptions')
 # _exceptions = []
@@ -27,6 +31,9 @@
 			set_as_cancel(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
 
 		for sle in sl_entries:
+			if sle.serial_no:
+				validate_serial_no(sle)
+
 			if cancel:
 				sle['actual_qty'] = -flt(sle.get('actual_qty'))
 
@@ -46,6 +53,30 @@
 			args = sle_doc.as_dict()
 			update_bin(args, allow_negative_stock, via_landed_cost_voucher)
 
+def validate_serial_no(sle):
+	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+	for sn in get_serial_nos(sle.serial_no):
+		args = copy.deepcopy(sle)
+		args.serial_no = sn
+		args.warehouse = ''
+
+		vouchers = []
+		for row in get_stock_ledger_entries(args, '>'):
+			voucher_type = frappe.bold(row.voucher_type)
+			voucher_no = frappe.bold(get_link_to_form(row.voucher_type, row.voucher_no))
+			vouchers.append(f'{voucher_type} {voucher_no}')
+
+		if vouchers:
+			serial_no = frappe.bold(sn)
+			msg = (f'''The serial no {serial_no} has been used in the future transactions so you need to cancel them first.
+				The list of the transactions are as below.''' + '<br><br><ul><li>')
+
+			msg += '</li><li>'.join(vouchers)
+			msg += '</li></ul>'
+
+			title = 'Cannot Submit' if not sle.get('is_cancelled') else 'Cannot Cancel'
+			frappe.throw(_(msg), title=_(title), exc=SerialNoExistsInFutureTransaction)
+
 def validate_cancellation(args):
 	if args[0].get("is_cancelled"):
 		repost_entry = frappe.db.get_value("Repost Item Valuation", {
@@ -718,7 +749,17 @@
 		conditions += " and " + previous_sle.get("warehouse_condition")
 
 	if check_serial_no and previous_sle.get("serial_no"):
-		conditions += " and serial_no like {}".format(frappe.db.escape('%{0}%'.format(previous_sle.get("serial_no"))))
+		# conditions += " and serial_no like {}".format(frappe.db.escape('%{0}%'.format(previous_sle.get("serial_no"))))
+		serial_no = previous_sle.get("serial_no")
+		conditions += (""" and
+			(
+				serial_no = {0}
+				or serial_no like {1}
+				or serial_no like {2}
+				or serial_no like {3}
+			)
+		""").format(frappe.db.escape(serial_no), frappe.db.escape('{}\n%'.format(serial_no)),
+			frappe.db.escape('%\n{}'.format(serial_no)), frappe.db.escape('%\n{}\n%'.format(serial_no)))
 
 	if not previous_sle.get("posting_date"):
 		previous_sle["posting_date"] = "1900-01-01"
@@ -793,12 +834,12 @@
 	if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
 			and cint(erpnext.is_perpetual_inventory_enabled(company)):
 		frappe.local.message_log = []
-		form_link = frappe.utils.get_link_to_form("Item", item_code)
+		form_link = get_link_to_form("Item", item_code)
 
 		message = _("Valuation Rate for the Item {0}, is required to do accounting entries for {1} {2}.").format(form_link, voucher_type, voucher_no)
-		message += "<br><br>" + _(" Here are the options to proceed:")
+		message += "<br><br>" + _("Here are the options to proceed:")
 		solutions = "<li>" + _("If the item is transacting as a Zero Valuation Rate item in this entry, please enable 'Allow Zero Valuation Rate' in the {0} Item table.").format(voucher_type) + "</li>"
-		solutions += "<li>" + _("If not, you can Cancel / Submit this entry ") + _("{0}").format(frappe.bold("after")) + _(" performing either one below:") + "</li>"
+		solutions += "<li>" + _("If not, you can Cancel / Submit this entry") + " {0} ".format(frappe.bold("after")) + _("performing either one below:") + "</li>"
 		sub_solutions = "<ul><li>" + _("Create an incoming stock transaction for the Item.") + "</li>"
 		sub_solutions += "<li>" + _("Mention Valuation Rate in the Item master.") + "</li></ul>"
 		msg = message + solutions + sub_solutions + "</li>"
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.js b/erpnext/support/doctype/warranty_claim/warranty_claim.js
index 79f4675..c9aa41f 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.js
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.js
@@ -36,8 +36,8 @@
 	}
 });
 
-erpnext.support.WarrantyClaim = frappe.ui.form.Controller.extend({
-	refresh: function() {
+erpnext.support.WarrantyClaim = class WarrantyClaim extends frappe.ui.form.Controller {
+	refresh() {
 		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
 
 		if(!cur_frm.doc.__islocal &&
@@ -45,15 +45,15 @@
 			cur_frm.add_custom_button(__('Maintenance Visit'),
 				this.make_maintenance_visit);
 		}
-	},
+	}
 
-	make_maintenance_visit: function() {
+	make_maintenance_visit() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit",
 			frm: cur_frm
 		})
 	}
-});
+};
 
 $.extend(cur_frm.cscript, new erpnext.support.WarrantyClaim({frm: cur_frm}));
 
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
index 135982d..17f6880 100644
--- a/erpnext/templates/generators/item/item.html
+++ b/erpnext/templates/generators/item/item.html
@@ -28,9 +28,7 @@
 
 {% block base_scripts %}
 <!-- js should be loaded in body! -->
-<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>
-<script type="text/javascript" src="/assets/js/frappe-web.min.js"></script>
-<script type="text/javascript" src="/assets/js/control.min.js"></script>
-<script type="text/javascript" src="/assets/js/dialog.min.js"></script>
-<script type="text/javascript" src="/assets/js/bootstrap-4-web.min.js"></script>
-{% endblock %}
\ No newline at end of file
+{{ include_script("frappe-web.bundle.js") }}
+{{ include_script("controls.bundle.js") }}
+{{ include_script("dialog.bundle.js") }}
+{% endblock %}
diff --git a/erpnext/templates/includes/rfq.js b/erpnext/templates/includes/rfq.js
index b56c416..37beb5a 100644
--- a/erpnext/templates/includes/rfq.js
+++ b/erpnext/templates/includes/rfq.js
@@ -11,23 +11,23 @@
 	doc.buying_price_list = "{{ doc.buying_price_list }}"
 });
 
-rfq = Class.extend({
-	init: function(){
+rfq = class rfq {
+	constructor(){
 		this.onfocus_select_all();
 		this.change_qty();
 		this.change_rate();
 		this.terms();
 		this.submit_rfq();
 		this.navigate_quotations();
-	},
+	}
 
-	onfocus_select_all: function(){
+	onfocus_select_all(){
 		$("input").click(function(){
 			$(this).select();
 		})
-	},
+	}
 
-	change_qty: function(){
+	change_qty(){
 		var me = this;
 		$('.rfq-items').on("change", ".rfq-qty", function(){
 			me.idx = parseFloat($(this).attr('data-idx'));
@@ -36,9 +36,9 @@
 			me.update_qty_rate();
 			$(this).val(format_number(me.qty, doc.number_format, 2));
 		})
-	},
+	}
 
-	change_rate: function(){
+	change_rate(){
 		var me = this;
 		$(".rfq-items").on("change", ".rfq-rate", function(){
 			me.idx = parseFloat($(this).attr('data-idx'));
@@ -47,15 +47,15 @@
 			me.update_qty_rate();
 			$(this).val(format_number(me.rate, doc.number_format, 2));
 		})
-	},
+	}
 
-	terms: function(){
+	terms(){
 		$(".terms").on("change", ".terms-feedback", function(){
 			doc.terms = $(this).val();
 		})
-	},
+	}
 
-	update_qty_rate: function(){
+	update_qty_rate(){
 		var me = this;
 		doc.grand_total = 0.0;
 		$.each(doc.items, function(idx, data){
@@ -69,9 +69,9 @@
 			doc.grand_total += flt(data.amount);
 			$('.tax-grand-total').text(format_number(doc.grand_total, doc.number_format, 2));
 		})
-	},
+	}
 
-	submit_rfq: function(){
+	submit_rfq(){
 		$('.btn-sm').click(function(){
 			frappe.freeze();
 			frappe.call({
@@ -90,12 +90,12 @@
 				}
 			})
 		})
-	},
+	}
 
-	navigate_quotations: function() {
+	navigate_quotations() {
 		$('.quotations').click(function(){
 			name = $(this).attr('idx')
 			window.location.href = "/quotations/" + encodeURIComponent(name);
 		})
 	}
-})
+}
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index ea34371..c64c634 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -139,9 +139,7 @@
 
 {% block base_scripts %}
 <!-- js should be loaded in body! -->
-<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>
-<script type="text/javascript" src="/assets/js/frappe-web.min.js"></script>
-<script type="text/javascript" src="/assets/js/control.min.js"></script>
-<script type="text/javascript" src="/assets/js/dialog.min.js"></script>
-<script type="text/javascript" src="/assets/js/bootstrap-4-web.min.js"></script>
+{{ include_script("frappe-web.bundle.js") }}
+{{ include_script("controls.bundle.js") }}
+{{ include_script("dialog.bundle.js") }}
 {% endblock %}
diff --git a/yarn.lock b/yarn.lock
index 635bb06..242695c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1540,16 +1540,11 @@
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
-ini@1.3.7:
+ini@1.3.7, ini@~1.3.0:
   version "1.3.7"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
   integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
 
-ini@~1.3.0:
-  version "1.3.5"
-  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
-  integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-
 is-callable@^1.1.5:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"