Merge pull request #39659 from rohitwaghchaure/fixed-timeout-error-while-making-auto-mr

perf: timeout for auto material request through reorder level
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 651599d..3f11798 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -118,6 +118,7 @@
 		self.validate_balance_must_be_debit_or_credit()
 		self.validate_account_currency()
 		self.validate_root_company_and_sync_account_to_children()
+		self.validate_receivable_payable_account_type()
 
 	def validate_parent_child_account_type(self):
 		if self.parent_account:
@@ -188,6 +189,24 @@
 				"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
 			)
 
+	def validate_receivable_payable_account_type(self):
+		doc_before_save = self.get_doc_before_save()
+		receivable_payable_types = ["Receivable", "Payable"]
+		if (
+			doc_before_save
+			and doc_before_save.account_type in receivable_payable_types
+			and doc_before_save.account_type != self.account_type
+		):
+			# check for ledger entries
+			if frappe.db.get_all("GL Entry", filters={"account": self.name, "is_cancelled": 0}, limit=1):
+				msg = _(
+					"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
+				).format(
+					frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
+				)
+				frappe.msgprint(msg)
+				self.add_comment("Comment", msg)
+
 	def validate_root_details(self):
 		doc_before_save = self.get_doc_before_save()
 
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index eb3e00b..7d0869b 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -6,6 +6,7 @@
 
 import frappe
 from frappe.test_runner import make_test_records
