Merge branch 'frappe:develop' into currency-exchange-settings
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
index 4b1147e..5b607a9 100644
--- a/.github/workflows/docker-release.yml
+++ b/.github/workflows/docker-release.yml
@@ -11,4 +11,4 @@
     - name: curl
       run: |
         apk add curl bash
-        curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests
+        curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
index 92a1962..f8abb6c 100644
--- a/.github/workflows/patch.yml
+++ b/.github/workflows/patch.yml
@@ -86,4 +86,27 @@
           cd ~/frappe-bench/
           wget https://erpnext.com/files/v10-erpnext.sql.gz
           bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz
+
+          git -C "apps/frappe" remote set-url upstream https://github.com/frappe/frappe.git
+          git -C "apps/erpnext" remote set-url upstream https://github.com/frappe/erpnext.git
+
+          for version in $(seq 12 13)
+          do
+              echo "Updating to v$version"
+              branch_name="version-$version"
+
+              git -C "apps/frappe" fetch --depth 1 upstream $branch_name:$branch_name
+              git -C "apps/erpnext" fetch --depth 1 upstream $branch_name:$branch_name
+
+              git -C "apps/frappe" checkout -q -f $branch_name
+              git -C "apps/erpnext" checkout -q -f $branch_name
+
+              bench setup requirements --python
+              bench --site test_site migrate
+          done
+
+
+          echo "Updating to latest version"
+          git -C "apps/frappe" checkout -q -f "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}"
+          git -C "apps/erpnext" checkout -q -f "$GITHUB_SHA"
           bench --site test_site migrate
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index 05caafe..3596c34 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -81,7 +81,7 @@
 def identify_is_group(child):
 	if child.get("is_group"):
 		is_group = child.get("is_group")
-	elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate", "account_number"])):
+	elif len(set(child.keys()) - set(["account_name", "account_type", "root_type", "is_group", "tax_rate", "account_number"])):
 		is_group = 1
 	else:
 		is_group = 0
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 1e983b1..60015f6 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -58,7 +58,8 @@
 
 			# Update outstanding amt on against voucher
 			if (self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees']
-				and self.against_voucher and self.flags.update_outstanding == 'Yes'):
+				and self.against_voucher and self.flags.update_outstanding == 'Yes'
+				and not frappe.flags.is_reverse_depr_entry):
 					update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
 						self.against_voucher)
 
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index e568a82..f3a0bdb 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -58,7 +58,10 @@
 		if not frappe.flags.in_import:
 			self.validate_total_debit_and_credit()
 
-		self.validate_against_jv()
+		if not frappe.flags.is_reverse_depr_entry:
+			self.validate_against_jv()
+			self.validate_stock_accounts()
+
 		self.validate_reference_doc()
 		if self.docstatus == 0:
 			self.set_against_account()
@@ -69,7 +72,6 @@
 		self.validate_empty_accounts_table()
 		self.set_account_and_party_balance()
 		self.validate_inter_company_accounts()
-		self.validate_stock_accounts()
 
 		if self.docstatus == 0:
 			self.apply_tax_withholding()
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 9b4a91d..8bbe3db 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -389,7 +389,7 @@
 						invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding
 						invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)
 
-		for key, allocated_amount in iteritems(invoice_payment_amount_map):
+		for idx, (key, allocated_amount) in enumerate(iteritems(invoice_payment_amount_map), 1):
 			if not invoice_paid_amount_map.get(key):
 				frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1]))
 
@@ -407,7 +407,7 @@
 					(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
 			else:
 				if allocated_amount > outstanding:
-					frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
+					frappe.throw(_('Row #{0}: Cannot allocate more than {1} against payment term {2}').format(idx, outstanding, key[0]))
 
 				if allocated_amount and outstanding:
 					frappe.db.sql("""
@@ -1053,12 +1053,6 @@
 	party_account_currency = get_account_currency(args.get("party_account"))
 	company_currency = frappe.get_cached_value('Company',  args.get("company"),  "default_currency")
 
-	# Get negative outstanding sales /purchase invoices
-	negative_outstanding_invoices = []
-	if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
-		negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
-			args.get("party_account"), args.get("company"), party_account_currency, company_currency)
-
 	# Get positive outstanding sales /purchase invoices/ Fees
 	condition = ""
 	if args.get("voucher_type") and args.get("voucher_no"):
@@ -1105,6 +1099,12 @@
 		orders_to_be_billed =  get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
 			args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)
 
+	# Get negative outstanding sales /purchase invoices
+	negative_outstanding_invoices = []
+	if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
+		negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
+			args.get("party_account"), party_account_currency, company_currency, condition=condition)
+
 	data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
 
 	if not data:
@@ -1137,22 +1137,26 @@
 								'invoice_amount': flt(d.invoice_amount),
 								'outstanding_amount': flt(d.outstanding_amount),
 								'payment_amount': payment_term.payment_amount,
-								'payment_term': payment_term.payment_term,
-								'allocated_amount': payment_term.outstanding
+								'payment_term': payment_term.payment_term
 							}))
 
+	outstanding_invoices_after_split = []
 	if invoice_ref_based_on_payment_terms:
 		for idx, ref in invoice_ref_based_on_payment_terms.items():
-			voucher_no = outstanding_invoices[idx]['voucher_no']
-			voucher_type = outstanding_invoices[idx]['voucher_type']
+			voucher_no = ref[0]['voucher_no']
+			voucher_type = ref[0]['voucher_type']
 
-			frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format(
+			frappe.msgprint(_("Spliting {} {} into {} row(s) as per Payment Terms").format(
 				voucher_type, voucher_no, len(ref)), alert=True)
 
-			outstanding_invoices.pop(idx - 1)
-			outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
+			outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]
 
-	return outstanding_invoices
+			existing_row = list(filter(lambda x: x.get('voucher_no') == voucher_no, outstanding_invoices))
+			index = outstanding_invoices.index(existing_row[0])
+			outstanding_invoices.pop(index)
+
+	outstanding_invoices_after_split += outstanding_invoices
+	return outstanding_invoices_after_split
 
 def get_orders_to_be_billed(posting_date, party_type, party,
 	company, party_account_currency, company_currency, cost_center=None, filters=None):
@@ -1219,7 +1223,7 @@
 	return order_list
 
 def get_negative_outstanding_invoices(party_type, party, party_account,
-	company, party_account_currency, company_currency, cost_center=None):
+	party_account_currency, company_currency, cost_center=None, condition=None):
 	voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
 	supplier_condition = ""
 	if voucher_type == "Purchase Invoice":
@@ -1241,19 +1245,21 @@
 			`tab{voucher_type}`
 		where
 			{party_type} = %s and {party_account} = %s and docstatus = 1 and
-			company = %s and outstanding_amount < 0
+			outstanding_amount < 0
 			{supplier_condition}
+			{condition}
 		order by
 			posting_date, name
 		""".format(**{
 			"supplier_condition": supplier_condition,
+			"condition": condition,
 			"rounded_total_field": rounded_total_field,
 			"grand_total_field": grand_total_field,
 			"voucher_type": voucher_type,
 			"party_type": scrub(party_type),
 			"party_account": "debit_to" if party_type == "Customer" else "credit_to",
 			"cost_center": cost_center
-		}), (party, party_account, company), as_dict=True)
+		}), (party, party_account), as_dict=True)
 
 
 @frappe.whitelist()
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js
index aa373bc..9074def 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.js
+++ b/erpnext/accounts/doctype/payment_order/payment_order.js
@@ -10,6 +10,9 @@
 				}
 			}
 		});
