Merge pull request #31942 from ruthra-kumar/bug_ar_ap_report_include_payment_against_po

fix: include payment against PO in AR/AP report
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
index 4d2dc58..9e06254 100644
--- a/.github/workflows/patch.yml
+++ b/.github/workflows/patch.yml
@@ -11,7 +11,7 @@
   workflow_dispatch:
 
 concurrency:
-  group: patch-develop-${{ github.event.number }}
+  group: patch-develop-${{ github.event_name }}-${{ github.event.number || github.event_name == 'workflow_dispatch' && github.run_id || '' }}
   cancel-in-progress: true
 
 jobs:
diff --git a/.github/workflows/server-tests-mariadb.yml b/.github/workflows/server-tests-mariadb.yml
index 64134bc..e3b92fd 100644
--- a/.github/workflows/server-tests-mariadb.yml
+++ b/.github/workflows/server-tests-mariadb.yml
@@ -27,7 +27,7 @@
         type: string
 
 concurrency:
-  group: server-mariadb-develop-${{ github.event.number }}
+  group: server-mariadb-develop-${{ github.event_name }}-${{ github.event.number || github.event_name == 'workflow_dispatch' && github.run_id || '' }}
   cancel-in-progress: true
 
 jobs:
diff --git a/.github/workflows/server-tests-postgres.yml b/.github/workflows/server-tests-postgres.yml
index 651c935..df43801 100644
--- a/.github/workflows/server-tests-postgres.yml
+++ b/.github/workflows/server-tests-postgres.yml
@@ -9,7 +9,7 @@
     types: [opened, labelled, synchronize, reopened]
 
 concurrency:
-  group: server-postgres-develop-${{ github.event.number }}
+  group: server-postgres-develop-${{ github.event_name }}-${{ github.event.number || github.event_name == 'workflow_dispatch' && github.run_id || '' }}
   cancel-in-progress: true
 
 jobs:
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 1987c83..7227b95 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -366,7 +366,7 @@
 	if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
 		ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
 
-		# Didn't use db_set for optimisation purpose
+		# Didn't use db_set for optimization purpose
 		ref_doc.outstanding_amount = bal
 		frappe.db.set_value(against_voucher_type, against_voucher, "outstanding_amount", bal)
 
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index af5a5e2..4618d08 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -181,7 +181,11 @@
 				frappe.throw(_("Party is mandatory"))
 
 			_party_name = "title" if self.party_type == "Shareholder" else self.party_type.lower() + "_name"
-			self.party_name = frappe.db.get_value(self.party_type, self.party, _party_name)
+
+			if frappe.db.has_column(self.party_type, _party_name):
+				self.party_name = frappe.db.get_value(self.party_type, self.party, _party_name)
+			else:
+				self.party_name = frappe.db.get_value(self.party_type, self.party, "name")
 
 		if self.party:
 			if not self.party_balance:
@@ -295,6 +299,9 @@
 	def validate_reference_documents(self):
 		valid_reference_doctypes = self.get_valid_reference_doctypes()
 
+		if not valid_reference_doctypes:
+			return
+
 		for d in self.get("references"):
 			if not d.allocated_amount:
 				continue
@@ -362,7 +369,7 @@
 			if not d.allocated_amount:
 				continue
 
-			if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Fees"):
+			if d.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
 				outstanding_amount, is_return = frappe.get_cached_value(
 					d.reference_doctype, d.reference_name, ["outstanding_amount", "is_return"]
 				)
@@ -1184,6 +1191,7 @@
 
 	ple = qb.DocType("Payment Ledger Entry")
 	common_filter = []
+	posting_and_due_date = []
 
 	# confirm that Supplier is not blocked
 	if args.get("party_type") == "Supplier":
@@ -1200,7 +1208,7 @@
 	party_account_currency = get_account_currency(args.get("party_account"))
 	company_currency = frappe.get_cached_value("Company", args.get("company"), "default_currency")
 
-	# Get positive outstanding sales /purchase invoices/ Fees
+	# Get positive outstanding sales /purchase invoices
 	condition = ""
 	if args.get("voucher_type") and args.get("voucher_no"):
 		condition = " and voucher_type={0} and voucher_no={1}".format(
@@ -1224,7 +1232,7 @@
 			condition += " and {0} between '{1}' and '{2}'".format(
 				fieldname, args.get(date_fields[0]), args.get(date_fields[1])
 			)
-			common_filter.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
+			posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
 
 	if args.get("company"):
 		condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
@@ -1235,6 +1243,7 @@
 		args.get("party"),
 		args.get("party_account"),
 		common_filter=common_filter,
+		posting_date=posting_and_due_date,
 		min_outstanding=args.get("outstanding_amt_greater_than"),
 		max_outstanding=args.get("outstanding_amt_less_than"),
 	)
@@ -1595,10 +1604,11 @@
 	elif reference_doctype != "Journal Entry":
 		if not total_amount:
 			if party_account_currency == company_currency:
-				total_amount = ref_doc.base_grand_total
+				# for handling cases that don't have multi-currency (base field)
+				total_amount = ref_doc.get("grand_total") or ref_doc.get("base_grand_total")
 				exchange_rate = 1
 			else:
-				total_amount = ref_doc.grand_total
+				total_amount = ref_doc.get("grand_total")
 		if not exchange_rate:
 			# Get the exchange rate from the original ref doc
 			# or get it based on the posting date of the ref doc.
@@ -1609,7 +1619,7 @@
 		if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
 			outstanding_amount = ref_doc.get("outstanding_amount")
 		else:
-			outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
+			outstanding_amount = flt(total_amount) - flt(ref_doc.get("advance_paid"))
 
 	else:
 		# Get the exchange rate based on the posting date of the ref doc.
@@ -1627,16 +1637,23 @@
 
 
 @frappe.whitelist()
-def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
+def get_payment_entry(
+	dt, dn, party_amount=None, bank_account=None, bank_amount=None, party_type=None, payment_type=None
+):
 	reference_doc = None
 	doc = frappe.get_doc(dt, dn)
 	if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
 		frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
 
-	party_type = set_party_type(dt)
+	if not party_type:
+		party_type = set_party_type(dt)
+
 	party_account = set_party_account(dt, dn, doc, party_type)
 	party_account_currency = set_party_account_currency(dt, party_account, doc)
-	payment_type = set_payment_type(dt, doc)
+
+	if not payment_type:
+		payment_type = set_payment_type(dt, doc)
+
 	grand_total, outstanding_amount = set_grand_total_and_outstanding_amount(
 		party_amount, dt, party_account_currency, doc
 	)
@@ -1786,8 +1803,6 @@
 		party_account = get_party_account_based_on_invoice_discounting(dn) or doc.debit_to
 	elif dt == "Purchase Invoice":
 		party_account = doc.credit_to
-	elif dt == "Fees":
-		party_account = doc.receivable_account
 	else:
 		party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
 	return party_account
@@ -1803,8 +1818,7 @@
 
 def set_payment_type(dt, doc):
 	if (
-		dt == "Sales Order"
-		or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)
+		dt == "Sales Order" or (dt in ("Sales Invoice", "Dunning") and doc.outstanding_amount > 0)
 	) or (dt == "Purchase Invoice" and doc.outstanding_amount < 0):
 		payment_type = "Receive"
 	else:
@@ -1822,18 +1836,15 @@
 		else:
 			grand_total = doc.rounded_total or doc.grand_total
 		outstanding_amount = doc.outstanding_amount
-	elif dt == "Fees":
-		grand_total = doc.grand_total
-		outstanding_amount = doc.outstanding_amount
 	elif dt == "Dunning":
 		grand_total = doc.grand_total
 		outstanding_amount = doc.grand_total
 	else:
 		if party_account_currency == doc.company_currency:
-			grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
+			grand_total = flt(doc.get("base_rounded_total") or doc.get("base_grand_total"))
 		else:
-			grand_total = flt(doc.get("rounded_total") or doc.grand_total)
-		outstanding_amount = grand_total - flt(doc.advance_paid)
+			grand_total = flt(doc.get("rounded_total") or doc.get("grand_total"))
+		outstanding_amount = doc.get("outstanding_amount") or (grand_total - flt(doc.advance_paid))
 	return grand_total, outstanding_amount
 
 
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 5ed34d3..601fc87 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -22,6 +22,7 @@
 	def __init__(self, *args, **kwargs):
 		super(PaymentReconciliation, self).__init__(*args, **kwargs)
 		self.common_filter_conditions = []
+		self.ple_posting_date_filter = []
 
 	@frappe.whitelist()
 	def get_unreconciled_entries(self):
@@ -150,6 +151,7 @@
 			return_outstanding = ple_query.get_voucher_outstandings(
 				vouchers=return_invoices,
 				common_filter=self.common_filter_conditions,
+				posting_date=self.ple_posting_date_filter,
 				min_outstanding=-(self.minimum_payment_amount) if self.minimum_payment_amount else None,
 				max_outstanding=-(self.maximum_payment_amount) if self.maximum_payment_amount else None,
 				get_payments=True,
@@ -187,6 +189,7 @@
 			self.party,
 			self.receivable_payable_account,
 			common_filter=self.common_filter_conditions,
+			posting_date=self.ple_posting_date_filter,
 			min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None,
 			max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None,
 		)
@@ -350,6 +353,7 @@
 
 	def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False):
 		self.common_filter_conditions.clear()
+		self.ple_posting_date_filter.clear()
 		ple = qb.DocType("Payment Ledger Entry")
 
 		self.common_filter_conditions.append(ple.company == self.company)
@@ -359,15 +363,15 @@
 
 		if get_invoices:
 			if self.from_invoice_date:
-				self.common_filter_conditions.append(ple.posting_date.gte(self.from_invoice_date))
+				self.ple_posting_date_filter.append(ple.posting_date.gte(self.from_invoice_date))
 			if self.to_invoice_date:
-				self.common_filter_conditions.append(ple.posting_date.lte(self.to_invoice_date))
+				self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_invoice_date))
 
 		elif get_return_invoices:
 			if self.from_payment_date:
-				self.common_filter_conditions.append(ple.posting_date.gte(self.from_payment_date))
+				self.ple_posting_date_filter.append(ple.posting_date.gte(self.from_payment_date))
 			if self.to_payment_date:
-				self.common_filter_conditions.append(ple.posting_date.lte(self.to_payment_date))
+				self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_payment_date))
 
 	def get_conditions(self, get_payments=False):
 		condition = " and company = '{0}' ".format(self.company)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
index 625382a..dae029b 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
@@ -283,6 +283,41 @@
 		self.assertEqual(len(pr.get("invoices")), 2)
 		self.assertEqual(len(pr.get("payments")), 2)
 
+	def test_filter_posting_date_case2(self):
+		"""
+		Posting date should not affect outstanding amount calculation
+		"""
+
+		from_date = add_days(nowdate(), -30)
+		to_date = nowdate()
+		self.create_payment_entry(amount=25, posting_date=from_date).submit()
+		self.create_sales_invoice(rate=25, qty=1, posting_date=to_date)
+
+		pr = self.create_payment_reconciliation()
+		pr.from_invoice_date = pr.from_payment_date = from_date
+		pr.to_invoice_date = pr.to_payment_date = to_date
+		pr.get_unreconciled_entries()
+
+		self.assertEqual(len(pr.invoices), 1)
+		self.assertEqual(len(pr.payments), 1)
+
+		invoices = [x.as_dict() for x in pr.invoices]
+		payments = [x.as_dict() for x in pr.payments]
+		pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
+		pr.reconcile()
+
+		pr.get_unreconciled_entries()
+
+		self.assertEqual(len(pr.invoices), 0)
+		self.assertEqual(len(pr.payments), 0)
+
+		pr.from_invoice_date = pr.from_payment_date = to_date
+		pr.to_invoice_date = pr.to_payment_date = to_date
+
+		pr.get_unreconciled_entries()
+
+		self.assertEqual(len(pr.invoices), 0)
+
 	def test_filter_invoice_limit(self):
 		# check filter condition - invoice limit
 		transaction_date = nowdate()
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 98f3420..1d596c1 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -36,6 +36,15 @@
 		});
 
 		set_html_data(frm);