+from frappe.utils import nowdate
 
 from erpnext.accounts.doctype.account.account import (
 	InvalidAccountMergeError,
@@ -324,6 +325,19 @@
 		acc.account_currency = "USD"
 		self.assertRaises(frappe.ValidationError, acc.save)
 
+	def test_account_balance(self):
+		from erpnext.accounts.utils import get_balance_on
+
+		if not frappe.db.exists("Account", "Test Percent Account %5 - _TC"):
+			acc = frappe.new_doc("Account")
+			acc.account_name = "Test Percent Account %5"
+			acc.parent_account = "Tax Assets - _TC"
+			acc.company = "_Test Company"
+			acc.insert()
+
+		balance = get_balance_on(account="Test Percent Account %5 - _TC", date=nowdate())
+		self.assertEqual(balance, 0)
+
 
 def _make_test_records(verbose=None):
 	from frappe.test_runner import make_test_objects
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
index 4b97619..8a505a8 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
@@ -5,7 +5,9 @@
 import frappe
 from frappe import _, msgprint
 from frappe.model.document import Document
+from frappe.query_builder.custom import ConstantColumn
 from frappe.utils import flt, fmt_money, getdate
+from pypika import Order
 
 import erpnext
 
@@ -179,39 +181,62 @@
 
 	pos_sales_invoices, pos_purchase_invoices = [], []
 	if include_pos_transactions:
-		pos_sales_invoices = frappe.db.sql(
-			"""
-				select
-					"Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
-					si.posting_date, si.customer as against_account, sip.clearance_date,
-					account.account_currency, 0 as credit
-				from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
-				where
-					sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
-					and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s
-				order by
-					si.posting_date ASC, si.name DESC
-			""",
-			{"account": account, "from": from_date, "to": to_date},
-			as_dict=1,
-		)
+		si_payment = frappe.qb.DocType("Sales Invoice Payment")
+		si = frappe.qb.DocType("Sales Invoice")
+		acc = frappe.qb.DocType("Account")
 
-		pos_purchase_invoices = frappe.db.sql(
-			"""
-				select
-					"Purchase Invoice" as payment_document, pi.name as payment_entry, pi.paid_amount as credit,
-					pi.posting_date, pi.supplier as against_account, pi.clearance_date,
-					account.account_currency, 0 as debit
-				from `tabPurchase Invoice` pi, `tabAccount` account
-				where
-					pi.cash_bank_account=%(account)s and pi.docstatus=1 and account.name = pi.cash_bank_account
-					and pi.posting_date >= %(from)s and pi.posting_date <= %(to)s
-				order by
-					pi.posting_date ASC, pi.name DESC
-			""",
-			{"account": account, "from": from_date, "to": to_date},
-			as_dict=1,
-		)
+		pos_sales_invoices = (
+			frappe.qb.from_(si_payment)
+			.inner_join(si)
+			.on(si_payment.parent == si.name)
+			.inner_join(acc)
+			.on(si_payment.account == acc.name)
+			.select(
+				ConstantColumn("Sales Invoice").as_("payment_document"),
+				si.name.as_("payment_entry"),
+				si_payment.reference_no.as_("cheque_number"),
+				si_payment.amount.as_("debit"),
+				si.posting_date,
+				si.customer.as_("against_account"),
+				si_payment.clearance_date,
+				acc.account_currency,
+				ConstantColumn(0).as_("credit"),
+			)
+			.where(
+				(si.docstatus == 1)
+				& (si_payment.account == account)
+				& (si.posting_date >= from_date)
+				& (si.posting_date <= to_date)
+			)
+			.orderby(si.posting_date)
+			.orderby(si.name, order=Order.desc)
+		).run(as_dict=True)
+
+		pi = frappe.qb.DocType("Purchase Invoice")
+
+		pos_purchase_invoices = (
+			frappe.qb.from_(pi)
+			.inner_join(acc)
+			.on(pi.cash_bank_account == acc.name)
+			.select(
+				ConstantColumn("Purchase Invoice").as_("payment_document"),
+				pi.name.as_("payment_entry"),
+				pi.paid_amount.as_("credit"),
+				pi.posting_date,
+				pi.supplier.as_("against_account"),
+				pi.clearance_date,
+				acc.account_currency,
+				ConstantColumn(0).as_("debit"),
+			)
+			.where(
+				(pi.docstatus == 1)
+				& (pi.cash_bank_account == account)
+				& (pi.posting_date >= from_date)
+				& (pi.posting_date <= to_date)
+			)
+			.orderby(pi.posting_date)
+			.orderby(pi.name, order=Order.desc)
+		).run(as_dict=True)
 
 	entries = (
 		list(payment_entries)
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
index 1a4747c..30e564c 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -80,7 +80,8 @@
 		from frappe.utils.background_jobs import is_job_enqueued
 		from frappe.utils.scheduler import is_scheduler_inactive
 
-		if is_scheduler_inactive() and not frappe.flags.in_test:
+		run_now = frappe.flags.in_test or frappe.conf.developer_mode
+		if is_scheduler_inactive() and not run_now:
 			frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive"))
 
 		job_id = f"bank_statement_import::{self.name}"
@@ -97,7 +98,7 @@
 				google_sheets_url=self.google_sheets_url,
 				bank=self.bank,
 				template_options=self.template_options,
-				now=frappe.conf.developer_mode or frappe.flags.in_test,
+				now=run_now,
 			)
 			return True
 
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 7e88b6b..f23d2c9 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1032,19 +1032,19 @@
 		)
 
 		base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
-
-		if self.payment_type == "Receive":
-			self.difference_amount = base_party_amount - self.base_received_amount
-		elif self.payment_type == "Pay":
-			self.difference_amount = self.base_paid_amount - base_party_amount
-		else:
-			self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
-
-		total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
 		included_taxes = self.get_included_taxes()
 
+		if self.payment_type == "Receive":
+			self.difference_amount = base_party_amount - self.base_received_amount + included_taxes
+		elif self.payment_type == "Pay":
+			self.difference_amount = self.base_paid_amount - base_party_amount - included_taxes
+		else:
+			self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) - included_taxes
+
+		total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
+
 		self.difference_amount = flt(
-			self.difference_amount - total_deductions - included_taxes, self.precision("difference_amount")
+			self.difference_amount - total_deductions, self.precision("difference_amount")
 		)
 
 	def get_included_taxes(self):
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index c03b18a..083c8fc 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -120,18 +120,6 @@
 	statement_dict = {}
 	ageing = ""
 
-	err_journals = None
-	if doc.report == "General Ledger" and doc.ignore_exchange_rate_revaluation_journals:
-		err_journals = frappe.db.get_all(
-			"Journal Entry",
-			filters={
-				"company": doc.company,
-				"docstatus": 1,
-				"voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
-			},
-			as_list=True,
-		)
-
 	for entry in doc.customers:
 		if doc.include_ageing:
 			ageing = set_ageing(doc, entry)