+
+		frm.set_df_property('references', 'cannot_add_rows', true);
+		frm.set_df_property('references', 'cannot_delete_rows', true);
 	},
 	refresh: function(frm) {
 		if (frm.doc.docstatus == 0) {
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 412833b..ad5a840 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -4,9 +4,14 @@
 frappe.provide("erpnext.accounts");
 erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller {
 	onload() {
-		var me = this;
+		const default_company = frappe.defaults.get_default('company');
+		this.frm.set_value('company', default_company);
 
-		this.frm.set_query("party_type", function() {
+		this.frm.set_value('party_type', '');
+		this.frm.set_value('party', '');
+		this.frm.set_value('receivable_payable_account', '');
+
+		this.frm.set_query("party_type", () => {
 			return {
 				"filters": {
 					"name": ["in", Object.keys(frappe.boot.party_account_types)],
@@ -14,44 +19,30 @@
 			}
 		});
 
-		this.frm.set_query('receivable_payable_account', function() {
-			check_mandatory(me.frm);
+		this.frm.set_query('receivable_payable_account', () => {
 			return {
 				filters: {
-					"company": me.frm.doc.company,
+					"company": this.frm.doc.company,
 					"is_group": 0,
-					"account_type": frappe.boot.party_account_types[me.frm.doc.party_type]
+					"account_type": frappe.boot.party_account_types[this.frm.doc.party_type]
 				}
 			};
 		});
 
-		this.frm.set_query('bank_cash_account', function() {
-			check_mandatory(me.frm, true);
+		this.frm.set_query('bank_cash_account', () => {
 			return {
 				filters:[
-					['Account', 'company', '=', me.frm.doc.company],
+					['Account', 'company', '=', this.frm.doc.company],
 					['Account', 'is_group', '=', 0],
 					['Account', 'account_type', 'in', ['Bank', 'Cash']]
 				]
 			};
 		});
-
-		this.frm.set_value('party_type', '');
-		this.frm.set_value('party', '');
-		this.frm.set_value('receivable_payable_account', '');
-
-		var check_mandatory = (frm, only_company=false) => {
-			var title = __("Mandatory");
-			if (only_company && !frm.doc.company) {
-				frappe.throw({message: __("Please Select a Company First"), title: title});
-			} else if (!frm.doc.company || !frm.doc.party_type) {
-				frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title});
-			}
-		};
 	}
 
 	refresh() {
 		this.frm.disable_save();
+
 		this.frm.set_df_property('invoices', 'cannot_delete_rows', true);
 		this.frm.set_df_property('payments', 'cannot_delete_rows', true);
 		this.frm.set_df_property('allocation', 'cannot_delete_rows', true);
@@ -85,76 +76,92 @@
 	}
 
 	company() {
-		var me = this;
+		this.frm.set_value('party', '');
 		this.frm.set_value('receivable_payable_account', '');
-		me.frm.clear_table("allocation");
-		me.frm.clear_table("invoices");
-		me.frm.clear_table("payments");
-		me.frm.refresh_fields();
-		me.frm.trigger('party');
+	}
+
+	party_type() {
+		this.frm.set_value('party', '');
 	}
 
 	party() {
-		var me = this;
-		if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
+		this.frm.set_value('receivable_payable_account', '');
+		this.frm.trigger("clear_child_tables");
+
+		if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) {
 			return frappe.call({
 				method: "erpnext.accounts.party.get_party_account",
 				args: {
-					company: me.frm.doc.company,
-					party_type: me.frm.doc.party_type,
-					party: me.frm.doc.party
+					company: this.frm.doc.company,
+					party_type: this.frm.doc.party_type,
+					party: this.frm.doc.party
 				},
-				callback: function(r) {
+				callback: (r) => {
 					if (!r.exc && r.message) {
-						me.frm.set_value("receivable_payable_account", r.message);
+						this.frm.set_value("receivable_payable_account", r.message);
 					}
-					me.frm.refresh();
+					this.frm.refresh();
+
 				}
 			});
 		}
 	}
 
+	receivable_payable_account() {
+		this.frm.trigger("clear_child_tables");
+		this.frm.refresh();
+	}
+
+	clear_child_tables() {
+		this.frm.clear_table("invoices");
+		this.frm.clear_table("payments");
+		this.frm.clear_table("allocation");
+		this.frm.refresh_fields();
+	}
+
 	get_unreconciled_entries() {
-		var me = this;
+		this.frm.clear_table("allocation");
 		return this.frm.call({
-			doc: me.frm.doc,
+			doc: this.frm.doc,
 			method: 'get_unreconciled_entries',
-			callback: function(r, rt) {
-				if (!(me.frm.doc.payments.length || me.frm.doc.invoices.length)) {
-					frappe.throw({message: __("No invoice and payment records found for this party")});
+			callback: () => {
+				if (!(this.frm.doc.payments.length || this.frm.doc.invoices.length)) {
+					frappe.throw({message: __("No Unreconciled Invoices and Payments found for this party and account")});
+				} else if (!(this.frm.doc.invoices.length)) {
+					frappe.throw({message: __("No Outstanding Invoices found for this party")});
+				} else if (!(this.frm.doc.payments.length)) {
+					frappe.throw({message: __("No Unreconciled Payments found for this party")});
 				}
-				me.frm.refresh();
+				this.frm.refresh();
 			}
 		});
 
 	}
 
 	allocate() {
-		var me = this;
-		let payments = me.frm.fields_dict.payments.grid.get_selected_children();
+		let payments = this.frm.fields_dict.payments.grid.get_selected_children();
 		if (!(payments.length)) {
-			payments = me.frm.doc.payments;
+			payments = this.frm.doc.payments;
 		}
-		let invoices = me.frm.fields_dict.invoices.grid.get_selected_children();
+		let invoices = this.frm.fields_dict.invoices.grid.get_selected_children();
 		if (!(invoices.length)) {
-			invoices = me.frm.doc.invoices;
+			invoices = this.frm.doc.invoices;
 		}
-		return me.frm.call({
-			doc: me.frm.doc,
+		return this.frm.call({
+			doc: this.frm.doc,
 			method: 'allocate_entries',
 			args: {
 				payments: payments,
 				invoices: invoices
 			},
-			callback: function() {
-				me.frm.refresh();
+			callback: () => {
+				this.frm.refresh();
 			}
 		});
 	}
 
 	reconcile() {
-		var me = this;
-		var show_dialog = me.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
+		var show_dialog = this.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
 
 		if (show_dialog && show_dialog.length) {
 
@@ -186,10 +193,10 @@
 							label: __("Difference Account"),
 							fieldname: 'difference_account',
 							reqd: 1,
-							get_query: function() {
+							get_query: () => {
 								return {
 									filters: {
-										company: me.frm.doc.company,
+										company: this.frm.doc.company,
 										is_group: 0
 									}
 								}
@@ -203,7 +210,7 @@
 						}]
 					},
 				],
-				primary_action: function() {
+				primary_action: () => {
 					const args = dialog.get_values()["allocation"];
 
 					args.forEach(d => {
@@ -211,7 +218,7 @@
 							"difference_account", d.difference_account);
 					});
 
-					me.reconcile_payment_entries();
+					this.reconcile_payment_entries();
 					dialog.hide();
 				},
 				primary_action_label: __('Reconcile Entries')
@@ -237,15 +244,12 @@
 	}
 
 	reconcile_payment_entries() {
-		var me = this;
-
 		return this.frm.call({
-			doc: me.frm.doc,
+			doc: this.frm.doc,
 			method: 'reconcile',
-			callback: function(r, rt) {
-				me.frm.clear_table("allocation");
-				me.frm.refresh_fields();
-				me.frm.refresh();
+			callback: () => {
+				this.frm.clear_table("allocation");
+				this.frm.refresh();
 			}
 		});
 	}
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 4f26ed4..28bd102 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -114,6 +114,8 @@
 	def merge_pos_invoice_into(self, invoice, data):
 		items, payments, taxes = [], [], []
 		loyalty_amount_sum, loyalty_points_sum = 0, 0
+		rounding_adjustment, base_rounding_adjustment = 0, 0
+		rounded_total, base_rounded_total = 0, 0
 		for doc in data:
 			map_doc(doc, invoice, table_map={ "doctype": invoice.doctype })
 
@@ -162,6 +164,11 @@
 						found = True
 				if not found:
 					payments.append(payment)
+			rounding_adjustment += doc.rounding_adjustment
+			rounded_total += doc.rounded_total
+			base_rounding_adjustment += doc.rounding_adjustment
+			base_rounded_total += doc.rounded_total
+
 
 		if loyalty_points_sum:
 			invoice.redeem_loyalty_points = 1
@@ -171,6 +178,10 @@
 		invoice.set('items', items)
 		invoice.set('payments', payments)
 		invoice.set('taxes', taxes)
+		invoice.set('rounding_adjustment',rounding_adjustment)
+		invoice.set('rounding_adjustment',base_rounding_adjustment)
+		invoice.set('base_rounded_total',base_rounded_total)
+		invoice.set('rounded_total',rounded_total)
 		invoice.additional_discount_percentage = 0
 		invoice.discount_amount = 0.0
 		invoice.taxes_and_charges = None
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js
index 9003af5..7d8f356 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.js
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js
@@ -2,11 +2,11 @@
 // For license information, please see license.txt
 
 let search_fields_datatypes = ['Data', 'Link', 'Dynamic Link', 'Long Text', 'Select', 'Small Text', 'Text', 'Text Editor'];
-let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "hub_sync_id", "asset_naming_series",
+let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "asset_naming_series",
 	"default_material_request_type", "valuation_method", "warranty_period", "weight_uom", "batch_number_series",
 	"serial_no_series", "purchase_uom", "customs_tariff_number", "sales_uom", "deferred_revenue_account",
 	"deferred_expense_account", "quality_inspection_template", "route", "slideshow", "website_image_alt", "thumbnail",
-	"web_long_description", "hub_sync_id"]
+	"web_long_description"]
 
 frappe.ui.form.on('POS Settings', {
 	onload: function(frm) {
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 0637fda..ef44b41 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -29,6 +29,9 @@
 	pricing_rules = []
 	values =  {}
 
+	if not frappe.db.exists('Pricing Rule', {'disable': 0, args.transaction_type: 1}):
+		return
+
 	for apply_on in ['Item Code', 'Item Group', 'Brand']:
 		pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
 		if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 40ad7b7..cd204ba 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -37,7 +37,7 @@
 	get_disposal_account_and_cost_center,
 	get_gl_entries_on_asset_disposal,
 	get_gl_entries_on_asset_regain,
-	post_depreciation_entries,
+	make_depreciation_entry,
 )
 from erpnext.controllers.selling_controller import SellingController
 from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
@@ -934,6 +934,7 @@
 						asset.db_set("disposal_date", None)
 
 						if asset.calculate_depreciation:
+							self.reverse_depreciation_entry_made_after_sale(asset)
 							self.reset_depreciation_schedule(asset)
 
 					else:
@@ -997,22 +998,20 @@
 
 	def depreciate_asset(self, asset):
 		asset.flags.ignore_validate_update_after_submit = True
-		asset.prepare_depreciation_data(self.posting_date)
+		asset.prepare_depreciation_data(date_of_sale=self.posting_date)
 		asset.save()
 
-		post_depreciation_entries(self.posting_date)
+		make_depreciation_entry(asset.name, self.posting_date)
 
 	def reset_depreciation_schedule(self, asset):
 		asset.flags.ignore_validate_update_after_submit = True
 
 		# recreate original depreciation schedule of the asset
-		asset.prepare_depreciation_data()
+		asset.prepare_depreciation_data(date_of_return=self.posting_date)
 
 		self.modify_depreciation_schedule_for_asset_repairs(asset)
 		asset.save()
 
-		self.delete_depreciation_entry_made_after_sale(asset)
-
 	def modify_depreciation_schedule_for_asset_repairs(self, asset):
 		asset_repairs = frappe.get_all(
 			'Asset Repair',
@@ -1026,7 +1025,7 @@
 				asset_repair.modify_depreciation_schedule()
 				asset.prepare_depreciation_data()
 
-	def delete_depreciation_entry_made_after_sale(self, asset):
+	def reverse_depreciation_entry_made_after_sale(self, asset):
 		from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
 
 		posting_date_of_original_invoice = self.get_posting_date_of_sales_invoice()
@@ -1041,11 +1040,19 @@
 				row += 1
 
 			if schedule.schedule_date == posting_date_of_original_invoice:
-				if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice):
+				if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice) \
+					or self.sale_happens_in_the_future(posting_date_of_original_invoice):
+
 					reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
 					reverse_journal_entry.posting_date = nowdate()
+					frappe.flags.is_reverse_depr_entry = True
 					reverse_journal_entry.submit()
 
+					frappe.flags.is_reverse_depr_entry = False
+					asset.flags.ignore_validate_update_after_submit = True
+					schedule.journal_entry = None
+					asset.save()
+
 	def get_posting_date_of_sales_invoice(self):
 		return frappe.db.get_value('Sales Invoice', self.return_against, 'posting_date')
 
@@ -1060,6 +1067,12 @@
 					return True
 		return False
 
+	def sale_happens_in_the_future(self, posting_date_of_original_invoice):
+		if posting_date_of_original_invoice > getdate():
+			return True
+
+		return False
+
 	@property
 	def enable_discount_accounting(self):
 		if not hasattr(self, "_enable_discount_accounting"):
@@ -1975,22 +1988,23 @@
 	def append_payment(payment_mode):
 		payment = doc.append('payments', {})
 		payment.default = payment_mode.default
-		payment.mode_of_payment = payment_mode.parent
+		payment.mode_of_payment = payment_mode.mop
 		payment.account = payment_mode.default_account
 		payment.type = payment_mode.type
 
 	doc.set('payments', [])
 	invalid_modes = []
-	for pos_payment_method in pos_profile.get('payments'):
-		pos_payment_method = pos_payment_method.as_dict()
+	mode_of_payments = [d.mode_of_payment for d in pos_profile.get('payments')]
+	mode_of_payments_info = get_mode_of_payments_info(mode_of_payments, doc.company)
 
-		payment_mode = get_mode_of_payment_info(pos_payment_method.mode_of_payment, doc.company)
+	for row in pos_profile.get('payments'):
+		payment_mode = mode_of_payments_info.get(row.mode_of_payment)
 		if not payment_mode:
-			invalid_modes.append(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment))
+			invalid_modes.append(get_link_to_form("Mode of Payment", row.mode_of_payment))
 			continue
 
-		payment_mode[0].default = pos_payment_method.default
-		append_payment(payment_mode[0])
+		payment_mode.default = row.default
+		append_payment(payment_mode)
 
 	if invalid_modes:
 		if invalid_modes == 1:
@@ -2006,6 +2020,24 @@
 		where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
 	{'company': doc.company}, as_dict=1)
 
+def get_mode_of_payments_info(mode_of_payments, company):
+	data = frappe.db.sql(
+		"""
+		select
+			mpa.default_account, mpa.parent as mop, mp.type as type
+		from
+			`tabMode of Payment Account` mpa,`tabMode of Payment` mp
+		where
+			mpa.parent = mp.name and
+			mpa.company = %s and
+			mp.enabled = 1 and
+			mp.name in (%s)
+		group by
+			mp.name
+		""", (company, mode_of_payments), as_dict=1)
+
+	return {row.get('mop'): row for row in data}
+
 def get_mode_of_payment_info(mode_of_payment, company):
 	return frappe.db.sql("""
 		select mpa.default_account, mpa.parent, mp.type as type
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 56de3c6..262c083 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2237,9 +2237,9 @@
 		check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
 		enable_discount_accounting(enable=0)
 
-	def test_asset_depreciation_on_sale(self):
+	def test_asset_depreciation_on_sale_with_pro_rata(self):
 		"""
-			Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on Sept 30.
+			Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale.
 		"""
 
 		create_asset_data()
@@ -2252,7 +2252,7 @@
 		expected_values = [
 			["2020-06-30", 1311.48, 1311.48],
 			["2021-06-30", 20000.0, 21311.48],
-			["2021-09-30", 3966.76, 25278.24]
+			["2021-09-30", 5041.1, 26352.58]
 		]
 
 		for i, schedule in enumerate(asset.schedules):
@@ -2261,6 +2261,59 @@
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
 			self.assertTrue(schedule.journal_entry)
 
+	def test_asset_depreciation_on_sale_without_pro_rata(self):
+		"""
+			Tests if an Asset set to depreciate yearly on Dec 31, that gets sold on Dec 31 after two years, created an additional depreciation entry on its date of sale.
+		"""
+
+		create_asset_data()
+		asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1,
+			available_for_use_date=getdate("2019-12-31"), total_number_of_depreciations=3,
+			expected_value_after_useful_life=10000, depreciation_start_date=getdate("2020-12-31"), submit=1)
+
+		post_depreciation_entries(getdate("2021-09-30"))
+
+		create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-12-31"))
+		asset.load_from_db()
+
+		expected_values = [
+			["2020-12-31", 30000, 30000],
+			["2021-12-31", 30000, 60000]
+		]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
+			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
+			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
+			self.assertTrue(schedule.journal_entry)
+
+	def test_depreciation_on_return_of_sold_asset(self):
+		from erpnext.controllers.sales_and_purchase_return import make_return_doc
+
+		create_asset_data()
+		asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1)
+		post_depreciation_entries(getdate("2021-09-30"))
+
+		si = create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-09-30"))
+		return_si = make_return_doc("Sales Invoice", si.name)
+		return_si.submit()
+		asset.load_from_db()
+
+		expected_values = [
+			["2020-06-30", 1311.48, 1311.48, True],
+			["2021-06-30", 20000.0, 21311.48, True],
+			["2022-06-30", 20000.0, 41311.48, False],
+			["2023-06-30", 20000.0, 61311.48, False],
+			["2024-06-30",  20000.0, 81311.48,  False],
+			["2025-06-06",  18688.52,  100000.0, False]
+		]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
+			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
+			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
+			self.assertEqual(schedule.journal_entry, schedule.journal_entry)
+
 	def test_sales_invoice_against_supplier(self):
 		from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
 			make_customer,
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index de95502..050c3e7 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -502,9 +502,11 @@
 		# Check invoice dates and make sure it doesn't have outstanding invoices
 		return getdate() >= getdate(self.current_invoice_start)
 
-	def is_current_invoice_generated(self):
+	def is_current_invoice_generated(self, _current_start_date=None, _current_end_date=None):
 		invoice = self.get_current_invoice()
-		_current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
+
+		if not (_current_start_date and _current_end_date):
+			_current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
 
 		if invoice and getdate(_current_start_date) <= getdate(invoice.posting_date) <= getdate(_current_end_date):
 			return True
@@ -523,7 +525,9 @@
 		if getdate() > getdate(self.current_invoice_end) and self.is_prepaid_to_invoice():
 			self.update_subscription_period(add_days(self.current_invoice_end, 1))
 
-		if not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
+		if not self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \
+			and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
+
 			prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
 			self.generate_invoice(prorate)
 
@@ -559,14 +563,17 @@
 			else:
 				self.set_status_grace_period()
 
+			if getdate() > getdate(self.current_invoice_end):
+				self.update_subscription_period(add_days(self.current_invoice_end, 1))
+
 			# Generate invoices periodically even if current invoice are unpaid
-			if self.generate_new_invoices_past_due_date and not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice()
-				or self.is_prepaid_to_invoice()):
+			if self.generate_new_invoices_past_due_date and not \
+				self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \
+				and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
+
 				prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
 				self.generate_invoice(prorate)
 
-			if getdate() > getdate(self.current_invoice_end):
-				self.update_subscription_period(add_days(self.current_invoice_end, 1))
 
 	@staticmethod
 	def is_paid(invoice):
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 c36f3cb..5162182 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -58,15 +58,24 @@
 	pan_no = ''
 	parties = []
 	party_type, party = get_party_details(inv)
+	has_pan_field = frappe.get_meta(party_type).has_field("pan")
 
 	if not tax_withholding_category:
-		tax_withholding_category, pan_no = frappe.db.get_value(party_type, party, ['tax_withholding_category', 'pan'])
+		if has_pan_field:
+			fields = ['tax_withholding_category', 'pan']
+		else:
+			fields = ['tax_withholding_category']
+
+		tax_withholding_details = frappe.db.get_value(party_type, party, fields, as_dict=1)
+
+		tax_withholding_category = tax_withholding_details.get('tax_withholding_category')
+		pan_no = tax_withholding_details.get('pan')
 
 	if not tax_withholding_category:
 		return
 
 	# if tax_withholding_category passed as an argument but not pan_no
-	if not pan_no:
+	if not pan_no and has_pan_field:
 		pan_no = frappe.db.get_value(party_type, party, 'pan')
 
 	# Get others suppliers with the same PAN No
@@ -174,6 +183,7 @@
 	ldc_name = frappe.db.get_value('Lower Deduction Certificate',
 		{
 			'pan_no': pan_no,
+			'tax_withholding_category': tax_details.tax_withholding_category,
 			'valid_from': ('>=', tax_details.from_date),
 			'valid_upto': ('<=', tax_details.to_date)
 		}, 'name')
diff --git a/erpnext/hub_node/doctype/__init__.py b/erpnext/accounts/print_format_field_template/__init__.py
similarity index 100%
rename from erpnext/hub_node/doctype/__init__.py
rename to erpnext/accounts/print_format_field_template/__init__.py
diff --git a/erpnext/hub/__init__.py b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/accounts/print_format_field_template/purchase_invoice_taxes/__init__.py
diff --git a/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json
new file mode 100644
index 0000000..f525f7b
--- /dev/null
+++ b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 18:06:53.083133",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Purchase Invoice",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:06:53.083133",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Purchase Invoice Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/hub/__init__.py b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/accounts/print_format_field_template/sales_invoice_taxes/__init__.py
diff --git a/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json
new file mode 100644
index 0000000..8ce62a8
--- /dev/null
+++ b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 17:50:00.152759",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Sales Invoice",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:13:20.894207",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Sales Invoice Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ 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 0de2a98..0475231 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -114,8 +114,9 @@
 
 		# opening_value = Aseet - liability - equity
 		for data in [asset_data, liability_data, equity_data]:
-			account_name = get_root_account_name(data[0].root_type, company)
-			opening_value += (get_opening_balance(account_name, data, company) or 0.0)
+			if data:
+				account_name = get_root_account_name(data[0].root_type, company)
+				opening_value += (get_opening_balance(account_name, data, company) or 0.0)
 
 		opening_balance[company] = opening_value
 
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 0094bc2..31416da 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -155,6 +155,8 @@
 
 	if filters.get("group_by") == "Group by Voucher":
 		order_by_statement = "order by posting_date, voucher_type, voucher_no"
+	if filters.get("group_by") == "Group by Account":
+		order_by_statement = "order by account, posting_date, creation"
 
 	if filters.get("include_default_book_entries"):
 		filters['company_fb'] = frappe.db.get_value("Company",
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index fdd8d09..fb23d6f 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -450,7 +450,8 @@
 
 	# new row with references
 	new_row = journal_entry.append("accounts")
-	new_row.update(jv_detail.as_dict().copy())
+
+	new_row.update((frappe.copy_doc(jv_detail)).as_dict())
 
 	new_row.set(d["dr_or_cr"], d["allocated_amount"])
 	new_row.set('debit' if d['dr_or_cr'] == 'debit_in_account_currency' else 'credit',
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 99a6cc3..cf62f49 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -75,12 +75,12 @@
 		if self.is_existing_asset and self.purchase_invoice:
 			frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
 
-	def prepare_depreciation_data(self, date_of_sale=None):
+	def prepare_depreciation_data(self, date_of_sale=None, date_of_return=None):
 		if self.calculate_depreciation:
 			self.value_after_depreciation = 0
 			self.set_depreciation_rate()
 			self.make_depreciation_schedule(date_of_sale)
-			self.set_accumulated_depreciation(date_of_sale)
+			self.set_accumulated_depreciation(date_of_sale, date_of_return)
 		else:
 			self.finance_books = []
 			self.value_after_depreciation = (flt(self.gross_purchase_amount) -
@@ -182,7 +182,7 @@
 				d.precision("rate_of_depreciation"))
 
 	def make_depreciation_schedule(self, date_of_sale):
-		if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.schedules:
+		if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.get('schedules'):
 			self.schedules = []
 
 		if not self.available_for_use_date:
@@ -232,13 +232,15 @@
 					depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
 						from_date, date_of_sale)
 
-					self.append("schedules", {
-						"schedule_date": date_of_sale,
-						"depreciation_amount": depreciation_amount,
-						"depreciation_method": d.depreciation_method,
-						"finance_book": d.finance_book,
-						"finance_book_id": d.idx
-					})
+					if depreciation_amount > 0:
+						self.append("schedules", {
+							"schedule_date": date_of_sale,
+							"depreciation_amount": depreciation_amount,
+							"depreciation_method": d.depreciation_method,
+							"finance_book": d.finance_book,
+							"finance_book_id": d.idx
+						})
+
 					break
 
 				# For first row
@@ -257,11 +259,15 @@
 						self.to_date = add_months(self.available_for_use_date,
 							n * cint(d.frequency_of_depreciation))
 
+					depreciation_amount_without_pro_rata = depreciation_amount
+
 					depreciation_amount, days, months = self.get_pro_rata_amt(d,
 						depreciation_amount, schedule_date, self.to_date)
 
-					monthly_schedule_date = add_months(schedule_date, 1)
+					depreciation_amount = self.get_adjusted_depreciation_amount(depreciation_amount_without_pro_rata,
+						depreciation_amount, d.finance_book)
 
+					monthly_schedule_date = add_months(schedule_date, 1)
 					schedule_date = add_days(schedule_date, days)
 					last_schedule_date = schedule_date
 
@@ -397,7 +403,28 @@
 			frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date")
 				.format(row.idx))
 
-	def set_accumulated_depreciation(self, date_of_sale=None, ignore_booked_entry = False):
+	# to ensure that final accumulated depreciation amount is accurate
+	def get_adjusted_depreciation_amount(self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book):
+		depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book)
+
+		if depreciation_amount_for_first_row + depreciation_amount_for_last_row != depreciation_amount_without_pro_rata:
+			depreciation_amount_for_last_row = depreciation_amount_without_pro_rata - depreciation_amount_for_first_row
+
+		return depreciation_amount_for_last_row
+
+	def get_depreciation_amount_for_first_row(self, finance_book):
+		if self.has_only_one_finance_book():
+			return self.schedules[0].depreciation_amount
+		else:
+			for schedule in self.schedules:
+				if schedule.finance_book == finance_book:
+					return schedule.depreciation_amount
+
+	def has_only_one_finance_book(self):
+		if len(self.finance_books) == 1:
+			return True
+
+	def set_accumulated_depreciation(self, date_of_sale=None, date_of_return=None, ignore_booked_entry = False):
 		straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line']
 		finance_books = []
 
@@ -414,7 +441,7 @@
 			value_after_depreciation -= flt(depreciation_amount)
 
 			# for the last row, if depreciation method = Straight Line
-			if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale:
+			if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale and not date_of_return:
 				book = self.get('finance_books')[cint(d.finance_book_id) - 1]
 				depreciation_amount += flt(value_after_depreciation -
 					flt(book.expected_value_after_useful_life), d.precision("depreciation_amount"))
@@ -833,7 +860,7 @@
 	if row.depreciation_method in ("Straight Line", "Manual"):
 		# if the Depreciation Schedule is being prepared for the first time
 		if not asset.flags.increase_in_asset_life:
-			depreciation_amount = (flt(row.value_after_depreciation) -
+			depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) -
 				flt(row.expected_value_after_useful_life)) / depreciation_left
 
 		# if the Depreciation Schedule is being modified after Asset Repair
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index cf4581b..f162d9f 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -21,12 +21,72 @@
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
 
 
-class TestAsset(unittest.TestCase):
-	def setUp(self):
+class AssetSetup(unittest.TestCase):
+	@classmethod
+	def setUpClass(cls):
 		set_depreciation_settings_in_company()
 		create_asset_data()
+		enable_cwip_accounting("Computers")
+		make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")
 		frappe.db.sql("delete from `tabTax Rule`")
 
+	@classmethod
+	def tearDownClass(cls):
+		frappe.db.rollback()
+
+class TestAsset(AssetSetup):
+	def test_asset_category_is_fetched(self):
+		"""Tests if the Item's Asset Category value is assigned to the Asset, if the field is empty."""
+
+		asset = create_asset(item_code="Macbook Pro", do_not_save=1)
+		asset.asset_category = None
+		asset.save()
+
+		self.assertEqual(asset.asset_category, "Computers")
+
+	def test_gross_purchase_amount_is_mandatory(self):
+		asset = create_asset(item_code="Macbook Pro", do_not_save=1)
+		asset.gross_purchase_amount = 0
+
+		self.assertRaises(frappe.MandatoryError, asset.save)
+
+	def test_pr_or_pi_mandatory_if_not_existing_asset(self):
+		"""Tests if either PI or PR is present if CWIP is enabled and is_existing_asset=0."""
+
+		asset = create_asset(item_code="Macbook Pro", do_not_save=1)
+		asset.is_existing_asset=0
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_available_for_use_date_is_after_purchase_date(self):
+		asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, do_not_save=1)
+		asset.is_existing_asset = 0
+		asset.purchase_date = getdate("2021-10-10")
+		asset.available_for_use_date = getdate("2021-10-1")
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_item_exists(self):
+		asset = create_asset(item_code="MacBook", do_not_save=1)
+
+		self.assertRaises(frappe.DoesNotExistError, asset.save)
+
+	def test_validate_item(self):
+		asset = create_asset(item_code="MacBook Pro", do_not_save=1)
+		item = frappe.get_doc("Item", "MacBook Pro")
+
+		item.disabled = 1
+		item.save()
+		self.assertRaises(frappe.ValidationError, asset.save)
+		item.disabled = 0
+
+		item.is_fixed_asset = 0
+		self.assertRaises(frappe.ValidationError, asset.save)
+		item.is_fixed_asset = 1
+
+		item.is_stock_item = 1
+		self.assertRaises(frappe.ValidationError, asset.save)
+
 	def test_purchase_asset(self):
 		pr = make_purchase_receipt(item_code="Macbook Pro",
 			qty=1, rate=100000.0, location="Test Location")
@@ -89,302 +149,16 @@
 		doc.set_missing_values()
 		self.assertEqual(doc.items[0].is_fixed_asset, 1)
 
-	def test_schedule_for_straight_line_method(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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-01-01'
-		asset.purchase_date = '2030-01-01'
-
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 12,
-			"depreciation_start_date": "2030-12-31"
-		})
-		asset.save()
-
-		self.assertEqual(asset.status, "Draft")
-		expected_schedules = [
-			["2030-12-31", 30000.00, 30000.00],
-			["2031-12-31", 30000.00, 60000.00],
-			["2032-12-31", 30000.00, 90000.00]
-		]
-
-		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")]
-
-		self.assertEqual(schedules, expected_schedules)
-
-	def test_schedule_for_straight_line_method_for_existing_asset(self):
-		create_asset(is_existing_asset=1)
-		asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
-		asset.calculate_depreciation = 1
-		asset.number_of_depreciations_booked = 1
-		asset.opening_accumulated_depreciation = 40000
-		asset.available_for_use_date = "2030-06-06"
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 12,
-			"depreciation_start_date": "2030-12-31"
-		})
-		self.assertEqual(asset.status, "Draft")
-		asset.save()
-		expected_schedules = [
-			["2030-12-31", 14246.58, 54246.58],
-			["2031-12-31", 25000.00, 79246.58],
-			["2032-06-06", 10753.42, 90000.00]
-		]
-		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")]
-
-		self.assertEqual(schedules, expected_schedules)
-
-	def test_schedule_for_double_declining_method(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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-01-01'
-		asset.purchase_date = '2030-01-01'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Double Declining Balance",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 12,
-			"depreciation_start_date": '2030-12-31'
-		})
-		asset.save()
-		self.assertEqual(asset.status, "Draft")
-
-		expected_schedules = [
-			['2030-12-31', 66667.00, 66667.00],
-			['2031-12-31', 22222.11, 88889.11],
-			['2032-12-31', 1110.89, 90000.0]
-		]
-
-		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")]
-
-		self.assertEqual(schedules, expected_schedules)
-
-	def test_schedule_for_double_declining_method_for_existing_asset(self):
-		create_asset(is_existing_asset = 1)
-		asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
-		asset.calculate_depreciation = 1
-		asset.is_existing_asset = 1
-		asset.number_of_depreciations_booked = 1
-		asset.opening_accumulated_depreciation = 50000
-		asset.available_for_use_date = '2030-01-01'
-		asset.purchase_date = '2029-11-30'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Double Declining Balance",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 12,
-			"depreciation_start_date": "2030-12-31"
-		})
-		asset.save()
-		self.assertEqual(asset.status, "Draft")
-
-		expected_schedules = [
-			["2030-12-31", 33333.50, 83333.50],
-			["2031-12-31", 6666.50, 90000.0]
-		]
-
-		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")]
-
-		self.assertEqual(schedules, expected_schedules)
-
-	def test_schedule_for_prorated_straight_line_method(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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.purchase_date = '2030-01-30'
-		asset.is_existing_asset = 0
-		asset.available_for_use_date = "2030-01-30"
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 12,
-			"depreciation_start_date": "2030-12-31"
-		})
-
-		asset.save()
-
-		expected_schedules = [
-			["2030-12-31", 27534.25, 27534.25],
-			["2031-12-31", 30000.0, 57534.25],
-			["2032-12-31", 30000.0, 87534.25],
-			["2033-01-30", 2465.75, 90000.0]
-		]
-
-		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)
-
-	def test_depreciation(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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.purchase_date = '2020-01-30'
-		asset.available_for_use_date = "2020-01-30"
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 10,
-			"depreciation_start_date": "2020-12-31"
-		})
-		asset.submit()
-		asset.load_from_db()
-		self.assertEqual(asset.status, "Submitted")
-
-		frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-")
-		post_depreciation_entries(date="2021-01-01")
-		asset.load_from_db()
-
-		# check depreciation entry series
-		self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
-
-		expected_gle = (
-			("_Test Accumulated Depreciations - _TC", 0.0, 30000.0),
-			("_Test Depreciations - _TC", 30000.0, 0.0)
-		)
-
-		gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
-			where against_voucher_type='Asset' and against_voucher = %s
-			order by account""", asset.name)
-
-		self.assertEqual(gle, expected_gle)
-		self.assertEqual(asset.get("value_after_depreciation"), 0)
-
-	def test_depreciation_entry_for_wdv_without_pro_rata(self):
-		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-01-01'
-		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", 4000.00, 4000.00],
-			["2031-12-31", 2000.00, 6000.00],
-			["2032-12-31", 1000.00, 7000.0],
-		]
-
-		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)
-
-	def test_pro_rata_depreciation_entry_for_wdv(self):
-		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-06'
-		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", 2279.45, 2279.45],
-			["2031-12-31", 2860.28, 5139.73],
-			["2032-12-31", 1430.14, 6569.87],
-			["2033-06-06", 430.13, 7000.0],
-		]
-
-		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)
-
-	def test_depreciation_entry_cancellation(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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 = '2020-06-06'
-		asset.purchase_date = '2020-06-06'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 10,
-			"depreciation_start_date": "2020-12-31"
-		})
-		asset.submit()
-		post_depreciation_entries(date="2021-01-01")
-
-		asset.load_from_db()
-
-		# cancel depreciation entry
-		depr_entry = asset.get("schedules")[0].journal_entry
-		self.assertTrue(depr_entry)
-		frappe.get_doc("Journal Entry", depr_entry).cancel()
-
-		asset.load_from_db()
-		depr_entry = asset.get("schedules")[0].journal_entry
-		self.assertFalse(depr_entry)
-
 	def test_scrap_asset(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.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 = '2020-01-01'
-		asset.purchase_date = '2020-01-01'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 10,
-			"frequency_of_depreciation": 1
-		})
-		asset.submit()
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = '2020-01-01',
+			purchase_date = '2020-01-01',
+			expected_value_after_useful_life = 10000,
+			total_number_of_depreciations = 10,
+			frequency_of_depreciation = 1,
+			submit = 1
+		)
 
 		post_depreciation_entries(date=add_months('2020-01-01', 4))
 
@@ -411,23 +185,18 @@
 		self.assertFalse(asset.journal_entry_for_scrap)
 		self.assertEqual(asset.status, "Partially Depreciated")
 
-	def test_asset_sale(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.0, location="Test Location")
+	def test_gle_made_by_asset_sale(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = '2020-06-06',
+			purchase_date = '2020-01-01',
+			expected_value_after_useful_life = 10000,
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 10,
+			depreciation_start_date = '2020-12-31',
+			submit = 1
+		)
 
-		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 = '2020-06-06'
-		asset.purchase_date = '2020-06-06'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 10,
-			"depreciation_start_date": "2020-12-31"
-		})
-		asset.submit()
 		post_depreciation_entries(date="2021-01-01")
 
 		si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company")
@@ -455,30 +224,14 @@
 		si.cancel()
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
 
-	def test_asset_expected_value_after_useful_life(self):
+	def test_expense_head(self):
 		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=1, rate=100000.0, location="Test Location")
+			qty=2, rate=200000.0, location="Test Location")
+		doc = make_invoice(pr.name)
 
-		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 = '2020-06-06'
-		asset.purchase_date = '2020-06-06'
-		asset.append("finance_books", {
-			"expected_value_after_useful_life": 10000,
-			"depreciation_method": "Straight Line",
-			"total_number_of_depreciations": 3,
-			"frequency_of_depreciation": 10
-		})
-		asset.save()
-		accumulated_depreciation_after_full_schedule = \
-			max(d.accumulated_depreciation_amount for d in asset.get("schedules"))
+		self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
 
-		asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) -
-			flt(accumulated_depreciation_after_full_schedule))
-
-		self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule)
-
+	# CWIP: Capital Work In Progress
 	def test_cwip_accounting(self):
 		pr = make_purchase_receipt(item_code="Macbook Pro",
 			qty=1, rate=5000, do_not_submit=True, location="Test Location")
@@ -561,14 +314,6 @@
 
 		self.assertEqual(gle, expected_gle)
 
-	def test_expense_head(self):
-		pr = make_purchase_receipt(item_code="Macbook Pro",
-			qty=2, rate=200000.0, location="Test Location")
-
-		doc = make_invoice(pr.name)
-
-		self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
-
 	def test_asset_cwip_toggling_cases(self):
 		cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
 		name = frappe.db.get_value("Asset Category Account", filters={"parent": "Computers"}, fieldname=["name"])
@@ -637,41 +382,211 @@
 		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)
 
+class TestDepreciationMethods(AssetSetup):
+	def test_schedule_for_straight_line_method(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-01-01",
+			purchase_date = "2030-01-01",
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.status, "Draft")
+		expected_schedules = [
+			["2030-12-31", 30000.00, 30000.00],
+			["2031-12-31", 30000.00, 60000.00],
+			["2032-12-31", 30000.00, 90000.00]
+		]
+
+		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+	def test_schedule_for_straight_line_method_for_existing_asset(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-06-06",
+			is_existing_asset = 1,
+			number_of_depreciations_booked = 1,
+			opening_accumulated_depreciation = 40000,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.status, "Draft")
+		expected_schedules = [
+			["2030-12-31", 14246.58, 54246.58],
+			["2031-12-31", 25000.00, 79246.58],
+			["2032-06-06", 10753.42, 90000.00]
+		]
+		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+	def test_schedule_for_double_declining_method(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-01-01",
+			purchase_date = "2030-01-01",
+			depreciation_method = "Double Declining Balance",
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.status, "Draft")
+
+		expected_schedules = [
+			['2030-12-31', 66667.00, 66667.00],
+			['2031-12-31', 22222.11, 88889.11],
+			['2032-12-31', 1110.89, 90000.0]
+		]
+
+		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+	def test_schedule_for_double_declining_method_for_existing_asset(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-01-01",
+			is_existing_asset = 1,
+			depreciation_method = "Double Declining Balance",
+			number_of_depreciations_booked = 1,
+			opening_accumulated_depreciation = 50000,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.status, "Draft")
+
+		expected_schedules = [
+			["2030-12-31", 33333.50, 83333.50],
+			["2031-12-31", 6666.50, 90000.0]
+		]
+
+		schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+	def test_schedule_for_prorated_straight_line_method(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-01-30",
+			purchase_date = "2030-01-30",
+			depreciation_method = "Straight Line",
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		expected_schedules = [
+			["2030-12-31", 27534.25, 27534.25],
+			["2031-12-31", 30000.0, 57534.25],
+			["2032-12-31", 30000.0, 87534.25],
+			["2033-01-30", 2465.75, 90000.0]
+		]
+
+		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)
+
+	# WDV: Written Down Value method
+	def test_depreciation_entry_for_wdv_without_pro_rata(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-01-01",
+			purchase_date = "2030-01-01",
+			depreciation_method = "Written Down Value",
+			expected_value_after_useful_life = 12500,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+		expected_schedules = [
+			["2030-12-31", 50000.0, 50000.0],
+			["2031-12-31", 25000.0, 75000.0],
+			["2032-12-31", 12500.0, 87500.0],
+		]
+
+		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)
+
+	# WDV: Written Down Value method
+	def test_pro_rata_depreciation_entry_for_wdv(self):
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-06-06",
+			purchase_date = "2030-01-01",
+			depreciation_method = "Written Down Value",
+			expected_value_after_useful_life = 12500,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
+
+		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+		expected_schedules = [
+			["2030-12-31", 28493.15, 28493.15],
+			["2031-12-31", 35753.43, 64246.58],
+			["2032-12-31", 17876.71, 82123.29],
+			["2033-06-06", 5376.71, 87500.0]
+		]
+
+		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)
+
 	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")
-
-		finance_book = frappe.new_doc('Finance Book')
-		finance_book.finance_book_name = 'Income Tax'
+		finance_book = frappe.new_doc("Finance Book")
+		finance_book.finance_book_name = "Income Tax"
 		finance_book.for_income_tax = 1
-		finance_book.insert(ignore_if_duplicate=1)
+		finance_book.insert(ignore_if_duplicate = True)
 
-		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-07-12'
-		asset.purchase_date = '2030-01-01'
-		asset.append("finance_books", {
-			"finance_book": finance_book.name,
-			"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)
+		asset = create_asset(
+			calculate_depreciation = 1,
+			available_for_use_date = "2030-07-12",
+			purchase_date = "2030-01-01",
+			finance_book = finance_book.name,
+			depreciation_method = "Written Down Value",
+			expected_value_after_useful_life = 12500,
+			depreciation_start_date = "2030-12-31",
+			total_number_of_depreciations = 3,
+			frequency_of_depreciation = 12
+		)
 
 		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
 
 		expected_schedules = [
-			["2030-12-31", 942.47, 942.47],
-			["2031-12-31", 3528.77, 4471.24],
-			["2032-12-31", 1764.38, 6235.62],
-			["2033-07-12", 764.38, 7000.00]
+			["2030-12-31", 11780.82, 11780.82],
+			["2031-12-31", 44109.59, 55890.41],
+			["2032-12-31", 22054.8, 77945.21],
+			["2033-07-12", 9554.79, 87500.0]
 		]
 
 		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
@@ -682,6 +597,379 @@
 		# reset indian company
 		frappe.flags.company = company_flag
 
+class TestDepreciationBasics(AssetSetup):
+	def test_depreciation_without_pro_rata(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = getdate("2019-12-31"),
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = getdate("2020-12-31"),
+			submit = 1
+		)
+
+		expected_values = [
+			["2020-12-31", 30000, 30000],
+			["2021-12-31", 30000, 60000],
+			["2022-12-31", 30000, 90000]
+		]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
+			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
+			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
+
+	def test_depreciation_with_pro_rata(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = getdate("2019-12-31"),
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = getdate("2020-07-01"),
+			submit = 1
+		)
+
+		expected_values = [
+			["2020-07-01", 15000, 15000],
+			["2021-07-01", 30000, 45000],
+			["2022-07-01", 30000, 75000],
+			["2022-12-31", 15000, 90000]
+		]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
+			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
+			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
+
+	def test_get_depreciation_amount(self):
+		"""Tests if get_depreciation_amount() returns the right value."""
+
+		from erpnext.assets.doctype.asset.asset import get_depreciation_amount
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			available_for_use_date = "2019-12-31"
+		)
+
+		asset.calculate_depreciation = 1
+		asset.append("finance_books", {
+			"depreciation_method": "Straight Line",
+			"frequency_of_depreciation": 12,
+			"total_number_of_depreciations": 3,
+			"expected_value_after_useful_life": 10000,
+			"depreciation_start_date": "2020-12-31"
+		})
+
+		depreciation_amount = get_depreciation_amount(asset, 100000, asset.finance_books[0])
+		self.assertEqual(depreciation_amount, 30000)
+
+	def test_make_depreciation_schedule(self):
+		"""Tests if make_depreciation_schedule() returns the right values."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_method = "Straight Line",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2020-12-31"
+		)
+
+		expected_values = [
+			['2020-12-31', 30000.0],
+			['2021-12-31', 30000.0],
+			['2022-12-31', 30000.0]
+		]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(expected_values[i][0], schedule.schedule_date)
+			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
+
+	def test_set_accumulated_depreciation(self):
+		"""Tests if set_accumulated_depreciation() returns the right values."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_method = "Straight Line",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2020-12-31"
+		)
+
+		expected_values = [30000.0, 60000.0, 90000.0]
+
+		for i, schedule in enumerate(asset.schedules):
+			self.assertEqual(expected_values[i], schedule.accumulated_depreciation_amount)
+
+	def test_check_is_pro_rata(self):
+		"""Tests if check_is_pro_rata() returns the right value(i.e. checks if has_pro_rata is accurate)."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			available_for_use_date = "2019-12-31",
+			do_not_save = 1
+		)
+
+		asset.calculate_depreciation = 1
+		asset.append("finance_books", {
+			"depreciation_method": "Straight Line",
+			"frequency_of_depreciation": 12,
+			"total_number_of_depreciations": 3,
+			"expected_value_after_useful_life": 10000,
+			"depreciation_start_date": "2020-12-31"
+		})
+
+		has_pro_rata = asset.check_is_pro_rata(asset.finance_books[0])
+		self.assertFalse(has_pro_rata)
+
+		asset.finance_books = []
+		asset.append("finance_books", {
+			"depreciation_method": "Straight Line",
+			"frequency_of_depreciation": 12,
+			"total_number_of_depreciations": 3,
+			"expected_value_after_useful_life": 10000,
+			"depreciation_start_date": "2020-07-01"
+		})
+
+		has_pro_rata = asset.check_is_pro_rata(asset.finance_books[0])
+		self.assertTrue(has_pro_rata)
+
+	def test_expected_value_after_useful_life_greater_than_purchase_amount(self):
+		"""Tests if an error is raised when expected_value_after_useful_life(110,000) > gross_purchase_amount(100,000)."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 110000,
+			depreciation_start_date = "2020-07-01",
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_depreciation_start_date(self):
+		"""Tests if an error is raised when neither depreciation_start_date nor available_for_use_date are specified."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 110000,
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_opening_accumulated_depreciation(self):
+		"""Tests if an error is raised when opening_accumulated_depreciation > (gross_purchase_amount - expected_value_after_useful_life)."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2020-07-01",
+			opening_accumulated_depreciation = 100000,
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_number_of_depreciations_booked(self):
+		"""Tests if an error is raised when number_of_depreciations_booked is not specified when opening_accumulated_depreciation is."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2020-07-01",
+			opening_accumulated_depreciation = 10000,
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_number_of_depreciations(self):
+		"""Tests if an error is raised when number_of_depreciations_booked > total_number_of_depreciations."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2020-07-01",
+			opening_accumulated_depreciation = 10000,
+			number_of_depreciations_booked = 5,
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_depreciation_start_date_is_before_purchase_date(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2014-07-01",
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_depreciation_start_date_is_before_available_for_use_date(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			depreciation_start_date = "2018-07-01",
+			do_not_save = 1
+		)
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_finance_books_are_present_if_calculate_depreciation_is_enabled(self):
+		asset = create_asset(item_code="Macbook Pro", do_not_save=1)
+		asset.calculate_depreciation = 1
+
+		self.assertRaises(frappe.ValidationError, asset.save)
+
+	def test_post_depreciation_entries(self):
+		"""Tests if post_depreciation_entries() works as expected."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		post_depreciation_entries(date="2021-06-01")
+		asset.load_from_db()
+
+		self.assertTrue(asset.schedules[0].journal_entry)
+		self.assertFalse(asset.schedules[1].journal_entry)
+		self.assertFalse(asset.schedules[2].journal_entry)
+
+	def test_clear_depreciation_schedule(self):
+		"""Tests if clear_depreciation_schedule() works as expected."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		post_depreciation_entries(date="2021-06-01")
+		asset.load_from_db()
+
+		asset.clear_depreciation_schedule()
+
+		self.assertEqual(len(asset.schedules), 1)
+
+	def test_depreciation_entry_cancellation(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			purchase_date = "2020-06-06",
+			available_for_use_date = "2020-06-06",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 10,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		post_depreciation_entries(date="2021-01-01")
+
+		asset.load_from_db()
+
+		# cancel depreciation entry
+		depr_entry = asset.get("schedules")[0].journal_entry
+		self.assertTrue(depr_entry)
+		frappe.get_doc("Journal Entry", depr_entry).cancel()
+
+		asset.load_from_db()
+		depr_entry = asset.get("schedules")[0].journal_entry
+		self.assertFalse(depr_entry)
+
+	def test_asset_expected_value_after_useful_life(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2020-06-06",
+			purchase_date = "2020-06-06",
+			frequency_of_depreciation = 10,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000
+		)
+
+		accumulated_depreciation_after_full_schedule = \
+			max(d.accumulated_depreciation_amount for d in asset.get("schedules"))
+
+		asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) -
+			flt(accumulated_depreciation_after_full_schedule))
+
+		self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule)
+
+	def test_gle_made_by_depreciation_entries(self):
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			purchase_date = "2020-01-30",
+			available_for_use_date = "2020-01-30",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 10,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		self.assertEqual(asset.status, "Submitted")
+
+		frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-")
+		post_depreciation_entries(date="2021-01-01")
+		asset.load_from_db()
+
+		# check depreciation entry series
+		self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
+
+		expected_gle = (
+			("_Test Accumulated Depreciations - _TC", 0.0, 30000.0),
+			("_Test Depreciations - _TC", 30000.0, 0.0)
+		)
+
+		gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
+			where against_voucher_type='Asset' and against_voucher = %s
+			order by account""", asset.name)
+
+		self.assertEqual(gle, expected_gle)
+		self.assertEqual(asset.get("value_after_depreciation"), 0)
 	def test_expected_value_change(self):
 		"""
 			tests if changing `expected_value_after_useful_life`
@@ -724,32 +1012,37 @@
 	asset = frappe.get_doc({
 		"doctype": "Asset",
 		"asset_name": args.asset_name or "Macbook Pro 1",
-		"asset_category": "Computers",
+		"asset_category": args.asset_category or "Computers",
 		"item_code": args.item_code or "Macbook Pro",
-		"company": args.company or"_Test Company",
-		"purchase_date": "2015-01-01",
+		"company": args.company or "_Test Company",
+		"purchase_date": args.purchase_date or "2015-01-01",
 		"calculate_depreciation": args.calculate_depreciation or 0,
-		"gross_purchase_amount": 100000,
-		"purchase_receipt_amount": 100000,
-		"expected_value_after_useful_life": 10000,
+		"opening_accumulated_depreciation": args.opening_accumulated_depreciation or 0,
+		"number_of_depreciations_booked": args.number_of_depreciations_booked or 0,
+		"gross_purchase_amount": args.gross_purchase_amount or 100000,
+		"purchase_receipt_amount": args.purchase_receipt_amount or 100000,
 		"warehouse": args.warehouse or "_Test Warehouse - _TC",
-		"available_for_use_date": "2020-06-06",
-		"location": "Test Location",
-		"asset_owner": "Company",
-		"is_existing_asset": 1
+		"available_for_use_date": args.available_for_use_date or "2020-06-06",
+		"location": args.location or "Test Location",
+		"asset_owner": args.asset_owner or "Company",
+		"is_existing_asset": args.is_existing_asset or 1
 	})
 
 	if asset.calculate_depreciation:
 		asset.append("finance_books", {
-			"depreciation_method": "Straight Line",
-			"frequency_of_depreciation": 12,
-			"total_number_of_depreciations": 5
+			"finance_book": args.finance_book,
+			"depreciation_method": args.depreciation_method or "Straight Line",
+			"frequency_of_depreciation": args.frequency_of_depreciation or 12,
+			"total_number_of_depreciations": args.total_number_of_depreciations or 5,
+			"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
+			"depreciation_start_date": args.depreciation_start_date
 		})
 
-	try:
-		asset.save()
-	except frappe.DuplicateEntryError:
-		pass
+	if not args.do_not_save:
+		try:
+			asset.save()
+		except frappe.DuplicateEntryError:
+			pass
 
 	if args.submit:
 		asset.submit()
@@ -800,3 +1093,6 @@
 
 	# Enable booking asset depreciation entry automatically
 	frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
+
+def enable_cwip_accounting(asset_category, enable=1):
+	frappe.db.set_value("Asset Category", asset_category, "enable_cwip_accounting", enable)
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
index 75f42a9..06989a9 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
@@ -16,9 +16,8 @@
 			fieldname:"status",
 			label: __("Status"),
 			fieldtype: "Select",
-			options: "In Location\nDisposed",
-			default: 'In Location',
-			reqd: 1
+			options: "\nIn Location\nDisposed",
+			default: 'In Location'
 		},
 		{
 			"fieldname":"filter_based_on",
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index e370b9d..63685fe 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -45,12 +45,13 @@
 	if filters.get('cost_center'):
 		conditions["cost_center"] = filters.get('cost_center')
 
-	# In Store assets are those that are not sold or scrapped
-	operand = 'not in'
-	if status not in 'In Location':
-		operand = 'in'
+	if status:
+		# In Store assets are those that are not sold or scrapped
+		operand = 'not in'
+		if status not in 'In Location':
+			operand = 'in'
 
-	conditions['status'] = (operand, ['Sold', 'Scrapped'])
+		conditions['status'] = (operand, ['Sold', 'Scrapped'])
 
 	return conditions
 
diff --git a/erpnext/hub/__init__.py b/erpnext/buying/print_format_field_template/__init__.py
similarity index 100%
rename from erpnext/hub/__init__.py
rename to erpnext/buying/print_format_field_template/__init__.py
diff --git a/erpnext/hub/__init__.py b/erpnext/buying/print_format_field_template/purchase_order_taxes/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/buying/print_format_field_template/purchase_order_taxes/__init__.py
diff --git a/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json b/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json
new file mode 100644
index 0000000..73b7730
--- /dev/null
+++ b/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 18:07:19.253457",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Purchase Order",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:07:19.253457",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Purchase Order Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/hub/__init__.py b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/buying/print_format_field_template/supplier_quotation_taxes/__init__.py
diff --git a/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json
new file mode 100644
index 0000000..2be17a1
--- /dev/null
+++ b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 18:09:08.103919",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Supplier Quotation",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:09:08.103919",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Quotation Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
index 1b25dd4..a566d56 100644
--- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
+++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
@@ -41,10 +41,13 @@
 	if filters.get("from_date") and filters.get("to_date"):
 		conditions += " and po.transaction_date between %(from_date)s and %(to_date)s"
 
-	for field in ['company', 'name', 'status']:
+	for field in ['company', 'name']:
 		if filters.get(field):
 			conditions += f" and po.{field} = %({field})s"
 
+	if filters.get('status'):
+		conditions += " and po.status in %(status)s"
+
 	if filters.get('project'):
 		conditions += " and poi.project = %(project)s"
 
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 904f221..37b8f9d 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -815,6 +815,38 @@
 			if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
 				unlink_ref_doc_from_payment_entries(self)
 
+			if self.doctype == "Sales Order":
+				self.unlink_ref_doc_from_po()
+
+	def unlink_ref_doc_from_po(self):
+		so_items = []
+		for item in self.items:
+			so_items.append(item.name)
+
+		linked_po = list(set(frappe.get_all(
+			'Purchase Order Item',
+			filters = {
+				'sales_order': self.name,
+				'sales_order_item': ['in', so_items],
+				'docstatus': ['<', 2]
+			},
+			pluck='parent'
+		)))
+
+		if linked_po:
+			frappe.db.set_value(
+				'Purchase Order Item', {
+					'sales_order': self.name,
+					'sales_order_item': ['in', so_items],
+					'docstatus': ['<', 2]
+				},{
+					'sales_order': None,
+					'sales_order_item': None
+				}
+			)
+
+			frappe.msgprint(_("Purchase Orders {0} are un-linked").format("\n".join(linked_po)))
+
 	def get_tax_map(self):
 		tax_map = {}
 		for tax in self.get('taxes'):
@@ -1354,8 +1386,8 @@
 			total = 0
 			base_total = 0
 			for d in self.get("payment_schedule"):
-				total += flt(d.payment_amount)
-				base_total += flt(d.base_payment_amount)
+				total += flt(d.payment_amount, d.precision("payment_amount"))
+				base_total += flt(d.base_payment_amount, d.precision("base_payment_amount"))
 
 			base_grand_total = self.get("base_rounded_total") or self.base_grand_total
 			grand_total = self.get("rounded_total") or self.grand_total
@@ -1371,8 +1403,9 @@
 				else:
 					grand_total -= self.get("total_advance")
 					base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
-			if total != flt(grand_total, self.precision("grand_total")) or \
-				base_total != flt(base_grand_total, self.precision("base_grand_total")):
+
+			if flt(total, self.precision("grand_total")) != flt(grand_total, self.precision("grand_total")) or \
+				flt(base_total, self.precision("base_grand_total")) != flt(base_grand_total, self.precision("base_grand_total")):
 				frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
 
 	def is_rounded_total_disabled(self):
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 7b4566a..05ece4d 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -132,7 +132,8 @@
 	return frappe.db.sql("""select {field} from `tabSupplier`
 		where docstatus < 2
 			and ({key} like %(txt)s
-				or supplier_name like %(txt)s) and disabled=0
+			or supplier_name like %(txt)s) and disabled=0
+			and (on_hold = 0 or (on_hold = 1 and CURDATE() > release_date))
 			{mcond}
 		order by
 			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