+
+		if (frm.doc.docstatus == 1) {
+			if (!frm.doc.posting_date) {
+				frm.set_value("posting_date", frappe.datetime.nowdate());
+			}
+			if (!frm.doc.posting_time) {
+				frm.set_value("posting_time", frappe.datetime.now_time());
+			}
+		}
 	},
 
 	refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
index d6e35c6..9d15e6c 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
@@ -11,6 +11,7 @@
   "period_end_date",
   "column_break_3",
   "posting_date",
+  "posting_time",
   "pos_opening_entry",
   "status",
   "section_break_5",
@@ -51,7 +52,6 @@
    "fieldtype": "Datetime",
    "in_list_view": 1,
    "label": "Period End Date",
-   "read_only": 1,
    "reqd": 1
   },
   {
@@ -219,6 +219,13 @@
    "fieldtype": "Small Text",
    "label": "Error",
    "read_only": 1
+  },
+  {
+   "fieldname": "posting_time",
+   "fieldtype": "Time",
+   "label": "Posting Time",
+   "no_copy": 1,
+   "reqd": 1
   }
  ],
  "is_submittable": 1,
@@ -228,10 +235,11 @@
    "link_fieldname": "pos_closing_entry"
   }
  ],
- "modified": "2021-10-20 16:19:25.340565",
+ "modified": "2022-08-01 11:37:14.991228",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Closing Entry",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -278,5 +286,6 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
index 49aab0d..655c4ec 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
@@ -15,6 +15,9 @@
 
 class POSClosingEntry(StatusUpdater):
 	def validate(self):
+		self.posting_date = self.posting_date or frappe.utils.nowdate()
+		self.posting_time = self.posting_time or frappe.utils.nowtime()
+
 		if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open":
 			frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry"))
 
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json
index d762087..a059455 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json
@@ -6,6 +6,7 @@
  "engine": "InnoDB",
  "field_order": [
   "posting_date",
+  "posting_time",
   "merge_invoices_based_on",
   "column_break_3",
   "pos_closing_entry",
@@ -105,12 +106,19 @@
    "label": "Customer Group",
    "mandatory_depends_on": "eval:doc.merge_invoices_based_on == 'Customer Group'",
    "options": "Customer Group"
+  },
+  {
+   "fieldname": "posting_time",
+   "fieldtype": "Time",
+   "label": "Posting Time",
+   "no_copy": 1,
+   "reqd": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-09-14 11:17:19.001142",
+ "modified": "2022-08-01 11:36:42.456429",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Invoice Merge Log",
@@ -173,5 +181,6 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
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 5003a1d..81a234a 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
@@ -9,7 +9,7 @@
 from frappe.core.page.background_jobs.background_jobs import get_info
 from frappe.model.document import Document
 from frappe.model.mapper import map_child_doc, map_doc
-from frappe.utils import cint, flt, getdate, nowdate
+from frappe.utils import cint, flt, get_time, getdate, nowdate, nowtime
 from frappe.utils.background_jobs import enqueue
 from frappe.utils.scheduler import is_scheduler_inactive
 
@@ -99,6 +99,7 @@
 		sales_invoice.is_consolidated = 1
 		sales_invoice.set_posting_time = 1
 		sales_invoice.posting_date = getdate(self.posting_date)
+		sales_invoice.posting_time = get_time(self.posting_time)
 		sales_invoice.save()
 		sales_invoice.submit()
 
@@ -115,6 +116,7 @@
 		credit_note.is_consolidated = 1
 		credit_note.set_posting_time = 1
 		credit_note.posting_date = getdate(self.posting_date)
+		credit_note.posting_time = get_time(self.posting_time)
 		# TODO: return could be against multiple sales invoice which could also have been consolidated?
 		# credit_note.return_against = self.consolidated_invoice
 		credit_note.save()
@@ -402,6 +404,9 @@
 				merge_log.posting_date = (
 					getdate(closing_entry.get("posting_date")) if closing_entry else nowdate()
 				)
+				merge_log.posting_time = (
+					get_time(closing_entry.get("posting_time")) if closing_entry else nowtime()
+				)
 				merge_log.customer = customer
 				merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None
 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index de3927e..e6ff128 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1791,4 +1791,6 @@
 		target_doc,
 	)
 
+	doc.set_onload("ignore_price_list", True)
+
 	return doc
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index ba4cdd6..73ec051 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -479,9 +479,13 @@
 
 	is_cash_or_non_trade_discount() {
 		this.frm.set_df_property("additional_discount_account", "hidden", 1 - this.frm.doc.is_cash_or_non_trade_discount);
+		this.frm.set_df_property("additional_discount_account", "reqd", this.frm.doc.is_cash_or_non_trade_discount);
+
 		if (!this.frm.doc.is_cash_or_non_trade_discount) {
 			this.frm.set_value("additional_discount_account", "");
 		}
+
+		this.calculate_taxes_and_totals();
 	}
 };
 
@@ -1024,7 +1028,7 @@
 		]
 	});
 
-	dialog.set_primary_action(__("Set"), function() {
+	dialog.set_primary_action(__("Set Loyalty Program"), function() {
 		dialog.hide();
 		return frappe.call({
 			method: "frappe.client.set_value",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index f8c26d1..4008863 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1033,22 +1033,6 @@
 				)
 			)
 
-		if self.apply_discount_on == "Grand Total" and self.get("is_cash_or_discount_account"):
-			gl_entries.append(
-				self.get_gl_dict(
-					{
-						"account": self.additional_discount_account,
-						"against": self.debit_to,
-						"debit": self.base_discount_amount,
-						"debit_in_account_currency": self.discount_amount,
-						"cost_center": self.cost_center,
-						"project": self.project,
-					},
-					self.currency,
-					item=self,
-				)
-			)
-
 	def make_tax_gl_entries(self, gl_entries):
 		enable_discount_accounting = cint(
 			frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
@@ -2103,13 +2087,13 @@
 		target_detail_field = "sales_invoice_item" if doctype == "Sales Invoice" else "sales_order_item"
 		source_document_warehouse_field = "target_warehouse"
 		target_document_warehouse_field = "from_warehouse"
+		received_items = get_received_items(source_name, target_doctype, target_detail_field)
 	else:
 		source_doc = frappe.get_doc(doctype, source_name)
 		target_doctype = "Sales Invoice" if doctype == "Purchase Invoice" else "Sales Order"
 		source_document_warehouse_field = "from_warehouse"
 		target_document_warehouse_field = "target_warehouse"
-
-	received_items = get_received_items(source_name, target_doctype, target_detail_field)
+		received_items = {}
 
 	validate_inter_company_transaction(source_doc, doctype)
 	details = get_inter_company_details(source_doc, doctype)
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 a519d8b..6004e2b 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -318,7 +318,6 @@
 		"is_cancelled": 0,
 		"party_type": party_type,
 		"party": ["in", parties],
-		"against_voucher": ["is", "not set"],
 	}
 
 	if company:
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index e39f22b..67cf644 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -207,7 +207,7 @@
 			)
 
 	if company_address:
-		party_details.update({"company_address": company_address})
+		party_details.company_address = company_address
 	else:
 		party_details.update(get_company_address(company))
 
@@ -219,12 +219,31 @@
 		get_regional_address_details(party_details, doctype, company)
 
 	elif doctype and doctype in ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]:
-		if party_details.company_address:
-			party_details["shipping_address"] = shipping_address or party_details["company_address"]
-			party_details.shipping_address_display = get_address_display(party_details["shipping_address"])
+		if shipping_address:
 			party_details.update(
-				get_fetch_values(doctype, "shipping_address", party_details.shipping_address)
+				shipping_address=shipping_address,
+				shipping_address_display=get_address_display(shipping_address),
+				**get_fetch_values(doctype, "shipping_address", shipping_address)
 			)
+
+		if party_details.company_address:
+			# billing address
+			party_details.update(
+				billing_address=party_details.company_address,
+				billing_address_display=(
+					party_details.company_address_display or get_address_display(party_details.company_address)
+				),
+				**get_fetch_values(doctype, "billing_address", party_details.company_address)
+			)
+
+			# shipping address - if not already set
+			if not party_details.shipping_address:
+				party_details.update(
+					shipping_address=party_details.billing_address,
+					shipping_address_display=party_details.billing_address_display,
+					**get_fetch_values(doctype, "shipping_address", party_details.billing_address)
+				)
+
 		get_regional_address_details(party_details, doctype, company)
 
 	return party_details.get(billing_address_field), party_details.shipping_address_name
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 526ea9d..54af225 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -616,7 +616,7 @@
 						previous_stock_value = len(my_sle) > i + 1 and flt(my_sle[i + 1].stock_value) or 0.0
 
 						if previous_stock_value:
-							return (previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
+							return abs(previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
 						else:
 							return flt(row.qty) * self.get_average_buying_rate(row, item_code)
 			else:
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
index 08d2008..db3d5d4 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
@@ -14,9 +14,9 @@
 	filters.naming_series = frappe.db.get_single_value("Buying Settings", "supp_master_name")
 
 	columns = get_columns(filters)
-	tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters)
+	tds_docs, tds_accounts, tax_category_map, journal_entry_party_map = get_tds_docs(filters)
 
-	res = get_result(filters, tds_docs, tds_accounts, tax_category_map)
+	res = get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map)
 	final_result = group_by_supplier_and_category(res)
 
 	return columns, final_result
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
index 16e0ac1..f2809a9 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
@@ -26,7 +26,6 @@
 	supplier_map = get_supplier_pan_map()
 	tax_rate_map = get_tax_rate_map(filters)
 	gle_map = get_gle_map(tds_docs)
-	print(journal_entry_party_map)
 
 	out = []
 	for name, details in gle_map.items():
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 9dafef7..018e8f9 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -823,7 +823,13 @@
 
 
 def get_outstanding_invoices(
-	party_type, party, account, common_filter=None, min_outstanding=None, max_outstanding=None
+	party_type,
+	party,
+	account,
+	common_filter=None,
+	posting_date=None,
+	min_outstanding=None,
+	max_outstanding=None,
 ):
 
 	ple = qb.DocType("Payment Ledger Entry")
@@ -850,6 +856,7 @@
 	ple_query = QueryPaymentLedger()
 	invoice_list = ple_query.get_voucher_outstandings(
 		common_filter=common_filter,
+		posting_date=posting_date,
 		min_outstanding=min_outstanding,
 		max_outstanding=max_outstanding,
 		get_invoices=True,
@@ -1501,6 +1508,7 @@
 		# query filters
 		self.vouchers = []
 		self.common_filter = []
+		self.voucher_posting_date = []
 		self.min_outstanding = None
 		self.max_outstanding = None
 
@@ -1571,6 +1579,7 @@
 			.where(ple.delinked == 0)
 			.where(Criterion.all(filter_on_voucher_no))
 			.where(Criterion.all(self.common_filter))
+			.where(Criterion.all(self.voucher_posting_date))
 			.groupby(ple.voucher_type, ple.voucher_no, ple.party_type, ple.party)
 		)
 
@@ -1652,6 +1661,7 @@
 		self,
 		vouchers=None,
 		common_filter=None,
+		posting_date=None,
 		min_outstanding=None,
 		max_outstanding=None,
 		get_payments=False,
@@ -1671,6 +1681,7 @@
 		self.reset()
 		self.vouchers = vouchers
 		self.common_filter = common_filter or []
+		self.voucher_posting_date = posting_date or []
 		self.min_outstanding = min_outstanding
 		self.max_outstanding = max_outstanding
 		self.get_payments = get_payments
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index 4e29ee5..31a4837 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -15,9 +15,12 @@
 		frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn) {
 			let d = locals[cdt][cdn];
 			return {
-				query: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_supplier_contacts",
-				filters: {'supplier': d.supplier}
-			}
+				query: "frappe.contacts.doctype.contact.contact.contact_query",
+				filters: {
+					link_doctype: "Supplier",
+					link_name: d.supplier || ""
+				}
+			};
 		}
 	},
 
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index 3ef57bb..ee28eb6 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -287,18 +287,6 @@
 
 
 @frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