@@ -144,8 +132,8 @@
 		)
 
 		filters = get_common_filters(doc)
-		if err_journals:
-			filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+		if doc.ignore_exchange_rate_revaluation_journals:
+			filters.update({"ignore_err": True})
 
 		if doc.report == "General Ledger":
 			filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
diff --git a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
index 5ab46b7..bd59f65 100644
--- a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
+++ b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
@@ -8,6 +8,7 @@
   "default",
   "mode_of_payment",
   "amount",
+  "reference_no",
   "column_break_3",
   "account",
   "type",
@@ -75,11 +76,16 @@
    "hidden": 1,
    "label": "Default",
    "read_only": 1
+  },
+  {
+   "fieldname": "reference_no",
+   "fieldtype": "Data",
+   "label": "Reference No"
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2020-08-03 12:45:39.986598",
+ "modified": "2024-01-23 16:20:06.436979",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice Payment",
@@ -87,5 +93,6 @@
  "permissions": [],
  "quick_entry": 1,
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
index 57d0142..e460a01 100644
--- a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
+++ b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
@@ -23,6 +23,7 @@
 		parent: DF.Data
 		parentfield: DF.Data
 		parenttype: DF.Data
+		reference_no: DF.Data | None
 		type: DF.ReadOnly | None
 	# end: auto-generated types
 
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 79b5e4d..b7b9d34 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -203,8 +203,14 @@
 			"fieldname": "show_remarks",
 			"label": __("Show Remarks"),
 			"fieldtype": "Check"
+		},
+		{
+			"fieldname": "ignore_err",
+			"label": __("Ignore Exchange Rate Revaluation Journals"),
+			"fieldtype": "Check"
 		}
 
+
 	]
 }
 
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 110ec75..cea3a7b 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -241,6 +241,19 @@
 	if filters.get("against_voucher_no"):
 		conditions.append("against_voucher=%(against_voucher_no)s")
 
+	if filters.get("ignore_err"):
+		err_journals = frappe.db.get_all(
+			"Journal Entry",
+			filters={
+				"company": filters.get("company"),
+				"docstatus": 1,
+				"voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
+			},
+			as_list=True,
+		)
+		if err_journals:
+			filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+
 	if filters.get("voucher_no_not_in"):
 		conditions.append("voucher_no not in %(voucher_no_not_in)s")
 
diff --git a/erpnext/accounts/report/general_ledger/test_general_ledger.py b/erpnext/accounts/report/general_ledger/test_general_ledger.py
index a8c362e..75f9430 100644
--- a/erpnext/accounts/report/general_ledger/test_general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/test_general_ledger.py
@@ -3,7 +3,7 @@
 
 import frappe
 from frappe.tests.utils import FrappeTestCase
-from frappe.utils import today
+from frappe.utils import flt, today
 
 from erpnext.accounts.report.general_ledger.general_ledger import execute
 
@@ -148,3 +148,105 @@
 		self.assertEqual(data[2]["credit"], 900)
 		self.assertEqual(data[3]["debit"], 100)
 		self.assertEqual(data[3]["credit"], 100)