@@ -565,7 +566,7 @@
 
 		query_filters.append(['name', query_selector, dimensions])
 
-	output = frappe.get_all(doctype, filters=query_filters)
+	output = frappe.get_list(doctype, filters=query_filters)
 	result = [d.name for d in output]
 
 	return [(d,) for d in set(result)]
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 70cc8a5..7e7f598 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -260,7 +260,9 @@
 		self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
 
 	def calculate_taxes(self):
-		self.doc.rounding_adjustment = 0
+		if not self.doc.get('is_consolidated'):
+			self.doc.rounding_adjustment = 0
+
 		# maintain actual tax rate based on idx
 		actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
 			for tax in self.doc.get("taxes") if tax.charge_type == "Actual"])
@@ -312,7 +314,9 @@
 
 					# adjust Discount Amount loss in last tax iteration
 					if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
-						and self.doc.discount_amount and self.doc.apply_discount_on == "Grand Total":
+						and self.doc.discount_amount \
+						and self.doc.apply_discount_on == "Grand Total" \
+						and not self.doc.get('is_consolidated'):
 							self.doc.rounding_adjustment = flt(self.doc.grand_total
 								- flt(self.doc.discount_amount) - tax.total,
 								self.doc.precision("rounding_adjustment"))
@@ -405,11 +409,16 @@
 				self.doc.rounding_adjustment = diff
 
 	def calculate_totals(self):
-		self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
-			if self.doc.get("taxes") else flt(self.doc.net_total)
+		if self.doc.get("taxes"):
+			self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
+		else:
+			self.doc.grand_total = flt(self.doc.net_total)
 
-		self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
+		if self.doc.get("taxes"):
+			self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
 			- flt(self.doc.rounding_adjustment), self.doc.precision("total_taxes_and_charges"))
+		else:
+			self.doc.total_taxes_and_charges = 0.0
 
 		self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
 
@@ -446,19 +455,20 @@
 					self.doc.total_net_weight += d.total_weight
 
 	def set_rounded_total(self):
-		if self.doc.meta.get_field("rounded_total"):
-			if self.doc.is_rounded_total_disabled():
-				self.doc.rounded_total = self.doc.base_rounded_total = 0
-				return
+		if not self.doc.get('is_consolidated'):
+			if self.doc.meta.get_field("rounded_total"):
+				if self.doc.is_rounded_total_disabled():
+					self.doc.rounded_total = self.doc.base_rounded_total = 0
+					return
 
-			self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
-				self.doc.currency, self.doc.precision("rounded_total"))
+				self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
+					self.doc.currency, self.doc.precision("rounded_total"))
 
-			#if print_in_rate is set, we would have already calculated rounding adjustment
-			self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
-				self.doc.precision("rounding_adjustment"))
+				#if print_in_rate is set, we would have already calculated rounding adjustment
+				self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
+					self.doc.precision("rounding_adjustment"))
 
-			self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
+				self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
 
 	def _cleanup(self):
 		if not self.doc.get('is_consolidated'):
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 55e0efa..0e469ac 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -314,6 +314,8 @@
 @frappe.whitelist()
 def make_customer(source_name, target_doc=None):
 	def set_missing_values(source, target):
+		target.opportunity_name = source.name
+
 		if source.opportunity_from == "Lead":
 			target.lead_name = source.party_name
 
diff --git a/erpnext/crm/doctype/prospect/prospect.json b/erpnext/crm/doctype/prospect/prospect.json
index 3d6fba5..0e872ac 100644
--- a/erpnext/crm/doctype/prospect/prospect.json
+++ b/erpnext/crm/doctype/prospect/prospect.json
@@ -20,6 +20,7 @@
   "website",
   "column_break_13",
   "prospect_owner",
+  "company",
   "leads_section",
   "prospect_lead",
   "address_and_contact_section",