-	return frappe.db.sql(
-		"""select `tabContact`.name from `tabContact`, `tabDynamic Link`
-		where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s
-		and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
-		limit %(page_len)s offset %(start)s""",
-		{"start": start, "page_len": page_len, "txt": "%%%s%%" % txt, "name": filters.get("supplier")},
-	)
-
-
-@frappe.whitelist()
 def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier=None):
 	def postprocess(source, target_doc):
 		if for_supplier:
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
index c772c1a..d13d970 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
@@ -4,6 +4,8 @@
 # Decompiled by https://python-decompiler.com
 
 
+import copy
+
 import frappe
 from frappe.tests.utils import FrappeTestCase
 
@@ -11,10 +13,12 @@
 	execute,
 )
 from erpnext.controllers.tests.test_subcontracting_controller import (
+	get_rm_items,
 	get_subcontracting_order,
 	make_service_item,
+	make_stock_in_entry,
+	make_stock_transfer_entry,
 )
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
 	make_subcontracting_receipt,
 )
@@ -36,15 +40,18 @@
 		sco = get_subcontracting_order(
 			service_items=service_items, supplier_warehouse="_Test Warehouse 1 - _TC"
 		)
-		make_stock_entry(
-			item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+
+		for item in rm_items:
+			item["sco_rm_detail"] = sco.items[0].name
+
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
 		)
-		make_stock_entry(
-			item_code="_Test Item Home Desktop 100",
-			target="_Test Warehouse 1 - _TC",
-			qty=100,
-			basic_rate=100,
-		)
+
 		make_subcontracting_receipt_against_sco(sco.name)
 		sco.reload()
 		col, data = execute(
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 70d2bc6..e689d56 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1109,17 +1109,17 @@
 				frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
 			)
 
+		if self.doctype == "Purchase Invoice":
+			dr_or_cr = "credit"
+			rev_dr_cr = "debit"
+			supplier_or_customer = self.supplier
+
+		else:
+			dr_or_cr = "debit"
+			rev_dr_cr = "credit"
+			supplier_or_customer = self.customer
+
 		if enable_discount_accounting:
-			if self.doctype == "Purchase Invoice":
-				dr_or_cr = "credit"
-				rev_dr_cr = "debit"
-				supplier_or_customer = self.supplier
-
-			else:
-				dr_or_cr = "debit"
-				rev_dr_cr = "credit"
-				supplier_or_customer = self.customer
-
 			for item in self.get("items"):
 				if item.get("discount_amount") and item.get("discount_account"):
 					discount_amount = item.discount_amount * item.qty
@@ -1173,18 +1173,22 @@
 						)
 					)
 
-			if self.get("discount_amount") and self.get("additional_discount_account"):
-				gl_entries.append(
-					self.get_gl_dict(
-						{
-							"account": self.additional_discount_account,
-							"against": supplier_or_customer,
-							dr_or_cr: self.discount_amount,
-							"cost_center": self.cost_center,
-						},
-						item=self,
-					)
+		if (
+			(enable_discount_accounting or self.get("is_cash_or_non_trade_discount"))
+			and self.get("additional_discount_account")
+			and self.get("discount_amount")
+		):
+			gl_entries.append(
+				self.get_gl_dict(
+					{
+						"account": self.additional_discount_account,
+						"against": supplier_or_customer,
+						dr_or_cr: self.discount_amount,
+						"cost_center": self.cost_center,
+					},
+					item=self,
 				)
+			)
 
 	def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
 		from erpnext.controllers.status_updater import get_allowance_for
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 036733c..7ab8f81 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -86,6 +86,7 @@
 					company=self.company,
 					party_address=self.get("supplier_address"),
 					shipping_address=self.get("shipping_address"),
+					company_address=self.get("billing_address"),
 					fetch_payment_terms_template=not self.get("ignore_default_payment_terms_template"),
 					ignore_permissions=self.flags.ignore_permissions,
 				)
@@ -307,7 +308,8 @@
 
 					rate = flt(outgoing_rate * (d.conversion_factor or 1), d.precision("rate"))
 				else:
-					rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), "rate")
+					field = "incoming_rate" if self.get("is_internal_supplier") else "rate"
+					rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), field)
 
 				if self.is_internal_transfer():
 					if rate != d.rate:
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index e27718a..36bed36 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -36,6 +36,10 @@
 	pass
 
 
+class BatchExpiredError(frappe.ValidationError):
+	pass
+
+
 class StockController(AccountsController):
 	def validate(self):
 		super(StockController, self).validate()
@@ -77,6 +81,10 @@
 	def validate_serialized_batch(self):
 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 
+		is_material_issue = False
+		if self.doctype == "Stock Entry" and self.purpose == "Material Issue":
+			is_material_issue = True
+
 		for d in self.get("items"):
 			if hasattr(d, "serial_no") and hasattr(d, "batch_no") and d.serial_no and d.batch_no:
 				serial_nos = frappe.get_all(
@@ -93,6 +101,9 @@
 							)
 						)
 
+			if is_material_issue:
+				continue
+
 			if flt(d.qty) > 0.0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
 				expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
 
@@ -100,7 +111,8 @@
 					frappe.throw(
 						_("Row #{0}: The batch {1} has already expired.").format(
 							d.idx, get_link_to_form("Batch", d.get("batch_no"))
-						)
+						),
+						BatchExpiredError,
 					)
 
 	def clean_serial_nos(self):
@@ -310,7 +322,13 @@
 			)
 			if (
 				self.doctype
-				not in ("Purchase Receipt", "Purchase Invoice", "Stock Reconciliation", "Stock Entry")
+				not in (
+					"Purchase Receipt",
+					"Purchase Invoice",
+					"Stock Reconciliation",
+					"Stock Entry",
+					"Subcontracting Receipt",
+				)
 				and not is_expense_account
 			):
 				frappe.throw(
@@ -374,9 +392,24 @@
 	def update_inventory_dimensions(self, row, sl_dict) -> None:
 		dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self)
 		for dimension in dimensions:
-			if dimension and row.get(dimension.source_fieldname):
+			if not dimension:
+				continue
+
+			if row.get(dimension.source_fieldname):
 				sl_dict[dimension.target_fieldname] = row.get(dimension.source_fieldname)
 
+			if not sl_dict.get(dimension.target_fieldname) and dimension.fetch_from_parent:
+				sl_dict[dimension.target_fieldname] = self.get(dimension.fetch_from_parent)
+
+				# Get value based on doctype name
+				if not sl_dict.get(dimension.target_fieldname):
+					fieldname = frappe.get_cached_value(
+						"DocField", {"parent": self.doctype, "options": dimension.fetch_from_parent}, "fieldname"
+					)
+
+					if fieldname and self.get(fieldname):
+						sl_dict[dimension.target_fieldname] = self.get(fieldname)
+
 	def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
 		from erpnext.stock.stock_ledger import make_sl_entries
 
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 2a2f8f5..1372c89 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -490,7 +490,7 @@
 						row.item_code,
 						row.get(self.subcontract_data.order_field),
 					) and transfer_item.qty > 0:
-						qty = self.__get_qty_based_on_material_transfer(row, transfer_item) or 0
+						qty = flt(self.__get_qty_based_on_material_transfer(row, transfer_item))
 						transfer_item.qty -= qty
 						self.__add_supplied_item(row, transfer_item.get("item_details"), qty)
 
@@ -720,6 +720,25 @@
 					sco_doc = frappe.get_doc("Subcontracting Order", sco)
 					sco_doc.update_status()
 
+	def set_missing_values_in_additional_costs(self):
+		self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs"))
+
+		if self.total_additional_costs:
+			if self.distribute_additional_costs_based_on == "Amount":
+				total_amt = sum(flt(item.amount) for item in self.get("items"))
+				for item in self.items:
+					item.additional_cost_per_qty = (
+						(item.amount * self.total_additional_costs) / total_amt
+					) / item.qty
+			else:
+				total_qty = sum(flt(item.qty) for item in self.get("items"))
+				additional_cost_per_qty = self.total_additional_costs / total_qty
+				for item in self.items:
+					item.additional_cost_per_qty = additional_cost_per_qty
+		else:
+			for item in self.items:
+				item.additional_cost_per_qty = 0
+
 	@frappe.whitelist()
 	def get_current_stock(self):
 		if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]:
@@ -730,7 +749,7 @@
 						{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
 						"actual_qty",
 					)
-					item.current_stock = flt(actual_qty) or 0
+					item.current_stock = flt(actual_qty)
 
 	@property
 	def sub_contracted_items(self):
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 0d8cffe..bc38d08 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -37,6 +37,11 @@
 			self.set_discount_amount()
 			self.apply_discount_amount()
 
+		# Update grand total as per cash and non trade discount
+		if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
+			self.doc.grand_total -= self.doc.discount_amount
+			self.doc.base_grand_total -= self.doc.base_discount_amount
+
 		self.calculate_shipping_charges()
 
 		if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
@@ -500,9 +505,6 @@
 		else:
 			self.doc.grand_total = flt(self.doc.net_total)
 
-		if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
-			self.doc.grand_total -= self.doc.discount_amount
-
 		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),
@@ -597,16 +599,16 @@
 			if not self.doc.apply_discount_on:
 				frappe.throw(_("Please select Apply Discount On"))
 
+			self.doc.base_discount_amount = flt(
+				self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
+			)
+
 			if self.doc.apply_discount_on == "Grand Total" and self.doc.get(
 				"is_cash_or_non_trade_discount"
 			):
 				self.discount_amount_applied = True
 				return
 
-			self.doc.base_discount_amount = flt(
-				self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
-			)
-
 			total_for_discount_amount = self.get_total_for_discount_amount()
 			taxes = self.doc.get("taxes")
 			net_total = 0
diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py
index 4fab805..bc503f5 100644
--- a/erpnext/controllers/tests/test_subcontracting_controller.py
+++ b/erpnext/controllers/tests/test_subcontracting_controller.py
@@ -36,6 +36,36 @@
 		sco.remove_empty_rows()
 		self.assertEqual((len_before - 1), len(sco.service_items))
 
+	def test_set_missing_values_in_additional_costs(self):
+		sco = get_subcontracting_order(do_not_submit=1)
+
+		rate_without_additional_cost = sco.items[0].rate
+		amount_without_additional_cost = sco.items[0].amount
+
+		additional_amount = 120
+		sco.append(
+			"additional_costs",
+			{
+				"expense_account": "Cost of Goods Sold - _TC",
+				"description": "Test",
+				"amount": additional_amount,
+			},
+		)
+		sco.save()
+
+		additional_cost_per_qty = additional_amount / sco.items[0].qty
+
+		self.assertEqual(sco.items[0].additional_cost_per_qty, additional_cost_per_qty)
+		self.assertEqual(rate_without_additional_cost + additional_cost_per_qty, sco.items[0].rate)
+		self.assertEqual(amount_without_additional_cost + additional_amount, sco.items[0].amount)
+
+		sco.additional_costs = []
+		sco.save()
+
+		self.assertEqual(sco.items[0].additional_cost_per_qty, 0)
+		self.assertEqual(rate_without_additional_cost, sco.items[0].rate)
+		self.assertEqual(amount_without_additional_cost, sco.items[0].amount)
+
 	def test_create_raw_materials_supplied(self):
 		sco = get_subcontracting_order()
 		sco.supplied_items = None
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index c946ae4..99c00ad 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -340,8 +340,8 @@
    "fieldname": "no_of_employees",
    "fieldtype": "Select",
    "label": "No of Employees",