+
+	def test_ignore_exchange_rate_journals_filter(self):
+		# create a new account with USD currency
+		account_name = "Test Debtors USD"
+		company = "_Test Company"
+		account = frappe.get_doc(
+			{
+				"account_name": account_name,
+				"is_group": 0,
+				"company": company,
+				"root_type": "Asset",
+				"report_type": "Balance Sheet",
+				"account_currency": "USD",
+				"parent_account": "Accounts Receivable - _TC",
+				"account_type": "Receivable",
+				"doctype": "Account",
+			}
+		)
+		account.insert(ignore_if_duplicate=True)
+		# create a JV to debit 1000 USD at 75 exchange rate
+		jv = frappe.new_doc("Journal Entry")
+		jv.posting_date = today()
+		jv.company = company
+		jv.multi_currency = 1
+		jv.cost_center = "_Test Cost Center - _TC"
+		jv.set(
+			"accounts",
+			[
+				{
+					"account": account.name,
+					"party_type": "Customer",
+					"party": "_Test Customer USD",
+					"debit_in_account_currency": 1000,
+					"credit_in_account_currency": 0,
+					"exchange_rate": 75,
+					"cost_center": "_Test Cost Center - _TC",
+				},
+				{
+					"account": "Cash - _TC",
+					"debit_in_account_currency": 0,
+					"credit_in_account_currency": 75000,
+					"cost_center": "_Test Cost Center - _TC",
+				},
+			],
+		)
+		jv.save()
+		jv.submit()
+
+		revaluation = frappe.new_doc("Exchange Rate Revaluation")
+		revaluation.posting_date = today()
+		revaluation.company = company
+		accounts = revaluation.get_accounts_data()
+		revaluation.extend("accounts", accounts)
+		row = revaluation.accounts[0]
+		row.new_exchange_rate = 83
+		row.new_balance_in_base_currency = flt(
+			row.new_exchange_rate * flt(row.balance_in_account_currency)
+		)
+		row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
+		revaluation.set_total_gain_loss()
+		revaluation = revaluation.save().submit()
+
+		# post journal entry for Revaluation doc
+		frappe.db.set_value(
+			"Company", company, "unrealized_exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
+		)
+		revaluation_jv = revaluation.make_jv_for_revaluation()
+		revaluation_jv.cost_center = "_Test Cost Center - _TC"
+		for acc in revaluation_jv.get("accounts"):
+			acc.cost_center = "_Test Cost Center - _TC"
+		revaluation_jv.save()
+		revaluation_jv.submit()
+
+		# With ignore_err enabled
+		columns, data = execute(
+			frappe._dict(
+				{
+					"company": company,
+					"from_date": today(),
+					"to_date": today(),
+					"account": [account.name],
+					"group_by": "Group by Voucher (Consolidated)",
+					"ignore_err": True,
+				}
+			)
+		)
+		self.assertNotIn(revaluation_jv.name, set([x.voucher_no for x in data]))
+
+		# Without ignore_err enabled
+		columns, data = execute(
+			frappe._dict(
+				{
+					"company": company,
+					"from_date": today(),
+					"to_date": today(),
+					"account": [account.name],
+					"group_by": "Group by Voucher (Consolidated)",
+					"ignore_err": False,
+				}
+			)
+		)
+		self.assertIn(revaluation_jv.name, set([x.voucher_no for x in data]))
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 30700d0..64bc39a 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -237,7 +237,7 @@
 			)
 
 		else:
-			cond.append("""gle.cost_center = %s """ % (frappe.db.escape(cost_center, percent=False),))
+			cond.append("""gle.cost_center = %s """ % (frappe.db.escape(cost_center),))
 
 	if account:
 		if not (frappe.flags.ignore_account_permission or ignore_account_permission):
@@ -258,7 +258,7 @@
 			if acc.account_currency == frappe.get_cached_value("Company", acc.company, "default_currency"):
 				in_account_currency = False
 		else:
-			cond.append("""gle.account = %s """ % (frappe.db.escape(account, percent=False),))
+			cond.append("""gle.account = %s """ % (frappe.db.escape(account),))
 
 	if account_type:
 		accounts = frappe.db.get_all(
@@ -278,11 +278,11 @@
 	if party_type and party:
 		cond.append(
 			"""gle.party_type = %s and gle.party = %s """
-			% (frappe.db.escape(party_type), frappe.db.escape(party, percent=False))
+			% (frappe.db.escape(party_type), frappe.db.escape(party))
 		)
 
 	if company:
-		cond.append("""gle.company = %s """ % (frappe.db.escape(company, percent=False)))
+		cond.append("""gle.company = %s """ % (frappe.db.escape(company)))
 
 	if account or (party_type and party) or account_type:
 		precision = get_currency_precision()
@@ -348,7 +348,7 @@
 				% (acc.lft, acc.rgt)
 			)
 		else:
-			cond.append("""gle.account = %s """ % (frappe.db.escape(account, percent=False),))
+			cond.append("""gle.account = %s """ % (frappe.db.escape(account),))
 
 		entries = frappe.db.sql(
 			"""
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 77ce5f7..d98a00f 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -151,6 +151,7 @@
   },
   {
    "default": "1",
+   "depends_on": "eval: frappe.boot.versions && frappe.boot.versions.payments",
    "fieldname": "show_pay_button",
    "fieldtype": "Check",
    "label": "Show Pay Button in Purchase Order Portal"
@@ -213,7 +214,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2024-01-30 14:04:43.177427",
+ "modified": "2024-01-31 13:34:18.101256",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Buying Settings",
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 8cb1a0e..3d7a947 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -98,6 +98,7 @@
 				item_doc = frappe.get_cached_doc("Item", item.item_code)
 				args = {
 					"net_rate": item.net_rate or item.rate,
+					"base_net_rate": item.base_net_rate or item.base_rate,
 					"tax_category": self.doc.get("tax_category"),
 					"posting_date": self.doc.get("posting_date"),
 					"bill_date": self.doc.get("bill_date"),
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 5dc5c38..f0392be 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -1334,10 +1334,10 @@
 	)
 
 	date_field_mapper = {
-		"from_date": self.from_date >= so.transaction_date,
-		"to_date": self.to_date <= so.transaction_date,
-		"from_delivery_date": self.from_delivery_date >= so_item.delivery_date,
-		"to_delivery_date": self.to_delivery_date <= so_item.delivery_date,
+		"from_date": so.transaction_date >= self.from_date,
+		"to_date": so.transaction_date <= self.to_date,
+		"from_delivery_date": so_item.delivery_date >= self.from_delivery_date,
+		"to_delivery_date": so_item.delivery_date <= self.to_delivery_date,
 	}
 
 	for field, value in date_field_mapper.items():
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index aa7bc5b..39beb36 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -1511,14 +1511,14 @@
 
 
 def validate_operation_data(row):
-	if row.get("qty") <= 0:
+	if flt(row.get("qty")) <= 0:
 		frappe.throw(
 			_("Quantity to Manufacture can not be zero for the operation {0}").format(
 				frappe.bold(row.get("operation"))
 			)
 		)
 
-	if row.get("qty") > row.get("pending_qty"):
+	if flt(row.get("qty")) > flt(row.get("pending_qty")):
 		frappe.throw(
 			_("For operation {0}: Quantity ({1}) can not be greater than pending quantity({2})").format(
 				frappe.bold(row.get("operation")),
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 4ea834b..26795f7 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -502,6 +502,7 @@
 							project: item.project || me.frm.doc.project,
 							qty: item.qty || 1,
 							net_rate: item.rate,
+							base_net_rate: item.base_net_rate,
 							stock_qty: item.stock_qty,
 							conversion_factor: item.conversion_factor,
 							weight_per_unit: item.weight_per_unit,
@@ -1902,7 +1903,7 @@
 			if (item.item_code) {
 				// Use combination of name and item code in case same item is added multiple times
 				item_codes.push([item.item_code, item.name]);
-				item_rates[item.name] = item.net_rate;
+				item_rates[item.name] = item.base_net_rate;
 				item_tax_templates[item.name] = item.item_tax_template;
 			}
 		});
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 2f6775f..415216c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -230,6 +230,7 @@
 
 		if self.flags.is_new_doc:
 			self.link_lead_address_and_contact()
+			self.copy_communication()
 
 		self.update_customer_groups()
 
@@ -291,6 +292,17 @@
 					linked_doc.append("links", dict(link_doctype="Customer", link_name=self.name))
 					linked_doc.save(ignore_permissions=self.flags.ignore_permissions)
 
+	def copy_communication(self):
+		if not self.lead_name or not frappe.db.get_single_value(
+			"CRM Settings", "carry_forward_communication_and_comments"
+		):
+			return
+
+		from erpnext.crm.utils import copy_comments, link_communications
+
+		copy_comments("Lead", self.lead_name, self)
+		link_communications("Lead", self.lead_name, self)
+
 	def validate_name_with_customer_group(self):
 		if frappe.db.exists("Customer Group", self.name):
 			frappe.throw(
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index b4f7708..dec7506 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -149,6 +149,13 @@
 				self.get("items")[item_count - 1].applicable_charges += diff
 
 	def validate_applicable_charges_for_item(self):
+		if self.distribute_charges_based_on == "Distribute Manually" and len(self.taxes) > 1:
+			frappe.throw(
+				_(
+					"Please keep one Applicable Charges, when 'Distribute Charges Based On' is 'Distribute Manually'. For more charges, please create another Landed Cost Voucher."
+				)
+			)
+
 		based_on = self.distribute_charges_based_on.lower()
 
 		if based_on != "distribute manually":
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index bf6080b..a1f97c9 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -1360,16 +1360,16 @@
 	for lcv in landed_cost_vouchers:
 		landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
 
+		based_on_field = None
 		# Use amount field for total item cost for manually cost distributed LCVs
-		if landed_cost_voucher_doc.distribute_charges_based_on == "Distribute Manually":
-			based_on_field = "amount"
-		else:
+		if landed_cost_voucher_doc.distribute_charges_based_on != "Distribute Manually":
 			based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
 
 		total_item_cost = 0
 
-		for item in landed_cost_voucher_doc.items:
-			total_item_cost += item.get(based_on_field)
+		if based_on_field:
+			for item in landed_cost_voucher_doc.items:
+				total_item_cost += item.get(based_on_field)
 
 		for item in landed_cost_voucher_doc.items:
 			if item.receipt_document == purchase_document:
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 693ccaa..1cb1057 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -546,7 +546,7 @@
 		args = {
 			"company": company,
 			"tax_category": tax_category,
-			"net_rate": item_rates.get(item_code[1]),
+			"base_net_rate": item_rates.get(item_code[1]),
 		}
 
 		if item_tax_templates:
@@ -638,7 +638,7 @@
 	if not flt(tax.maximum_net_rate):
 		# No range specified, just ignore
 		return True
-	elif flt(tax.minimum_net_rate) <= flt(args.get("net_rate")) <= flt(tax.maximum_net_rate):
+	elif flt(tax.minimum_net_rate) <= flt(args.get("base_net_rate")) <= flt(tax.maximum_net_rate):
 		return True
 
 	return False
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 45764f3..e88b192 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -897,9 +897,12 @@
 
 		self.wh_data.stock_value = round_off_if_near_zero(self.wh_data.stock_value + doc.total_amount)
 
-		self.wh_data.qty_after_transaction += doc.total_qty
+		precision = doc.precision("total_qty")
+		self.wh_data.qty_after_transaction += flt(doc.total_qty, precision)
 		if self.wh_data.qty_after_transaction:
-			self.wh_data.valuation_rate = self.wh_data.stock_value / self.wh_data.qty_after_transaction
+			self.wh_data.valuation_rate = flt(self.wh_data.stock_value, precision) / flt(
+				self.wh_data.qty_after_transaction, precision
+			)
 
 	def validate_negative_stock(self, sle):
 		"""
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 97bf487..6c59a96 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -34,6 +34,18 @@
 				</a>
 			</ul>
 		</div>
+		{% if show_pay_button %}
+			<div class="form-column col-sm-6">
+				<div class="page-header-actions-block" data-html-block="header-actions">
+					<p>
+						<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
+							class="btn btn-primary btn-sm" id="pay-for-order">
+							{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
+						</a>
+					</p>
+				</div>
+			</div>
+		{% endif %}
 	</div>
 {% endblock %}
 
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index d0968bf..21d4b86 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -48,7 +48,10 @@
 			)
 			context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
 
-	context.show_pay_button = frappe.db.get_single_value("Buying Settings", "show_pay_button")
+	context.show_pay_button = (
+		"payments" in frappe.get_installed_apps()
+		and frappe.db.get_single_value("Buying Settings", "show_pay_button")
+	)
 	context.show_make_pi_button = False
 	if context.doc.get("supplier"):
 		# show Make Purchase Invoice button based on permission