@@ -153,14 +154,23 @@
    "fieldname": "address_and_contact_section",
    "fieldtype": "Section Break",
    "label": "Address and Contact"
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-08-27 16:24:42.961967",
+ "migration_hash": "f39fb8f4e18a0e7fd391f0b4b52d8375",
+ "modified": "2021-11-01 13:10:36.759249",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Prospect",
+ "naming_rule": "By fieldname",
  "owner": "Administrator",
  "permissions": [
   {
diff --git a/erpnext/demo/data/drug_list.json b/erpnext/demo/data/drug_list.json
index e91c30d..3069042 100644
--- a/erpnext/demo/data/drug_list.json
+++ b/erpnext/demo/data/drug_list.json
@@ -60,7 +60,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -144,7 +143,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -226,7 +224,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -308,7 +305,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -390,7 +386,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -472,7 +467,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -554,7 +548,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -636,7 +629,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -718,7 +710,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -800,7 +791,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -882,7 +872,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -964,7 +953,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1046,7 +1034,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1128,7 +1115,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1210,7 +1196,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1292,7 +1277,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1374,7 +1358,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1456,7 +1439,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1538,7 +1520,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1620,7 +1601,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1702,7 +1682,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1784,7 +1763,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1866,7 +1844,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -1948,7 +1925,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2030,7 +2006,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2112,7 +2087,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2194,7 +2168,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2276,7 +2249,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2358,7 +2330,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2440,7 +2411,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2522,7 +2492,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2604,7 +2573,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2686,7 +2654,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2768,7 +2735,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2850,7 +2816,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -2932,7 +2897,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3014,7 +2978,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3098,7 +3061,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3180,7 +3142,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3262,7 +3223,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3344,7 +3304,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3426,7 +3385,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3508,7 +3466,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3590,7 +3547,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3672,7 +3628,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3754,7 +3709,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3836,7 +3790,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -3918,7 +3871,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4000,7 +3952,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4082,7 +4033,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4164,7 +4114,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4246,7 +4195,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4328,7 +4276,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4410,7 +4357,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4492,7 +4438,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4574,7 +4519,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4656,7 +4600,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4738,7 +4681,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4820,7 +4762,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4902,7 +4843,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -4984,7 +4924,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -5066,7 +5005,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
@@ -5148,7 +5086,6 @@
   "standard_rate": 0.0,
   "stock_uom": "Nos",
   "supplier_items": [],
-  "synced_with_hub": 0,
   "taxes": [],
   "thumbnail": null,
   "tolerance": 0.0,
diff --git a/erpnext/hr/doctype/employee/employee_reminders.py b/erpnext/hr/doctype/employee/employee_reminders.py
index 216d8f6..559bd39 100644
--- a/erpnext/hr/doctype/employee/employee_reminders.py
+++ b/erpnext/hr/doctype/employee/employee_reminders.py
@@ -157,6 +157,8 @@
 			AND
 				MONTH({condition_column}) = MONTH(%(today)s)
 			AND
+				YEAR({condition_column}) < YEAR(%(today)s)
+			AND
 				`status` = 'Active'
 		""",
 		"postgres": f"""
@@ -167,6 +169,8 @@
 			AND
 				DATE_PART('month', {condition_column}) = date_part('month', %(today)s)
 			AND
+				DATE_PART('year', {condition_column}) < date_part('year', %(today)s)
+			AND
 				"status" = 'Active'
 		""",
 	}, dict(today=today(), condition_column=condition_column), as_dict=1)
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
index 4a1064b..2f7b8fc 100644
--- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
@@ -100,7 +100,7 @@
  ],
  "istable": 1,
  "links": [],
- "modified": "2020-09-23 20:27:36.027728",
+ "modified": "2021-10-26 20:27:36.027728",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Expense Taxes and Charges",
diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py
deleted file mode 100644
index 6ac3255..0000000
--- a/erpnext/hub_node/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-
-
-@frappe.whitelist()
-def enable_hub():
-	hub_settings = frappe.get_doc('Marketplace Settings')
-	hub_settings.register()
-	frappe.db.commit()
-	return hub_settings
-
-@frappe.whitelist()
-def sync():
-	hub_settings = frappe.get_doc('Marketplace Settings')
-	hub_settings.sync()
diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py
deleted file mode 100644
index 5530491..0000000
--- a/erpnext/hub_node/api.py
+++ /dev/null
@@ -1,233 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe import _
-from frappe.desk.form.load import get_attachments
-from frappe.frappeclient import FrappeClient
-from six import string_types
-
-current_user = frappe.session.user
-
-
-@frappe.whitelist()
-def register_marketplace(company, company_description):
-	validate_registerer()
-
-	settings = frappe.get_single('Marketplace Settings')
-	message = settings.register_seller(company, company_description)
-
-	if message.get('hub_seller_name'):
-		settings.registered = 1
-		settings.hub_seller_name = message.get('hub_seller_name')
-		settings.save()
-
-		settings.add_hub_user(frappe.session.user)
-
-	return { 'ok': 1 }
-
-
-@frappe.whitelist()
-def register_users(user_list):
-	user_list = json.loads(user_list)
-
-	settings = frappe.get_single('Marketplace Settings')
-
-	for user in user_list:
-		settings.add_hub_user(user)
-
-	return user_list
-
-
-def validate_registerer():
-	if current_user == 'Administrator':
-		frappe.throw(_('Please login as another user to register on Marketplace'))
-
-	valid_roles = ['System Manager', 'Item Manager']
-
-	if not frappe.utils.is_subset(valid_roles, frappe.get_roles()):
-		frappe.throw(_('Only users with {0} role can register on Marketplace').format(', '.join(valid_roles)),
-			frappe.PermissionError)
-
-
-@frappe.whitelist()
-def call_hub_method(method, params=None):
-	connection = get_hub_connection()
-
-	if isinstance(params, string_types):
-		params = json.loads(params)
-
-	params.update({
-		'cmd': 'hub.hub.api.' + method
-	})
-
-	response = connection.post_request(params)
-	return response
-
-
-def map_fields(items):
-	field_mappings = get_field_mappings()
-	table_fields = [d.fieldname for d in frappe.get_meta('Item').get_table_fields()]
-
-	hub_seller_name = frappe.db.get_value('Marketplace Settings', 'Marketplace Settings', 'hub_seller_name')
-
-	for item in items:
-		for fieldname in table_fields:
-			item.pop(fieldname, None)
-
-		for mapping in field_mappings:
-			local_fieldname = mapping.get('local_fieldname')
-			remote_fieldname = mapping.get('remote_fieldname')
-
-			value = item.get(local_fieldname)
-			item.pop(local_fieldname, None)
-			item[remote_fieldname] = value
-
-		item['doctype'] = 'Hub Item'
-		item['hub_seller'] = hub_seller_name
-		item.pop('attachments', None)
-
-	return items
-
-
-@frappe.whitelist()
-def get_valid_items(search_value=''):
-	items = frappe.get_list(
-		'Item',
-		fields=["*"],
-		filters={
-			'disabled': 0,
-			'item_name': ['like', '%' + search_value + '%'],
-			'publish_in_hub': 0
-		},
-		order_by="modified desc"
-	)
-
-	valid_items = filter(lambda x: x.image and x.description, items)
-
-	def prepare_item(item):
-		item.source_type = "local"
-		item.attachments = get_attachments('Item', item.item_code)
-		return item
-
-	valid_items = map(prepare_item, valid_items)
-
-	return valid_items
-
-@frappe.whitelist()
-def update_item(ref_doc, data):
-	data = json.loads(data)
-
-	data.update(dict(doctype='Hub Item', name=ref_doc))
-	try:
-		connection = get_hub_connection()
-		connection.update(data)
-	except Exception as e:
-		frappe.log_error(message=e, title='Hub Sync Error')
-
-@frappe.whitelist()
-def publish_selected_items(items_to_publish):
-	items_to_publish = json.loads(items_to_publish)
-	items_to_update = []
-	if not len(items_to_publish):
-		frappe.throw(_('No items to publish'))
-
-	for item in items_to_publish:
-		item_code = item.get('item_code')
-		frappe.db.set_value('Item', item_code, 'publish_in_hub', 1)
-
-		hub_dict = {
-			'doctype': 'Hub Tracked Item',
-			'item_code': item_code,
-			'published': 1,
-			'hub_category': item.get('hub_category'),
-			'image_list': item.get('image_list')
-		}
-		frappe.get_doc(hub_dict).insert(ignore_if_duplicate=True)
-
-	items = map_fields(items_to_publish)
-
-	try:
-		item_sync_preprocess(len(items))
-		convert_relative_image_urls_to_absolute(items)
-
-		# TODO: Publish Progress
-		connection = get_hub_connection()
-		connection.insert_many(items)
-
-		item_sync_postprocess()
-	except Exception as e:
-		frappe.log_error(message=e, title='Hub Sync Error')
-
-@frappe.whitelist()
-def unpublish_item(item_code, hub_item_name):
-	''' Remove item listing from the marketplace '''
-
-	response = call_hub_method('unpublish_item', {
-		'hub_item_name': hub_item_name
-	})
-
-	if response:
-		frappe.db.set_value('Item', item_code, 'publish_in_hub', 0)
-		frappe.delete_doc('Hub Tracked Item', item_code)
-	else:
-		frappe.throw(_('Unable to update remote activity'))
-
-@frappe.whitelist()
-def get_unregistered_users():
-	settings = frappe.get_single('Marketplace Settings')
-	registered_users = [user.user for user in settings.users] + ['Administrator', 'Guest']
-	all_users = [user.name for user in frappe.db.get_all('User', filters={'enabled': 1})]
-	unregistered_users = [user for user in all_users if user not in registered_users]
-	return unregistered_users
-
-
-def item_sync_preprocess(intended_item_publish_count):
-	response = call_hub_method('pre_items_publish', {
-		'intended_item_publish_count': intended_item_publish_count
-	})
-
-	if response:
-		frappe.db.set_value("Marketplace Settings", "Marketplace Settings", "sync_in_progress", 1)
-		return response
-	else:
-		frappe.throw(_('Unable to update remote activity'))
-
-
-def item_sync_postprocess():
-	response = call_hub_method('post_items_publish', {})
-	if response:
-		frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'last_sync_datetime', frappe.utils.now())
-	else:
-		frappe.throw(_('Unable to update remote activity'))
-
-	frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'sync_in_progress', 0)
-
-
-def convert_relative_image_urls_to_absolute(items):
-	from six.moves.urllib.parse import urljoin
-
-	for item in items:
-		file_path = item['image']
-
-		if file_path.startswith('/files/'):
-			item['image'] = urljoin(frappe.utils.get_url(), file_path)
-
-
-def get_hub_connection():
-	settings = frappe.get_single('Marketplace Settings')
-	marketplace_url = settings.marketplace_url
-	hub_user = settings.get_hub_user(frappe.session.user)
-
-	if hub_user:
-		password = hub_user.get_password()
-		hub_connection = FrappeClient(marketplace_url, hub_user.user, password)
-		return hub_connection
-	else:
-		read_only_hub_connection = FrappeClient(marketplace_url)
-		return read_only_hub_connection
-
-
-def get_field_mappings():
-	return []
diff --git a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json
deleted file mode 100644
index b1e421d..0000000
--- a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "condition": "{'name': ('=', frappe.db.get_single_value('Hub Settings', 'company'))}",
- "creation": "2017-09-07 11:38:43.169065",
- "docstatus": 0,
- "doctype": "Data Migration Mapping",
- "fields": [
-  {
-   "is_child_table": 0,
-   "local_fieldname": "name",
-   "remote_fieldname": "company_name"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "country",
-   "remote_fieldname": "country"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "\"city\"",
-   "remote_fieldname": "seller_city"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "eval:frappe.local.site",
-   "remote_fieldname": "site_name"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "eval:frappe.session.user",
-   "remote_fieldname": "user"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "company_logo",
-   "remote_fieldname": "company_logo"
-  }
- ],
- "idx": 2,
- "local_doctype": "Company",
- "mapping_name": "Company to Hub Company",
- "mapping_type": "Push",
- "migration_id_field": "hub_sync_id",
- "modified": "2020-09-18 17:26:09.703215",
- "modified_by": "Administrator",
- "name": "Company to Hub Company",
- "owner": "Administrator",
- "page_length": 10,
- "remote_objectname": "Hub Company",
- "remote_primary_key": "name"
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json
deleted file mode 100644
index d11abeb..0000000
--- a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "condition": "{'reference_doctype': 'Lead', 'user': frappe.db.get_single_value('Hub Settings', 'user'), 'status': 'Pending'}",
- "creation": "2017-09-20 15:06:40.279930",
- "docstatus": 0,
- "doctype": "Data Migration Mapping",
- "fields": [
-  {
-   "is_child_table": 0,
-   "local_fieldname": "email_id",
-   "remote_fieldname": "email_id"
-  },
-  {
-   "is_child_table": 0,
-   "local_fieldname": "lead_name",
-   "remote_fieldname": "lead_name"
-  }
- ],
- "idx": 0,
- "local_doctype": "Lead",
- "local_primary_key": "email_id",
- "mapping_name": "Hub Message to Lead",
- "mapping_type": "Pull",
- "migration_id_field": "hub_sync_id",
- "modified": "2020-09-18 17:26:09.703215",
- "modified_by": "Administrator",
- "name": "Hub Message to Lead",
- "owner": "Administrator",
- "page_length": 10,
- "remote_objectname": "Hub Message",
- "remote_primary_key": "name"
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json
deleted file mode 100644
index bcece69..0000000
--- a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "condition": "{\"publish_in_hub\": 1}", 
- "creation": "2017-09-07 13:27:52.726350", 
- "docstatus": 0, 
- "doctype": "Data Migration Mapping", 
- "fields": [
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "item_code", 
-   "remote_fieldname": "item_code"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "item_name", 
-   "remote_fieldname": "item_name"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "eval:frappe.db.get_value('Hub Settings' , 'Hub Settings', 'company_email')", 
-   "remote_fieldname": "hub_seller"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "image", 
-   "remote_fieldname": "image"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "image_list", 
-   "remote_fieldname": "image_list"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "item_group", 
-   "remote_fieldname": "item_group"
-  }, 
-  {
-   "is_child_table": 0, 
-   "local_fieldname": "hub_category", 
-   "remote_fieldname": "hub_category"
-  }
- ], 
- "idx": 1, 
- "local_doctype": "Item", 
- "mapping_name": "Item to Hub Item", 
- "mapping_type": "Push", 
- "migration_id_field": "hub_sync_id", 
- "modified": "2018-08-19 22:20:25.727581", 
- "modified_by": "Administrator", 
- "name": "Item to Hub Item", 
- "owner": "Administrator", 
- "page_length": 10, 
- "remote_objectname": "Hub Item", 
- "remote_primary_key": "item_code"
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json
deleted file mode 100644
index e90b1dd..0000000
--- a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "creation": "2017-09-07 11:39:38.445902", 
- "docstatus": 0, 
- "doctype": "Data Migration Plan", 
- "idx": 1, 
- "mappings": [
-  {
-   "enabled": 1, 
-   "mapping": "Item to Hub Item"
-  }
- ], 
- "modified": "2018-08-19 22:20:25.644602", 
- "modified_by": "Administrator", 
- "module": "Hub Node", 
- "name": "Hub Sync", 
- "owner": "Administrator", 
- "plan_name": "Hub Sync", 
- "postprocess_method": "erpnext.hub_node.api.item_sync_postprocess"
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/__init__.py b/erpnext/hub_node/doctype/hub_tracked_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/hub_node/doctype/hub_tracked_item/__init__.py
+++ /dev/null
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js
deleted file mode 100644
index 660532d..0000000
--- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Hub Tracked Item', {
-	refresh: function(frm) {
-
-	}
-});
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json
deleted file mode 100644
index 7d07ba4..0000000
--- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json
+++ /dev/null
@@ -1,210 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "field:item_code", 
- "beta": 0, 
- "creation": "2018-03-18 09:33:50.267762", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_code", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Item Code", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 1
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "hub_category", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Hub Category", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-    "allow_bulk_edit": 0,
-    "allow_in_quick_entry": 0,
-    "allow_on_submit": 0,
-    "bold": 0,
-    "collapsible": 0,
-    "columns": 0,
-    "fieldname": "published",
-    "fieldtype": "Check",
-    "hidden": 0,
-    "ignore_user_permissions": 0,
-    "ignore_xss_filter": 0,
-    "in_filter": 0,
-    "in_global_search": 0,
-    "in_list_view": 0,
-    "in_standard_filter": 0,
-    "label": "Published",
-    "length": 0,
-    "no_copy": 0,
-    "permlevel": 0,
-    "precision": "",
-    "print_hide": 0,
-    "print_hide_if_no_value": 0,
-    "read_only": 0,
-    "remember_last_selected_value": 0,
-    "report_hide": 0,
-    "reqd": 0,
-    "search_index": 0,
-    "set_only_once": 0,
-    "translatable": 0,
-    "unique": 0
-   },
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "image_list", 
-   "fieldtype": "Long Text", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Image List", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2019-12-10 11:37:35.951019", 
- "modified_by": "Administrator", 
- "module": "Hub Node", 
- "name": "Hub Tracked Item", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [
-  {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
-   "write": 1
-  }, 
-  {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Item Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
-   "write": 1
-  }
- ], 
- "quick_entry": 1, 
- "read_only": 1, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0, 
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py
deleted file mode 100644
index 823c79e..0000000
--- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class HubTrackedItem(Document):
-	pass
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py
deleted file mode 100644
index c403f90..0000000
--- a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-
-class TestHubTrackedItem(unittest.TestCase):
-	pass
diff --git a/erpnext/hub_node/doctype/hub_user/__init__.py b/erpnext/hub_node/doctype/hub_user/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/hub_node/doctype/hub_user/__init__.py
+++ /dev/null
diff --git a/erpnext/hub_node/doctype/hub_user/hub_user.json b/erpnext/hub_node/doctype/hub_user/hub_user.json
deleted file mode 100644
index f51ffb4..0000000
--- a/erpnext/hub_node/doctype/hub_user/hub_user.json
+++ /dev/null
@@ -1,140 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "", 
- "beta": 0, 
- "creation": "2018-08-31 12:36:45.627531", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "user", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "User", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "User", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 1
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "hub_user_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Hub User", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "password", 
-   "fieldtype": "Password", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Hub Password", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }
- ], 
- "has_web_view": 0, 
- "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": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Hub Node", 
- "name": "Hub User", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0, 
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_user/hub_user.py b/erpnext/hub_node/doctype/hub_user/hub_user.py
deleted file mode 100644
index 1f7c8fc..0000000
--- a/erpnext/hub_node/doctype/hub_user/hub_user.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class HubUser(Document):
-	pass
diff --git a/erpnext/hub_node/doctype/hub_users/hub_users.json b/erpnext/hub_node/doctype/hub_users/hub_users.json
deleted file mode 100644
index d42f3fd..0000000
--- a/erpnext/hub_node/doctype/hub_users/hub_users.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2018-03-06 04:38:49.891787", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "user", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "User", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "User", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }
- ], 
- "has_web_view": 0, 
- "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": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Hub Node", 
- "name": "Hub Users", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_users/hub_users.py b/erpnext/hub_node/doctype/hub_users/hub_users.py
deleted file mode 100644
index e08ed68..0000000
--- a/erpnext/hub_node/doctype/hub_users/hub_users.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class HubUsers(Document):
-	pass
diff --git a/erpnext/hub_node/doctype/marketplace_settings/__init__.py b/erpnext/hub_node/doctype/marketplace_settings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/hub_node/doctype/marketplace_settings/__init__.py
+++ /dev/null
diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js
deleted file mode 100644
index 36da832..0000000
--- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Marketplace Settings', {
-	refresh: function(frm) {
-		$('#toolbar-user .marketplace-link').toggle(!frm.doc.disable_marketplace);
-	},
-});
diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json
deleted file mode 100644
index e784f68..0000000
--- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json
+++ /dev/null
@@ -1,410 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 1, 
- "creation": "2018-08-31 15:54:38.795263", 
- "custom": 0, 
- "description": "", 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 0, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "disable_marketplace", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Disable Marketplace", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:!doc.disable_marketplace", 
-   "fieldname": "marketplace_settings_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Marketplace Settings", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "https://hubmarket.org", 
-   "fieldname": "marketplace_url", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Marketplace URL (to hide and update label)", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "registered", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Registered", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sync_in_progress", 
-   "fieldtype": "Check", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Sync in Progress", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "hub_seller_name", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Hub Seller Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "users", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Users", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Hub User", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "", 
-   "fieldname": "last_sync_datetime", 
-   "fieldtype": "Datetime", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Last Sync On", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "", 
-   "depends_on": "eval:1", 
-   "fieldname": "custom_data", 
-   "fieldtype": "Code", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Custom Data", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 1, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Hub Node", 
- "name": "Marketplace Settings", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [
-  {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 1
-  }, 
-  {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 0, 
-   "role": "All", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
-   "write": 0
-  }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0, 
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py
deleted file mode 100644
index 33d23f6..0000000
--- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe.frappeclient import FrappeClient
-from frappe.model.document import Document
-from frappe.utils import cint
-
-
-class MarketplaceSettings(Document):
-
-	def register_seller(self, company, company_description):
-
-		country, currency, company_logo = frappe.db.get_value('Company', company,
-			['country', 'default_currency', 'company_logo'])
-
-		company_details = {
-			'company': company,
-			'country': country,
-			'currency': currency,
-			'company_description': company_description,
-			'company_logo': company_logo,
-			'site_name': frappe.utils.get_url()
-		}
-
-		hub_connection = self.get_connection()
-
-		response = hub_connection.post_request({
-			'cmd': 'hub.hub.api.add_hub_seller',
-			'company_details': json.dumps(company_details)
-		})
-
-		return response
-
-
-	def add_hub_user(self, user_email):
-		'''Create a Hub User and User record on hub server
-		and if successfull append it to Hub User table
-		'''
-
-		if not self.registered:
-			return
-
-		hub_connection = self.get_connection()
-
-		first_name, last_name = frappe.db.get_value('User', user_email, ['first_name', 'last_name'])
-
-		hub_user = hub_connection.post_request({
-			'cmd': 'hub.hub.api.add_hub_user',
-			'user_email': user_email,
-			'first_name': first_name,
-			'last_name': last_name,
-			'hub_seller': self.hub_seller_name
-		})
-
-		self.append('users', {
-			'user': hub_user.get('user_email'),
-			'hub_user_name': hub_user.get('hub_user_name'),
-			'password': hub_user.get('password')
-		})
-
-		self.save()
-
-	def get_hub_user(self, user):
-		'''Return the Hub User doc from the `users` table if password is set'''
-
-		filtered_users = list(filter(
-			lambda x: x.user == user and x.password,
-			self.users
-		))
-
-		if filtered_users:
-			return filtered_users[0]
-
-
-	def get_connection(self):
-		return FrappeClient(self.marketplace_url)
-
-
-	def unregister(self):
-		"""Disable the User on hubmarket.org"""
-
-@frappe.whitelist()
-def is_marketplace_enabled():
-	if not hasattr(frappe.local, 'is_marketplace_enabled'):
-		frappe.local.is_marketplace_enabled = cint(frappe.db.get_single_value('Marketplace Settings',
-			'disable_marketplace'))
-
-	return frappe.local.is_marketplace_enabled
diff --git a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py
deleted file mode 100644
index 7922f45..0000000
--- a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-
-class TestMarketplaceSettings(unittest.TestCase):
-	pass
diff --git a/erpnext/hub_node/legacy.py b/erpnext/hub_node/legacy.py
deleted file mode 100644
index 2e4c266..0000000
--- a/erpnext/hub_node/legacy.py
+++ /dev/null
@@ -1,148 +0,0 @@
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe.contacts.doctype.contact.contact import get_default_contact
-from frappe.frappeclient import FrappeClient
-from frappe.utils import nowdate
-from frappe.utils.nestedset import get_root_of
-
-
-def get_list(doctype, start, limit, fields, filters, order_by):
-	pass
-
-def get_hub_connection():
-	if frappe.db.exists('Data Migration Connector', 'Hub Connector'):
-		hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector')
-		hub_connection = hub_connector.get_connection()
-		return hub_connection.connection
-
-	# read-only connection
-	hub_connection = FrappeClient(frappe.conf.hub_url)
-	return hub_connection
-
-def make_opportunity(buyer_name, email_id):
-	buyer_name = "HUB-" + buyer_name
-
-	if not frappe.db.exists('Lead', {'email_id': email_id}):
-		lead = frappe.new_doc("Lead")
-		lead.lead_name = buyer_name
-		lead.email_id = email_id
-		lead.save(ignore_permissions=True)
-
-	o = frappe.new_doc("Opportunity")
-	o.opportunity_from = "Lead"
-	o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"]
-	o.save(ignore_permissions=True)
-
-@frappe.whitelist()
-def make_rfq_and_send_opportunity(item, supplier):
-	supplier = make_supplier(supplier)
-	contact = make_contact(supplier)
-	item = make_item(item)
-	rfq = make_rfq(item, supplier, contact)
-	status = send_opportunity(contact)
-
-	return {
-		'rfq': rfq,
-		'hub_document_created': status
-	}
-
-def make_supplier(supplier):
-	# make supplier if not already exists
-	supplier = frappe._dict(json.loads(supplier))
-
-	if not frappe.db.exists('Supplier', {'supplier_name': supplier.supplier_name}):
-		supplier_doc = frappe.get_doc({
-			'doctype': 'Supplier',
-			'supplier_name': supplier.supplier_name,
-			'supplier_group': supplier.supplier_group,
-			'supplier_email': supplier.supplier_email
-		}).insert()
-	else:
-		supplier_doc = frappe.get_doc('Supplier', supplier.supplier_name)
-
-	return supplier_doc
-
-def make_contact(supplier):
-	contact_name = get_default_contact('Supplier', supplier.supplier_name)
-	# make contact if not already exists
-	if not contact_name:
-		contact = frappe.get_doc({
-			'doctype': 'Contact',
-			'first_name': supplier.supplier_name,
-			'is_primary_contact': 1,
-			'links': [
-				{'link_doctype': 'Supplier', 'link_name': supplier.supplier_name}
-			]
-		})
-		contact.add_email(supplier.supplier_email, is_primary=True)
-		contact.insert()
-	else:
-		contact = frappe.get_doc('Contact', contact_name)
-
-	return contact
-
-def make_item(item):
-	# make item if not already exists
-	item = frappe._dict(json.loads(item))
-
-	if not frappe.db.exists('Item', {'item_code': item.item_code}):
-		item_doc = frappe.get_doc({
-			'doctype': 'Item',
-			'item_code': item.item_code,
-			'item_group': item.item_group,
-			'is_item_from_hub': 1
-		}).insert()
-	else:
-		item_doc = frappe.get_doc('Item', item.item_code)
-
-	return item_doc
-
-def make_rfq(item, supplier, contact):
-	# make rfq
-	rfq = frappe.get_doc({
-		'doctype': 'Request for Quotation',
-		'transaction_date': nowdate(),
-		'status': 'Draft',
-		'company': frappe.db.get_single_value('Marketplace Settings', 'company'),
-		'message_for_supplier': 'Please supply the specified items at the best possible rates',
-		'suppliers': [
-			{ 'supplier': supplier.name, 'contact': contact.name }
-		],
-		'items': [
-			{
-				'item_code': item.item_code,
-				'qty': 1,
-				'schedule_date': nowdate(),
-				'warehouse': item.default_warehouse or get_root_of("Warehouse"),
-				'description': item.description,
-				'uom': item.stock_uom
-			}
-		]
-	}).insert()
-
-	rfq.save()
-	rfq.submit()
-	return rfq
-
-def send_opportunity(contact):
-	# Make Hub Message on Hub with lead data
-	doc = {
-		'doctype': 'Lead',
-		'lead_name': frappe.db.get_single_value('Marketplace Settings', 'company'),
-		'email_id': frappe.db.get_single_value('Marketplace Settings', 'user')
-	}
-
-	args = frappe._dict(dict(
-		doctype='Hub Message',
-		reference_doctype='Lead',
-		data=json.dumps(doc),
-		user=contact.email_id
-	))
-
-	connection = get_hub_connection()
-	response = connection.insert('Hub Message', args)
-
-	return response.ok
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 7e53918..6218707 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -436,7 +436,7 @@
    "description": "Item Image (if not slideshow)",
    "fieldname": "website_image",
    "fieldtype": "Attach Image",
-   "label": "Image"
+   "label": "Website Image"
   },
   {
    "allow_on_submit": 1,
@@ -539,7 +539,7 @@
  "image_field": "image",
  "is_submittable": 1,
  "links": [],
- "modified": "2021-05-16 12:25:09.081968",
+ "modified": "2021-10-27 14:52:04.500251",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 232e3a0..2cd8f8c 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -307,6 +307,9 @@
 		existing_bom_cost = self.total_cost
 
 		for d in self.get("items"):
+			if not d.item_code:
+				continue
+
 			rate = self.get_rm_rate({
 				"company": self.company,
 				"item_code": d.item_code,
@@ -599,7 +602,7 @@
 		for d in self.get('items'):
 			if d.bom_no:
 				self.get_child_exploded_items(d.bom_no, d.stock_qty)
-			else:
+			elif d.item_code:
 				self.add_to_cur_exploded_items(frappe._dict({
 					'item_code'		: d.item_code,
 					'item_name'		: d.item_name,
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index e1d79be..b3b9407 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -605,7 +605,8 @@
 			"doctype": "Material Request Item",
 			"field_map": {
 				"required_qty": "qty",
-				"uom": "stock_uom"
+				"uom": "stock_uom",
+				"name": "job_card_item"
 			},
 			"postprocess": update_item,
 		}
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 7e6fc3c..2424ef9 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -311,7 +311,7 @@
 
 		if self.total_produced_qty > 0:
 			self.status = "In Process"
-			if self.total_produced_qty >= self.total_planned_qty:
+			if self.check_have_work_orders_completed():
 				self.status = "Completed"
 
 		if self.status != 'Completed':
@@ -575,6 +575,15 @@
 
 			self.append("sub_assembly_items", data)
 
+	def check_have_work_orders_completed(self):
+		wo_status = frappe.db.get_list(
+			"Work Order",
+			filters={"production_plan": self.name},
+			fields="status",
+			pluck="status"
+		)
+		return all(s == "Completed" for s in wo_status)
+
 @frappe.whitelist()
 def download_raw_materials(doc, warehouses=None):
 	if isinstance(doc, str):
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index 913fc85..7f8e816 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -182,6 +182,7 @@
    "reqd": 1
   },
   {
+   "default": "1.0",
    "fieldname": "qty",
    "fieldtype": "Float",
    "label": "Qty To Manufacture",
@@ -572,10 +573,11 @@
  "image_field": "image",
  "is_submittable": 1,
  "links": [],
- "modified": "2021-08-24 15:14:03.844937",
+ "modified": "2021-10-27 19:21:35.139888",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Work Order",
+ "naming_rule": "By \"Naming Series\" field",
  "nsm_parent_field": "parent_work_order",
  "owner": "Administrator",
  "permissions": [
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index e282dd3..f881e1b 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -685,9 +685,7 @@
 					if not d.operation:
 						d.operation = operation
 			else:
-				# Attribute a big number (999) to idx for sorting putpose in case idx is NULL
-				# For instance in BOM Explosion Item child table, the items coming from sub assembly items
-				for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
+				for item in sorted(item_dict.values(), key=lambda d: d['idx'] or float('inf')):
 					self.append('required_items', {
 						'rate': item.rate,
 						'amount': item.rate * item.qty,
diff --git a/erpnext/modules.txt b/erpnext/modules.txt
index a9f94ce..15a24a7 100644
--- a/erpnext/modules.txt
+++ b/erpnext/modules.txt
@@ -20,9 +20,8 @@
 ERPNext Integrations
 Non Profit
 Hotels
-Hub Node
 Quality Management
 Communication
 Loan Management
 Payroll
-Telephony
+Telephony
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 20e54e0..2c21ab6 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -58,11 +58,7 @@
 erpnext.patches.v11_0.update_allow_transfer_for_manufacture
 erpnext.patches.v11_0.add_item_group_defaults
 erpnext.patches.v11_0.add_expense_claim_default_account
-execute:frappe.delete_doc("Page", "hub")
-erpnext.patches.v11_0.reset_publish_in_hub_for_all_items
-erpnext.patches.v11_0.update_hub_url # 2018-08-31  # 2018-09-03
 erpnext.patches.v11_0.make_job_card
-erpnext.patches.v10_0.delete_hub_documents # 12-08-2018
 erpnext.patches.v11_0.add_default_dispatch_notification_template
 erpnext.patches.v11_0.add_market_segments
 erpnext.patches.v11_0.add_sales_stages
@@ -153,7 +149,6 @@
 erpnext.patches.v12_0.add_eway_bill_in_delivery_note
 erpnext.patches.v12_0.set_lead_title_field
 erpnext.patches.v12_0.set_permission_einvoicing
-erpnext.patches.v12_0.set_published_in_hub_tracked_item
 erpnext.patches.v12_0.set_job_offer_applicant_email
 erpnext.patches.v12_0.create_irs_1099_field_united_states
 erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
@@ -308,6 +303,9 @@
 erpnext.patches.v13_0.add_default_interview_notification_templates
 erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
 erpnext.patches.v13_0.requeue_failed_reposts
+erpnext.patches.v12_0.update_production_plan_status
 erpnext.patches.v13_0.healthcare_deprecation_warning
 erpnext.patches.v14_0.delete_healthcare_doctypes
+erpnext.patches.v13_0.update_category_in_ltds_certificate
 erpnext.patches.v13_0.create_pan_field_for_india #2
+erpnext.patches.v14_0.delete_hub_doctypes
diff --git a/erpnext/patches/v10_0/delete_hub_documents.py b/erpnext/patches/v10_0/delete_hub_documents.py
deleted file mode 100644
index 16c7abf..0000000
--- a/erpnext/patches/v10_0/delete_hub_documents.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from __future__ import unicode_literals
-
-import frappe
-
-
-def execute():
-	for dt, dn in (("Page", "Hub"), ("DocType", "Hub Settings"), ("DocType", "Hub Category")):
-		frappe.delete_doc(dt, dn, ignore_missing=True)
-
-	if frappe.db.exists("DocType", "Data Migration Plan"):
-		data_migration_plans = frappe.get_all("Data Migration Plan", filters={"module": 'Hub Node'})
-		for plan in data_migration_plans:
-			plan_doc = frappe.get_doc("Data Migration Plan", plan.name)
-			for m in plan_doc.get("mappings"):
-				frappe.delete_doc("Data Migration Mapping", m.mapping, force=True)
-			docs = frappe.get_all("Data Migration Run", filters={"data_migration_plan": plan.name})
-			for doc in docs:
-				frappe.delete_doc("Data Migration Run", doc.name)
-			frappe.delete_doc("Data Migration Plan", plan.name)
diff --git a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py b/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py
deleted file mode 100644
index a664baf..0000000
--- a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from __future__ import unicode_literals
-
-import frappe
-
-
-def execute():
-	frappe.reload_doc('stock', 'doctype', 'item')
-	frappe.db.sql("""update `tabItem` set publish_in_hub = 0""")
diff --git a/erpnext/patches/v11_0/update_hub_url.py b/erpnext/patches/v11_0/update_hub_url.py
deleted file mode 100644
index c89b9b5..0000000
--- a/erpnext/patches/v11_0/update_hub_url.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from __future__ import unicode_literals
-
-import frappe
-
-
-def execute():
-	frappe.reload_doc('hub_node', 'doctype', 'Marketplace Settings')
-	frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'marketplace_url', 'https://hubmarket.org')
diff --git a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
deleted file mode 100644
index 73c6ce8..0000000
--- a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from __future__ import unicode_literals
-
-import frappe
-
-
-def execute():
-	frappe.reload_doc("Hub Node", "doctype", "Hub Tracked Item")
-	if not frappe.db.a_row_exists("Hub Tracked Item"):
-		return
-
-	frappe.db.sql('''
-		Update `tabHub Tracked Item`
-		SET published = 1
-	''')
diff --git a/erpnext/patches/v12_0/update_production_plan_status.py b/erpnext/patches/v12_0/update_production_plan_status.py
new file mode 100644
index 0000000..06fc503
--- /dev/null
+++ b/erpnext/patches/v12_0/update_production_plan_status.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2021, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+
+
+def execute():
+	frappe.reload_doc("manufacturing", "doctype", "production_plan")
+	frappe.db.sql("""
+		UPDATE `tabProduction Plan` ppl
+		SET status = "Completed"
+		WHERE ppl.name IN (
+			SELECT ss.name FROM (
+				SELECT
+					(
+						count(wo.status = "Completed") =
+						count(pp.name)
+					) =
+					(
+						pp.status != "Completed"
+						AND pp.total_produced_qty >= pp.total_planned_qty
+					) AS should_set,
+					pp.name AS name
+				FROM
+					`tabWork Order` wo INNER JOIN`tabProduction Plan` pp
+					ON wo.production_plan = pp.name
+				GROUP BY pp.name
+				HAVING should_set = 1
+			) ss
+		)
+	""")
diff --git a/erpnext/patches/v13_0/update_category_in_ltds_certificate.py b/erpnext/patches/v13_0/update_category_in_ltds_certificate.py
new file mode 100644
index 0000000..a5f5a23
--- /dev/null
+++ b/erpnext/patches/v13_0/update_category_in_ltds_certificate.py
@@ -0,0 +1,20 @@
+import frappe
+
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	frappe.reload_doc('regional', 'doctype', 'lower_deduction_certificate')
+
+	ldc = frappe.qb.DocType("Lower Deduction Certificate").as_("ldc")
+	supplier = frappe.qb.DocType("Supplier")
+
+	frappe.qb.update(ldc).inner_join(supplier).on(
+		ldc.supplier == supplier.name
+	).set(
+		ldc.tax_withholding_category, supplier.tax_withholding_category
+	).where(
+		ldc.tax_withholding_category.isnull()
+	).run()
\ No newline at end of file
diff --git a/erpnext/patches/v14_0/delete_hub_doctypes.py b/erpnext/patches/v14_0/delete_hub_doctypes.py
new file mode 100644
index 0000000..d1e9e31
--- /dev/null
+++ b/erpnext/patches/v14_0/delete_hub_doctypes.py
@@ -0,0 +1,10 @@
+import frappe
+
+
+def execute():
+
+	doctypes = frappe.get_all("DocType", {"module": "Hub Node", "custom": 0}, pluck='name')
+	for doctype in doctypes:
+		frappe.delete_doc("DocType", doctype, ignore_missing=True)
+
+	frappe.delete_doc("Module Def", "Hub Node", ignore_missing=True, force=True)
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 6b70dab..f8e8177 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -1,14 +1,10 @@
 {
 	"css/erpnext.css": [
 		"public/less/erpnext.less",
-		"public/less/hub.less",
 		"public/scss/call_popup.scss",
 		"public/scss/point-of-sale.scss",
 		"public/scss/hierarchy_chart.scss"
 	],
-	"css/marketplace.css": [
-		"public/less/hub.less"
-	],
 	"js/erpnext-web.min.js": [
 		"public/js/website_utils.js",
 		"public/js/shopping_cart.js"
@@ -17,9 +13,6 @@
 		"public/scss/website.scss",
 		"public/scss/shopping_cart.scss"
 	],
-	"js/marketplace.min.js": [
-		"public/js/hub/marketplace.js"
-	],
 	"js/erpnext.min.js": [
 		"public/js/conf.js",
 		"public/js/utils.js",
@@ -41,7 +34,6 @@
 		"public/js/utils/supplier_quick_entry.js",
 		"public/js/education/student_button.html",
 		"public/js/education/assessment_result_tool.html",
-		"public/js/hub/hub_factory.js",
 		"public/js/call_popup/call_popup.js",
 		"public/js/utils/dimension_tree_filter.js",
 		"public/js/telephony.js",
diff --git a/erpnext/public/images/hub_logo.svg b/erpnext/public/images/hub_logo.svg
deleted file mode 100644
index 4af4821..0000000
--- a/erpnext/public/images/hub_logo.svg
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="330"
-   height="345.43808"
-   viewBox="0 0 87.312496 91.397155"
-   version="1.1"
-   id="svg4635"
-   inkscape:version="0.92.2 5c3e80d, 2017-08-06"
-   sodipodi:docname="hub-logo.svg"
-   inkscape:export-filename="/home/raghu/Desktop/hub-logo.png"
-   inkscape:export-xdpi="95.878258"
-   inkscape:export-ydpi="95.878258">
-  <defs
-     id="defs4629" />
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.7"
-     inkscape:cx="234.27717"
-     inkscape:cy="167.57445"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     units="px"
-     inkscape:window-width="1920"
-     inkscape:window-height="1149"
-     inkscape:window-x="0"
-     inkscape:window-y="24"
-     inkscape:window-maximized="1" />
-  <metadata
-     id="metadata4632">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-        <cc:license
-           rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
-      </cc:Work>
-      <cc:License
-         rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Reproduction" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Distribution" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#Notice" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#Attribution" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#ShareAlike" />
-      </cc:License>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(121.51931,-138.66452)">
-    <rect
-       rx="13.229166"
-       inkscape:export-ydpi="96"
-       inkscape:export-xdpi="96"
-       inkscape:export-filename="/home/raghu/Desktop/send/hub-02.png"
-       style="opacity:1;vector-effect:none;fill:#89da29;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
-       id="rect828"
-       width="87.3125"
-       height="87.3125"
-       x="-121.51931"
-       y="142.74918"
-       ry="13.229166" />
-    <path
-       style="opacity:1;vector-effect:none;fill:#63c923;fill-opacity:1;stroke:none;stroke-width:3.96875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
-       clip-path="none"
-       d="m -121.51931,202.96343 v 13.86892 c 0,7.32897 5.90017,13.22917 13.22916,13.22917 h 60.854162 c 6.610072,0 12.056133,-4.80013 13.061216,-11.1187 -43.339761,0.1608 -54.359752,-16.03276 -87.144538,-15.97939 z"
-       id="path830"
-       inkscape:connector-curvature="0" />
-    <path
-       style="opacity:1;vector-effect:none;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:3.96875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
-       clip-path="none"
-       d="m -34.20681,202.96343 c -32.784694,-0.0533 -43.804846,16.14019 -87.14455,15.97939 1.00509,6.31857 6.45115,11.1187 13.06122,11.1187 h 60.854164 c 7.328992,0 13.229166,-5.9002 13.229166,-13.22917 z"
-       id="path832"
-       inkscape:connector-curvature="0" />
-    <path
-       id="path834"
-       d="m -84.351263,175.75725 c -1.30945,0 -2.376091,1.06665 -2.376091,2.37608 v 10.02885 0.001 c 0.06583,4.83083 4.01156,8.73477 8.857351,8.73486 4.8718,5e-5 8.846821,-3.94421 8.871295,-8.81134 v -0.001 -9.95288 c 0,-1.30943 -1.066113,-2.37557 -2.375589,-2.37557 -1.309396,0 -2.376064,1.06614 -2.376064,2.37557 v 9.8888 c 0,2.26045 -1.858169,4.10983 -4.119642,4.10983 -2.263616,0 -4.105699,-1.82766 -4.105699,-4.08968 v -9.90844 c 0,-1.30943 -1.066138,-2.37608 -2.375561,-2.37608 z m -20.887107,0.0925 c -1.30943,0 -2.37609,1.06717 -2.37609,2.3766 v 16.45119 c 0,1.30944 1.06666,2.37609 2.37609,2.37609 1.30945,0 2.37556,-1.06665 2.37556,-2.37609 v -5.97327 h 8.22534 v 5.97327 c 0,1.30944 1.066641,2.37609 2.376091,2.37609 1.309423,0 2.375561,-1.06665 2.375561,-2.37609 v -16.45119 c 0,-1.30943 -1.066138,-2.3766 -2.375561,-2.3766 -1.30945,0 -2.376091,1.06717 -2.376091,2.3766 v 5.72627 h -8.22534 v -5.72627 c 0,-1.30943 -1.06611,-2.3766 -2.37556,-2.3766 z m 41.77419,0 c -0.654712,0 -1.248675,0.26711 -1.678967,0.69764 -0.05368,0.0537 -0.105119,0.10983 -0.153458,0.16846 v 5.3e-4 c -0.04839,0.0586 -0.09427,0.11929 -0.136949,0.18242 v 5.3e-4 c -0.256381,0.37936 -0.406691,0.83617 -0.406691,1.32705 v 16.45119 c 0,0.1635 0.01693,0.3242 0.04858,0.47852 0.09512,0.46331 0.32594,0.87828 0.64852,1.20096 0.161369,0.16136 0.345308,0.29938 0.547264,0.40928 v 0 c 0.134567,0.0732 0.276781,0.13403 0.425318,0.18035 v 0 c 0.148537,0.0463 0.303186,0.0783 0.462518,0.0946 v 0 c 0.07959,0.008 0.160708,0.0124 0.242358,0.0124 h 8.33181 c 0.08747,0 0.167931,-0.0145 0.251142,-0.0238 l 0.09509,0.005 c 0.06019,0.003 0.119407,0.005 0.178779,0.006 h 0.0037 0.0048 c 3.578305,-2e-5 6.487954,-2.90916 6.487981,-6.48747 v -0.001 c -0.0026,-1.51334 -0.578009,-2.9475 -1.540484,-4.10673 0.962448,-1.15892 1.537785,-2.59314 1.540484,-4.10621 v -0.001 c -2.7e-5,-3.57831 -2.909676,-6.48744 -6.487981,-6.48746 h -0.533294 z m 8.865103,4.75062 c 0.96393,0 1.736831,0.77394 1.736831,1.73788 0,0.96394 -0.772901,1.73684 -1.736831,1.73684 v 0 h -0.532792 -5.955718 v -3.47317 h 5.956248 z m 0,8.21552 v 0 c 0.963507,5.3e-4 1.735799,0.77373 1.735799,1.73736 0,0.96394 -0.772901,1.73684 -1.736831,1.73684 h -0.0048 l -0.533294,0.0119 h -5.951591 v -3.4742 h 5.959846 z"
-       style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.79375005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
-       inkscape:connector-curvature="0" />
-    <path
-       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#63c923;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.93750048;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
-       d="m -77.859375,138.66406 c -9.653316,0 -18.439915,3.93483 -24.767575,10.28125 a 3.9691471,3.9691471 0 1 0 5.621091,5.60352 c 4.899576,-4.9141 11.6422,-7.94727 19.146484,-7.94727 7.501101,0 14.241542,3.03098 19.140625,7.94141 a 3.9691471,3.9691471 0 1 0 5.619141,-5.60547 c -6.327038,-6.34169 -15.110547,-10.27344 -24.759766,-10.27344 z"
-       id="path838"
-       inkscape:connector-curvature="0" />
-  </g>
-</svg>
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index febdb24..5259bdc 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -18,7 +18,6 @@
 import "./utils/supplier_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";
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 0d79b10..1a309ba 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -113,15 +113,15 @@
 			"fieldname":"period_start_date",
 			"label": __("Start Date"),
 			"fieldtype": "Date",
-			"hidden": 1,
-			"reqd": 1
+			"reqd": 1,
+			"depends_on": "eval:doc.filter_based_on == 'Date Range'"
 		},
 		{
 			"fieldname":"period_end_date",
 			"label": __("End Date"),
 			"fieldtype": "Date",
-			"hidden": 1,
-			"reqd": 1
+			"reqd": 1,
+			"depends_on": "eval:doc.filter_based_on == 'Date Range'"
 		},
 		{
 			"fieldname":"from_fiscal_year",
@@ -129,7 +129,8 @@
 			"fieldtype": "Link",
 			"options": "Fiscal Year",
 			"default": frappe.defaults.get_user_default("fiscal_year"),
-			"reqd": 1
+			"reqd": 1,
+			"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
 		},
 		{
 			"fieldname":"to_fiscal_year",
@@ -137,7 +138,8 @@
 			"fieldtype": "Link",
 			"options": "Fiscal Year",
 			"default": frappe.defaults.get_user_default("fiscal_year"),
-			"reqd": 1
+			"reqd": 1,
+			"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
 		},
 		{
 			"fieldname": "periodicity",
diff --git a/erpnext/public/js/hub/PageContainer.vue b/erpnext/public/js/hub/PageContainer.vue
deleted file mode 100644
index 54c3597..0000000
--- a/erpnext/public/js/hub/PageContainer.vue
+++ /dev/null
@@ -1,119 +0,0 @@
-<template>
-	<div class="hub-page-container">
-		<component :is="current_page.component" :key="current_page.key"></component>
-	</div>
-</template>
-
-<script>
-
-import Home from './pages/Home.vue';
-import Search from './pages/Search.vue';
-import Category from './pages/Category.vue';
-import SavedItems from './pages/SavedItems.vue';
-import FeaturedItems from './pages/FeaturedItems.vue';
-import PublishedItems from './pages/PublishedItems.vue';
-import Item from './pages/Item.vue';
-import Seller from './pages/Seller.vue';
-import SellerItems from './pages/SellerItems.vue';
-import Publish from './pages/Publish.vue';
-import Buying from './pages/Buying.vue';
-import Selling from './pages/Selling.vue';
-import Messages from './pages/Messages.vue';
-import NotFound from './pages/NotFound.vue';
-
-function get_route_map() {
-	const read_only_routes = {
-		'marketplace/home': Home,
-		'marketplace/search/:category/:keyword': Search,
-		'marketplace/category/:category': Category,
-		'marketplace/item/:item': Item,
-		'marketplace/seller/:seller': Seller,
-		'marketplace/seller/:seller/items': SellerItems,
-		'marketplace/not-found': NotFound,
-	}
-	const registered_routes = {
-		'marketplace/profile': Seller,
-		'marketplace/saved-items': SavedItems,
-		'marketplace/featured-items': FeaturedItems,
-		'marketplace/publish': Publish,
-		'marketplace/published-items': PublishedItems,
-		'marketplace/buying': Buying,
-		'marketplace/buying/:item': Messages,
-		'marketplace/selling': Selling,
-		'marketplace/selling/:buyer/:item': Messages
-	}
-
-	return hub.is_seller_registered()
-		? Object.assign({}, read_only_routes, registered_routes)
-		: read_only_routes;
-}
-
-export default {
-	data() {
-		return {
-			current_page: this.get_current_page()
-		}
-	},
-	mounted() {
-		frappe.route.on('change', () => {
-			if (frappe.get_route()[0] === 'marketplace') {
-				this.set_current_page();
-				frappe.utils.scroll_to(0);
-			}
-		});
-	},
-	methods: {
-		set_current_page() {
-			this.current_page = this.get_current_page();
-		},
-		get_current_page() {
-			const route_map = get_route_map();
-			const curr_route = frappe.get_route_str();
-			let route = Object.keys(route_map).filter(route => route == curr_route)[0];
-			if (!route) {
-				// find route by matching it with dynamic part
-				const curr_route_parts = curr_route.split('/');
-				const weighted_routes = Object.keys(route_map)
-					.map(route_str => route_str.split('/'))
-					.filter(route_parts => route_parts.length === curr_route_parts.length)
-					.reduce((obj, route_parts) => {
-						const key = route_parts.join('/');
-						let weight = 0;
-						route_parts.forEach((part, i) => {
-							const curr_route_part = curr_route_parts[i];
-							if (part === curr_route_part || part.includes(':')) {
-								weight += 1;
-							}
-						});
-
-						obj[key] = weight;
-						return obj;
-					}, {});
-
-				// get the route with the highest weight
-				for (let key in weighted_routes) {
-					const route_weight = weighted_routes[key];
-					if (route_weight === curr_route_parts.length) {
-						route = key;
-						break;
-					} else {
-						route = null;
-					}
-				}
-			}
-
-			if (!route) {
-				return {
-					key: 'not-found',
-					component: NotFound
-				};
-			}
-
-			return {
-				key: curr_route,
-				component: route_map[route]
-			}
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/Sidebar.vue b/erpnext/public/js/hub/Sidebar.vue
deleted file mode 100644
index 66c291e..0000000
--- a/erpnext/public/js/hub/Sidebar.vue
+++ /dev/null
@@ -1,110 +0,0 @@
-<template>
-	<div ref="sidebar-container">
-		<ul class="list-unstyled hub-sidebar-group" data-nav-buttons>
-			<li class="hub-sidebar-item" v-for="item in items" :key="item.label" v-route="item.route" v-show="item.condition === undefined || item.condition()">
-				{{ item.label }}
-			</li>
-		</ul>
-		<ul class="list-unstyled hub-sidebar-group" data-categories>
-			<li class="hub-sidebar-item is-title bold text-muted">
-				{{ __('Categories') }}
-			</li>
-			<li class="hub-sidebar-item" v-for="category in categories" :key="category.label" v-route="category.route">
-				{{ category.label }}
-			</li>
-		</ul>
-	</div>
-</template>
-<script>
-export default {
-	data() {
-		return {
-			hub_registered: hub.is_user_registered(),
-			items: [
-				{
-					label: __('Browse'),
-					route: 'marketplace/home'
-				},
-				{
-					label: __('Saved Items'),
-					route: 'marketplace/saved-items',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Your Featured Items'),
-					route: 'marketplace/featured-items',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Your Profile'),
-					route: 'marketplace/profile',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Your Items'),
-					route: 'marketplace/published-items',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Publish Items'),
-					route: 'marketplace/publish',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Selling'),
-					route: 'marketplace/selling',
-					condition: () => this.hub_registered
-				},
-				{
-					label: __('Buying'),
-					route: 'marketplace/buying',
-					condition: () => this.hub_registered
-				},
-			],
-			categories: []
-		}
-	},
-	created() {
-		this.get_categories()
-			.then(categories => {
-				this.categories = categories.map(c => {
-					return {
-						label: __(c.name),
-						route: 'marketplace/category/' + c.name
-					}
-				});
-				this.categories.unshift({
-					label: __('All'),
-					route: 'marketplace/home'
-				});
-				this.$nextTick(() => {
-					this.update_sidebar_state();
-				});
-			});
-
-		erpnext.hub.on('seller-registered', () => {
-			this.hub_registered = true;
-		})
-	},
-	mounted() {
-		this.update_sidebar_state();
-		frappe.route.on('change', () => this.update_sidebar_state());
-	},
-	methods: {
-		get_categories() {
-			return hub.call('get_categories');
-		},
-		update_sidebar_state() {
-			const container = $(this.$refs['sidebar-container']);
-			const route = frappe.get_route();
-			const route_str = route.join('/');
-			const part_route_str = route.slice(0, 2).join('/');
-			const $sidebar_item = container.find(`[data-route="${route_str}"], [data-route="${part_route_str}"]`);
-
-			const $siblings = container.find('[data-route]');
-			$siblings.removeClass('active').addClass('text-muted');
-			$sidebar_item.addClass('active').removeClass('text-muted');
-		},
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/components/CommentInput.vue b/erpnext/public/js/hub/components/CommentInput.vue
deleted file mode 100644
index 31562c7..0000000
--- a/erpnext/public/js/hub/components/CommentInput.vue
+++ /dev/null
@@ -1,39 +0,0 @@
-<template>
-	<div>
-		<div ref="comment-input"></div>
-		<div class="level">
-			<div class="level-left">
-				<span class="text-muted">{{ __('Ctrl + Enter to submit') }}</span>
-			</div>
-			<div class="level-right">
-				<button class="btn btn-primary btn-xs" @click="submit_input">{{ __('Submit') }}</button>
-			</div>
-		</div>
-	</div>
-</template>
-<script>
-export default {
-	mounted() {
-		this.make_input();
-	},
-	methods: {
-		make_input() {
-			this.message_input = frappe.ui.form.make_control({
-				parent: this.$refs['comment-input'],
-				on_submit: (message) => {
-					this.message_input.reset();
-					this.$emit('change', message);
-				},
-				only_input: true,
-				no_wrapper: true
-			});
-		},
-		submit_input() {
-			if (!this.message_input) return;
-			const value = this.message_input.get_value();
-			if (!value) return;
-			this.message_input.submit();
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/components/DetailHeaderItem.vue b/erpnext/public/js/hub/components/DetailHeaderItem.vue
deleted file mode 100644
index a6c5f06..0000000
--- a/erpnext/public/js/hub/components/DetailHeaderItem.vue
+++ /dev/null
@@ -1,26 +0,0 @@
-<template>
-	<p class="text-muted" v-if="!Array.isArray(this.header_items)" v-html="header_items"></p>
-	<p class="text-muted" v-else>
-		<span v-for="(header_item , index) in header_items" :key="index">
-			<span v-if="index" v-html="spacer"></span>
-			<span v-if="typeof(header_item) == 'string'" v-html="header_item"></span>
-			<a v-else-if="typeof(header_item) == 'object'" @click="header_item.on_click(header_item.value)" v-html="header_item.value"></a>
-		</span>
-	</p>
-</template>
-
-<script>
-
-const spacer = '<span aria-hidden="true"> · </span>';
-
-export default {
-	name: 'detail-header-item',
-	props: ['value'],
-	data() {
-		return {
-			header_items: this.value,
-			spacer: spacer
-		}
-	},
-}
-</script>
diff --git a/erpnext/public/js/hub/components/DetailView.vue b/erpnext/public/js/hub/components/DetailView.vue
deleted file mode 100644
index 942c1eb..0000000
--- a/erpnext/public/js/hub/components/DetailView.vue
+++ /dev/null
@@ -1,86 +0,0 @@
-<template>
-	<div class="hub-item-container">
-		<div class="row visible-xs">
-			<div class="col-xs-12 margin-bottom">
-				<button class="btn btn-xs btn-default" data-route="marketplace/home">{{ back_to_home_text }}</button>
-			</div>
-		</div>
-
-		<div v-if="show_skeleton" class="row margin-bottom">
-			<div class="col-md-3">
-				<div class="hub-item-skeleton-image"></div>
-			</div>
-			<div class="col-md-6">
-				<h2 class="hub-skeleton" style="width: 75%;">Name</h2>
-				<div class="text-muted">
-					<p class="hub-skeleton" style="width: 35%;">Details</p>
-					<p class="hub-skeleton" style="width: 50%;">Ratings</p>
-				</div>
-				<hr>
-				<div class="hub-item-description">
-					<p class="hub-skeleton">Desc</p>
-					<p class="hub-skeleton" style="width: 85%;">Desc</p>
-				</div>
-			</div>
-		</div>
-
-		<div v-else>
-			<div class="row margin-bottom">
-				<div class="col-md-3">
-					<div class="hub-item-image">
-						<base-image :src="image" :alt="title" />
-					</div>
-				</div>
-				<div class="col-md-8" style='padding-left: 30px;'>
-					<h2>{{ title }}</h2>
-					<div class="text-muted">
-						<slot name="detail-header-item"></slot>
-					</div>
-				</div>
-
-				<div v-if="menu_items && menu_items.length" class="col-md-1">
-					<div class="dropdown pull-right hub-item-dropdown">
-						<a class="dropdown-toggle btn btn-xs btn-default" data-toggle="dropdown">
-							<span class="caret"></span>
-						</a>
-						<ul class="dropdown-menu dropdown-right" role="menu">
-							<li v-for="menu_item in menu_items"
-								v-if="menu_item.condition"
-								:key="menu_item.label"
-							>
-								<a @click="menu_item.action">{{ menu_item.label }}</a>
-							</li>
-						</ul>
-					</div>
-				</div>
-			</div>
-			<div v-for="section in sections" class="row hub-item-description margin-bottom"
-				:key="section.title"
-			>
-				<h6 class="col-md-12 margin-top">
-					<b class="text-muted">{{ section.title }}</b>
-				</h6>
-				<p class="col-md-12" v-html="section.content">
-				</p>
-			</div>
-		</div>
-
-	</div>
-</template>
-
-<script>
-
-export default {
-	name: 'detail-view',
-	props: ['title', 'image', 'sections', 'show_skeleton', 'menu_items'],
-	data() {
-		return {
-			back_to_home_text: __('Back to Home')
-		}
-	},
-	computed: {}
-}
-</script>
-
-<style lang="less" scoped>
-</style>
diff --git a/erpnext/public/js/hub/components/EmptyState.vue b/erpnext/public/js/hub/components/EmptyState.vue
deleted file mode 100644
index e3a33a0..0000000
--- a/erpnext/public/js/hub/components/EmptyState.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<template>
-	<div class="empty-state flex flex-column"
-		:class="{ 'bordered': bordered, 'align-center': centered, 'justify-center': centered }"
-		:style="{ height: height + 'px' }"
-	>
-		<p class="text-muted" v-html="message" ></p>
-		<p v-if="action">
-			<button class="btn btn-default btn-xs"
-				@click="action.on_click"
-			>
-				{{ action.label }}
-			</button>
-		</p>
-	</div>
-</template>
-
-<script>
-
-export default {
-	name: 'empty-state',
-	props: {
-		message: String,
-		bordered: Boolean,
-		height: Number,
-		action: Object,
-		centered: {
-			type: Boolean,
-			default: true
-		}
-	}
-}
-</script>
-
-<style lang="less">
-	@import "../../../../../../frappe/frappe/public/less/variables.less";
-
-	.empty-state {
-		height: 500px;
-	}
-
-	.empty-state.bordered {
-		border-radius: 4px;
-		border: 1px solid @border-color;
-		border-style: dashed;
-
-		// bad, due to item card column layout, that is inner 15px margin
-		margin: 0 15px;
-	}
-
-</style>
diff --git a/erpnext/public/js/hub/components/Image.vue b/erpnext/public/js/hub/components/Image.vue
deleted file mode 100644
index 9acf421..0000000
--- a/erpnext/public/js/hub/components/Image.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-<template>
-	<div class="hub-image">
-		<img :src="src" :alt="alt" v-show="!is_loading && !is_broken"/>
-		<div class="hub-image-loading" v-if="is_loading">
-			<span class="octicon octicon-cloud-download"></span>
-		</div>
-		<div class="hub-image-broken" v-if="is_broken">
-			<span class="octicon octicon-file-media"></span>
-		</div>
-	</div>
-</template>
-<script>
-export default {
-	name: 'Image',
-	props: ['src', 'alt'],
-	data() {
-		return {
-			is_loading: true,
-			is_broken: false
-		}
-	},
-	created() {
-		this.handle_image();
-	},
-	methods: {
-		handle_image() {
-			let img = new Image();
-			img.src = this.src;
-
-			img.onload = () => {
-				this.is_loading = false;
-			};
-			img.onerror = () => {
-				this.is_loading = false;
-				this.is_broken = true;
-			};
-		}
-	}
-};
-</script>
diff --git a/erpnext/public/js/hub/components/ItemCard.vue b/erpnext/public/js/hub/components/ItemCard.vue
deleted file mode 100644
index 675ad86..0000000
--- a/erpnext/public/js/hub/components/ItemCard.vue
+++ /dev/null
@@ -1,142 +0,0 @@
-<template>
-	<div v-if="seen" class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
-		<div class="hub-card"
-			@click="on_click(item_id)"
-		>
-			<div class="hub-card-header flex justify-between">
-				<div class="ellipsis" :style="{ width: '85%' }">
-					<div class="hub-card-title ellipsis bold">{{ title }}</div>
-					<div class="hub-card-subtitle ellipsis text-muted" v-html='subtitle'></div>
-				</div>
-				<i v-if="allow_clear"
-					class="octicon octicon-x text-extra-muted"
-					@click.stop="$emit('remove-item', item_id)"
-				>
-				</i>
-			</div>
-			<div class="hub-card-body">
-				<base-image class="hub-card-image" :src="item.image" :alt="title" />
-				<div class="hub-card-overlay">
-					<div v-if="is_local" class="hub-card-overlay-body">
-						<div class="hub-card-overlay-button">
-							<button class="btn btn-default zoom-view">
-								<i class="octicon octicon-pencil text-muted"></i>
-							</button>
-						</div>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-
-export default {
-	name: 'item-card',
-	props: ['item', 'item_id_fieldname', 'is_local', 'on_click', 'allow_clear', 'seen'],
-	computed: {
-		title() {
-			const item_name = this.item.item_name || this.item.name;
-			return strip_html(item_name);
-		},
-		subtitle() {
-			const dot_spacer = '<span aria-hidden="true"> · </span>';
-			if(this.is_local){
-				return comment_when(this.item.creation);
-			} else {
-				let subtitle_items = [comment_when(this.item.creation)];
-				const rating = this.item.average_rating;
-
-				if (rating > 0) {
-					subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
-				}
-
-				subtitle_items.push(this.item.company);
-
-				return subtitle_items.join(dot_spacer);
-			}
-		},
-		item_id() {
-			return this.item[this.item_id_fieldname];
-		}
-	}
-}
-</script>
-
-<style lang="less" scoped>
-	@import "../../../../../../frappe/frappe/public/less/variables.less";
-
-	.hub-card {
-		margin-bottom: 25px;
-		position: relative;
-		border: 1px solid @border-color;
-		border-radius: 4px;
-		overflow: hidden;
-		cursor: pointer;
-
-		&:hover .hub-card-overlay {
-			display: block;
-		}
-
-		.octicon-x {
-			display: block;
-			font-size: 20px;
-			margin-left: 10px;
-			cursor: pointer;
-		}
-	}
-
-	.hub-card.closable {
-		.octicon-x {
-			display: block;
-		}
-	}
-
-	.hub-card.is-local {
-		&.active {
-			.hub-card-header {
-				background-color: #f4ffe5;
-			}
-		}
-	}
-
-	.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 {
-		width: 100%;
-		height: 100%;
-		object-fit: contain;
-	}
-
-</style>
diff --git a/erpnext/public/js/hub/components/ItemCardsContainer.vue b/erpnext/public/js/hub/components/ItemCardsContainer.vue
deleted file mode 100644
index 0a20bcd..0000000
--- a/erpnext/public/js/hub/components/ItemCardsContainer.vue
+++ /dev/null
@@ -1,62 +0,0 @@
-<template>
-	<div class="item-cards-container">
-		<empty-state
-			v-if="items.length === 0"
-			:message="empty_state_message"
-			:action="empty_state_action"
-			:bordered="true"
-			:height="empty_state_height"
-		/>
-		<item-card
-			v-for="item in items"
-			:key="container_name + '_' +item[item_id_fieldname]"
-			:item="item"
-			:item_id_fieldname="item_id_fieldname"
-			:is_local="is_local"
-			:on_click="on_click"
-			:allow_clear="editable"
-			:seen="item.hasOwnProperty('seen') ? item.seen : true"
-			@remove-item="$emit('remove-item', item[item_id_fieldname])"
-		>
-		</item-card>
-	</div>
-</template>
-
-<script>
-import ItemCard from './ItemCard.vue';
-import EmptyState from './EmptyState.vue';
-
-export default {
-	name: 'item-cards-container',
-	props: {
-		container_name: String,
-		items: Array,
-		item_id_fieldname: String,
-		is_local: Boolean,
-		on_click: Function,
-		editable: Boolean,
-
-		empty_state_message: String,
-		empty_state_action: Object,
-		empty_state_height: Number,
-		empty_state_bordered: Boolean
-	},
-	components: {
-		ItemCard,
-		EmptyState
-	},
-	watch: {
-		items() {
-			// TODO: handling doesn't work
-			frappe.dom.handle_broken_images($(this.$el));
-		}
-	}
-}
-</script>
-
-<style scoped>
-	.item-cards-container {
-		margin: 0 -15px;
-		overflow: overlay;
-	}
-</style>
diff --git a/erpnext/public/js/hub/components/ItemListCard.vue b/erpnext/public/js/hub/components/ItemListCard.vue
deleted file mode 100644
index 7f6fb77..0000000
--- a/erpnext/public/js/hub/components/ItemListCard.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-<template>
-	<div class="hub-list-item" :data-route="item.route">
-		<div class="hub-list-left">
-			<base-image class="hub-list-image" :src="item.image" />
-			<div class="hub-list-body ellipsis">
-				<div class="hub-list-title">{{item.item_name}}</div>
-				<div class="hub-list-subtitle ellipsis">
-					<slot name="subtitle"></slot>
-				</div>
-			</div>
-		</div>
-		<div class="hub-list-right" v-if="message">
-			<span class="text-muted" v-html="frappe.datetime.comment_when(message.creation, true)" />
-		</div>
-	</div>
-</template>
-<script>
-export default {
-	props: ['item', 'message']
-}
-</script>
diff --git a/erpnext/public/js/hub/components/NotificationMessage.vue b/erpnext/public/js/hub/components/NotificationMessage.vue
deleted file mode 100644
index c266726..0000000
--- a/erpnext/public/js/hub/components/NotificationMessage.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-<template>
-	<div v-if="message" class="subpage-message">
-        <p class="text-muted flex">
-            <span v-html="message"></span>
-            <i class="octicon octicon-x text-extra-muted"
-                @click="$emit('remove-message')"
-            >
-            </i>
-        </p>
-    </div>
-</template>
-
-<script>
-
-export default {
-	name: 'notification-message',
-	props: {
-		message: String,
-    }
-}
-</script>
-
-<style lang="less" scoped>
-    .subpage-message {
-		p {
-			padding: 10px 15px;
-			margin-top: 0px;
-			margin-bottom: 15px;
-			background-color: #f9fbf7;
-			border-radius: 4px;
-			justify-content: space-between;
-		}
-
-		.octicon-x {
-			cursor: pointer;
-		}
-	}
-</style>
diff --git a/erpnext/public/js/hub/components/Rating.vue b/erpnext/public/js/hub/components/Rating.vue
deleted file mode 100644
index 33290b8..0000000
--- a/erpnext/public/js/hub/components/Rating.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-<template>
-    <span>
-        <i v-for="index in max_rating"
-            :key="index"
-            class="fa fa-fw star-icon"
-            :class="{'fa-star': index <= rating, 'fa-star-o': index > rating}"
-        >
-        </i>
-    </span>
-</template>
-
-<script>
-export default {
-    props: ['rating', 'max_rating']
-}
-</script>
diff --git a/erpnext/public/js/hub/components/ReviewArea.vue b/erpnext/public/js/hub/components/ReviewArea.vue
deleted file mode 100644
index aa83bb0..0000000
--- a/erpnext/public/js/hub/components/ReviewArea.vue
+++ /dev/null
@@ -1,140 +0,0 @@
-<template>
-	<div>
-		<div class="timeline-head">
-			<div class="comment-input-wrapper">
-				<div class="comment-input-header">
-					<span class="text-muted">{{ __('Add your review') }}</span>
-					<div class="btn btn-default btn-xs pull-right"
-						@click="on_submit_review"
-						:disabled="!(user_review.rating && user_review.subject)"
-					>
-						{{ __('Submit Review') }}
-					</div>
-				</div>
-				<div class="comment-input-container">
-					<div class="rating-area text-muted">
-						<span>{{ __('Your rating:') }}</span>
-						<div
-							v-for="i in [1, 2, 3, 4, 5]"
-							:key="i"
-							:class="['fa fa-fw', user_review.rating < i ? 'fa-star-o' : 'fa-star']"
-							:data-index="i"
-							@click="set_rating(i)"
-						>
-						</div>
-					</div>
-					<div class="comment-input-body margin-top" v-show="user_review.rating">
-						<input
-							type="text"
-							placeholder="Subject"
-							class="form-control margin-bottom"
-							style="border-color: #ebeff2"
-							v-model="user_review.subject"
-						>
-						<div ref="review-content"></div>
-						<div>
-							<span class="text-muted text-small">{{ __('Ctrl+Enter to submit') }}</span>
-						</div>
-					</div>
-				</div>
-			</div>
-		</div>
-		<div class="timeline-items">
-			<review-timeline-item v-for="review in reviews"
-				:key="review.user"
-				:username="review.username"
-				:avatar="review.user_image"
-				:comment_when="when(review.modified)"
-				:rating="review.rating"
-				:subject="review.subject"
-				:content="review.content"
-			>
-			</review-timeline-item>
-		</div>
-	</div>
-</template>
-<script>
-import ReviewTimelineItem from '../components/ReviewTimelineItem.vue';
-
-export default {
-	props: ['hub_item_name'],
-	data() {
-		return {
-			user_review: {
-				rating: 0,
-				subject: '',
-				content: ''
-			},
-			reviews: []
-		}
-	},
-	components: {
-		ReviewTimelineItem
-	},
-	created() {
-		this.get_item_reviews();
-	},
-	mounted() {
-		this.make_input();
-	},
-	methods: {
-		set_rating(i) {
-			this.user_review.rating = i;
-		},
-
-		when(datetime) {
-			return comment_when(datetime);
-		},
-
-		get_item_reviews() {
-			hub.call('get_item_reviews', { hub_item_name: this.hub_item_name })
-				.then(reviews => {
-					this.reviews = reviews;
-				})
-				.catch(() => {});
-		},
-
-		make_input() {
-			this.review_content = frappe.ui.form.make_control({
-				parent: this.$refs['review-content'],
-				on_submit: this.on_submit_review.bind(this),
-				no_wrapper: true,
-				only_input: true,
-				render_input: true,
-				df: {
-					fieldtype: 'Comment',
-					fieldname: 'comment'
-				}
-			});
-		},
-
-		on_submit_review() {
-			const review = Object.assign({}, this.user_review, {
-				content: this.review_content.get_value()
-			});
-
-			if (!hub.is_seller_registered()) {
-				frappe.throw(__('You need to login as a Marketplace User before you can add any reviews.'));
-			}
-
-			hub.call('add_item_review', {
-				hub_item_name: this.hub_item_name,
-				review: JSON.stringify(review)
-			})
-			.then(this.push_review.bind(this));
-
-			this.reset_user_review();
-		},
-
-		reset_user_review() {
-			this.user_review.rating = 0;
-			this.user_review.subject = '';
-			this.review_content.set_value('');
-		},
-
-		push_review(review){
-			this.reviews.unshift(review);
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/components/ReviewTimelineItem.vue b/erpnext/public/js/hub/components/ReviewTimelineItem.vue
deleted file mode 100644
index d0e83f3..0000000
--- a/erpnext/public/js/hub/components/ReviewTimelineItem.vue
+++ /dev/null
@@ -1,53 +0,0 @@
-<template>
-    <div class="media timeline-item user-content" data-doctype="${''}" data-name="${''}">
-		<span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px">
-			<!-- ${image_html} -->
-		</span>
-		<div class="pull-left media-body">
-			<div class="media-content-wrapper">
-				<div class="action-btns">
-                    <!-- ${edit_html} -->
-                </div>
-
-				<div class="comment-header clearfix">
-					<span class="pull-left avatar avatar-small visible-xs">
-						<!-- ${image_html} -->
-					</span>
-
-					<div class="asset-details">
-						<span class="author-wrap">
-							<i class="octicon octicon-quote hidden-xs fa-fw"></i>
-							<span>
-                                {{ username }}
-                            </span>
-						</span>
-						<a class="text-muted">
-							<span class="text-muted hidden-xs">&ndash;</span>
-							<span class="hidden-xs" v-html="comment_when"></span>
-						</a>
-					</div>
-				</div>
-				<div class="reply timeline-content-show">
-					<div class="timeline-item-content">
-						<p class="text-muted">
-							<rating :rating="rating" :max_rating="5"></rating>
-						</p>
-						<h6 class="bold">{{ subject }}</h6>
-						<p class="text-muted" v-html="content"></p>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-import Rating from '../components/Rating.vue';
-
-export default {
-    props: ['username', 'comment_when', 'avatar', 'rating', 'subject', 'content'],
-    components: {
-        Rating
-    }
-}
-</script>
diff --git a/erpnext/public/js/hub/components/SearchInput.vue b/erpnext/public/js/hub/components/SearchInput.vue
deleted file mode 100644
index 4b1ce6e..0000000
--- a/erpnext/public/js/hub/components/SearchInput.vue
+++ /dev/null
@@ -1,26 +0,0 @@
-<template>
-  <div class="hub-search-container">
-	<input
-		type="text"
-		class="form-control"
-		:placeholder="placeholder"
-		:value="value"
-		@keydown.enter="on_input">
-  </div>
-</template>
-
-<script>
-export default {
-	props: {
-		placeholder: String,
-		value: String,
-		on_search: Function
-	},
-	methods: {
-		on_input(event) {
-			this.$emit('input', event.target.value);
-			this.on_search();
-		}
-	}
-};
-</script>
diff --git a/erpnext/public/js/hub/components/SectionHeader.vue b/erpnext/public/js/hub/components/SectionHeader.vue
deleted file mode 100644
index 05a2f83..0000000
--- a/erpnext/public/js/hub/components/SectionHeader.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-<template>
-    <div class="hub-items-header level"><slot></slot></div>
-</template>
diff --git a/erpnext/public/js/hub/components/TimelineItem.vue b/erpnext/public/js/hub/components/TimelineItem.vue
deleted file mode 100644
index d13c842..0000000
--- a/erpnext/public/js/hub/components/TimelineItem.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Saving this for later */
-<template>
-	<div class="media timeline-item  notification-content">
-		<div class="small">
-			<i class="octicon octicon-bookmark fa-fw"></i>
-			<span title="Administrator"><b>4 weeks ago</b> Published 1 item to Marketplace</span>
-		</div>
-	</div>
-</template>
diff --git a/erpnext/public/js/hub/components/edit_details_dialog.js b/erpnext/public/js/hub/components/edit_details_dialog.js
deleted file mode 100644
index 97c5f83..0000000
--- a/erpnext/public/js/hub/components/edit_details_dialog.js
+++ /dev/null
@@ -1,41 +0,0 @@
-function edit_details_dialog(params) {
-	let dialog = new frappe.ui.Dialog({
-		title: __('Update Details'),
-		fields: [
-			{
-				label: 'Item Name',
-				fieldname: 'item_name',
-				fieldtype: 'Data',
-				default: params.defaults.item_name,
-				reqd: 1
-			},
-			{
-				label: 'Hub Category',
-				fieldname: 'hub_category',
-				fieldtype: 'Autocomplete',
-				default: params.defaults.hub_category,
-				options: [],
-				reqd: 1
-			},
-			{
-				label: 'Description',
-				fieldname: 'description',
-				fieldtype: 'Text',
-				default: params.defaults.description,
-				options: [],
-				reqd: 1
-			}
-		],
-		primary_action_label: params.primary_action.label || __('Update Details'),
-		primary_action: params.primary_action.fn
-	});
-
-	hub.call('get_categories').then(categories => {
-		categories = categories.map(d => d.name);
-		dialog.fields_dict.hub_category.set_data(categories);
-	});
-
-	return dialog;
-}
-
-export { edit_details_dialog };
diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js
deleted file mode 100644
index 08de5b3..0000000
--- a/erpnext/public/js/hub/components/item_publish_dialog.js
+++ /dev/null
@@ -1,39 +0,0 @@
-function ItemPublishDialog(primary_action, secondary_action) {
-	let dialog = new frappe.ui.Dialog({
-		title: __('Edit Publishing Details'),
-		fields: [
-			{
-				label: __('Item Code'),
-				fieldname: 'item_code',
-				fieldtype: 'Data',
-				read_only: 1
-			},
-			{
-				label: __('Hub Category'),
-				fieldname: 'hub_category',
-				fieldtype: 'Autocomplete',
-				options: [],
-				reqd: 1
-			},
-			{
-				label: __('Images'),
-				fieldname: 'image_list',
-				fieldtype: 'MultiSelect',
-				options: [],
-				reqd: 1
-			}
-		],
-		primary_action_label: primary_action.label || __('Set Details'),
-		primary_action: primary_action.fn,
-		secondary_action: secondary_action.fn
-	});
-
-	hub.call('get_categories').then(categories => {
-		categories = categories.map(d => d.name);
-		dialog.fields_dict.hub_category.set_data(categories);
-	});
-
-	return dialog;
-}
-
-export { ItemPublishDialog };
diff --git a/erpnext/public/js/hub/components/profile_dialog.js b/erpnext/public/js/hub/components/profile_dialog.js
deleted file mode 100644
index 8e3abc3..0000000
--- a/erpnext/public/js/hub/components/profile_dialog.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const ProfileDialog = (title = __('Edit Profile'), action={}) => {
-	const fields = [
-		{
-			fieldtype: 'Link',
-			fieldname: 'company',
-			label: __('Company'),
-			options: 'Company'
-		},
-		{
-			fieldtype: 'Read Only',
-			fieldname: 'email',
-			label: __('Email')
-		},
-		{
-			label: __('About your company'),
-			fieldname: 'company_description',
-			fieldtype: 'Text'
-		}
-	];
-
-	let dialog = new frappe.ui.Dialog({
-		title: title,
-		fields: fields,
-		primary_action_label: action.label || __('Update'),
-		primary_action: () => {
-			const form_values = dialog.get_values();
-			let values_filled = true;
-
-			// TODO: Say "we notice that the company description and logo isn't set. Please set them in master."
-			// Only then allow to register
-
-			const mandatory_fields = ['company', 'company_description'];
-			mandatory_fields.forEach(field => {
-				const value = form_values[field];
-				if (!value) {
-					dialog.set_df_property(field, 'reqd', 1);
-					values_filled = false;
-				}
-			});
-			if (!values_filled) return;
-
-			action.on_submit(form_values);
-		}
-	});
-
-	// Post create
-	const default_company = frappe.defaults.get_default('company');
-	dialog.set_value('company', default_company);
-	dialog.set_value('email', frappe.session.user);
-
-	return dialog;
-}
-
-export {
-	ProfileDialog
-}
diff --git a/erpnext/public/js/hub/components/reviews.js b/erpnext/public/js/hub/components/reviews.js
deleted file mode 100644
index e34d680..0000000
--- a/erpnext/public/js/hub/components/reviews.js
+++ /dev/null
@@ -1,80 +0,0 @@
-function get_review_html(review) {
-	let username = review.username || review.user || __("Anonymous");
-
-	let image_html = review.user_image
-		? `<div class="avatar-frame" style="background-image: url(${review.user_image})"></div>`
-		: `<div class="standard-image" style="background-color: #fafbfc">${frappe.get_abbr(username)}</div>`
-
-	let edit_html = review.own
-		? `<div class="pull-right hidden-xs close-btn-container">
-			<span class="small text-muted">
-				${'data.delete'}
-			</span>
-		</div>
-		<div class="pull-right edit-btn-container">
-			<span class="small text-muted">
-				${'data.edit'}
-			</span>
-		</div>`
-		: '';
-
-	let rating_html = get_rating_html(review.rating);
-
-	return get_timeline_item(review, image_html, edit_html, rating_html);
-}
-
-function get_timeline_item(data, image_html, edit_html, rating_html) {
-	return `<div class="media timeline-item user-content" data-doctype="${''}" data-name="${''}">
-		<span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px">
-			${image_html}
-		</span>
-		<div class="pull-left media-body">
-			<div class="media-content-wrapper">
-				<div class="action-btns">${edit_html}</div>
-
-				<div class="comment-header clearfix">
-					<span class="pull-left avatar avatar-small visible-xs">
-						${image_html}
-					</span>
-
-					<div class="asset-details">
-						<span class="author-wrap">
-							<i class="octicon octicon-quote hidden-xs fa-fw"></i>
-							<span>${data.username}</span>
-						</span>
-						<a class="text-muted">
-							<span class="text-muted hidden-xs">&ndash;</span>
-							<span class="hidden-xs">${comment_when(data.modified)}</span>
-						</a>
-					</div>
-				</div>
-				<div class="reply timeline-content-show">
-					<div class="timeline-item-content">
-						<p class="text-muted">
-							${rating_html}
-						</p>
-						<h6 class="bold">${data.subject}</h6>
-						<p class="text-muted">
-							${data.content}
-						</p>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>`;
-}
-
-function get_rating_html(rating) {
-	let rating_html = ``;
-	for (var i = 0; i < 5; i++) {
-		let star_class = 'fa-star';
-		if (i >= rating) star_class = 'fa-star-o';
-		rating_html += `<i class='fa fa-fw ${star_class} star-icon' data-index=${i}></i>`;
-	}
-	return rating_html;
-}
-
-export {
-	get_review_html,
-    get_rating_html
-}
diff --git a/erpnext/public/js/hub/hub_call.js b/erpnext/public/js/hub/hub_call.js
deleted file mode 100644
index 5545a49..0000000
--- a/erpnext/public/js/hub/hub_call.js
+++ /dev/null
@@ -1,68 +0,0 @@
-frappe.provide('hub');
-frappe.provide('erpnext.hub');
-
-erpnext.hub.cache = {};
-hub.call = function call_hub_method(method, args={}, clear_cache_on_event) { // eslint-disable-line
-	return new Promise((resolve, reject) => {
-
-		// cache
-		const key = method + JSON.stringify(args);
-		if (erpnext.hub.cache[key]) {
-			resolve(erpnext.hub.cache[key]);
-		}
-
-		// cache invalidation
-		const clear_cache = () => delete erpnext.hub.cache[key];
-
-		if (!clear_cache_on_event) {
-			invalidate_after_5_mins(clear_cache);
-		} else {
-			erpnext.hub.on(clear_cache_on_event, () => {
-				clear_cache(key);
-			});
-		}
-
-		let res;
-		if (hub.is_server) {
-			res = frappe.call({
-				method: 'hub.hub.api.' + method,
-				args
-			});
-		} else {
-			res = frappe.call({
-				method: 'erpnext.hub_node.api.call_hub_method',
-				args: {
-					method,
-					params: args
-				}
-			});
-		}
-
-		res.then(r => {
-			if (r.message) {
-				const response = r.message;
-				if (response.error) {
-					frappe.throw({
-						title: __('Marketplace Error'),
-						message: response.error
-					});
-				}
-
-				erpnext.hub.cache[key] = response;
-				erpnext.hub.trigger(`response:${key}`, { response });
-				resolve(response);
-			}
-			reject(r);
-
-		}).fail(reject);
-	});
-};
-
-function invalidate_after_5_mins(clear_cache) {
-	// cache invalidation after 5 minutes
-	const timeout = 5 * 60 * 1000;
-
-	setTimeout(() => {
-		clear_cache();
-	}, timeout);
-}
diff --git a/erpnext/public/js/hub/hub_factory.js b/erpnext/public/js/hub/hub_factory.js
deleted file mode 100644
index 9c67c1c..0000000
--- a/erpnext/public/js/hub/hub_factory.js
+++ /dev/null
@@ -1,34 +0,0 @@
-frappe.provide('erpnext.hub');
-
-frappe.views.MarketplaceFactory = class MarketplaceFactory extends frappe.views.Factory {
-	show() {
-		is_marketplace_disabled()
-			.then(disabled => {
-				if (disabled) {
-					frappe.show_not_found('Marketplace');
-					return;
-				}
-
-				if (frappe.pages.marketplace) {
-					frappe.container.change_to('marketplace');
-					erpnext.hub.marketplace.refresh();
-				} else {
-					this.make('marketplace');
-				}
-			});
-	}
-
-	make(page_name) {
-		frappe.require('marketplace.bundle.js', () => {
-			erpnext.hub.marketplace = new erpnext.hub.Marketplace({
-				parent: this.make_page(true, page_name)
-			});
-		});
-	}
-};
-
-function is_marketplace_disabled() {
-	return frappe.call({
-		method: "erpnext.hub_node.doctype.marketplace_settings.marketplace_settings.is_marketplace_enabled"
-	}).then(r => r.message)
-}
diff --git a/erpnext/public/js/hub/marketplace.bundle.js b/erpnext/public/js/hub/marketplace.bundle.js
deleted file mode 100644
index a1596e0..0000000
--- a/erpnext/public/js/hub/marketplace.bundle.js
+++ /dev/null
@@ -1,225 +0,0 @@
-import Vue from 'vue/dist/vue.js';
-import './vue-plugins';
-
-// components
-import PageContainer from './PageContainer.vue';
-import Sidebar from './Sidebar.vue';
-import { ProfileDialog } from './components/profile_dialog';
-
-// helpers
-import './hub_call';
-
-frappe.provide('hub');
-frappe.provide('erpnext.hub');
-frappe.provide('frappe.route');
-
-frappe.utils.make_event_emitter(frappe.route);
-frappe.utils.make_event_emitter(erpnext.hub);
-
-erpnext.hub.Marketplace = class Marketplace {
-	constructor({ parent }) {
-		this.$parent = $(parent);
-		this.page = parent.page;
-
-		this.update_hub_settings().then(() => {
-
-			this.setup_header();
-			this.make_sidebar();
-			this.make_body();
-			this.setup_events();
-			this.refresh();
-
-			if (!hub.is_server) {
-				if (!hub.is_seller_registered()) {
-					this.page.set_primary_action('Become a Seller', this.show_register_dialog.bind(this))
-				} else {
-					this.page.set_secondary_action('Add Users', this.show_add_user_dialog.bind(this));
-				}
-			}
-		});
-	}
-
-	setup_header() {
-		if (hub.is_server) return;
-		this.page.set_title(__('Marketplace'));
-	}
-
-	setup_events() {
-		this.$parent.on('click', '[data-route]', (e) => {
-			const $target = $(e.currentTarget);
-			const route = $target.data().route;
-			frappe.set_route(route);
-		});
-
-		// generic action handler
-		this.$parent.on('click', '[data-action]', e => {
-			const $target = $(e.currentTarget);
-			const action = $target.data().action;
-
-			if (action && this[action]) {
-				this[action].apply(this, $target);
-			}
-		})
-	}
-
-	make_sidebar() {
-		this.$sidebar = this.$parent.find('.layout-side-section').addClass('hidden-xs');
-
-		new Vue({
-			el: $('<div>').appendTo(this.$sidebar)[0],
-			render: h => h(Sidebar)
-		});
-	}
-
-	make_body() {
-		this.$body = this.$parent.find('.layout-main-section');
-		this.$page_container = $('<div class="hub-page-container">').appendTo(this.$body);
-
-		new Vue({
-			el: '.hub-page-container',
-			render: h => h(PageContainer)
-		});
-
-		if (!hub.is_server) {
-			erpnext.hub.on('seller-registered', () => {
-				this.page.clear_primary_action();
-			});
-		}
-	}
-
-	refresh() {
-
-	}
-
-	show_register_dialog() {
-		if(frappe.session.user === 'Administrator') {
-			frappe.msgprint(__('You need to be a user other than Administrator with System Manager and Item Manager roles to register on Marketplace.'));
-			return;
-		}
-
-		if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) {
-			frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to register on Marketplace.'));
-			return;
-		}
-
-		this.register_dialog = ProfileDialog(
-			__('Become a Seller'),
-			{
-				label: __('Register'),
-				on_submit: this.register_marketplace.bind(this)
-			}
-		);
-
-		this.register_dialog.show();
-	}
-
-	register_marketplace({company, company_description}) {
-		frappe.call({
-		    method: 'erpnext.hub_node.api.register_marketplace',
-		    args: {
-				company,
-				company_description
-			}
-		}).then((r) => {
-			if (r.message && r.message.ok) {
-				this.register_dialog.hide();
-
-				this.update_hub_settings()
-					.then(() => {
-						frappe.set_route('marketplace', 'publish');
-						erpnext.hub.trigger('seller-registered');
-					});
-			}
-		});
-	}
-
-	show_add_user_dialog() {
-		if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) {
-			frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to add users to Marketplace.'));
-			return;
-		}
-
-		this.get_unregistered_users()
-			.then(r => {
-				const user_list = r.message;
-
-				const d = new frappe.ui.Dialog({
-					title: __('Add Users to Marketplace'),
-					fields: [
-						{
-							label: __('Users'),
-							fieldname: 'users',
-							fieldtype: 'MultiSelect',
-							reqd: 1,
-							get_data() {
-								return user_list;
-							}
-						}
-					],
-					primary_action({ users }) {
-						const selected_users = users.split(',').map(d => d.trim()).filter(Boolean);
-
-						if (!selected_users.every(user => user_list.includes(user))) {
-							d.set_df_property('users', 'description', __('Some emails are invalid'));
-							return;
-						} else {
-							d.set_df_property('users', 'description', '');
-						}
-
-						frappe.call('erpnext.hub_node.api.register_users', {
-							user_list: selected_users
-						})
-						.then(r => {
-							d.hide();
-
-							if (r.message && r.message.length) {
-								frappe.show_alert(__('Added {0} users', [r.message.length]));
-							}
-						});
-					}
-				});
-
-				d.show();
-			});
-	}
-
-	get_unregistered_users() {
-		return frappe.call('erpnext.hub_node.api.get_unregistered_users')
-	}
-
-	update_hub_settings() {
-		return hub.get_settings().then(doc => {
-			hub.settings = doc;
-		});
-	}
-}
-
-Object.assign(hub, {
-	is_seller_registered() {
-		return hub.settings.registered;
-	},
-
-	is_user_registered() {
-		return this.is_seller_registered() && hub.settings.users
-			.filter(hub_user => hub_user.user === frappe.session.user)
-			.length === 1;
-	},
-
-	get_settings() {
-		if (frappe.session.user === 'Guest') {
-			return Promise.resolve({
-				registered: 0
-			});
-		}
-		return frappe.db.get_doc('Marketplace Settings');
-	}
-});
-
-/**
- * Returns true if list_a is subset of list_b
- * @param {Array} list_a
- * @param {Array} list_b
- */
-function is_subset(list_a, list_b) {
-	return list_a.every(item => list_b.includes(item));
-}
diff --git a/erpnext/public/js/hub/pages/Buying.vue b/erpnext/public/js/hub/pages/Buying.vue
deleted file mode 100644
index ebf593a..0000000
--- a/erpnext/public/js/hub/pages/Buying.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-<template>
-	<div>
-		<section-header>
-			<h4>{{ __('Buying') }}</h4>
-		</section-header>
-		<div class="row" v-if="items && items.length">
-			<div class="col-md-7 margin-bottom"
-				v-for="item of items"
-				:key="item.name"
-			>
-				<item-list-card
-					:item="item"
-					v-route="'marketplace/buying/' + item.name"
-				>
-					<div slot="subtitle">
-						<span>{{ get_sender(item.recent_message) }}: </span>
-						<span>{{ item.recent_message.message | striphtml }}</span>
-					</div>
-				</item-list-card>
-			</div>
-		</div>
-		<empty-state v-else :message="__('This page keeps track of items you want to buy from sellers.')" :centered="false" />
-	</div>
-</template>
-<script>
-import EmptyState from '../components/EmptyState.vue';
-import SectionHeader from '../components/SectionHeader.vue';
-import ItemListCard from '../components/ItemListCard.vue';
-
-export default {
-	components: {
-		SectionHeader,
-		ItemListCard,
-		EmptyState
-	},
-	data() {
-		return {
-			items: null
-		}
-	},
-	created() {
-		this.get_items_for_messages()
-			.then(items => {
-				this.items = items;
-			});
-	},
-	methods: {
-		get_items_for_messages() {
-			return hub.call('get_buying_items_for_messages', {}, 'action:send_message');
-		},
-		get_sender(message) {
-			return message.sender === frappe.session.user ? __('You') : (message.sender_name || message.sender);
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue
deleted file mode 100644
index 16d0601..0000000
--- a/erpnext/public/js/hub/pages/Category.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<search-input
-			:placeholder="search_placeholder"
-			:on_search="set_search_route"
-			v-model="search_value"
-		/>
-
-		<h5>{{ page_title }}</h5>
-
-		<item-cards-container
-			:container_name="page_title"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-			:empty_state_message="empty_state_message"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			category: frappe.get_route()[2],
-			items: [],
-			item_id_fieldname: 'name',
-
-			// Constants
-			empty_state_message: __('No items in this category yet.'),
-
-			search_value: '',
-
-			// Constants
-			search_placeholder: __('Search for anything ...'),
-
-		};
-	},
-	computed: {
-		page_title() {
-			return __(this.category);
-		}
-	},
-	created() {
-		this.search_value = '';
-		this.get_items();
-	},
-	methods: {
-		get_items() {
-			hub.call('get_items', {
-				filters: {
-					hub_category: this.category
-				}
-			})
-			.then((items) => {
-				this.items = items;
-			})
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		},
-
-		set_search_route() {
-			frappe.set_route('marketplace', 'search', this.category, this.search_value);
-		},
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/FeaturedItems.vue b/erpnext/public/js/hub/pages/FeaturedItems.vue
deleted file mode 100644
index 8380b2b..0000000
--- a/erpnext/public/js/hub/pages/FeaturedItems.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<h5>{{ page_title }}</h5>
-		<p v-if="items.length"
-			class="text-muted margin-bottom">
-			{{ __('You can Feature upto 8 items.') }}
-		</p>
-
-		<item-cards-container
-			:container_name="page_title"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-			:editable="true"
-			@remove-item="on_item_remove"
-			:empty_state_message="empty_state_message"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	name: 'featured-items-page',
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			items: [],
-			item_id_fieldname: 'name',
-
-			// Constants
-			page_title: __('Your Featured Items'),
-			empty_state_message: __('No featured items yet. Got to your {0} and feature up to eight items that you want to highlight to your customers.',
-				[`<a href="#marketplace/published-items">${__("Published Items")}</a>`])
-		};
-	},
-	created() {
-		this.get_items();
-	},
-	methods: {
-		get_items() {
-			hub.call(
-				'get_featured_items_of_seller', {},
-				'action:item_feature'
-			)
-			.then((items) => {
-				this.items = items;
-			})
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		},
-
-		on_item_remove(hub_item_name) {
-			const grace_period = 5000;
-			let reverted = false;
-			let alert;
-
-			const undo_remove = () => {
-				this.toggle_item(hub_item_name);;
-				reverted = true;
-				alert.hide();
-				return false;
-			}
-
-			const item_name = this.items.filter(item => item.hub_item_name === hub_item_name);
-
-			alert_message = __('{0} removed. {1}', [item_name,
-				`<a href="#" data-action="undo-remove"><b>${__('Undo')}</b></a>`]);
-			alert = frappe.show_alert(alert_message, grace_period / 1000,
-				{
-					'undo-remove': undo_remove.bind(this)
-				}
-			);
-
-			this.toggle_item(hub_item_name, false);
-
-			setTimeout(() => {
-				if(!reverted) {
-					this.remove_item_from_featured_items(hub_item_name);
-				}
-			}, grace_period);
-		},
-
-		remove_item_from_featured_items(hub_item_name) {
-			erpnext.hub.trigger('action:item_feature');
-			hub.call('remove_item_from_seller_featured_items', {
-				hub_item_name,
-				hub_user: frappe.session.user
-			})
-			.then(() => {
-				this.get_items();
-			})
-			.catch(e => {
-				console.log(e);
-			});
-		},
-
-		// By default show
-		toggle_item(hub_item_name, show=true) {
-			this.items = this.items.map(item => {
-				if(item.name === hub_item_name) {
-					item.seen = show;
-				}
-				return item;
-			});
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Home.vue b/erpnext/public/js/hub/pages/Home.vue
deleted file mode 100644
index 8fe8245..0000000
--- a/erpnext/public/js/hub/pages/Home.vue
+++ /dev/null
@@ -1,114 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<search-input
-			:placeholder="search_placeholder"
-			:on_search="set_search_route"
-			v-model="search_value"
-		/>
-
-		<div v-if="show_skeleton">
-			<section-header>
-				<h4 class="hub-skeleton">Explore Explore Explore</h4>
-			</section-header>
-			<div class="row">
-				<div class="col-md-3 col-sm-4 col-xs-6 hub-card-container" v-for="(f, $index) in [1, 2, 3, 4, 5, 6, 7]" :key="$index">
-					<div class="hub-skeleton" style="height: 262px; width: 100%; margin-bottom: 25px;"></div>
-				</div>
-			</div>
-		</div>
-
-		<div v-else v-for="section in sections" :key="section.title">
-
-			<section-header>
-				<h4>{{ section.title }}</h4>
-				<p v-if="section.expandable" :data-route="'marketplace/category/' + section.title">{{ 'See All' }}</p>
-			</section-header>
-
-			<item-cards-container
-				:container_name="section.title"
-				:items="section.items"
-				:item_id_fieldname="item_id_fieldname"
-				:on_click="go_to_item_details_page"
-			/>
-		</div>
-	</div>
-</template>
-
-<script>
-export default {
-	name: 'home-page',
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			item_id_fieldname: 'name',
-			search_value: '',
-
-			sections: [],
-			show_skeleton: true,
-
-			// Constants
-			search_placeholder: __('Search for anything ...'),
-		};
-	},
-	created() {
-		// refreshed
-		this.search_value = '';
-		this.get_items();
-	},
-	mounted() {
-		frappe.route.on('change', () => {
-			if (frappe.get_route_str() === 'marketplace/home') {
-				this.get_items();
-			}
-		})
-	},
-	methods: {
-		get_items() {
-			hub.call('get_data_for_homepage', frappe.defaults ? {
-				country: frappe.defaults.get_user_default('country')
-			} : null)
-			.then((data) => {
-				this.show_skeleton = false;
-
-				this.sections.push({
-					title: __('Explore'),
-					items: data.random_items
-				});
-				if (data.items_by_country.length) {
-					this.sections.push({
-						title: __('Near you'),
-						items: data.items_by_country
-					});
-				}
-
-				const category_items = data.category_items;
-
-				if (category_items) {
-					Object.keys(category_items).map(category => {
-						const items = category_items[category];
-
-						this.sections.push({
-							title: __(category),
-							expandable: true,
-							items
-						});
-					});
-				}
-			})
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		},
-
-		set_search_route() {
-			frappe.set_route('marketplace', 'search', 'All', this.search_value);
-		},
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
deleted file mode 100644
index 93002a7..0000000
--- a/erpnext/public/js/hub/pages/Item.vue
+++ /dev/null
@@ -1,356 +0,0 @@
-<template>
-	<div class="marketplace-page" :data-page-name="page_name" v-if="init || item">
-		<detail-view
-			:title="title"
-			:image="image"
-			:sections="sections"
-			:menu_items="menu_items"
-			:show_skeleton="init"
-		>
-			<detail-header-item slot="detail-header-item" :value="item_subtitle"></detail-header-item>
-			<detail-header-item slot="detail-header-item" :value="item_views_and_ratings"></detail-header-item>
-
-			<button
-				v-if="primary_action"
-				slot="detail-header-item"
-				class="btn btn-primary btn-sm margin-top"
-				@click="primary_action.action"
-			>{{ primary_action.label }}</button>
-		</detail-view>
-
-		<review-area v-if="!init" :hub_item_name="hub_item_name"></review-area>
-	</div>
-</template>
-
-<script>
-import ReviewArea from '../components/ReviewArea.vue';
-import { get_rating_html } from '../components/reviews';
-import { edit_details_dialog } from '../components/edit_details_dialog';
-
-export default {
-	name: 'item-page',
-	components: {
-		ReviewArea
-	},
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			hub_item_name: frappe.get_route()[2],
-
-			init: true,
-
-			item: null,
-			title: null,
-			image: null,
-			sections: []
-		};
-	},
-	computed: {
-		is_own_item() {
-			let is_own_item = false;
-			if (this.item) {
-				if (this.item.hub_seller === hub.settings.hub_seller_name) {
-					is_own_item = true;
-				}
-			}
-			return is_own_item;
-		},
-		menu_items() {
-			return [
-				{
-					label: __('Save Item'),
-					condition: hub.is_user_registered() && !this.is_own_item,
-					action: this.add_to_saved_items
-				},
-				{
-					label: __('Add to Featured Item'),
-					condition: hub.is_user_registered() && this.is_own_item,
-					action: this.add_to_featured_items
-				},
-				{
-					label: __('Report this Item'),
-					condition: !this.is_own_item,
-					action: this.report_item
-				},
-				{
-					label: __('Edit Details'),
-					condition: hub.is_user_registered() && this.is_own_item,
-					action: this.edit_details
-				},
-				{
-					label: __('Unpublish Item'),
-					condition: hub.is_user_registered() && this.is_own_item,
-					action: this.unpublish_item
-				}
-			];
-		},
-
-		item_subtitle() {
-			if (!this.item) {
-				return '';
-			}
-
-			const dot_spacer = '<span aria-hidden="true"> · </span>';
-			let subtitle_items = [comment_when(this.item.creation)];
-			const rating = this.item.average_rating;
-
-			if (rating > 0) {
-				subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`);
-			}
-
-			subtitle_items.push({
-				value: this.item.company,
-				on_click: this.go_to_seller_profile_page
-			});
-
-			return subtitle_items;
-		},
-
-		item_views_and_ratings() {
-			if (!this.item) {
-				return '';
-			}
-
-			let stats = __('No views yet');
-			if (this.item.view_count) {
-				const views_message = __('{0} Views', [this.item.view_count]);
-
-				const rating_html = get_rating_html(this.item.average_rating);
-				const rating_count =
-					this.item.no_of_ratings > 0
-						? __('{0} reviews', [this.item.no_of_ratings])
-						: __('No reviews yet');
-
-				stats = [views_message, rating_html, rating_count];
-			}
-
-			return stats;
-		},
-
-		primary_action() {
-			if (hub.is_user_registered()) {
-				return {
-					label: __('Contact Seller'),
-					action: this.contact_seller.bind(this)
-				};
-			} else {
-				return undefined;
-			}
-		}
-	},
-	created() {
-		this.get_item_details();
-	},
-	mounted() {
-		// To record a single view per session, (later)
-		// erpnext.hub.item_view_cache = erpnext.hub.item_view_cache || [];
-		// if (erpnext.hub.item_view_cache.includes(this.hub_item_name)) {
-		// 	return;
-		// }
-
-		this.item_received.then(() => {
-			setTimeout(() => {
-				hub.call('add_item_view', {
-					hub_item_name: this.hub_item_name
-				});
-				// .then(() => {
-				// 	erpnext.hub.item_view_cache.push(this.hub_item_name);
-				// });
-			}, 5000);
-		});
-	},
-	methods: {
-		get_item_details() {
-			this.item_received = hub
-				.call('get_item_details', { hub_item_name: this.hub_item_name })
-				.then(item => {
-					this.init = false;
-					this.item = item;
-
-					this.build_data();
-					this.make_dialogs();
-				});
-		},
-		go_to_seller_profile_page(seller_name) {
-			frappe.set_route(`marketplace/seller/${seller_name}`);
-		},
-		build_data() {
-			this.title = this.item.item_name || this.item.name;
-			this.image = this.item.image;
-
-			this.sections = [
-				{
-					title: __('Item Description'),
-					content: this.item.description
-						? __(this.item.description)
-						: __('No description')
-				},
-				{
-					title: __('Seller Information'),
-					content: this.item.seller_description
-						? __(this.item.seller_description)
-						: __('No description')
-				}
-			];
-		},
-
-		make_dialogs() {
-			this.make_contact_seller_dialog();
-			this.make_report_item_dialog();
-			this.make_editing_dialog();
-		},
-
-		add_to_saved_items() {
-			hub.call('add_item_to_user_saved_items', {
-					hub_item_name: this.hub_item_name,
-					hub_user: frappe.session.user
-				})
-				.then(() => {
-					const saved_items_link = `<b><a href="#marketplace/saved-items">${__('Saved')}</a></b>`;
-					frappe.show_alert(saved_items_link);
-					erpnext.hub.trigger('action:item_save');
-				})
-				.catch(e => {
-					console.error(e);
-				});
-		},
-
-		add_to_featured_items() {
-			hub.call('add_item_to_seller_featured_items', {
-					hub_item_name: this.hub_item_name,
-					hub_user: frappe.session.user
-				})
-				.then(() => {
-					const featured_items_link = `<b><a href="#marketplace/featured-items">${__('Added to Featured Items')}</a></b>`;
-					frappe.show_alert(featured_items_link);
-					erpnext.hub.trigger('action:item_feature');
-				})
-				.catch(e => {
-					console.error(e);
-				});
-		},
-
-		make_contact_seller_dialog() {
-			this.contact_seller_dialog = new frappe.ui.Dialog({
-				title: __('Send a message'),
-				fields: [
-					{
-						fieldname: 'to',
-						fieldtype: 'Read Only',
-						label: __('To'),
-						default: this.item.company
-					},
-					{
-						fieldtype: 'Text',
-						fieldname: 'message',
-						label: __('Message')
-					}
-				],
-				primary_action: ({ message }) => {
-					if (!message) return;
-
-					hub.call('send_message', {
-							hub_item: this.item.name,
-							message
-						})
-						.then(() => {
-							this.contact_seller_dialog.hide();
-							frappe.set_route('marketplace', 'buying', this.item.name);
-							erpnext.hub.trigger('action:send_message');
-						});
-				}
-			});
-		},
-
-		make_report_item_dialog() {
-			this.report_item_dialog = new frappe.ui.Dialog({
-				title: __('Report Item'),
-				fields: [
-					{
-						label: __('Why do think this Item should be removed?'),
-						fieldtype: 'Text',
-						fieldname: 'message'
-					}
-				],
-				primary_action: ({ message }) => {
-					hub.call('add_reported_item', {
-							hub_item_name: this.item.name,
-							message
-						})
-						.then(() => {
-							d.hide();
-							frappe.show_alert(__('Item Reported'));
-						});
-				}
-			});
-		},
-
-		make_editing_dialog() {
-			this.edit_dialog = edit_details_dialog({
-				primary_action: {
-					fn: values => {
-						this.update_details(values);
-						this.edit_dialog.hide();
-					}
-				},
-				defaults: {
-					item_name: this.item.item_name,
-					hub_category: this.item.hub_category,
-					description: this.item.description
-				}
-			});
-		},
-
-		update_details(values) {
-			frappe.call('erpnext.hub_node.api.update_item', {
-					ref_doc: this.item.name,
-					data: values
-				})
-				.then(r => {
-					return this.get_item_details();
-				})
-				.then(() => {
-					frappe.show_alert(__('{0} Updated', [this.item.item_name]));
-				});
-		},
-
-		contact_seller() {
-			this.contact_seller_dialog.show();
-		},
-
-		report_item() {
-			if (!hub.is_seller_registered()) {
-				frappe.throw(
-					__('Please login as a Marketplace User to report this item.')
-				);
-			}
-			this.report_item_dialog.show();
-		},
-
-		edit_details() {
-			if (!hub.is_seller_registered()) {
-				frappe.throw(
-					__('Please login as a Marketplace User to edit this item.')
-				);
-			}
-			this.edit_dialog.show();
-		},
-
-		unpublish_item() {
-			frappe.confirm(__('Unpublish {0}?', [this.item.item_name]), () => {
-				frappe
-					.call('erpnext.hub_node.api.unpublish_item', {
-						item_code: this.item.item_code,
-						hub_item_name: this.hub_item_name
-					})
-					.then(r => {
-						frappe.set_route(`marketplace/home`);
-						frappe.show_alert(__('Item listing removed'));
-					});
-			});
-		}
-	}
-};
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Messages.vue b/erpnext/public/js/hub/pages/Messages.vue
deleted file mode 100644
index 73506e9..0000000
--- a/erpnext/public/js/hub/pages/Messages.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-<template>
-	<div v-if="item_details">
-		<div>
-			<a class="text-muted" v-route="back_link">← {{ __('Back to Messages') }}</a>
-		</div>
-		<section-header>
-			<div class="flex flex-column margin-bottom">
-				<h4>{{ item_details.item_name }}</h4>
-				<span class="text-muted">{{ item_details.company }}</span>
-			</div>
-		</section-header>
-		<div class="row">
-			<div class="col-md-7">
-				<div class="message-container">
-					<div class="message-list">
-						<div class="level margin-bottom" v-for="message in messages" :key="message.name">
-							<div class="level-left ellipsis" style="width: 80%;">
-								<div v-html="frappe.avatar(message.sender)" />
-								<div style="white-space: normal;" v-html="message.message" />
-							</div>
-							<div class="level-right text-muted" v-html="frappe.datetime.comment_when(message.creation, true)" />
-						</div>
-					</div>
-					<div class="message-input">
-						<comment-input @change="send_message" />
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-</template>
-<script>
-import CommentInput from '../components/CommentInput.vue';
-import ItemListCard from '../components/ItemListCard.vue';
-
-export default {
-	components: {
-		CommentInput,
-		ItemListCard
-	},
-	data() {
-		return {
-			message_type: frappe.get_route()[1],
-			item_details: null,
-			messages: []
-		}
-	},
-	created() {
-		const hub_item_name = this.get_hub_item_name();
-		this.get_item_details(hub_item_name)
-			.then(item_details => {
-				this.item_details = item_details;
-				this.get_messages()
-					.then(messages => {
-						this.messages = messages;
-					});
-			});
-	},
-	computed: {
-		back_link() {
-			return 'marketplace/' + this.message_type;
-		}
-	},
-	methods: {
-		send_message(message) {
-			this.messages.push({
-				sender: frappe.session.user,
-				message: message,
-				creation: Date.now(),
-				name: frappe.utils.get_random(6)
-			});
-			hub.call('send_message', {
-				to_seller: this.get_against_seller(),
-				hub_item: this.item_details.name,
-				message
-			});
-		},
-		get_item_details(hub_item_name) {
-			return hub.call('get_item_details', { hub_item_name })
-		},
-		get_messages() {
-			if (!this.item_details) return [];
-			return hub.call('get_messages', {
-				against_seller: this.get_against_seller(),
-				against_item: this.item_details.name
-			});
-		},
-		get_against_seller() {
-			if (this.message_type === 'buying') {
-				return this.item_details.hub_seller;
-			} else if (this.message_type === 'selling') {
-				return frappe.get_route()[2];
-			}
-		},
-		get_hub_item_name() {
-			if (this.message_type === 'buying') {
-				return frappe.get_route()[2];
-			} else if (this.message_type === 'selling') {
-				return frappe.get_route()[3];
-			}
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/pages/NotFound.vue b/erpnext/public/js/hub/pages/NotFound.vue
deleted file mode 100644
index 8901b97..0000000
--- a/erpnext/public/js/hub/pages/NotFound.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<empty-state
-			:message="empty_state_message"
-			:height="500"
-			:action="action"
-		>
-		</empty-state>
-
-	</div>
-</template>
-
-<script>
-export default {
-	name: 'not-found-page',
-	data() {
-		return {
-			page_name: 'not-found',
-			action: {
-				label: __('Back to Home'),
-				on_click: () => {
-					frappe.set_route(`marketplace/home`);
-				}
-			},
-
-			// Constants
-			empty_state_message: __('Sorry! We could not find what you were looking for.')
-		};
-	},
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Publish.vue b/erpnext/public/js/hub/pages/Publish.vue
deleted file mode 100644
index ecba4b1..0000000
--- a/erpnext/public/js/hub/pages/Publish.vue
+++ /dev/null
@@ -1,212 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<notification-message
-			v-if="last_sync_message"
-			:message="last_sync_message"
-			@remove-message="clear_last_sync_message"
-		></notification-message>
-
-		<div class="flex justify-between align-flex-end margin-bottom">
-			<h5>{{ page_title }}</h5>
-
-			<button class="btn btn-primary btn-sm publish-items"
-				:disabled="no_selected_items"
-				@click="publish_selected_items"
-			>
-				<span>{{ publish_button_text }}</span>
-			</button>
-		</div>
-
-		<item-cards-container
-			:container_name="page_title"
-			:items="selected_items"
-			:item_id_fieldname="item_id_fieldname"
-			:is_local="true"
-			:editable="true"
-			@remove-item="remove_item_from_selection"
-
-			:empty_state_message="empty_state_message"
-			:empty_state_bordered="true"
-			:empty_state_height="80"
-		>
-		</item-cards-container>
-
-		<p class="text-muted">{{ valid_items_instruction }}</p>
-
-		<search-input
-			:placeholder="search_placeholder"
-			:on_search="get_valid_items"
-			v-model="search_value"
-		>
-		</search-input>
-
-		<item-cards-container
-			:items="valid_items"
-			:item_id_fieldname="item_id_fieldname"
-			:is_local="true"
-			:on_click="show_publishing_dialog_for_item"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-import NotificationMessage from '../components/NotificationMessage.vue';
-import { ItemPublishDialog } from '../components/item_publish_dialog';
-
-export default {
-	name: 'publish-page',
-	components: {
-		NotificationMessage
-	},
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			valid_items: [],
-			selected_items: [],
-			items_data_to_publish: {},
-			search_value: '',
-			item_id_fieldname: 'item_code',
-
-			// Constants
-			// TODO: multiline translations don't work
-			page_title: __('Publish Items'),
-			search_placeholder: __('Search Items ...'),
-			empty_state_message: __('No Items selected yet. Browse and click on items below to publish.'),
-			valid_items_instruction: __('Only items with an image and description can be published. Please update them if an item in your inventory does not appear.'),
-			last_sync_message: (hub.settings.last_sync_datetime)
-				? __('Last sync was {0}.', [`<a href="#marketplace/profile">${comment_when(hub.settings.last_sync_datetime)}</a>`]) +
-				  ` <a href="#marketplace/published-items">${__('See your Published Items.')}</a>`
-				: ''
-		};
-	},
-	computed: {
-		no_selected_items() {
-			return this.selected_items.length === 0;
-		},
-
-		publish_button_text() {
-			const number = this.selected_items.length;
-			let text = __('Publish');
-			if(number === 1) {
-				text = __('Publish 1 Item');
-			}
-			if(number > 1) {
-				text = __('Publish {0} Items', [number]);
-			}
-			return text;
-		},
-
-		items_dict() {
-			let items_dict = {};
-			this.valid_items.map(item => {
-				items_dict[item[this.item_id_fieldname]] = item
-			})
-
-			return items_dict;
-		},
-	},
-	created() {
-		this.get_valid_items();
-		this.make_publishing_dialog();
-	},
-	methods: {
-		get_valid_items() {
-			frappe.call(
-				'erpnext.hub_node.api.get_valid_items',
-				{
-					search_value: this.search_value
-				}
-			)
-			.then((r) => {
-				this.valid_items = r.message;
-			})
-		},
-
-		publish_selected_items() {
-			frappe.call(
-			'erpnext.hub_node.api.publish_selected_items',
-				{
-					items_to_publish: this.selected_items
-				}
-			)
-			.then((r) => {
-				this.selected_items = [];
-				return frappe.db.get_doc('Marketplace Settings');
-			})
-			.then(doc => {
-				hub.settings = doc;
-				this.add_last_sync_message();
-			});
-		},
-
-		add_last_sync_message() {
-			this.last_sync_message = __('Last sync was {0}.',
-				[`<a href="#marketplace/profile">${comment_when(hub.settings.last_sync_datetime)}</a>`]
-			) + `<a href="#marketplace/published-items">${__('See your Published Items')}</a>.`;
-		},
-
-		clear_last_sync_message() {
-			this.last_sync_message = '';
-		},
-
-		remove_item_from_selection(item_code) {
-			this.selected_items = this.selected_items
-				.filter(item => item.item_code !== item_code);
-		},
-
-		make_publishing_dialog() {
-			this.item_publish_dialog = ItemPublishDialog(
-				{
-					fn: (values) => {
-						this.add_item_to_publish(values);
-						this.item_publish_dialog.hide();
-					}
-				},
-				{
-					fn: () => {
-						const values = this.item_publish_dialog.get_values(true);
-						this.update_items_data_to_publish(values);
-					}
-				}
-			);
-		},
-
-		add_item_to_publish(values) {
-			this.update_items_data_to_publish(values);
-
-			const item_code  = values.item_code;
-			let item_doc = this.items_dict[item_code];
-
-			const item_to_publish = Object.assign({}, item_doc, values);
-			this.selected_items.push(item_to_publish);
-		},
-
-		update_items_data_to_publish(values) {
-			this.items_data_to_publish[values.item_code] = values;
-		},
-
-		show_publishing_dialog_for_item(item_code) {
-			let item_data = this.items_data_to_publish[item_code];
-			if(!item_data) { item_data = { item_code }; };
-
-			this.item_publish_dialog.clear();
-
-			const item_doc = this.items_dict[item_code];
-			if(item_doc) {
-				this.item_publish_dialog.fields_dict.image_list.set_data(
-					item_doc.attachments.map(attachment => attachment.file_url)
-				);
-			}
-
-			this.item_publish_dialog.set_values(item_data);
-			this.item_publish_dialog.show();
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/PublishedItems.vue b/erpnext/public/js/hub/pages/PublishedItems.vue
deleted file mode 100644
index cbb2216..0000000
--- a/erpnext/public/js/hub/pages/PublishedItems.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<section-header>
-			<div>
-				<h5>{{ __('Published Items') }}</h5>
-				<p v-if="items.length"
-					class="text-muted margin-bottom">
-					{{ __('You can publish upto 200 items.') }}
-				</p>
-			</div>
-
-			<button v-if="items.length"
-				class="btn btn-default btn-xs publish-items"
-				v-route="'marketplace/publish'"
-			>
-				<span>{{ __('Publish More Items') }}</span>
-			</button>
-
-		</section-header>
-
-		<item-cards-container
-			:container_name="__('Published Items')"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-			:empty_state_message="__('You haven\'t published any items yet.')"
-			:empty_state_action="publish_page_action"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			items: [],
-			item_id_fieldname: 'name',
-
-			publish_page_action: {
-				label: __('Publish Your First Items'),
-				on_click: () => {
-					frappe.set_route(`marketplace/publish`);
-				}
-			}
-		};
-	},
-	created() {
-		this.get_items();
-	},
-	methods: {
-		get_items() {
-			hub.call('get_items', {
-				filters: {
-					hub_seller: hub.settings.hub_seller_name
-				}
-			})
-			.then((items) => {
-				this.items = items;
-			})
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/SavedItems.vue b/erpnext/public/js/hub/pages/SavedItems.vue
deleted file mode 100644
index 7007ddc..0000000
--- a/erpnext/public/js/hub/pages/SavedItems.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<h5>{{ page_title }}</h5>
-
-		<item-cards-container
-			:container_name="page_title"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-			:editable="true"
-			@remove-item="on_item_remove"
-			:empty_state_message="empty_state_message"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	name: 'saved-items-page',
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			items: [],
-			item_id_fieldname: 'name',
-
-			// Constants
-			page_title: __('Saved Items'),
-			empty_state_message: __('You have not saved any items yet.')
-		};
-	},
-	created() {
-		this.get_items();
-	},
-	methods: {
-		get_items() {
-			hub.call(
-				'get_saved_items_of_user', {},
-				'action:item_save'
-			)
-			.then((items) => {
-				this.items = items;
-			})
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		},
-
-		on_item_remove(hub_item_name) {
-			const grace_period = 5000;
-			let reverted = false;
-			let alert;
-
-			const undo_remove = () => {
-				this.toggle_item(hub_item_name);;
-				reverted = true;
-				alert.hide();
-				return false;
-			}
-
-			const item_name = this.items.filter(item => item.hub_item_name === hub_item_name);
-
-			alert = frappe.show_alert(`
-				<span>
-					${__('{0} removed.', [item_name], 'A specific Item has been removed.')}
-					<a href="#" data-action="undo-remove">
-						<b>${__('Undo', None, 'Undo removal of item.')}</b>
-					</a>
-				</span>`,
-				grace_period/1000,
-				{
-					'undo-remove': undo_remove.bind(this)
-				}
-			);
-
-			this.toggle_item(hub_item_name, false);
-
-			setTimeout(() => {
-				if(!reverted) {
-					this.remove_item_from_saved_items(hub_item_name);
-				}
-			}, grace_period);
-		},
-
-		remove_item_from_saved_items(hub_item_name) {
-			erpnext.hub.trigger('action:item_save');
-			hub.call('remove_item_from_user_saved_items', {
-				hub_item_name,
-				hub_user: frappe.session.user
-			})
-			.then(() => {
-				this.get_items();
-			})
-			.catch(e => {
-				console.log(e);
-			});
-		},
-
-		// By default show
-		toggle_item(hub_item_name, show=true) {
-			this.items = this.items.map(item => {
-				if(item.name === hub_item_name) {
-					item.seen = show;
-				}
-				return item;
-			});
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue
deleted file mode 100644
index c10841e..0000000
--- a/erpnext/public/js/hub/pages/Search.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-	>
-		<search-input
-			:placeholder="search_placeholder"
-			:on_search="set_route_and_get_items"
-			v-model="search_value"
-		>
-		</search-input>
-
-		<h5>{{ page_title }}</h5>
-
-		<item-cards-container
-			container_name="Search"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-			:empty_state_message="empty_state_message"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			items: [],
-			category: frappe.get_route()[2],
-			search_value: frappe.get_route()[3],
-			item_id_fieldname: 'name',
-			filters: {},
-
-			// Constants
-			search_placeholder: __('Search for anything ...'),
-			empty_state_message: __('')
-		};
-	},
-	computed: {
-		page_title() {
-			return this.items.length
-				? __('Results for "{0}" {1}', [
-					this.search_value,
-					this.category !== 'All' ? __('in category {0}', [this.category]) : ''
-				  ])
-				: __('No Items found.');
-		}
-	},
-	created() {
-		this.get_items();
-	},
-	methods: {
-		get_items() {
-			if (this.category !== 'All') {
-				this.filters['hub_category'] = this.category;
-			}
-			hub.call('get_items', {
-				keyword: this.search_value,
-				filters: this.filters
-			})
-			.then((items) => {
-				this.items = items;
-			})
-		},
-
-		set_route_and_get_items() {
-			frappe.set_route('marketplace', 'search', this.category, this.search_value);
-			this.get_items();
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Seller.vue b/erpnext/public/js/hub/pages/Seller.vue
deleted file mode 100644
index 3c9b800..0000000
--- a/erpnext/public/js/hub/pages/Seller.vue
+++ /dev/null
@@ -1,201 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-		v-if="init || profile"
-	>
-		<detail-view
-			:title="title"
-			:image="image"
-			:sections="sections"
-			:show_skeleton="init"
-		>
-			<detail-header-item slot="detail-header-item"
-				:value="country"
-			></detail-header-item>
-			<detail-header-item slot="detail-header-item"
-				:value="site_name"
-			></detail-header-item>
-			<detail-header-item slot="detail-header-item"
-				:value="joined_when"
-			></detail-header-item>
-
-		</detail-view>
-
-		<div v-if="items.length">
-			<h5>
-				{{ item_container_heading }}
-				<small v-if="is_user_registered() && is_own_company">
-					<a class="pull-right" href="#marketplace/featured-items">Customize your Featured Items</a>
-				</small>
-			</h5>
-			<item-cards-container
-				:container_name="item_container_heading"
-				:items="items"
-				:item_id_fieldname="item_id_fieldname"
-				:on_click="go_to_item_details_page"
-			>
-			</item-cards-container>
-			<a class="pull-right" @click="go_to_seller_items_page(seller_company)">Show all items</a>
-		</div>
-
-		<div v-if="recent_seller_reviews.length">
-			<h5>Customer Reviews</h5>
-			<div class="container" v-for="review in recent_seller_reviews" :key="review.name">
-				<br>
-				<span class="text-muted">
-					<rating :rating="review.rating" :max_rating="5"></rating>
-				</span>
-				<i class="octicon octicon-quote hidden-xs fa-fw"></i>
-				<span class="bold">{{ review.subject }}</span>
-				<i class="octicon octicon-quote hidden-xs fa-fw fa-rotate-180"></i>
-				<div class="container">
-					by {{ review.username }}
-					<a class="text-muted">
-						<span class="text-muted hidden-xs">&ndash;</span>
-						<span class="hidden-xs" v-html="comment_when(review.timestamp)"></span>
-					</a>
-				</div>
-			</div>
-		</div>
-
-		<div v-if="seller_product_view_stats.length">
-			<h5>Stats</h5>
-			<div id="seller_traffic_chart"></div>
-		</div>
-
-
-
-	</div>
-</template>
-
-<script>
-import Rating from '../components/Rating.vue';
-
-
-export default {
-	name: 'seller-page',
-	components: {
-        Rating
-    },
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			seller_company: frappe.get_route()[2],
-			hub_seller: null,
-
-			init: true,
-
-			profile: null,
-			items:[],
-			recent_seller_reviews: [],
-			seller_product_view_stats: [],
-			seller_traffic_chart: null,
-			item_id_fieldname: 'name',
-			item_container_heading: 'Items',
-
-			title: null,
-			image: null,
-			sections: [],
-
-			country: '',
-			site_name: '',
-			joined_when: '',
-		};
-	},
-	created() {
-		this.get_seller_profile_and_items();
-	},
-	computed: {
-		is_own_company() {
-			let is_own_company = false;
-			if(this.hub_seller) {
-				if(this.hub_seller === hub.settings.hub_seller_name) {
-					is_own_company = true;
-				}
-			}
-			return is_own_company;
-		},
-	},
-	methods: {
-		comment_when(timestamp){
-			return comment_when(timestamp)
-		},
-		is_user_registered(){
-			return hub.is_user_registered()
-		},
-		get_seller_profile_and_items() {
-			let post_data = {company: this.seller_company}
-			if (this.page_name == 'profile'){
-				this.seller_company = null;
-				this.hub_seller = hub.settings.hub_seller_name
-				post_data = {hub_seller: this.hub_seller}
-			}
-			hub.call('get_hub_seller_page_info', post_data)
-			.then(data => {
-				this.init = false;
-				this.profile = data.profile;
-				this.items = data.items;
-				this.item_container_heading = data.is_featured_item ? __('Featured Items') : __('Popular Items');
-				this.hub_seller = this.items[0].hub_seller;
-				this.recent_seller_reviews = data.recent_seller_reviews;
-				this.seller_product_view_stats = data.seller_product_view_stats;
-
-				const profile = this.profile;
-
-				this.title = profile.company;
-
-				this.country = __(profile.country);
-				this.site_name = __(profile.site_name);
-				this.joined_when = __('Joined {0}', [comment_when(profile.creation)]);
-
-				this.image = profile.logo;
-				this.sections = [
-					{
-						title: __('About the Company'),
-						content: profile.company_description
-							? __(profile.company_description)
-							: __('No description')
-					}
-				];
-
-				setTimeout(() => this.init_seller_traffic_chart(), 1);
-
-			});
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		},
-		go_to_seller_items_page(hub_seller) {
-			frappe.set_route(`marketplace/seller/${hub_seller}/items`);
-		},
-		init_seller_traffic_chart() {
-			let lables = []
-			let tooltip_lables = {}
-			let datasets = [{name:"Product Views",chartType: 'line',values: []}]
-			this.seller_product_view_stats.map((stat) => {
-				lables.push(stat.date.substring(5));
-				tooltip_lables[stat.date.substring(5)] = new Date(stat.date).toDateString();
-				datasets[0].values.push(stat.view_count);
-			});
-			let data = {labels: lables, datasets:datasets, tooltip_lables:tooltip_lables}
-			this.seller_traffic_chart = new Chart( "#seller_traffic_chart", { // or DOM element
-			data: data,
-
-			title: "Daily Product Views",
-			type: 'axis-mixed', // or 'bar', 'line', 'pie', 'percentage'
-			height: 300,
-			colors: ['purple', '#ffa3ef', 'light-blue'],
-
-			tooltipOptions: {
-			formatTooltipX: d => this.seller_traffic_chart.data.tooltip_lables[d],
-			formatTooltipY: d => d + ' Views',
-			}
-		});
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/SellerItems.vue b/erpnext/public/js/hub/pages/SellerItems.vue
deleted file mode 100644
index 852fbae..0000000
--- a/erpnext/public/js/hub/pages/SellerItems.vue
+++ /dev/null
@@ -1,57 +0,0 @@
-<template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-		v-if="init || items.length"
-	>
-		<h5>{{ item_container_heading }}</h5>
-		<item-cards-container
-			:container_name="item_container_heading"
-			:items="items"
-			:item_id_fieldname="item_id_fieldname"
-			:on_click="go_to_item_details_page"
-		>
-		</item-cards-container>
-	</div>
-</template>
-
-<script>
-export default {
-	name: 'seller-items-page',
-	data() {
-		return {
-			page_name: frappe.get_route()[1],
-			seller_company: frappe.get_route()[2],
-
-			init: true,
-			items:[],
-			item_id_fieldname: 'name',
-		};
-	},
-	created() {
-		this.get_seller_and_items();
-	},
-	computed: {
-		item_container_heading() {
-			return __('Items by ' + this.seller_company);
-		}
-	},
-	methods: {
-		get_seller_and_items() {
-			hub.call(
-				'get_items',
-				{ company: this.seller_company }
-			).then(data => {
-				this.init = false;
-				this.items = data;
-			});
-		},
-
-		go_to_item_details_page(hub_item_name) {
-			frappe.set_route(`marketplace/item/${hub_item_name}`);
-		}
-	}
-}
-</script>
-
-<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Selling.vue b/erpnext/public/js/hub/pages/Selling.vue
deleted file mode 100644
index 8743027..0000000
--- a/erpnext/public/js/hub/pages/Selling.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<template>
-	<div>
-		<section-header>
-			<h4>{{ __('Selling') }}</h4>
-		</section-header>
-		<div class="row" v-if="items && items.length">
-			<div class="col-md-7"
-				style="margin-bottom: 30px;"
-				v-for="item of items"
-				:key="item.name"
-			>
-				<item-list-card
-					:item="item"
-				>
-					<div slot="subtitle">
-						<span class="text-muted">{{ __('{0} conversations', [item.received_messages.length]) }}</span>
-					</div>
-				</item-list-card>
-				<div class="hub-list-item" v-for="(message, index) in item.received_messages" :key="index"
-					v-route="'marketplace/selling/' + message.buyer + '/' + item.name"
-				>
-					<div class="hub-list-left">
-						<div class="hub-list-body">
-							<div class="hub-list-title">
-								{{ message.buyer_name }}
-							</div>
-							<div class="hub-list-subtitle">
-								{{ message.sender }}: {{ message.message | striphtml }}
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-		</div>
-		<empty-state v-else :message="__('This page keeps track of your items in which buyers have showed some interest.')" :centered="false" />
-	</div>
-</template>
-<script>
-import EmptyState from '../components/EmptyState.vue';
-import SectionHeader from '../components/SectionHeader.vue';
-import ItemListCard from '../components/ItemListCard.vue';
-
-export default {
-	components: {
-		SectionHeader,
-		ItemListCard,
-		EmptyState
-	},
-	data() {
-		return {
-			items: null
-		}
-	},
-	created() {
-		this.get_items_for_messages()
-			.then(items => {
-				this.items = items;
-			});
-	},
-	methods: {
-		get_items_for_messages() {
-			return hub.call('get_selling_items_for_messages');
-		}
-	}
-}
-</script>
diff --git a/erpnext/public/js/hub/vue-plugins.js b/erpnext/public/js/hub/vue-plugins.js
deleted file mode 100644
index 4912d68..0000000
--- a/erpnext/public/js/hub/vue-plugins.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import Vue from 'vue/dist/vue.js';
-
-// Global components
-import ItemCardsContainer from './components/ItemCardsContainer.vue';
-import SectionHeader from './components/SectionHeader.vue';
-import SearchInput from './components/SearchInput.vue';
-import DetailView from './components/DetailView.vue';
-import DetailHeaderItem from './components/DetailHeaderItem.vue';
-import EmptyState from './components/EmptyState.vue';
-import Image from './components/Image.vue';
-
-Vue.prototype.__ = window.__;
-Vue.prototype.frappe = window.frappe;
-
-Vue.component('item-cards-container', ItemCardsContainer);
-Vue.component('section-header', SectionHeader);
-Vue.component('search-input', SearchInput);
-Vue.component('detail-view', DetailView);
-Vue.component('detail-header-item', DetailHeaderItem);
-Vue.component('empty-state', EmptyState);
-Vue.component('base-image', Image);
-
-Vue.directive('route', {
-	bind(el, binding) {
-		const route = binding.value;
-		if (!route) return;
-		el.classList.add('cursor-pointer');
-		el.dataset.route = route;
-		el.addEventListener('click', () => frappe.set_route(route));
-	},
-	unbind(el) {
-		el.classList.remove('cursor-pointer');
-	}
-});
-
-const handleImage = (el, src) => {
-	let img = new Image();
-	// add loading class
-	el.src = '';
-	el.classList.add('img-loading');
-
-	img.onload = () => {
-		// image loaded, remove loading class
-		el.classList.remove('img-loading');
-		// set src
-		el.src = src;
-	}
-	img.onerror = () => {
-		el.classList.remove('img-loading');
-		el.classList.add('no-image');
-		el.src = null;
-	}
-	img.src = src;
-}
-
-Vue.filter('striphtml', function (text) {
-	return strip_html(text || '');
-});
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
index f48fe6f..c32ab6b 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
@@ -7,7 +7,7 @@
  "engine": "InnoDB",
  "field_order": [
   "certificate_details_section",
-  "section_code",
+  "tax_withholding_category",
   "fiscal_year",
   "column_break_3",
   "certificate_no",
@@ -34,13 +34,6 @@
    "unique": 1
   },
   {
-   "fieldname": "section_code",
-   "fieldtype": "Select",
-   "label": "Section Code",
-   "options": "192\n193\n194\n194A\n194C\n194D\n194H\n194I\n194J\n194LA\n194LBB\n194LBC\n195",
-   "reqd": 1
-  },
-  {
    "fieldname": "section_break_3",
    "fieldtype": "Section Break",
    "label": "Deductee Details"
@@ -123,13 +116,22 @@
    "label": "Fiscal Year",
    "options": "Fiscal Year",
    "reqd": 1
+  },
+  {
+   "fieldname": "tax_withholding_category",
+   "fieldtype": "Link",
+   "label": "Tax Withholding Category",
+   "options": "Tax Withholding Category",
+   "reqd": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2020-04-23 23:04:41.203721",
+ "modified": "2021-10-23 18:33:38.962622",
  "modified_by": "Administrator",
  "module": "Regional",
  "name": "Lower Deduction Certificate",
+ "naming_rule": "By fieldname",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index d8553f1..821e017 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -15,7 +15,7 @@
 class LowerDeductionCertificate(Document):
 	def validate(self):
 		self.validate_dates()
-		self.validate_supplier_against_section_code()
+		self.validate_supplier_against_tax_category()
 
 	def validate_dates(self):
 		if getdate(self.valid_upto) < getdate(self.valid_from):
@@ -31,12 +31,14 @@
 			<= fiscal_year.year_end_date):
 			frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
 
-	def validate_supplier_against_section_code(self):
-		duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', {'supplier': self.supplier, 'section_code': self.section_code}, ['name', 'valid_from', 'valid_upto'], as_dict=True)
+	def validate_supplier_against_tax_category(self):
+		duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate',
+			{'supplier': self.supplier, 'tax_withholding_category': self.tax_withholding_category, 'name': ("!=", self.name)},
+			['name', 'valid_from', 'valid_upto'], as_dict=True)
 		if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate):
 			certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name)
-			frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against Section Code {2} for this time period.")
-				.format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.section_code)))
+			frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against category {2} for this time period.")
+				.format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.tax_withholding_category)))
 
 	def are_dates_overlapping(self,duplicate_certificate):
 		valid_from = duplicate_certificate.valid_from
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 1733220..0c87421 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -855,7 +855,7 @@
 	if row.depreciation_method in ("Straight Line", "Manual"):
 		# if the Depreciation Schedule is being prepared for the first time
 		if not asset.flags.increase_in_asset_life:
-			depreciation_amount = (flt(row.value_after_depreciation) -
+			depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) -
 				flt(row.expected_value_after_useful_life)) / depreciation_left
 
 		# if the Depreciation Schedule is being modified after Asset Repair
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
index f4c049d..2b5ecc3 100644
--- a/erpnext/regional/report/uae_vat_201/uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -122,7 +122,7 @@
 	try:
 		return frappe.db.sql("""
 			select
-				s.vat_emirate as emirate, sum(i.base_amount) as total, sum(s.total_taxes_and_charges)
+				s.vat_emirate as emirate, sum(i.base_amount) as total, sum(i.tax_amount)
 			from
 				`tabSales Invoice Item` i inner join `tabSales Invoice` s
 			on
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index f692690..d46c46f 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -78,6 +78,8 @@
 		});
 
 		erpnext.queries.setup_warehouse_query(frm);