-   "options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
-  }, 
+   "options": "1-10\n11-50\n51-200\n201-500\n501-1000\n1000+"
+  },
   {
    "fieldname": "column_break_22",
    "fieldtype": "Column Break"
@@ -514,7 +514,7 @@
  "idx": 5,
  "image_field": "image",
  "links": [],
- "modified": "2022-07-22 15:55:03.176094",
+ "modified": "2022-08-09 18:26:17.101521",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Lead",
diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json
index 68a2156..fed0c7c 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.json
+++ b/erpnext/crm/doctype/opportunity/opportunity.json
@@ -463,7 +463,7 @@
    "fieldname": "no_of_employees",
    "fieldtype": "Select",
    "label": "No of Employees",
-   "options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
+   "options": "1-10\n11-50\n51-200\n201-500\n501-1000\n1000+"
   },
   {
    "fieldname": "annual_revenue",
@@ -622,7 +622,7 @@
  "icon": "fa fa-info-sign",
  "idx": 195,
  "links": [],
- "modified": "2022-07-22 18:46:32.858696",
+ "modified": "2022-08-09 18:26:37.235964",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Opportunity",
diff --git a/erpnext/crm/doctype/prospect/prospect.json b/erpnext/crm/doctype/prospect/prospect.json
index 7f33c08..820a6c7 100644
--- a/erpnext/crm/doctype/prospect/prospect.json
+++ b/erpnext/crm/doctype/prospect/prospect.json
@@ -82,7 +82,7 @@
    "fieldname": "no_of_employees",
    "fieldtype": "Select",
    "label": "No. of Employees",
-   "options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
+   "options": "1-10\n11-50\n51-200\n201-500\n501-1000\n1000+"
   },
   {
    "fieldname": "annual_revenue",
@@ -218,7 +218,7 @@
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2022-06-22 15:10:26.887502",
+ "modified": "2022-08-09 18:26:56.950185",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Prospect",
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
index 7d676e4..cd4aaee 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
@@ -12,7 +12,9 @@
 import frappe
 from bs4 import BeautifulSoup as bs
 from frappe import _
-from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.custom.doctype.custom_field.custom_field import (
+	create_custom_fields as _create_custom_fields,
+)
 from frappe.model.document import Document
 from frappe.utils.data import format_datetime
 
@@ -577,22 +579,25 @@
 				new_year.save()
 				oldest_year = new_year
 
-		def create_custom_fields(doctypes):
-			tally_guid_df = {
-				"fieldtype": "Data",
-				"fieldname": "tally_guid",
-				"read_only": 1,
-				"label": "Tally GUID",
-			}
-			tally_voucher_no_df = {
-				"fieldtype": "Data",
-				"fieldname": "tally_voucher_no",
-				"read_only": 1,
-				"label": "Tally Voucher Number",
-			}
-			for df in [tally_guid_df, tally_voucher_no_df]:
-				for doctype in doctypes:
-					create_custom_field(doctype, df)
+		def create_custom_fields():
+			_create_custom_fields(
+				{
+					("Journal Entry", "Purchase Invoice", "Sales Invoice"): [
+						{
+							"fieldtype": "Data",
+							"fieldname": "tally_guid",
+							"read_only": 1,
+							"label": "Tally GUID",
+						},
+						{
+							"fieldtype": "Data",
+							"fieldname": "tally_voucher_no",
+							"read_only": 1,
+							"label": "Tally Voucher Number",
+						},
+					]
+				}
+			)
 
 		def create_price_list():
 			frappe.get_doc(
@@ -628,7 +633,7 @@
 
 			create_fiscal_years(vouchers)
 			create_price_list()
-			create_custom_fields(["Journal Entry", "Purchase Invoice", "Sales Invoice"])
+			create_custom_fields()
 
 			total = len(vouchers)
 			is_last = False
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index 2e18776..4aa98aa 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -6,7 +6,7 @@
 
 import frappe
 from frappe import _
-from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 from frappe.model.document import Document
 from frappe.utils.nestedset import get_root_of
 
@@ -19,27 +19,24 @@
 
 	def create_delete_custom_fields(self):
 		if self.enable_sync:
-			custom_fields = {}
-			# create
-			for doctype in ["Customer", "Sales Order", "Item", "Address"]:
-				df = dict(
-					fieldname="woocommerce_id",
-					label="Woocommerce ID",
-					fieldtype="Data",
-					read_only=1,
-					print_hide=1,
-				)
-				create_custom_field(doctype, df)
-
-			for doctype in ["Customer", "Address"]:
-				df = dict(
-					fieldname="woocommerce_email",
-					label="Woocommerce Email",
-					fieldtype="Data",
-					read_only=1,
-					print_hide=1,
-				)
-				create_custom_field(doctype, df)
+			create_custom_fields(
+				{
+					("Customer", "Sales Order", "Item", "Address"): dict(
+						fieldname="woocommerce_id",
+						label="Woocommerce ID",
+						fieldtype="Data",
+						read_only=1,
+						print_hide=1,
+					),
+					("Customer", "Address"): dict(
+						fieldname="woocommerce_email",
+						label="Woocommerce Email",
+						fieldtype="Data",
+						read_only=1,
+						print_hide=1,
+					),
+				}
+			)
 
 			if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}):
 				item_group = frappe.new_doc("Item Group")
diff --git a/erpnext/erpnext_integrations/exotel_integration.py b/erpnext/erpnext_integrations/exotel_integration.py
index fd9f74e..fd0f783 100644
--- a/erpnext/erpnext_integrations/exotel_integration.py
+++ b/erpnext/erpnext_integrations/exotel_integration.py
@@ -26,6 +26,7 @@
 	except Exception as e:
 		frappe.db.rollback()
 		exotel_settings.log_error("Error in Exotel incoming call")
+		frappe.db.commit()
 
 
 @frappe.whitelist(allow_guest=True)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index aa10e31..a08feb4 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -507,6 +507,7 @@
 	"Shipping Rule",
 	"Landed Cost Item",
 	"Asset Value Adjustment",
+	"Asset Repair",
 	"Loyalty Program",
 	"Stock Reconciliation",
 	"POS Profile",
@@ -519,6 +520,10 @@
 	"Purchase Order",
 	"Purchase Receipt",
 	"Sales Order",
+	"Subcontracting Order",
+	"Subcontracting Order Item",
+	"Subcontracting Receipt",
+	"Subcontracting Receipt Item",
 ]
 
 # get matching queries for Bank Reconciliation
diff --git a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
index 0a576d6..514a5fc 100644
--- a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
@@ -99,7 +99,7 @@
 		loan_account = frappe.db.get_value("Loan", self.loan, "loan_account")
 		remarks = "{} against loan {}".format(self.adjustment_type.capitalize(), self.loan)
 		if self.reference_number:
-			remarks += "with reference no. {}".format(self.reference_number)
+			remarks += " with reference no. {}".format(self.reference_number)
 
 		loan_entry = {
 			"account": loan_account,
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
index 50926d7..c7b5c03 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
@@ -163,11 +163,11 @@
   },
   {
    "fetch_from": "against_loan.disbursement_account",
+   "fetch_if_empty": 1,
    "fieldname": "disbursement_account",
    "fieldtype": "Link",
    "label": "Disbursement Account",
-   "options": "Account",
-   "read_only": 1
+   "options": "Account"
   },
   {
    "fieldname": "column_break_16",
@@ -185,7 +185,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-02-17 18:23:44.157598",
+ "modified": "2022-08-04 17:16:04.922444",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Disbursement",
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index 0c2042b..b73dee2 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -209,6 +209,9 @@
 			"loan_amount",
 			"disbursed_amount",
 			"total_payment",
+			"debit_adjustment_amount",
+			"credit_adjustment_amount",
+			"refund_amount",
 			"total_principal_paid",
 			"total_interest_payable",
 			"status",
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
index 0aeb448..6d62aef 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
@@ -135,7 +135,11 @@
 def make_accrual_interest_entry_for_demand_loans(
 	posting_date, process_loan_interest, open_loans=None, loan_type=None, accrual_type="Regular"
 ):
-	query_filters = {"status": ("in", ["Disbursed", "Partially Disbursed"]), "docstatus": 1}
+	query_filters = {
+		"status": ("in", ["Disbursed", "Partially Disbursed"]),
+		"docstatus": 1,
+		"is_term_loan": 0,
+	}
 
 	if loan_type:
 		query_filters.update({"loan_type": loan_type})
@@ -147,6 +151,9 @@
 				"name",
 				"total_payment",
 				"total_amount_paid",
+				"debit_adjustment_amount",
+				"credit_adjustment_amount",
+				"refund_amount",
 				"loan_account",
 				"interest_income_account",
 				"loan_amount",
@@ -229,6 +236,7 @@
 			AND l.is_term_loan =1
 			AND rs.payment_date <= %s
 			AND rs.is_accrued=0 {0}
+			AND rs.interest_amount > 0
 			AND l.status = 'Disbursed'
 			ORDER BY rs.payment_date""".format(
 			condition
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 76dc8b4..3e7dc28 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -264,11 +264,11 @@
   },
   {
    "fetch_from": "against_loan.payment_account",
+   "fetch_if_empty": 1,
    "fieldname": "payment_account",
    "fieldtype": "Link",
    "label": "Repayment Account",
-   "options": "Account",
-   "read_only": 1
+   "options": "Account"
   },
   {
    "fieldname": "column_break_36",
@@ -294,7 +294,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-06-21 10:10:07.742298",
+ "modified": "2022-08-04 17:13:51.964203",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 07a1d0d..29da988 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -149,6 +149,9 @@
 				"status",
 				"is_secured_loan",
 				"total_payment",
+				"debit_adjustment_amount",
+				"credit_adjustment_amount",
+				"refund_amount",
 				"loan_amount",
 				"disbursed_amount",
 				"total_interest_payable",
@@ -398,7 +401,7 @@
 			remarks = "Repayment against loan " + self.against_loan
 
 		if self.reference_number:
-			remarks += "with reference no. {}".format(self.reference_number)
+			remarks += " with reference no. {}".format(self.reference_number)
 
 		if hasattr(self, "repay_from_salary") and self.repay_from_salary:
 			payment_account = self.payroll_payable_account
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index 0ab7beb..15a9c4a 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -57,6 +57,9 @@
 			self.loan,
 			[
 				"total_payment",
+				"debit_adjustment_amount",
+				"credit_adjustment_amount",
+				"refund_amount",
 				"total_principal_paid",
 				"loan_amount",
 				"total_interest_payable",
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
index 25aecf6..ae483f9 100644
--- a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
@@ -9,6 +9,9 @@
 import erpnext
 from erpnext.accounts.general_ledger import make_gl_entries
 from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import (
+	get_pending_principal_amount,
+)
 
 
 class LoanWriteOff(AccountsController):
@@ -22,16 +25,26 @@
 
 	def validate_write_off_amount(self):
 		precision = cint(frappe.db.get_default("currency_precision")) or 2
-		total_payment, principal_paid, interest_payable, written_off_amount = frappe.get_value(
+
+		loan_details = frappe.get_value(
 			"Loan",
 			self.loan,
-			["total_payment", "total_principal_paid", "total_interest_payable", "written_off_amount"],
+			[
+				"total_payment",
+				"debit_adjustment_amount",
+				"credit_adjustment_amount",
+				"refund_amount",
+				"total_principal_paid",
+				"loan_amount",
+				"total_interest_payable",
+				"written_off_amount",
+				"disbursed_amount",
+				"status",
+			],
+			as_dict=1,
 		)
 
-		pending_principal_amount = flt(
-			flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount),
-			precision,
-		)
+		pending_principal_amount = flt(get_pending_principal_amount(loan_details), precision)
 
 		if self.write_off_amount > pending_principal_amount:
 			frappe.throw(_("Write off amount cannot be greater than pending principal amount"))
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index b29f671..70637d3 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -189,8 +189,8 @@
 		self.validate_transfer_against()
 		self.set_routing_operations()
 		self.validate_operations()
-		self.update_exploded_items(save=False)
 		self.calculate_cost()
+		self.update_exploded_items(save=False)
 		self.update_stock_qty()
 		self.update_cost(update_parent=False, from_child_bom=True, update_hour_rate=False, save=False)
 		self.validate_scrap_items()
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index a190cc7..27f3cc9 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -611,6 +611,34 @@
 		bom.reload()
 		self.assertEqual(frappe.get_value("Item", fg_item.item_code, "default_bom"), bom.name)
 
+	def test_exploded_items_rate(self):
+		rm_item = make_item(
+			properties={"is_stock_item": 1, "valuation_rate": 99, "last_purchase_rate": 89}
+		).name
+		fg_item = make_item(properties={"is_stock_item": 1}).name
+
+		from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+		bom = make_bom(item=fg_item, raw_materials=[rm_item], do_not_save=True)
+
+		bom.rm_cost_as_per = "Last Purchase Rate"
+		bom.save()
+		self.assertEqual(bom.items[0].base_rate, 89)
+		self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate)
+
+		bom.rm_cost_as_per = "Price List"
+		bom.save()
+		self.assertEqual(bom.items[0].base_rate, 0.0)
+		self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate)
+
+		bom.rm_cost_as_per = "Valuation Rate"
+		bom.save()
+		self.assertEqual(bom.items[0].base_rate, 99)
+		self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate)
+
+		bom.submit()
+		self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate)
+
 
 def get_default_bom(item_code="_Test FG Item 2"):
 	return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json
index 0a8ae7b..c526611 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -184,6 +184,7 @@
    "in_list_view": 1,
    "label": "Rate",
    "options": "currency",
+   "read_only": 1,
    "reqd": 1
   },
   {
@@ -288,7 +289,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-05-19 02:32:43.785470",
+ "modified": "2022-07-28 10:20:51.559010",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM Item",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 70ccb78..2cdf8d3 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -482,7 +482,6 @@
 			"bom_no",
 			"stock_uom",
 			"bom_level",
-			"production_plan_item",
 			"schedule_date",
 		]:
 			if row.get(field):
@@ -639,6 +638,9 @@
 		sub_assembly_items_store = []  # temporary store to process all subassembly items
 
 		for row in self.po_items:
+			if not row.item_code:
+				frappe.throw(_("Row #{0}: Please select Item Code in Assembly Items").format(row.idx))
+
 			bom_data = []
 			get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
 			self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 040e791..e2415ad 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -11,8 +11,9 @@
 	get_warehouse_list,
 )
 from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError
+from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry as make_se_from_wo
 from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
-from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.item.test_item import create_item, make_item
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
 	create_stock_reconciliation,
@@ -583,9 +584,6 @@
 		Test Prod Plan impact via: SO -> Prod Plan -> WO -> SE -> SE (cancel)
 		"""
 		from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
-		from erpnext.manufacturing.doctype.work_order.work_order import (
-			make_stock_entry as make_se_from_wo,
-		)
 
 		make_stock_entry(
 			item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100
@@ -629,9 +627,6 @@
 	def test_production_plan_pending_qty_independent_items(self):
 		"Test Prod Plan impact if items are added independently (no from SO or MR)."
 		from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
-		from erpnext.manufacturing.doctype.work_order.work_order import (
-			make_stock_entry as make_se_from_wo,
-		)
 
 		make_stock_entry(
 			item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100
@@ -728,6 +723,57 @@
 		for po_item, subassy_item in zip(pp.po_items, pp.sub_assembly_items):
 			self.assertEqual(po_item.name, subassy_item.production_plan_item)
 
+	def test_produced_qty_for_multi_level_bom_item(self):
+		# Create Items and BOMs
+		rm_item = make_item(properties={"is_stock_item": 1}).name
+		sub_assembly_item = make_item(properties={"is_stock_item": 1}).name
+		fg_item = make_item(properties={"is_stock_item": 1}).name
+
+		make_stock_entry(
+			item_code=rm_item,
+			qty=60,
+			to_warehouse="Work In Progress - _TC",
+			rate=99,
+			purpose="Material Receipt",
+		)
+
+		make_bom(item=sub_assembly_item, raw_materials=[rm_item], rm_qty=3)
+		make_bom(item=fg_item, raw_materials=[sub_assembly_item], rm_qty=4)
+
+		# Step - 1: Create Production Plan
+		pln = create_production_plan(item_code=fg_item, planned_qty=5, skip_getting_mr_items=1)
+		pln.get_sub_assembly_items()
+
+		# Step - 2: Create Work Orders
+		pln.make_work_order()
+		work_orders = frappe.get_all("Work Order", filters={"production_plan": pln.name}, pluck="name")
+		sa_wo = fg_wo = None
+		for work_order in work_orders:
+			wo_doc = frappe.get_doc("Work Order", work_order)
+			if wo_doc.production_plan_item:
+				wo_doc.update(
+					{"wip_warehouse": "Work In Progress - _TC", "fg_warehouse": "Finished Goods - _TC"}
+				)
+				fg_wo = wo_doc.name
+			else:
+				wo_doc.update(
+					{"wip_warehouse": "Work In Progress - _TC", "fg_warehouse": "Work In Progress - _TC"}
+				)
+				sa_wo = wo_doc.name
+			wo_doc.submit()
+
+		# Step - 3: Complete Work Orders
+		se = frappe.get_doc(make_se_from_wo(sa_wo, "Manufacture"))
+		se.submit()
+
+		se = frappe.get_doc(make_se_from_wo(fg_wo, "Manufacture"))
+		se.submit()
+
+		# Step - 4: Check Production Plan Item Produced Qty
+		pln.load_from_db()
+		self.assertEqual(pln.status, "Completed")
+		self.assertEqual(pln.po_items[0].produced_qty, 5)
+
 
 def create_production_plan(**args):
 	"""
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index b556d99..a53c42c 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -26,6 +26,8 @@
 from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
 from erpnext.stock.utils import get_bin
 
+test_dependencies = ["BOM"]
+
 
 class TestWorkOrder(FrappeTestCase):
 	def setUp(self):
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 1d5f5d7..d92353a 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -268,6 +268,7 @@
 erpnext.patches.v13_0.show_india_localisation_deprecation_warning
 erpnext.patches.v13_0.show_hr_payroll_deprecation_warning
 erpnext.patches.v13_0.reset_corrupt_defaults
+erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
 
 [post_model_sync]
 execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
@@ -308,4 +309,6 @@
 erpnext.patches.v14_0.crm_ux_cleanup
 erpnext.patches.v14_0.remove_india_localisation # 14-07-2022
 erpnext.patches.v13_0.fix_number_and_frequency_for_monthly_depreciation
-erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
\ No newline at end of file
+erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
+erpnext.patches.v14_0.fix_crm_no_of_employees
+erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/create_accounting_dimensions_for_asset_repair.py b/erpnext/patches/v13_0/create_accounting_dimensions_for_asset_repair.py
new file mode 100644
index 0000000..61a5c86
--- /dev/null
+++ b/erpnext/patches/v13_0/create_accounting_dimensions_for_asset_repair.py
@@ -0,0 +1,29 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+
+
+def execute():
+	accounting_dimensions = frappe.db.get_all(
+		"Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"]
+	)
+
+	if not accounting_dimensions:
+		return
+
+	for d in accounting_dimensions:
+		doctype = "Asset Repair"
+		field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
+
+		if field:
+			continue
+
+		df = {
+			"fieldname": d.fieldname,
+			"label": d.label,
+			"fieldtype": "Link",
+			"options": d.document_type,
+			"insert_after": "accounting_dimensions_section",
+		}
+
+		create_custom_field(doctype, df, ignore_validate=True)
+		frappe.clear_cache(doctype=doctype)
diff --git a/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py b/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py
new file mode 100644
index 0000000..b349c07
--- /dev/null
+++ b/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py
@@ -0,0 +1,47 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+
+
+def execute():
+	accounting_dimensions = frappe.db.get_all(
+		"Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"]
+	)
+
+	if not accounting_dimensions:
+		return
+
+	count = 1
+	for d in accounting_dimensions:
+
+		if count % 2 == 0:
+			insert_after_field = "dimension_col_break"
+		else:
+			insert_after_field = "accounting_dimensions_section"
+
+		for doctype in [
+			"Subcontracting Order",
+			"Subcontracting Order Item",
+			"Subcontracting Receipt",
+			"Subcontracting Receipt Item",
+		]:
+
+			field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
+
+			if field:
+				continue
+
+			df = {
+				"fieldname": d.fieldname,
+				"label": d.label,
+				"fieldtype": "Link",
+				"options": d.document_type,
+				"insert_after": insert_after_field,
+			}
+
+			try:
+				create_custom_field(doctype, df, ignore_validate=True)
+				frappe.clear_cache(doctype=doctype)
+			except Exception:
+				pass
+
+		count += 1
diff --git a/erpnext/patches/v14_0/fix_crm_no_of_employees.py b/erpnext/patches/v14_0/fix_crm_no_of_employees.py
new file mode 100644
index 0000000..268eb95
--- /dev/null
+++ b/erpnext/patches/v14_0/fix_crm_no_of_employees.py
@@ -0,0 +1,26 @@
+import frappe
+
+
+def execute():
+	options = {
+		"11-20": "11-50",
+		"21-30": "11-50",
+		"31-100": "51-200",
+		"101-500": "201-500",
+		"500-1000": "501-1000",
+		">1000": "1000+",
+	}
+
+	for doctype in ("Lead", "Opportunity", "Prospect"):
+		frappe.reload_doctype(doctype)
+		for key, value in options.items():
+			frappe.db.sql(
+				"""
+                update `tab{doctype}`
+                set no_of_employees = %s
+                where no_of_employees = %s
+            """.format(
+					doctype=doctype
+				),
+				(value, key),
+			)
diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
index 27b0169..27c8fe4 100644
--- a/erpnext/portal/doctype/homepage_section/test_homepage_section.py
+++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
@@ -57,7 +57,11 @@
 		self.assertEqual(cards[0].h5.text, "Card 1")
 		self.assertEqual(cards[0].a["href"], "/card-1")
 		self.assertEqual(cards[1].p.text, "Subtitle 2")
-		self.assertEqual(cards[1].find(class_="website-image-lazy")["data-src"], "test.jpg")
+
+		img = cards[1].find(class_="card-img-top")
+
+		self.assertEqual(img["src"], "test.jpg")
+		self.assertEqual(img["loading"], "lazy")
 
 		# cleanup
 		frappe.db.rollback()
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index e78e4b6..a2be936 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -379,7 +379,7 @@
 			{fcond} {mcond}
 		order by
 			(case when locate(%(_txt)s, name) > 0 then locate(%(_txt)s, name) else 99999 end),
-			(case when locate(%(_txt)s, full_name) > 0 then locate(%(_txt)s, full_name) else 99999 end)
+			(case when locate(%(_txt)s, full_name) > 0 then locate(%(_txt)s, full_name) else 99999 end),
 			idx desc,
 			name, full_name
 		limit %(page_len)s offset %(start)s""".format(
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 16b0b4a..4c3e9dc 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -39,6 +39,12 @@
 		this._calculate_taxes_and_totals();
 		this.calculate_discount_amount();
 
+		// # Update grand total as per cash and non trade discount
+		if (this.frm.doc.apply_discount_on == "Grand Total" && this.frm.doc.is_cash_or_non_trade_discount) {
+			this.frm.doc.grand_total -= this.frm.doc.discount_amount;
+			this.frm.doc.base_grand_total -= this.frm.doc.base_discount_amount;
+		}
+
 		await this.calculate_shipping_charges();
 
 		// Advance calculation applicable to Sales /Purchase Invoice
@@ -633,6 +639,10 @@
 			this.frm.doc.base_discount_amount = flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate,
 				precision("base_discount_amount"));
 
+			if (this.frm.doc.apply_discount_on == "Grand Total" && this.frm.doc.is_cash_or_non_trade_discount) {
+				return;
+			}
+
 			var total_for_discount_amount = this.get_total_for_discount_amount();
 			var net_total = 0;
 			// calculate item amount after Discount Amount
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 85485fc..c0a8c9e 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1,7 +1,6 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-frappe.provide('erpnext.accounts.dimensions');
 
 erpnext.TransactionController = class TransactionController extends erpnext.taxes_and_totals {
 	setup() {
@@ -794,24 +793,6 @@
 				set_party_account(set_pricing);
 			});
 
-			// Get default company billing address in Purchase Invoice, Order and Receipt
-			if (this.frm.doc.company && frappe.meta.get_docfield(this.frm.doctype, "billing_address")) {
-				frappe.call({
-					method: "erpnext.setup.doctype.company.company.get_default_company_address",
-					args: {name: this.frm.doc.company, existing_address: this.frm.doc.billing_address || ""},
-					debounce: 2000,
-					callback: function(r) {
-						if (r.message) {
-							me.frm.set_value("billing_address", r.message);
-						} else {
-							if (frappe.meta.get_docfield(me.frm.doctype, 'company_address')) {
-								me.frm.set_value("company_address", "");
-							}
-						}
-					}
-				});
-			}
-
 		} else {
 			set_party_account(set_pricing);
 		}
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index a492b32..58594b0 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -3,25 +3,14 @@
 
 frappe.provide("erpnext.utils");
 
+const SALES_DOCTYPES = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice'];
+const PURCHASE_DOCTYPES = ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'];
+
 erpnext.utils.get_party_details = function(frm, method, args, callback) {
 	if (!method) {
 		method = "erpnext.accounts.party.get_party_details";
 	}
 
-	if (args) {
-		if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) {
-			if (frm.doc.company_address && (!args.company_address)) {
-				args.company_address = frm.doc.company_address;
-			}
-		}
-
-		if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) {
-			if (frm.doc.shipping_address && (!args.shipping_address)) {
-				args.shipping_address = frm.doc.shipping_address;
-			}
-		}
-	}
-
 	if (!args) {
 		if ((frm.doctype != "Purchase Order" && frm.doc.customer)
 			|| (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) {
@@ -45,41 +34,44 @@
 			};
 		}
 
-		if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) {
-			if (!args) {
+		if (!args) {
+			if (in_list(SALES_DOCTYPES, frm.doc.doctype)) {
 				args = {
 					party: frm.doc.customer || frm.doc.party_name,
 					party_type: 'Customer'
-				}
-			}
-			if (frm.doc.company_address && (!args.company_address)) {
-				args.company_address = frm.doc.company_address;
+				};
 			}
 
-			if (frm.doc.shipping_address_name &&(!args.shipping_address_name)) {
-				args.shipping_address_name = frm.doc.shipping_address_name;
-			}
-		}
-
-		if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) {
-			if (!args) {
+			if (in_list(PURCHASE_DOCTYPES, frm.doc.doctype)) {
 				args = {
 					party: frm.doc.supplier,
 					party_type: 'Supplier'
-				}
-			}
-
-			if (frm.doc.shipping_address && (!args.shipping_address)) {
-				args.shipping_address = frm.doc.shipping_address;
+				};
 			}
 		}
 
-		if (args) {
-			args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
-			args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template);
+		if (!args || !args.party) return;
+
+		args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
+		args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template);
+	}
+
+	if (in_list(SALES_DOCTYPES, frm.doc.doctype)) {
+		if (!args.company_address && frm.doc.company_address) {
+			args.company_address = frm.doc.company_address;
 		}
 	}
-	if (!args || !args.party) return;
+
+	if (in_list(PURCHASE_DOCTYPES, frm.doc.doctype)) {
+		if (!args.company_address && frm.doc.billing_address) {
+			args.company_address = frm.doc.billing_address;
+		}
+
+		if (!args.shipping_address && frm.doc.shipping_address) {
+			args.shipping_address = frm.doc.shipping_address;
+		}
+	}
+
 
 	if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
 		if (!erpnext.utils.validate_mandatory(frm, "Posting / Transaction Date",
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 13d5069..c12a9f8 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -253,16 +253,20 @@
 			"POS Invoice",
 			filters={"customer": ["like", "%{}%".format(search_term)], "status": status},
 			fields=fields,
+			page_length=limit,
 		)
 		invoices_by_name = frappe.db.get_all(
 			"POS Invoice",
 			filters={"name": ["like", "%{}%".format(search_term)], "status": status},
 			fields=fields,
+			page_length=limit,
 		)
 
 		invoice_list = invoices_by_customer + invoices_by_name
 	elif status:
-		invoice_list = frappe.db.get_all("POS Invoice", filters={"status": status}, fields=fields)
+		invoice_list = frappe.db.get_all(
+			"POS Invoice", filters={"status": status}, fields=fields, page_length=limit
+		)
 
 	return invoice_list
 
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index eacf480..e7dd211 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -524,7 +524,8 @@
 			const currency = this.events.get_frm().doc.currency;
 			const taxes_html = taxes.map(t => {
 				if (t.tax_amount_after_discount_amount == 0.0) return;
-				const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`;
+				// if tax rate is 0, don't print it.
+				const description = /[0-9]+/.test(t.description) ? t.description : ((t.rate != 0) ? `${t.description} @ ${t.rate}%`: t.description);
 				return `<div class="tax-row">
 					<div class="tax-label">${description}</div>
 					<div class="tax-value">${format_currency(t.tax_amount_after_discount_amount, currency)}</div>
diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
index eeb8523..40165c3 100644
--- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
+++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
@@ -130,7 +130,8 @@
 		if (!doc.taxes.length) return '';
 
 		let taxes_html = doc.taxes.map(t => {
-			const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`;
+			// if tax rate is 0, don't print it.
+			const description = /[0-9]+/.test(t.description) ? t.description : ((t.rate != 0) ? `${t.description} @ ${t.rate}%`: t.description);
 			return `
 				<div class="tax-row">
 					<div class="tax-label">${description}</div>
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 7d7e6b5..2076dde 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -4,7 +4,7 @@
 
 import frappe
 from frappe import _
-from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
 from frappe.utils import cint
 
@@ -83,35 +83,32 @@
 
 
 def create_print_setting_custom_fields():
-	create_custom_field(
-		"Print Settings",
+	create_custom_fields(
 		{
-			"label": _("Compact Item Print"),
-			"fieldname": "compact_item_print",
-			"fieldtype": "Check",
-			"default": 1,
-			"insert_after": "with_letterhead",
-		},
-	)
-	create_custom_field(
-		"Print Settings",
-		{
-			"label": _("Print UOM after Quantity"),
-			"fieldname": "print_uom_after_quantity",
-			"fieldtype": "Check",
-			"default": 0,
-			"insert_after": "compact_item_print",
-		},
-	)
-	create_custom_field(
-		"Print Settings",
-		{
-			"label": _("Print taxes with zero amount"),
-			"fieldname": "print_taxes_with_zero_amount",
-			"fieldtype": "Check",
-			"default": 0,
-			"insert_after": "allow_print_for_cancelled",
-		},
+			"Print Settings": [
+				{
+					"label": _("Compact Item Print"),
+					"fieldname": "compact_item_print",
+					"fieldtype": "Check",
+					"default": "1",
+					"insert_after": "with_letterhead",
+				},
+				{
+					"label": _("Print UOM after Quantity"),
+					"fieldname": "print_uom_after_quantity",
+					"fieldtype": "Check",
+					"default": "0",
+					"insert_after": "compact_item_print",
+				},
+				{
+					"label": _("Print taxes with zero amount"),
+					"fieldname": "print_taxes_with_zero_amount",
+					"fieldtype": "Check",
+					"default": "0",
+					"insert_after": "allow_print_for_cancelled",
+				},
+			]
+		}
 	)
 
 
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 3e470d4..271e2e0 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -473,7 +473,13 @@
 				"doctype": "Batch",
 				"batch_id": args.batch_id,
 				"item": args.item_code,
+				"expiry_date": args.expiry_date,
 			}
-		).insert()
+		)
+
+		if args.expiry_date:
+			batch.expiry_date = args.expiry_date
+
+		batch.insert()
 
 	return batch
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
index 91a21f4..07cb73b 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
@@ -35,14 +35,39 @@
 	refresh(frm) {
 		if (frm.doc.__onload && frm.doc.__onload.has_stock_ledger
 			&& frm.doc.__onload.has_stock_ledger.length) {
-			let msg = __('Stock transactions exists against this dimension, user can not update document.');
-			frm.dashboard.add_comment(msg, 'blue', true);
+			let allow_to_edit_fields = ['disabled', 'fetch_from_parent',
+				'type_of_transaction', 'condition'];
 
 			frm.fields.forEach((field) => {
-				if (field.df.fieldname !== 'disabled') {
+				if (!in_list(allow_to_edit_fields, field.df.fieldname)) {
 					frm.set_df_property(field.df.fieldname, "read_only", "1");
 				}
 			});
 		}
+
+		if (!frm.is_new()) {
+			frm.add_custom_button(__('Delete Dimension'), () => {
+				frm.trigger('delete_dimension');
+			});
+		}
+	},
+
+	delete_dimension(frm) {
+		let msg = (`
+			Custom fields related to this dimension will be deleted on deletion of dimension.
+			<br> Do you want to delete {0} dimension?
+		`);
+
+		frappe.confirm(__(msg, [frm.doc.name.bold()]), () => {
+			frappe.call({
+				method: 'erpnext.stock.doctype.inventory_dimension.inventory_dimension.delete_dimension',
+				args: {
+					dimension: frm.doc.name
+				},
+				callback: function() {
+					frappe.set_route('List', 'Inventory Dimension');
+				}
+			});
+		});
 	}
 });
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
index 8b334d1..03e7fda 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
@@ -1,6 +1,5 @@
 {
  "actions": [],
- "allow_rename": 1,
  "autoname": "field:dimension_name",
  "creation": "2022-06-17 13:04:16.554051",
  "doctype": "DocType",
@@ -22,6 +21,7 @@
   "document_type",
   "istable",
   "type_of_transaction",
+  "fetch_from_parent",
   "column_break_16",
   "condition",
   "applicable_condition_example_section",
@@ -101,12 +101,14 @@
    "fieldname": "target_fieldname",
    "fieldtype": "Data",
    "label": "Target Fieldname (Stock Ledger Entry)",
+   "no_copy": 1,
    "read_only": 1
   },
   {
    "fieldname": "source_fieldname",
    "fieldtype": "Data",
    "label": "Source Fieldname",
+   "no_copy": 1,
    "read_only": 1
   },
   {
@@ -123,7 +125,7 @@
    "fieldname": "type_of_transaction",
    "fieldtype": "Select",
    "label": "Type of Transaction",
-   "options": "\nInward\nOutward"
+   "options": "\nInward\nOutward\nBoth"
   },
   {
    "fieldname": "html_19",
@@ -140,11 +142,18 @@
   {
    "fieldname": "column_break_4",
    "fieldtype": "Column Break"
+  },
+  {
+   "depends_on": "istable",
+   "description": "Set fieldname or DocType name like Supplier, Customer etc.",
+   "fieldname": "fetch_from_parent",
+   "fieldtype": "Data",
+   "label": "Fetch Value From Parent Form"
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2022-07-19 21:06:11.824976",
+ "modified": "2022-08-17 11:43:24.722441",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Inventory Dimension",
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
index 5a9541f..4ff8f33 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
@@ -43,13 +43,37 @@
 			return
 
 		old_doc = self._doc_before_save
+		allow_to_edit_fields = [
+			"disabled",
+			"fetch_from_parent",
+			"type_of_transaction",
+			"condition",
+		]
+
 		for field in frappe.get_meta("Inventory Dimension").fields:
-			if field.fieldname != "disabled" and old_doc.get(field.fieldname) != self.get(field.fieldname):
+			if field.fieldname not in allow_to_edit_fields and old_doc.get(field.fieldname) != self.get(
+				field.fieldname
+			):
 				msg = f"""The user can not change value of the field {bold(field.label)} because
 					stock transactions exists against the dimension {bold(self.name)}."""
 
 				frappe.throw(_(msg), DoNotChangeError)
 
+	def on_trash(self):
+		self.delete_custom_fields()
+
+	def delete_custom_fields(self):
+		filters = {"fieldname": self.source_fieldname}
+
+		if self.document_type:
+			filters["dt"] = self.document_type
+
+		for field in frappe.get_all("Custom Field", filters=filters):
+			frappe.delete_doc("Custom Field", field.name)
+
+		msg = f"Deleted custom fields related to the dimension {self.name}"
+		frappe.msgprint(_(msg))
+
 	def reset_value(self):
 		if self.apply_to_all_doctypes:
 			self.istable = 0
@@ -76,30 +100,35 @@
 		self.add_custom_fields()
 
 	def add_custom_fields(self):
-		dimension_field = dict(
-			fieldname=self.source_fieldname,
-			fieldtype="Link",
-			insert_after="warehouse",
-			options=self.reference_document,
-			label=self.dimension_name,
-		)
+		dimension_fields = [
+			dict(
+				fieldname="inventory_dimension",
+				fieldtype="Section Break",
+				insert_after="warehouse",
+				label="Inventory Dimension",
+				collapsible=1,
+			),
+			dict(
+				fieldname=self.source_fieldname,
+				fieldtype="Link",
+				insert_after="inventory_dimension",
+				options=self.reference_document,
+				label=self.dimension_name,
+			),
+		]
 
 		custom_fields = {}
 
 		if self.apply_to_all_doctypes:
 			for doctype in get_inventory_documents():
-				if not frappe.db.get_value(
-					"Custom Field", {"dt": doctype[0], "fieldname": self.source_fieldname}
-				):
-					custom_fields.setdefault(doctype[0], dimension_field)
-		elif not frappe.db.get_value(
-			"Custom Field", {"dt": self.document_type, "fieldname": self.source_fieldname}
-		):
-			custom_fields.setdefault(self.document_type, dimension_field)
+				custom_fields.setdefault(doctype[0], dimension_fields)
+		else:
+			custom_fields.setdefault(self.document_type, dimension_fields)
 
 		if not frappe.db.get_value(
 			"Custom Field", {"dt": "Stock Ledger Entry", "fieldname": self.target_fieldname}
 		):
+			dimension_field = dimension_fields[1]
 			dimension_field["fieldname"] = self.target_fieldname
 			custom_fields["Stock Ledger Entry"] = dimension_field
 
@@ -143,7 +172,7 @@
 		elif (
 			row.type_of_transaction == "Outward"
 			if doc.docstatus == 1
-			else row.type_of_transaction != "Inward"
+			else row.type_of_transaction != "Outward"
 		) and sl_dict.actual_qty > 0:
 			continue
 
@@ -166,7 +195,14 @@
 	if not frappe.local.document_wise_inventory_dimensions.get(doctype):
 		dimensions = frappe.get_all(
 			"Inventory Dimension",
-			fields=["name", "source_fieldname", "condition", "target_fieldname", "type_of_transaction"],
+			fields=[
+				"name",
+				"source_fieldname",
+				"condition",
+				"target_fieldname",
+				"type_of_transaction",
+				"fetch_from_parent",
+			],
 			filters={"disabled": 0},
 			or_filters={"document_type": doctype, "apply_to_all_doctypes": 1},
 		)
@@ -194,3 +230,9 @@
 		frappe.local.inventory_dimensions = dimensions
 
 	return frappe.local.inventory_dimensions
+
+
+@frappe.whitelist()
+def delete_dimension(dimension):
+	doc = frappe.get_doc("Inventory Dimension", dimension)
+	doc.delete()
diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
index 998a0e9..cc90b74 100644
--- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
@@ -8,6 +8,7 @@
 	CanNotBeChildDoc,
 	CanNotBeDefaultDimension,
 	DoNotChangeError,
+	delete_dimension,
 )
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
@@ -42,6 +43,32 @@
 
 		self.assertRaises(CanNotBeDefaultDimension, inv_dim1.insert)
 
+	def test_delete_inventory_dimension(self):
+		inv_dim1 = create_inventory_dimension(
+			reference_document="Shelf",
+			type_of_transaction="Outward",
+			dimension_name="From Shelf",
+			apply_to_all_doctypes=0,
+			document_type="Stock Entry Detail",
+			condition="parent.purpose == 'Material Issue'",
+		)
+
+		inv_dim1.save()
+
+		custom_field = frappe.db.get_value(
+			"Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
+		)
+
+		self.assertTrue(custom_field)
+
+		delete_dimension(inv_dim1.name)
+
+		custom_field = frappe.db.get_value(
+			"Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
+		)
+
+		self.assertFalse(custom_field)
+
 	def test_inventory_dimension(self):
 		warehouse = "Shelf Warehouse - _TC"
 		item_code = "_Test Item"
diff --git a/erpnext/stock/doctype/item/item_dashboard.py b/erpnext/stock/doctype/item/item_dashboard.py
index 897acb7..34bb4d1 100644
--- a/erpnext/stock/doctype/item/item_dashboard.py
+++ b/erpnext/stock/doctype/item/item_dashboard.py
@@ -5,7 +5,7 @@
 	return {
 		"heatmap": True,
 		"heatmap_message": _("This is based on stock movement. See {0} for details").format(
-			'<a href="#query-report/Stock Ledger">' + _("Stock Ledger") + "</a>"
+			'<a href="/app/query-report/Stock Ledger">' + _("Stock Ledger") + "</a>"
 		),
 		"fieldname": "item_code",
 		"non_standard_fieldnames": {
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index c97dbee..39833b5 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -792,10 +792,8 @@
   {
    "fieldname": "expense_account",
    "fieldtype": "Link",
-   "hidden": 1,
    "label": "Expense Account",
-   "options": "Account",
-   "read_only": 1
+   "options": "Account"
   },
   {
    "fieldname": "accounting_dimensions_section",
@@ -1001,7 +999,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-06-17 05:32:16.483178",
+ "modified": "2022-07-28 19:27:54.880781",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
index 4cd40bf..d6e00ea 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -15,7 +15,7 @@
 			return {
 				filters: {
 					name: ['in', ['Purchase Receipt', 'Purchase Invoice', 'Delivery Note',
-						'Sales Invoice', 'Stock Entry', 'Stock Reconciliation']]
+						'Sales Invoice', 'Stock Entry', 'Stock Reconciliation', 'Subcontracting Receipt']]
 				}
 			};
 		});
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 1c514a9..e3a8438 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -583,18 +583,23 @@
 	},
 
 	add_to_transit: function(frm) {
-		if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') {
-			frm.set_value('to_warehouse', '');
+		if(frm.doc.purpose=='Material Transfer') {
+			var filters = {
+				'is_group': 0,
+				'company': frm.doc.company
+			}
+
+			if(frm.doc.add_to_transit){
+				filters['warehouse_type'] = 'Transit';
+				frm.set_value('to_warehouse', '');
+				frm.trigger('set_transit_warehouse');
+			}
+
 			frm.fields_dict.to_warehouse.get_query = function() {
 				return {
-					filters:{
-						'warehouse_type' : 'Transit',
-						'is_group': 0,
-						'company': frm.doc.company
-					}
+					filters:filters
 				};
 			};
-			frm.trigger('set_transit_warehouse');
 		}
 	},
 
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index a2f9978..b574b71 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe.permissions import add_user_permission, remove_user_permission
 from frappe.tests.utils import FrappeTestCase, change_settings