+
+		frm.ignore_doctypes_on_cancel_all = ['Purchase Order'];
 	},
 
 	delivery_date: function(frm) {
diff --git a/erpnext/hub/__init__.py b/erpnext/selling/print_format_field_template/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/selling/print_format_field_template/__init__.py
diff --git a/erpnext/hub_node/doctype/hub_users/__init__.py b/erpnext/selling/print_format_field_template/quotation_taxes/__init__.py
similarity index 100%
rename from erpnext/hub_node/doctype/hub_users/__init__.py
rename to erpnext/selling/print_format_field_template/quotation_taxes/__init__.py
diff --git a/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json
new file mode 100644
index 0000000..eaa17ce
--- /dev/null
+++ b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 15:48:56.416449",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Quotation",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:11:33.553722",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Quotation Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/hub/__init__.py b/erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py
similarity index 100%
copy from erpnext/hub/__init__.py
copy to erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py
diff --git a/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json
new file mode 100644
index 0000000..2aacb44
--- /dev/null
+++ b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 18:04:24.443076",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Sales Order",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:04:24.443076",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Sales Order Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index ddd4c4e..a86e604 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -206,8 +206,10 @@
 		var me = this;
 		var item = frappe.get_doc(cdt, cdn);
 
-		if (item.serial_no && item.qty === item.serial_no.split(`\n`).length) {
-			return;
+		// check if serial nos entered are as much as qty in row
+		if (item.serial_no) {
+			let serial_nos = item.serial_no.split(`\n`).filter(sn => sn.trim()); // filter out whitespaces
+			if (item.qty === serial_nos.length) return;
 		}
 
 		if (item.serial_no && !item.batch_no) {
diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json
index b7e895d..8a13385 100644
--- a/erpnext/setup/setup_wizard/data/country_wise_tax.json
+++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json
@@ -1195,7 +1195,7 @@
 			"*": {
 				"item_tax_templates": [
 					{
-						"title": "GST 9%",
+						"title": "GST 18%",
 						"taxes": [
 							{
 								"tax_type": {
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index c473395..d61d94c 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -202,7 +202,6 @@
 		{'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"},
 		{'doctype': "Party Type", "party_type": "Donor", "account_type": "Receivable"},
 
-		{'doctype': "Opportunity Type", "name": "Hub"},
 		{'doctype': "Opportunity Type", "name": _("Sales")},
 		{'doctype': "Opportunity Type", "name": _("Support")},
 		{'doctype': "Opportunity Type", "name": _("Maintenance")},
diff --git a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
index 320cb7b..1412acf 100644
--- a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
+++ b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
@@ -1,6 +1,6 @@
 {
  "charts": [],
- "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Projects Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Accounts Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"HR Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Selling Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Buying Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Support Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Shopping Cart Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Portal Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Manufacturing Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Education Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Hotel Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Domain Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Products Settings\", \"col\": 4}}]",
+ "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Projects Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Stock Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"HR Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Selling Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Buying Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Support Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Shopping Cart Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Portal Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Domain Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Products Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Naming Series\",\"col\":4}}]",
  "creation": "2020-03-12 14:47:51.166455",
  "docstatus": 0,
  "doctype": "Workspace",
@@ -10,7 +10,7 @@
  "idx": 0,
  "label": "ERPNext Settings",
  "links": [],
- "modified": "2021-08-05 12:15:59.052328",
+ "modified": "2021-10-26 21:32:55.323591",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "ERPNext Settings",
@@ -28,6 +28,14 @@
    "type": "DocType"
   },
   {
+   "color": "Grey",
+   "doc_view": "",
+   "icon": "dot-horizontal",
+   "label": "Naming Series",
+   "link_to": "Naming Series",
+   "type": "DocType"
+  },
+  {
    "icon": "accounting",
    "label": "Accounts Settings",
    "link_to": "Accounts Settings",
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index db5caf9..4b314a0 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -17,7 +17,6 @@
   "variant_of",
   "item_name",
   "item_group",
-  "is_item_from_hub",
   "stock_uom",
   "column_break0",
   "disabled",
@@ -134,12 +133,7 @@
   "website_specifications",
   "web_long_description",
   "website_content",
-  "total_projected_qty",
-  "hub_publishing_sb",
-  "publish_in_hub",
-  "hub_category_to_publish",
-  "hub_warehouse",
-  "synced_with_hub"
+  "total_projected_qty"
  ],
  "fields": [
   {
@@ -203,14 +197,6 @@
    "search_index": 1
   },
   {
-   "default": "0",
-   "depends_on": "eval:!doc.is_fixed_asset",
-   "fieldname": "is_item_from_hub",
-   "fieldtype": "Check",
-   "label": "Is Item from Hub",
-   "read_only": 1
-  },
-  {
    "fieldname": "stock_uom",
    "fieldtype": "Link",
    "ignore_user_permissions": 1,
@@ -997,41 +983,6 @@
    "read_only": 1
   },
   {
-   "collapsible": 1,
-   "depends_on": "eval:(!doc.is_item_from_hub && !doc.is_fixed_asset)",
-   "fieldname": "hub_publishing_sb",
-   "fieldtype": "Section Break",
-   "label": "Hub Publishing Details"
-  },
-  {
-   "default": "0",
-   "description": "Publish Item to hub.erpnext.com",
-   "fieldname": "publish_in_hub",
-   "fieldtype": "Check",
-   "label": "Publish in Hub"
-  },
-  {
-   "fieldname": "hub_category_to_publish",
-   "fieldtype": "Data",
-   "label": "Hub Category to Publish",
-   "read_only": 1
-  },
-  {
-   "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.",
-   "fieldname": "hub_warehouse",
-   "fieldtype": "Link",
-   "ignore_user_permissions": 1,
-   "label": "Hub Warehouse",
-   "options": "Warehouse"
-  },
-  {
-   "default": "0",
-   "fieldname": "synced_with_hub",
-   "fieldtype": "Check",
-   "label": "Synced With Hub",
-   "read_only": 1
-  },
-  {
    "depends_on": "eval:!doc.__islocal && !doc.is_fixed_asset",
    "fieldname": "over_delivery_receipt_allowance",
    "fieldtype": "Float",
@@ -1078,10 +1029,11 @@
  "index_web_pages_for_search": 1,
  "links": [],
  "max_attachments": 1,
- "modified": "2021-08-26 12:23:07.277077",
+ "modified": "2021-10-27 21:04:00.324786",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
+ "naming_rule": "By fieldname",
  "owner": "Administrator",
  "permissions": [
   {
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 8cc9f74..fa42c7d 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -123,7 +123,6 @@
 		self.validate_barcode()
 		self.validate_warehouse_for_reorder()
 		self.update_bom_item_desc()
-		self.synced_with_hub = 0
 
 		self.validate_has_variants()
 		self.validate_attributes_in_variants()
@@ -677,6 +676,8 @@
 	def after_rename(self, old_name, new_name, merge):
 		if merge:
 			self.validate_duplicate_item_in_stock_reconciliation(old_name, new_name)
+			frappe.msgprint(_("It can take upto few hours for accurate stock values to be visible after merging items."),
+					indicator="orange", title="Note")
 
 		if self.route:
 			invalidate_cache_for_item(self)
diff --git a/erpnext/stock/doctype/item_alternative/item_alternative.py b/erpnext/stock/doctype/item_alternative/item_alternative.py
index 6080fb4..6f2a389 100644
--- a/erpnext/stock/doctype/item_alternative/item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/item_alternative.py
@@ -25,19 +25,29 @@
 			frappe.throw(_("Alternative item must not be same as item code"))
 
 		item_meta = frappe.get_meta("Item")
-		fields = ["is_stock_item", "include_item_in_manufacturing","has_serial_no","has_batch_no"]
-		item_data = frappe.db.get_values("Item", self.item_code, fields, as_dict=1)
-		alternative_item_data = frappe.db.get_values("Item", self.alternative_item_code, fields, as_dict=1)
+		fields = ["is_stock_item", "include_item_in_manufacturing","has_serial_no", "has_batch_no", "allow_alternative_item"]
+		item_data = frappe.db.get_value("Item", self.item_code, fields, as_dict=1)
+		alternative_item_data = frappe.db.get_value("Item", self.alternative_item_code, fields, as_dict=1)
 
 		for field in fields:
-			if  item_data[0].get(field) != alternative_item_data[0].get(field):
+			if  item_data.get(field) != alternative_item_data.get(field):
 				raise_exception, alert = [1, False] if field == "is_stock_item" else [0, True]
 
 				frappe.msgprint(_("The value of {0} differs between Items {1} and {2}") \
 					.format(frappe.bold(item_meta.get_label(field)),
 							frappe.bold(self.alternative_item_code),
 							frappe.bold(self.item_code)),
-					alert=alert, raise_exception=raise_exception)
+					alert=alert, raise_exception=raise_exception, indicator="Orange")
+
+		alternate_item_check_msg = _("Allow Alternative Item must be checked on Item {}")
+
+		if not item_data.allow_alternative_item:
+			frappe.throw(alternate_item_check_msg.format(self.item_code))
+		if self.two_way and not alternative_item_data.allow_alternative_item:
+			frappe.throw(alternate_item_check_msg.format(self.item_code))
+
+
+
 
 	def validate_duplicate(self):
 		if frappe.db.get_value("Item Alternative", {'item_code': self.item_code,
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 17df977..ec01cae 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -502,7 +502,8 @@
 			"field_map": {
 				"name": "material_request_item",
 				"parent": "material_request",
-				"uom": "stock_uom"
+				"uom": "stock_uom",
+				"job_card_item": "job_card_item"
 			},
 			"postprocess": update_item,
 			"condition": lambda doc: doc.ordered_qty < doc.stock_qty
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index 25bbbbd..2bad42a 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -52,6 +52,7 @@
   "sales_order_item",
   "production_plan",
   "material_request_plan_item",
+  "job_card_item",
   "col_break4",
   "expense_account",
   "section_break_46",
@@ -444,16 +445,25 @@
   {
    "fieldname": "qty_info_col_break",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "job_card_item",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "no_copy": 1,
+   "print_hide": 1,
+   "label": "Job Card Item"
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-10-02 11:44:36.553064",
+ "modified": "2021-11-03 14:40:24.409826",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Material Request Item",
+ "naming_rule": "Random",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 2146793..c604c71 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -18,7 +18,9 @@
   "get_item_locations",
   "section_break_6",
   "locations",
-  "amended_from"
+  "amended_from",
+  "print_settings_section",
+  "group_same_items"
  ],
  "fields": [
   {
@@ -110,14 +112,28 @@
    "options": "STO-PICK-.YYYY.-",
    "reqd": 1,
    "set_only_once": 1
+  },
+  {
+   "fieldname": "print_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Print Settings"
+  },
+  {
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "group_same_items",
+   "fieldtype": "Check",
+   "label": "Group Same Items",
+   "print_hide": 1
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-03-17 11:38:41.932875",
+ "modified": "2021-10-05 15:08:40.369957",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Pick List",
+ "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
   {
@@ -184,4 +200,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index dffbe80..4c02f3d 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -2,10 +2,8 @@
 # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-from __future__ import unicode_literals
-
 import json
-from collections import OrderedDict
+from collections import OrderedDict, defaultdict
 
 import frappe
 from frappe import _
@@ -121,6 +119,34 @@
 				and (self.for_qty is None or self.for_qty == 0):
 			frappe.throw(_("Qty of Finished Goods Item should be greater than 0."))
 
+	def before_print(self, settings=None):
+		if self.get("group_same_items"):
+			self.group_similar_items()
+
+	def group_similar_items(self):
+		group_item_qty = defaultdict(float)
+		group_picked_qty = defaultdict(float)
+
+		for item in self.locations:
+			group_item_qty[(item.item_code, item.warehouse)] +=  item.qty
+			group_picked_qty[(item.item_code, item.warehouse)] += item.picked_qty
+
+		duplicate_list = []
+		for item in self.locations:
+			if (item.item_code, item.warehouse) in group_item_qty:
+				item.qty = group_item_qty[(item.item_code, item.warehouse)]
+				item.picked_qty = group_picked_qty[(item.item_code, item.warehouse)]
+				item.stock_qty = group_item_qty[(item.item_code, item.warehouse)]
+				del group_item_qty[(item.item_code, item.warehouse)]
+			else:
+				duplicate_list.append(item)
+
+		for item in duplicate_list:
+			self.remove(item)
+
+		for idx, item in enumerate(self.locations, start=1):
+			item.idx = idx
+
 
 def validate_item_locations(pick_list):
 	if not pick_list.locations:
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index fd0b368..58b46e1 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 
 import frappe
+from frappe import _dict
 
 test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
 
@@ -356,6 +357,39 @@
 		sales_order.cancel()
 		purchase_receipt.cancel()
 
+	def test_pick_list_grouping_before_print(self):
+		def _compare_dicts(a, b):
+			"compare dicts but ignore missing keys in `a`"
+			for key, value in a.items():
+				self.assertEqual(b.get(key), value, msg=f"{key} doesn't match")
+
+		# nothing should be grouped
+		pl = frappe.get_doc(doctype="Pick List", group_same_items=True, locations=[
+			_dict(item_code="A", warehouse="X", qty=1, picked_qty=2),
+			_dict(item_code="B", warehouse="X", qty=1, picked_qty=2),
+			_dict(item_code="A", warehouse="Y", qty=1, picked_qty=2),
+			_dict(item_code="B", warehouse="Y", qty=1, picked_qty=2),
+		])
+		pl.before_print()
+		self.assertEqual(len(pl.locations), 4)
+
+		# grouping should halve the number of items
+		pl = frappe.get_doc(doctype="Pick List", group_same_items=True, locations=[
+			_dict(item_code="A", warehouse="X", qty=5, picked_qty=1),
+			_dict(item_code="B", warehouse="Y", qty=4, picked_qty=2),
+			_dict(item_code="A", warehouse="X", qty=3, picked_qty=2),
+			_dict(item_code="B", warehouse="Y", qty=2, picked_qty=2),
+		])
+		pl.before_print()
+		self.assertEqual(len(pl.locations), 2)
+
+		expected_items = [
+			_dict(item_code="A", warehouse="X", qty=8, picked_qty=3),
+			_dict(item_code="B", warehouse="Y", qty=6, picked_qty=4),
+		]
+		for expected_item, created_item in zip(expected_items, pl.locations):
+			_compare_dicts(expected_item, created_item)
+
 	# def test_pick_list_skips_items_in_expired_batch(self):
 	# 	pass
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index ac8303e..c4b8131 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -88,7 +88,11 @@
 					}
 				}
 
-				filters["warehouse"] = item.s_warehouse || item.t_warehouse;
+				// User could want to select a manually created empty batch (no warehouse)
+				// or a pre-existing batch
+				if (frm.doc.purpose != "Material Receipt") {
+					filters["warehouse"] = item.s_warehouse || item.t_warehouse;
+				}
 
 				return {
 					query : "erpnext.controllers.queries.get_batch_no",
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index cbff214..e0190b6 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -89,7 +89,13 @@
 		out.update(get_bin_details(args.item_code, args.get("from_warehouse")))
 
 	elif out.get("warehouse"):
-		out.update(get_bin_details(args.item_code, out.warehouse, args.company))
+		if doc and doc.get('doctype') == 'Purchase Order':
+			# calculate company_total_stock only for po
+			bin_details = get_bin_details(args.item_code, out.warehouse, args.company)
+		else:
+			bin_details = get_bin_details(args.item_code, out.warehouse)
+
+		out.update(bin_details)
 
 	# update args with out, if key or value not exists
 	for key, value in iteritems(out):
@@ -485,8 +491,9 @@
 			"item_tax_template": None
 		}
 	"""
-	item_tax_template = args.get("item_tax_template")
-	item_tax_template = _get_item_tax_template(args, item.taxes, out)
+	item_tax_template = None
+	if item.taxes:
+		item_tax_template = _get_item_tax_template(args, item.taxes, out)
 
 	if not item_tax_template:
 		item_group = item.item_group
@@ -502,17 +509,17 @@
 	taxes_with_no_validity = []
 
 	for tax in taxes:
-		tax_company = frappe.get_value("Item Tax Template", tax.item_tax_template, 'company')
-		if (tax.valid_from or tax.maximum_net_rate) and tax_company == args['company']:
-			# In purchase Invoice first preference will be given to supplier invoice date
-			# if supplier date is not present then posting date
-			validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
+		tax_company = frappe.get_cached_value("Item Tax Template", tax.item_tax_template, 'company')
+		if tax_company == args['company']:
+			if (tax.valid_from or tax.maximum_net_rate):
+				# In purchase Invoice first preference will be given to supplier invoice date
+				# if supplier date is not present then posting date
+				validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
 
-			if getdate(tax.valid_from) <= getdate(validation_date) \
-				and is_within_valid_range(args, tax):
-				taxes_with_validity.append(tax)
-		else:
-			if tax_company == args['company']:
+				if getdate(tax.valid_from) <= getdate(validation_date) \
+					and is_within_valid_range(args, tax):
+					taxes_with_validity.append(tax)
+			else:
 				taxes_with_no_validity.append(tax)
 
 	if taxes_with_validity:
@@ -890,8 +897,7 @@
 				res[fieldname] = pos_profile.get(fieldname)
 
 		if res.get("warehouse"):
-			res.actual_qty = get_bin_details(args.item_code,
-				res.warehouse).get("actual_qty")
+			res.actual_qty = get_bin_details(args.item_code, res.warehouse).get("actual_qty")
 
 	return res
 
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index e9d5b6a..70f4bca 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -123,12 +123,11 @@
 		(now(), frappe.session.user, voucher_type, voucher_no))
 
 def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
-	args.update({"doctype": "Stock Ledger Entry"})
+	args["doctype"] = "Stock Ledger Entry"
 	sle = frappe.get_doc(args)
 	sle.flags.ignore_permissions = 1
 	sle.allow_negative_stock=allow_negative_stock
 	sle.via_landed_cost_voucher = via_landed_cost_voucher
-	sle.insert()
 	sle.submit()
 	return sle
 
@@ -601,7 +600,7 @@
 			if not allow_zero_rate:
 				self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
 					sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
-					currency=erpnext.get_company_currency(sle.company))
+					currency=erpnext.get_company_currency(sle.company), company=sle.company)
 
 	def get_incoming_value_for_serial_nos(self, sle, serial_nos):
 		# get rate from serial nos within same company
@@ -668,7 +667,7 @@
 				if not allow_zero_valuation_rate:
 					self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
 						sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
-						currency=erpnext.get_company_currency(sle.company))
+						currency=erpnext.get_company_currency(sle.company), company=sle.company)
 
 	def get_fifo_values(self, sle):
 		incoming_rate = flt(sle.incoming_rate)
@@ -701,7 +700,7 @@
 					if not allow_zero_valuation_rate:
 						_rate = get_valuation_rate(sle.item_code, sle.warehouse,
 							sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
-							currency=erpnext.get_company_currency(sle.company))
+							currency=erpnext.get_company_currency(sle.company), company=sle.company)
 					else:
 						_rate = 0
 
@@ -912,10 +911,11 @@
 
 def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
 	allow_zero_rate=False, currency=None, company=None, raise_error_if_no_rate=True):
-	# Get valuation rate from last sle for the same item and warehouse
-	if not company:
-		company = erpnext.get_default_company()
 
+	if not company:
+		company =  frappe.get_cached_value("Warehouse", warehouse, "company")
+
+	# Get valuation rate from last sle for the same item and warehouse
 	last_valuation_rate = frappe.db.sql("""select valuation_rate
 		from `tabStock Ledger Entry` force index (item_warehouse)
 		where
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index c4a0497..e1d5a89 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -101,11 +101,7 @@
 
 	if with_valuation_rate:
 		if with_serial_no:
-			serial_nos = last_entry.get("serial_no")
-
-			if (serial_nos and
-				len(get_serial_nos_data(serial_nos)) < last_entry.qty_after_transaction):
-				serial_nos = get_serial_nos_data_after_transactions(args)
+			serial_nos = get_serial_nos_data_after_transactions(args)
 
 			return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
 				if last_entry else (0.0, 0.0, 0.0))
@@ -115,19 +111,32 @@
 		return last_entry.qty_after_transaction if last_entry else 0.0
 
 def get_serial_nos_data_after_transactions(args):
-	serial_nos = []
-	data = frappe.db.sql(""" SELECT serial_no, actual_qty
-		FROM `tabStock Ledger Entry`
-		WHERE
-			item_code = %(item_code)s and warehouse = %(warehouse)s
-			and timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)
-			order by posting_date, posting_time asc """, args, as_dict=1)
+	from pypika import CustomFunction
 
-	for d in data:
-		if d.actual_qty > 0:
-			serial_nos.extend(get_serial_nos_data(d.serial_no))
+	serial_nos = set()
+	args = frappe._dict(args)
+	sle = frappe.qb.DocType('Stock Ledger Entry')
+	Timestamp = CustomFunction('timestamp', ['date', 'time'])
+
+	stock_ledger_entries = frappe.qb.from_(
+		sle
+	).select(
+		'serial_no','actual_qty'
+	).where(
+		(sle.item_code == args.item_code)
+		& (sle.warehouse == args.warehouse)
+		& (Timestamp(sle.posting_date, sle.posting_time) < Timestamp(args.posting_date, args.posting_time))
+		& (sle.is_cancelled == 0)
+	).orderby(
+		sle.posting_date, sle.posting_time, sle.creation
+	).run(as_dict=1)
+
+	for stock_ledger_entry in stock_ledger_entries:
+		changed_serial_no = get_serial_nos_data(stock_ledger_entry.serial_no)
+		if stock_ledger_entry.actual_qty > 0:
+			serial_nos.update(changed_serial_no)
 		else:
-			serial_nos = list(set(serial_nos) - set(get_serial_nos_data(d.serial_no)))
+			serial_nos.difference_update(changed_serial_no)
 
 	return '\n'.join(serial_nos)
 
diff --git a/erpnext/templates/print_formats/includes/taxes_and_charges.html b/erpnext/templates/print_formats/includes/taxes_and_charges.html
new file mode 100644
index 0000000..0d8e383
--- /dev/null
+++ b/erpnext/templates/print_formats/includes/taxes_and_charges.html
@@ -0,0 +1,34 @@
+{% macro render_row(label, value) %}
+<div class="field row">
+	<div class="col-7 {%- if doc.align_labels_right %} text-right{%- endif -%}">
+		<div class="label">{{ label }}</div>
+	</div>
+	<div class="text-right col-5">
+		{{ value }}
+	</div>
+</div>
+{% endmacro %}
+
+{%- macro render_discount_amount(doc) -%}
+	{%- if doc.discount_amount -%}
+	{{ render_row(_(doc.meta.get_label('discount_amount')), '- ' + doc.get_formatted("discount_amount", doc)) }}
+	{%- endif -%}
+{%- endmacro -%}
+
+<div class="row">
+    <div class="col"></div>
+	<div class="col">
+		{%- if doc.apply_discount_on == "Net Total" -%}
+			{{ render_discount_amount(doc) }}
+		{%- endif -%}
+		{%- for charge in doc.taxes -%}
+			{%- if (charge.tax_amount or print_settings.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
+			{{ render_row(charge.get_formatted("description"), charge.get_formatted('tax_amount', doc)) }}
+			{%- endif -%}
+		{%- endfor -%}
+		{%- if doc.apply_discount_on == "Grand Total" -%}
+			{{ render_discount_amount(doc) }}
+		{%- endif -%}
+	</div>
+</div>
+
diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py
index 881f286..3ce68d8 100644
--- a/erpnext/tests/test_woocommerce.py
+++ b/erpnext/tests/test_woocommerce.py
@@ -12,12 +12,6 @@
 
 class TestWoocommerce(unittest.TestCase):
 	def setUp(self):
-		if not frappe.db.exists('Company', 'Woocommerce'):
-			company = frappe.new_doc("Company")
-			company.company_name = "Woocommerce"
-			company.abbr = "W"
-			company.default_currency = "INR"
-			company.save()
 
 		woo_settings = frappe.get_doc("Woocommerce Settings")
 		if not woo_settings.secret:
@@ -26,14 +20,14 @@
 			woo_settings.api_consumer_key = "ck_fd43ff5756a6abafd95fadb6677100ce95a758a1"
 			woo_settings.api_consumer_secret = "cs_94360a1ad7bef7fa420a40cf284f7b3e0788454e"
 			woo_settings.enable_sync = 1
-			woo_settings.company = "Woocommerce"
-			woo_settings.tax_account = "Sales Expenses - W"
-			woo_settings.f_n_f_account = "Expenses - W"
+			woo_settings.company = "_Test Company"
+			woo_settings.tax_account = "Sales Expenses - _TC"
+			woo_settings.f_n_f_account = "Expenses - _TC"
 			woo_settings.creation_user = "Administrator"
 			woo_settings.save(ignore_permissions=True)
 
 	def test_sales_order_for_woocommerce(self):
-		frappe.flags.woocomm_test_order_data = {"id":75,"parent_id":0,"number":"74","order_key":"wc_order_5aa1281c2dacb","created_via":"checkout","version":"3.3.3","status":"processing","currency":"INR","date_created":"2018-03-08T12:10:04","date_created_gmt":"2018-03-08T12:10:04","date_modified":"2018-03-08T12:10:04","date_modified_gmt":"2018-03-08T12:10:04","discount_total":"0.00","discount_tax":"0.00","shipping_total":"150.00","shipping_tax":"0.00","cart_tax":"0.00","total":"649.00","total_tax":"0.00","prices_include_tax":False,"customer_id":12,"customer_ip_address":"103.54.99.5","customer_user_agent":"mozilla\\/5.0 (x11; linux x86_64) applewebkit\\/537.36 (khtml, like gecko) chrome\\/64.0.3282.186 safari\\/537.36","customer_note":"","billing":{"first_name":"Tony","last_name":"Stark","company":"Woocommerce","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN","email":"tony@gmail.com","phone":"123457890"},"shipping":{"first_name":"Tony","last_name":"Stark","company":"","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN"},"payment_method":"cod","payment_method_title":"Cash on delivery","transaction_id":"","date_paid":"","date_paid_gmt":"","date_completed":"","date_completed_gmt":"","cart_hash":"8e76b020d5790066496f244860c4703f","meta_data":[],"line_items":[{"id":80,"name":"Marvel","product_id":56,"variation_id":0,"quantity":1,"tax_class":"","subtotal":"499.00","subtotal_tax":"0.00","total":"499.00","total_tax":"0.00","taxes":[],"meta_data":[],"sku":"","price":499}],"tax_lines":[],"shipping_lines":[{"id":81,"method_title":"Flat rate","method_id":"flat_rate:1","total":"150.00","total_tax":"0.00","taxes":[],"meta_data":[{"id":623,"key":"Items","value":"Marvel &times; 1"}]}],"fee_lines":[],"coupon_lines":[],"refunds":[]}
+		frappe.flags.woocomm_test_order_data = {"id":75,"parent_id":0,"number":"74","order_key":"wc_order_5aa1281c2dacb","created_via":"checkout","version":"3.3.3","status":"processing","currency":"INR","date_created":"2018-03-08T12:10:04","date_created_gmt":"2018-03-08T12:10:04","date_modified":"2018-03-08T12:10:04","date_modified_gmt":"2018-03-08T12:10:04","discount_total":"0.00","discount_tax":"0.00","shipping_total":"150.00","shipping_tax":"0.00","cart_tax":"0.00","total":"649.00","total_tax":"0.00","prices_include_tax":False,"customer_id":12,"customer_ip_address":"103.54.99.5","customer_user_agent":"mozilla\\/5.0 (x11; linux x86_64) applewebkit\\/537.36 (khtml, like gecko) chrome\\/64.0.3282.186 safari\\/537.36","customer_note":"","billing":{"first_name":"Tony","last_name":"Stark","company":"_Test Company","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN","email":"tony@gmail.com","phone":"123457890"},"shipping":{"first_name":"Tony","last_name":"Stark","company":"","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN"},"payment_method":"cod","payment_method_title":"Cash on delivery","transaction_id":"","date_paid":"","date_paid_gmt":"","date_completed":"","date_completed_gmt":"","cart_hash":"8e76b020d5790066496f244860c4703f","meta_data":[],"line_items":[{"id":80,"name":"Marvel","product_id":56,"variation_id":0,"quantity":1,"tax_class":"","subtotal":"499.00","subtotal_tax":"0.00","total":"499.00","total_tax":"0.00","taxes":[],"meta_data":[],"sku":"","price":499}],"tax_lines":[],"shipping_lines":[{"id":81,"method_title":"Flat rate","method_id":"flat_rate:1","total":"150.00","total_tax":"0.00","taxes":[],"meta_data":[{"id":623,"key":"Items","value":"Marvel &times; 1"}]}],"fee_lines":[],"coupon_lines":[],"refunds":[]}
 		order()
 
 		self.assertTrue(frappe.get_value("Customer",{"woocommerce_email":"tony@gmail.com"}))