-from frappe.utils import add_days, flt, nowdate, nowtime
+from frappe.utils import add_days, flt, nowdate, nowtime, today
 
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
 from erpnext.stock.doctype.item.test_item import (
@@ -1589,6 +1589,31 @@
 			self.assertEqual(obj.items[index].basic_rate, 200)
 			self.assertEqual(obj.items[index].basic_amount, 2000)
 
+	def test_batch_expiry(self):
+		from erpnext.controllers.stock_controller import BatchExpiredError
+		from erpnext.stock.doctype.batch.test_batch import make_new_batch
+
+		item_code = "Test Batch Expiry Test Item - 001"
+		item_doc = create_item(item_code=item_code, is_stock_item=1, valuation_rate=10)
+
+		item_doc.has_batch_no = 1
+		item_doc.save()
+
+		batch = make_new_batch(
+			batch_id=frappe.generate_hash("", 5), item_code=item_doc.name, expiry_date=add_days(today(), -1)
+		)
+
+		se = make_stock_entry(
+			item_code=item_code,
+			purpose="Material Receipt",
+			qty=4,
+			to_warehouse="_Test Warehouse - _TC",
+			batch_no=batch.name,
+			do_not_save=True,
+		)
+
+		self.assertRaises(BatchExpiredError, se.save)
+
 
 def make_serialized_item(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js
index ff8a69f..1d76a3d 100644
--- a/erpnext/stock/landed_taxes_and_charges_common.js
+++ b/erpnext/stock/landed_taxes_and_charges_common.js
@@ -1,4 +1,4 @@
-let document_list = ['Landed Cost Voucher', 'Stock Entry'];
+let document_list = ['Landed Cost Voucher', 'Stock Entry', 'Subcontracting Order', 'Subcontracting Receipt'];
 
 document_list.forEach((doctype) => {
 	frappe.ui.form.on(doctype, {
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index fd1aece..3524a47 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -646,6 +646,24 @@
 					voucher_detail_no=sle.voucher_detail_no,
 					sle=sle,
 				)
+
+			elif (
+				sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
+				and sle.actual_qty > 0
+				and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
+			):
+				sle_details = frappe.db.get_value(
+					"Stock Ledger Entry",
+					{
+						"voucher_type": sle.voucher_type,
+						"voucher_no": sle.voucher_no,
+						"dependant_sle_voucher_detail_no": sle.voucher_detail_no,
+					},
+					["stock_value_difference", "actual_qty"],
+					as_dict=1,
+				)
+
+				rate = abs(sle_details.stock_value_difference / sle.actual_qty)
 			else:
 				if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
 					rate_field = "valuation_rate"
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
index dbd337a..c20f8ab 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
@@ -3,6 +3,8 @@
 
 frappe.provide('erpnext.buying');
 
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
+
 frappe.ui.form.on('Subcontracting Order', {
 	setup: (frm) => {
 		frm.get_field("items").grid.cannot_add_rows = true;
@@ -136,6 +138,16 @@
 	}
 });
 
+frappe.ui.form.on('Landed Cost Taxes and Charges', {
+	amount: function (frm, cdt, cdn) {
+		frm.events.set_base_amount(frm, cdt, cdn);
+	},
+
+	expense_account: function (frm, cdt, cdn) {
+		frm.events.set_account_currency(frm, cdt, cdn);
+	}
+});
+
 erpnext.buying.SubcontractingOrderController = class SubcontractingOrderController {
 	setup() {
 		this.frm.custom_make_buttons = {
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json
index c6e76c7..f98f559 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json
@@ -19,6 +19,10 @@
         "transaction_date",
         "schedule_date",
         "amended_from",
+        "accounting_dimensions_section",
+        "cost_center",
+        "dimension_col_break",
+        "project",
         "address_and_contact_section",
         "supplier_address",
         "address_display",
@@ -422,12 +426,34 @@
             "fieldtype": "Select",
             "label": "Distribute Additional Costs Based On ",
             "options": "Qty\nAmount"
+        },
+        {
+            "collapsible": 1,
+            "fieldname": "accounting_dimensions_section",
+            "fieldtype": "Section Break",
+            "label": "Accounting Dimensions"
+        },
+        {
+            "fieldname": "cost_center",
+            "fieldtype": "Link",
+            "label": "Cost Center",
+            "options": "Cost Center"
+        },
+        {
+            "fieldname": "dimension_col_break",
+            "fieldtype": "Column Break"
+        },
+        {
+            "fieldname": "project",
+            "fieldtype": "Link",
+            "label": "Project",
+            "options": "Project"
         }
     ],
     "icon": "fa fa-file-text",
     "is_submittable": 1,
     "links": [],
-    "modified": "2022-04-11 21:02:44.097841",
+    "modified": "2022-08-15 14:08:49.204218",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Order",
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index 71cdc94..156f027 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -82,25 +82,6 @@
 		self.set_missing_values_in_supplied_items()
 		self.set_missing_values_in_items()
 
-	def set_missing_values_in_additional_costs(self):
-		if self.get("additional_costs"):
-			self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs"))
-
-			if self.total_additional_costs:
-				if self.distribute_additional_costs_based_on == "Amount":
-					total_amt = sum(flt(item.amount) for item in self.get("items"))
-					for item in self.items:
-						item.additional_cost_per_qty = (
-							(item.amount * self.total_additional_costs) / total_amt
-						) / item.qty
-				else:
-					total_qty = sum(flt(item.qty) for item in self.get("items"))
-					additional_cost_per_qty = self.total_additional_costs / total_qty
-					for item in self.items:
-						item.additional_cost_per_qty = additional_cost_per_qty
-		else:
-			self.total_additional_costs = 0
-
 	def set_missing_values_in_service_items(self):
 		for idx, item in enumerate(self.get("service_items")):
 			self.items[idx].service_cost_per_qty = item.amount / self.items[idx].qty
@@ -114,9 +95,7 @@
 	def set_missing_values_in_items(self):
 		total_qty = total = 0
 		for item in self.items:
-			item.rate = (
-				item.rm_cost_per_qty + item.service_cost_per_qty + (item.additional_cost_per_qty or 0)
-			)
+			item.rate = item.rm_cost_per_qty + item.service_cost_per_qty + flt(item.additional_cost_per_qty)
 			item.amount = item.qty * item.rate
 			total_qty += flt(item.qty)
 			total += flt(item.amount)
@@ -187,7 +166,7 @@
 					total_required_qty = total_supplied_qty = 0
 					for item in self.supplied_items:
 						total_required_qty += item.required_qty
-						total_supplied_qty += item.supplied_qty or 0
+						total_supplied_qty += flt(item.supplied_qty)
 					if total_supplied_qty:
 						status = "Partial Material Transferred"
 						if total_supplied_qty >= total_required_qty:
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
index 291f47a..3675a4e 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -40,6 +40,10 @@
         "manufacture_section",
         "manufacturer",
         "manufacturer_part_no",
+        "accounting_dimensions_section",
+        "cost_center",
+        "dimension_col_break",
+        "project",
         "section_break_34",
         "page_break"
     ],
@@ -304,13 +308,35 @@
             "no_copy": 1,
             "print_hide": 1,
             "read_only": 1
+        },
+        {
+            "collapsible": 1,
+            "fieldname": "accounting_dimensions_section",
+            "fieldtype": "Section Break",
+            "label": "Accounting Dimensions"
+        },
+        {
+            "fieldname": "cost_center",
+            "fieldtype": "Link",
+            "label": "Cost Center",
+            "options": "Cost Center"
+        },
+        {
+            "fieldname": "dimension_col_break",
+            "fieldtype": "Column Break"
+        },
+        {
+            "fieldname": "project",
+            "fieldtype": "Link",
+            "label": "Project",
+            "options": "Project"
         }
     ],
     "idx": 1,
     "index_web_pages_for_search": 1,
     "istable": 1,
     "links": [],
-    "modified": "2022-04-11 21:28:06.585338",
+    "modified": "2022-08-15 14:25:45.177703",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Order Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index b2506cd..aff76eb 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -3,6 +3,8 @@
 
 frappe.provide('erpnext.buying');
 
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
+
 frappe.ui.form.on('Subcontracting Receipt', {
 	setup: (frm) => {
 		frm.get_field('supplied_items').grid.cannot_add_rows = true;
@@ -48,6 +50,13 @@
 				is_group: 0
 			}
 		}));
+
+		frm.set_query("expense_account", "items", function () {
+			return {
+				query: "erpnext.controllers.queries.get_expense_account",
+				filters: { 'company': frm.doc.company }
+			};
+		});
 	},
 
 	refresh: (frm) => {
@@ -121,6 +130,16 @@
 	},
 });
 
+frappe.ui.form.on('Landed Cost Taxes and Charges', {
+	amount: function (frm, cdt, cdn) {
+		frm.events.set_base_amount(frm, cdt, cdn);
+	},
+
+	expense_account: function (frm, cdt, cdn) {
+		frm.events.set_account_currency(frm, cdt, cdn);
+	}
+});
+
 frappe.ui.form.on('Subcontracting Receipt Item', {
 	item_code(frm) {
 		set_missing_values(frm);
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
index e963814..84e9554 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
@@ -15,8 +15,13 @@
         "company",
         "posting_date",
         "posting_time",
+        "set_posting_time",
         "is_return",
         "return_against",
+        "accounting_dimensions_section",
+        "cost_center",
+        "dimension_col_break",
+        "project",
         "section_addresses",
         "supplier_address",
         "contact_person",
@@ -43,12 +48,14 @@
         "raw_material_details",
         "get_current_stock",
         "supplied_items",
+        "additional_costs_section",
+        "distribute_additional_costs_based_on",
+        "additional_costs",
+        "total_additional_costs",
         "section_break_46",
         "in_words",
         "bill_no",
         "bill_date",
-        "accounting_details_section",
-        "provisional_expense_account",
         "more_info",
         "status",
         "column_break_39",
@@ -132,6 +139,7 @@
             "label": "Date",
             "no_copy": 1,
             "print_width": "100px",
+            "read_only_depends_on": "eval: !doc.set_posting_time",
             "reqd": 1,
             "search_index": 1,
             "width": "100px"
@@ -144,6 +152,7 @@
             "no_copy": 1,
             "print_hide": 1,
             "print_width": "100px",
+            "read_only_depends_on": "eval: !doc.set_posting_time",
             "reqd": 1,
             "width": "100px"
         },
@@ -521,19 +530,6 @@
             "read_only": 1
         },
         {
-            "collapsible": 1,
-            "fieldname": "accounting_details_section",
-            "fieldtype": "Section Break",
-            "label": "Accounting Details"
-        },
-        {
-            "fieldname": "provisional_expense_account",
-            "fieldtype": "Link",
-            "hidden": 1,
-            "label": "Provisional Expense Account",
-            "options": "Account"
-        },
-        {
             "default": "0",
             "fieldname": "is_return",
             "fieldtype": "Check",
@@ -569,11 +565,70 @@
         {
             "fieldname": "section_break_47",
             "fieldtype": "Section Break"
+        },
+        {
+            "collapsible": 1,
+            "fieldname": "accounting_dimensions_section",
+            "fieldtype": "Section Break",
+            "label": "Accounting Dimensions "
+        },
+        {
+            "fieldname": "cost_center",
+            "fieldtype": "Link",
+            "label": "Cost Center",
+            "options": "Cost Center"
+        },
+        {
+            "fieldname": "dimension_col_break",
+            "fieldtype": "Column Break"
+        },
+        {
+            "fieldname": "project",
+            "fieldtype": "Link",
+            "label": "Project",
+            "options": "Project"
+        },
+        {
+            "collapsible": 1,
+            "collapsible_depends_on": "total_additional_costs",
+            "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)",
+            "fieldname": "additional_costs_section",
+            "fieldtype": "Section Break",
+            "label": "Additional Costs"
+        },
+        {
+            "default": "Qty",
+            "fieldname": "distribute_additional_costs_based_on",
+            "fieldtype": "Select",
+            "label": "Distribute Additional Costs Based On ",
+            "options": "Qty\nAmount"
+        },
+        {
+            "fieldname": "additional_costs",
+            "fieldtype": "Table",
+            "label": "Additional Costs",
+            "options": "Landed Cost Taxes and Charges"
+        },
+        {
+            "fieldname": "total_additional_costs",
+            "fieldtype": "Currency",
+            "label": "Total Additional Costs",
+            "print_hide_if_no_value": 1,
+            "read_only": 1
+        },
+        {
+            "default": "0",
+            "depends_on": "eval:doc.docstatus==0",
+            "fieldname": "set_posting_time",
+            "fieldtype": "Check",
+            "label": "Edit Posting Date and Time",
+            "print_hide": 1
         }
     ],
+    "in_create": 1,
     "is_submittable": 1,
     "links": [],
-    "modified": "2022-04-18 13:15:12.011682",
+    "modified": "2022-08-22 17:30:40.827517",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Receipt",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 0c4ec6f..021d9aa 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -3,7 +3,7 @@
 
 import frappe
 from frappe import _
-from frappe.utils import cint, getdate, nowdate
+from frappe.utils import cint, flt, getdate, nowdate
 
 from erpnext.controllers.subcontracting_controller import SubcontractingController
 
@@ -103,6 +103,7 @@
 
 	@frappe.whitelist()
 	def set_missing_values(self):
+		self.set_missing_values_in_additional_costs()
 		self.set_missing_values_in_supplied_items()
 		self.set_missing_values_in_items()
 
@@ -125,12 +126,12 @@
 				item.rm_cost_per_qty = item.rm_supp_cost / item.qty
 				rm_supp_cost.pop(item.name)
 
-			if self.is_new() and item.rm_supp_cost > 0:
+			if item.recalculate_rate:
 				item.rate = (
-					item.rm_cost_per_qty + (item.service_cost_per_qty or 0) + item.additional_cost_per_qty
+					flt(item.rm_cost_per_qty) + flt(item.service_cost_per_qty) + flt(item.additional_cost_per_qty)
 				)
 
-			item.received_qty = item.qty + (item.rejected_qty or 0)
+			item.received_qty = item.qty + flt(item.rejected_qty)
 			item.amount = item.qty * item.rate
 			total_qty += item.qty
 			total_amount += item.amount
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
index e2785ce..fd86895 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -29,6 +29,7 @@
         "rate_and_amount",
         "rate",
         "amount",
+        "recalculate_rate",
         "column_break_19",
         "rm_cost_per_qty",
         "service_cost_per_qty",
@@ -49,15 +50,16 @@
         "col_break5",
         "batch_no",
         "rejected_serial_no",
-        "expense_account",
         "manufacture_details",
         "manufacturer",
         "column_break_16",
         "manufacturer_part_no",
+        "accounting_details_section",
+        "expense_account",
         "accounting_dimensions_section",
-        "project",
-        "dimension_col_break",
         "cost_center",
+        "dimension_col_break",
+        "project",
         "section_break_80",
         "page_break"
     ],
@@ -192,6 +194,8 @@
             "label": "Rate",
             "options": "currency",
             "print_width": "100px",
+            "read_only": 1,
+            "read_only_depends_on": "eval: doc.recalculate_rate",
             "width": "100px"
         },
         {
@@ -363,10 +367,8 @@
         {
             "fieldname": "expense_account",
             "fieldtype": "Link",
-            "hidden": 1,
             "label": "Expense Account",
-            "options": "Account",
-            "read_only": 1
+            "options": "Account"
         },
         {
             "collapsible": 1,
@@ -456,12 +458,23 @@
             "no_copy": 1,
             "print_hide": 1,
             "read_only": 1
+        },
+        {
+            "fieldname": "accounting_details_section",
+            "fieldtype": "Section Break",
+            "label": "Accounting Details"
+        },
+        {
+            "default": "1",
+            "fieldname": "recalculate_rate",
+            "fieldtype": "Check",
+            "label": "Recalculate Rate"
         }
     ],
     "idx": 1,
     "istable": 1,
     "links": [],
-    "modified": "2022-04-21 12:07:55.899701",
+    "modified": "2022-08-20 17:16:48.269164",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Receipt Item",
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 3e20e50..f56dc3a 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -46,7 +46,7 @@
 		<div class="col-md-{{ section.column_value }} mb-4">
 			<div class="card h-100 justify-content-between">
 				{% if card.image %}
-				<div class="website-image-lazy" data-class="card-img-top h-75" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
+				<img class="card-img-top h-75" src="{{ card.image }}" loading="lazy" alt="{{ card.title }}"></img>
 				{% endif %}
 				<div class="card-body">
 					<h5 class="card-title">{{ card.title }}</h5>
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index 4c69b83..27d966a 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -37,7 +37,7 @@
 			{% for item in homepage.products %}
 			<div class="col-md-4 mb-4">
 				<div class="card h-100 justify-content-between">
-					<div class="website-image-lazy" data-class="card-img-top website-image-extra-large" data-src="{{ item.image }}" data-alt="{{ item.item_name }}"></div>
+					<img class="card-img-top website-image-extra-large" src="{{ item.image }}" loading="lazy" alt="{{ item.item_name }}"></img>
 					<div class="card-body flex-grow-0">
 						<h5 class="card-title">{{ item.item_name }}</h5>
 						<a href="{{ item.route }}" class="card-link">{{ _('More details') }}</a>
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 01795af..d6bceb3 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -4051,7 +4051,7 @@
 Service Level Agreement has been changed to {0}.,Service Level Agreement wurde in {0} geändert.,
 Service Level Agreement was reset.,Service Level Agreement wurde zurückgesetzt.,
 Service Level Agreement with Entity Type {0} and Entity {1} already exists.,Service Level Agreement mit Entitätstyp {0} und Entität {1} ist bereits vorhanden.,
-Set,Menge,
+Set Loyalty Program,Treueprogramm eintragen,
 Set Meta Tags,Festlegen von Meta-Tags,
 Set {0} in company {1},{0} in Firma {1} festlegen,
 Setup,Einstellungen,
@@ -4231,10 +4231,8 @@
 Write Off,Abschreiben,
 {0} Created,{0} Erstellt,
 Email Id,E-Mail-ID,
-No,Kein,
 Reference Doctype,Referenz-DocType,
 User Id,Benutzeridentifikation,
-Yes,Ja,
 Actual ,Tatsächlich,
 Add to cart,In den Warenkorb legen,
 Budget,Budget,