Merge branch 'develop' into make-against-field-dynamic
diff --git a/README.md b/README.md
index 44bd729..710187a 100644
--- a/README.md
+++ b/README.md
@@ -73,8 +73,6 @@
 1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
 1. [Report Security Vulnerabilities](https://erpnext.com/security)
 1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
-1. [Translations](https://translate.erpnext.com)
-
 
 ## License
 
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 061bab3..fd052d0 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -66,7 +66,12 @@
   "show_balance_in_coa",
   "banking_tab",
   "enable_party_matching",
-  "enable_fuzzy_matching"
+  "enable_fuzzy_matching",
+  "reports_tab",
+  "remarks_section",
+  "general_ledger_remarks_length",
+  "column_break_lvjk",
+  "receivable_payable_remarks_length"
  ],
  "fields": [
   {
@@ -422,6 +427,34 @@
    "fieldname": "round_row_wise_tax",
    "fieldtype": "Check",
    "label": "Round Tax Amount Row-wise"
+  },
+  {
+   "fieldname": "reports_tab",
+   "fieldtype": "Tab Break",
+   "label": "Reports"
+  },
+  {
+   "default": "0",
+   "description": "Truncates 'Remarks' column to set character length",
+   "fieldname": "general_ledger_remarks_length",
+   "fieldtype": "Int",
+   "label": "General Ledger"
+  },
+  {
+   "default": "0",
+   "description": "Truncates 'Remarks' column to set character length",
+   "fieldname": "receivable_payable_remarks_length",
+   "fieldtype": "Int",
+   "label": "Accounts Receivable/Payable"
+  },
+  {
+   "fieldname": "column_break_lvjk",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "remarks_section",
+   "fieldtype": "Section Break",
+   "label": "Remarks Column Length"
   }
  ],
  "icon": "icon-cog",
@@ -429,7 +462,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-08-28 00:12:02.740633",
+ "modified": "2023-11-20 09:37:47.650347",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js
index d61f8a6..56fa6ce 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js
@@ -53,10 +53,18 @@
 								of Accounts. Please enter the account names and add more rows as per your requirement.`);
 						}
 					}
-				}
+				},
+				{
+					label : "Company",
+					fieldname: "company",
+					fieldtype: "Link",
+					reqd: 1,
+					hidden: 1,
+					default: frm.doc.company,
+				},
 			],
 			primary_action: function() {
-				var data = d.get_values();
+				let data = d.get_values();
 
 				if (!data.template_type) {
 					frappe.throw(__('Please select <b>Template Type</b> to download template'));
@@ -66,7 +74,8 @@
 					'/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
 					{
 						file_type: data.file_type,
-						template_type: data.template_type
+						template_type: data.template_type,
+						company: data.company
 					}
 				);
 
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index d6e1be4..5a1c139 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -8,6 +8,7 @@
 
 import frappe
 from frappe import _
+from frappe.desk.form.linked_with import get_linked_fields
 from frappe.model.document import Document
 from frappe.utils import cint, cstr
 from frappe.utils.csvutils import UnicodeWriter
@@ -294,10 +295,8 @@
 
 
 @frappe.whitelist()
-def download_template(file_type, template_type):
-	data = frappe._dict(frappe.local.form_dict)
-
-	writer = get_template(template_type)
+def download_template(file_type, template_type, company):
+	writer = get_template(template_type, company)
 
 	if file_type == "CSV":
 		# download csv file
@@ -308,8 +307,7 @@
 		build_response_as_excel(writer)
 
 
-def get_template(template_type):
-
+def get_template(template_type, company):
 	fields = [
 		"Account Name",
 		"Parent Account",
@@ -335,34 +333,17 @@
 				["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
 			)
 	else:
-		writer = get_sample_template(writer)
+		writer = get_sample_template(writer, company)
 
 	return writer
 
 
-def get_sample_template(writer):
-	template = [
-		["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
-		["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
-		["Equity", "", "", "", 1, "", "Equity"],
-		["Expenses", "", "", "", 1, "", "Expense"],
-		["Income", "", "", "", 1, "", "Income"],
-		["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
-		["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
-		["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
-		["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
-		["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
-		["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
-		["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
-		["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
-		["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
-		["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
-		["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
-		["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
-	]
-
-	for row in template:
-		writer.writerow(row)
+def get_sample_template(writer, company):
+	currency = frappe.db.get_value("Company", company, "default_currency")
+	with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
+		for row in f:
+			row = row.strip().split(",") + [currency]
+			writer.writerow(row)
 
 	return writer
 
@@ -453,14 +434,11 @@
 
 
 def unset_existing_data(company):
-	linked = frappe.db.sql(
-		'''select fieldname from tabDocField
-		where fieldtype="Link" and options="Account" and parent="Company"''',
-		as_dict=True,
-	)
-
 	# remove accounts data from company
-	update_values = {d.fieldname: "" for d in linked}
+
+	fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", [])
+	linked = [{"fieldname": name} for name in fieldnames]
+	update_values = {d.get("fieldname"): "" for d in linked}
 	frappe.db.set_value("Company", company, update_values, update_values)
 
 	# remove accounts data from various doctypes
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/coa_sample_template.csv b/erpnext/accounts/doctype/chart_of_accounts_importer/coa_sample_template.csv
new file mode 100644
index 0000000..85a2f21
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/coa_sample_template.csv
@@ -0,0 +1,17 @@
+Application Of Funds(Assets),,,,1,,Asset
+Sources Of Funds(Liabilities),,,,1,,Liability
+Equity,,,,1,,Equity
+Expenses,,,,1,Expense Account,Expense
+Income,,,,1,Income Account,Income
+Bank Accounts,Application Of Funds(Assets),,,1,Bank,Asset
+Cash In Hand,Application Of Funds(Assets),,,1,Cash,Asset
+Stock Assets,Application Of Funds(Assets),,,1,Stock,Asset
+Cost Of Goods Sold,Expenses,,,0,Cost of Goods Sold,Expense
+Asset Depreciation,Expenses,,,0,Depreciation,Expense
+Fixed Assets,Application Of Funds(Assets),,,0,Fixed Asset,Asset
+Accounts Payable,Sources Of Funds(Liabilities),,,0,Payable,Liability
+Accounts Receivable,Application Of Funds(Assets),,,1,Receivable,Asset
+Stock Expenses,Expenses,,,0,Stock Adjustment,Expense
+Sample Bank,Bank Accounts,,,0,Bank,Asset
+Cash,Cash In Hand,,,0,Cash,Asset
+Stores,Stock Assets,,,0,Stock,Asset
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 22b6880..9684a0d 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -51,7 +51,7 @@
 				}, __('Make'));
 		}
 
-		erpnext.accounts.unreconcile_payments.add_unreconcile_btn(frm);
+		erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
 	},
 	before_save: function(frm) {
 		if ((frm.doc.docstatus == 0) && (!frm.doc.is_system_generated)) {
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 2eb54a5..906760e 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -548,8 +548,16 @@
  "icon": "fa fa-file-text",
  "idx": 176,
  "is_submittable": 1,
- "links": [],
- "modified": "2023-08-10 14:32:22.366895",
+ "links": [
+  {
+   "is_child_table": 1,
+   "link_doctype": "Bank Transaction Payments",
+   "link_fieldname": "payment_entry",
+   "parent_doctype": "Bank Transaction",
+   "table_fieldname": "payment_entries"
+  }
+ ],
+ "modified": "2023-11-23 12:11:04.128015",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index c70ad2f..0b5a37f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -910,7 +910,7 @@
 					party_account_currency = d.account_currency
 
 			elif frappe.get_cached_value("Account", d.account, "account_type") in ["Bank", "Cash"]:
-				bank_amount += d.debit_in_account_currency or d.credit_in_account_currency
+				bank_amount += flt(d.debit_in_account_currency) or flt(d.credit_in_account_currency)
 				bank_account_currency = d.account_currency
 
 		if party_type and pay_to_recd_from:
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index 8d8c837..2b423ac 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -205,7 +205,8 @@
    "fieldtype": "Select",
    "label": "Reference Type",
    "no_copy": 1,
-   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry"
+   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry",
+   "search_index": 1
   },
   {
    "fieldname": "reference_name",
@@ -213,7 +214,8 @@
    "in_list_view": 1,
    "label": "Reference Name",
    "no_copy": 1,
-   "options": "reference_type"
+   "options": "reference_type",
+   "search_index": 1
   },
   {
    "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
@@ -301,7 +303,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-11-08 12:20:21.489496",
+ "modified": "2023-11-23 11:44:25.841187",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Journal Entry Account",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 0203c45..2611240 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -9,7 +9,7 @@
 
 frappe.ui.form.on('Payment Entry', {
 	onload: function(frm) {
-		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payments', 'Unreconcile Payment Entries'];
+		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payment', 'Unreconcile Payment Entries'];
 
 		if(frm.doc.__islocal) {
 			if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
@@ -154,13 +154,13 @@
 		frm.events.set_dynamic_labels(frm);
 		frm.events.show_general_ledger(frm);
 		erpnext.accounts.ledger_preview.show_accounting_ledger_preview(frm);
-		if(frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0})) {
+		if((frm.doc.references) && (frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0}))) {
 			frm.add_custom_button(__("View Exchange Gain/Loss Journals"), function() {
 				frappe.set_route("List", "Journal Entry", {"voucher_type": "Exchange Gain Or Loss", "reference_name": frm.doc.name});
 			}, __('Actions'));
 
 		}
-		erpnext.accounts.unreconcile_payments.add_unreconcile_btn(frm);
+		erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
 	},
 
 	validate_company: (frm) => {
@@ -853,6 +853,7 @@
 
 			var allocated_positive_outstanding =  paid_amount + allocated_negative_outstanding;
 		} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
+			total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount"))
 			if(paid_amount > total_negative_outstanding) {
 				if(total_negative_outstanding == 0) {
 					frappe.msgprint(
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index d7b6a19..aa18156 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -595,6 +595,7 @@
    "fieldname": "status",
    "fieldtype": "Select",
    "label": "Status",
+   "no_copy": 1,
    "options": "\nDraft\nSubmitted\nCancelled",
    "read_only": 1
   },
@@ -749,8 +750,16 @@
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
- "links": [],
- "modified": "2023-06-23 18:07:38.023010",
+ "links": [
+  {
+   "is_child_table": 1,
+   "link_doctype": "Bank Transaction Payments",
+   "link_fieldname": "payment_entry",
+   "parent_doctype": "Bank Transaction",
+   "table_fieldname": "payment_entries"
+  }
+ ],
+ "modified": "2023-11-23 12:07:20.887885",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index ff8695f..16b32bd 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -33,6 +33,7 @@
 	get_account_currency,
 	get_balance_on,
 	get_outstanding_invoices,
+	get_party_types_from_account_type,
 )
 from erpnext.controllers.accounts_controller import (
 	AccountsController,
@@ -83,7 +84,6 @@
 		self.apply_taxes()
 		self.set_amounts_after_tax()
 		self.clear_unallocated_reference_document_rows()
-		self.validate_payment_against_negative_invoice()
 		self.validate_transaction_reference()
 		self.set_title()
 		self.set_remarks()
@@ -148,7 +148,7 @@
 			"Repost Payment Ledger Items",
 			"Repost Accounting Ledger",
 			"Repost Accounting Ledger Items",
-			"Unreconcile Payments",
+			"Unreconcile Payment",
 			"Unreconcile Payment Entries",
 		)
 		super(PaymentEntry, self).on_cancel()
@@ -952,35 +952,6 @@
 			self.name,
 		)
 
-	def validate_payment_against_negative_invoice(self):
-		if (self.payment_type != "Pay" or self.party_type != "Customer") and (
-			self.payment_type != "Receive" or self.party_type != "Supplier"
-		):
-			return
-
-		total_negative_outstanding = sum(
-			abs(flt(d.outstanding_amount)) for d in self.get("references") if flt(d.outstanding_amount) < 0
-		)
-
-		paid_amount = self.paid_amount if self.payment_type == "Receive" else self.received_amount
-		additional_charges = sum(flt(d.amount) for d in self.deductions)
-
-		if not total_negative_outstanding:
-			if self.party_type == "Customer":
-				msg = _("Cannot pay to Customer without any negative outstanding invoice")
-			else:
-				msg = _("Cannot receive from Supplier without any negative outstanding invoice")
-
-			frappe.throw(msg, InvalidPaymentEntry)
-
-		elif paid_amount - additional_charges > total_negative_outstanding:
-			frappe.throw(
-				_("Paid Amount cannot be greater than total negative outstanding amount {0}").format(
-					fmt_money(total_negative_outstanding)
-				),
-				InvalidPaymentEntry,
-			)
-
 	def set_title(self):
 		if frappe.flags.in_import and self.title:
 			# do not set title dynamically if title exists during data import.
@@ -1051,6 +1022,7 @@
 		self.add_bank_gl_entries(gl_entries)
 		self.add_deductions_gl_entries(gl_entries)
 		self.add_tax_gl_entries(gl_entries)
+		add_regional_gl_entries(gl_entries, self)
 		return gl_entries
 
 	def make_gl_entries(self, cancel=0, adv_adj=0):
@@ -1085,11 +1057,9 @@
 				item=self,
 			)
 
-			dr_or_cr = (
-				"credit" if erpnext.get_party_account_type(self.party_type) == "Receivable" else "debit"
-			)
-
 			for d in self.get("references"):
+				# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
+				dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
 				cost_center = self.cost_center
 				if d.reference_doctype == "Sales Invoice" and not cost_center:
 					cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
@@ -1105,10 +1075,25 @@
 					against_voucher_type = d.reference_doctype
 					against_voucher = d.reference_name
 
+				reverse_dr_or_cr = 0
+				if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
+					is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
+					payable_party_types = get_party_types_from_account_type("Payable")
+					receivable_party_types = get_party_types_from_account_type("Receivable")
+					if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"):
+						reverse_dr_or_cr = 1
+					elif (
+						is_return and self.party_type in payable_party_types and (self.payment_type == "Receive")
+					):
+						reverse_dr_or_cr = 1
+
+					if is_return and not reverse_dr_or_cr:
+						dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
+
 				gle.update(
 					{
-						dr_or_cr: allocated_amount_in_company_currency,
-						dr_or_cr + "_in_account_currency": d.allocated_amount,
+						dr_or_cr: abs(allocated_amount_in_company_currency),
+						dr_or_cr + "_in_account_currency": abs(d.allocated_amount),
 						"against_voucher_type": against_voucher_type,
 						"against_voucher": against_voucher,
 						"cost_center": cost_center,
@@ -1116,6 +1101,7 @@
 				)
 				gl_entries.append(gle)
 
+			dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
 			if self.unallocated_amount:
 				exchange_rate = self.get_exchange_rate()
 				base_unallocated_amount = self.unallocated_amount * exchange_rate
@@ -1711,13 +1697,42 @@
 	return data
 
 
-def split_invoices_based_on_payment_terms(outstanding_invoices, company):
-	invoice_ref_based_on_payment_terms = {}
+def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list:
+	"""Split a list of invoices based on their payment terms."""
+	exc_rates = get_currency_data(outstanding_invoices, company)
 
+	outstanding_invoices_after_split = []
+	for entry in outstanding_invoices:
+		if entry.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
+			if payment_term_template := frappe.db.get_value(
+				entry.voucher_type, entry.voucher_no, "payment_terms_template"
+			):
+				split_rows = get_split_invoice_rows(entry, payment_term_template, exc_rates)
+				if not split_rows:
+					continue
+
+				frappe.msgprint(
+					_("Splitting {0} {1} into {2} rows as per Payment Terms").format(
+						_(entry.voucher_type), frappe.bold(entry.voucher_no), len(split_rows)
+					),
+					alert=True,
+				)
+				outstanding_invoices_after_split += split_rows
+				continue
+
+		# If not an invoice or no payment terms template, add as it is
+		outstanding_invoices_after_split.append(entry)
+
+	return outstanding_invoices_after_split
+
+
+def get_currency_data(outstanding_invoices: list, company: str = None) -> dict:
+	"""Get currency and conversion data for a list of invoices."""
+	exc_rates = frappe._dict()
 	company_currency = (
 		frappe.db.get_value("Company", company, "default_currency") if company else None
 	)
-	exc_rates = frappe._dict()
+
 	for doctype in ["Sales Invoice", "Purchase Invoice"]:
 		invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
 		for x in frappe.db.get_all(
@@ -1732,72 +1747,54 @@
 				company_currency=company_currency,
 			)
 
-	for idx, d in enumerate(outstanding_invoices):
-		if d.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
-			payment_term_template = frappe.db.get_value(
-				d.voucher_type, d.voucher_no, "payment_terms_template"
+	return exc_rates
+
+
+def get_split_invoice_rows(invoice: dict, payment_term_template: str, exc_rates: dict) -> list:
+	"""Split invoice based on its payment schedule table."""
+	split_rows = []
+	allocate_payment_based_on_payment_terms = frappe.db.get_value(
+		"Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms"
+	)
+
+	if not allocate_payment_based_on_payment_terms:
+		return [invoice]
+
+	payment_schedule = frappe.get_all(
+		"Payment Schedule", filters={"parent": invoice.voucher_no}, fields=["*"], order_by="due_date"
+	)
+	for payment_term in payment_schedule:
+		if not payment_term.outstanding > 0.1:
+			continue
+
+		doc_details = exc_rates.get(payment_term.parent, None)
+		is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
+			doc_details.party_account_currency != doc_details.company_currency
+		)
+		payment_term_outstanding = flt(payment_term.outstanding)
+		if not is_multi_currency_acc:
+			payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
+
+		split_rows.append(
+			frappe._dict(
+				{
+					"due_date": invoice.due_date,
+					"currency": invoice.currency,
+					"voucher_no": invoice.voucher_no,
+					"voucher_type": invoice.voucher_type,
+					"posting_date": invoice.posting_date,
+					"invoice_amount": flt(invoice.invoice_amount),
+					"outstanding_amount": payment_term_outstanding
+					if payment_term_outstanding
+					else invoice.outstanding_amount,
+					"payment_term_outstanding": payment_term_outstanding,
+					"payment_amount": payment_term.payment_amount,
+					"payment_term": payment_term.payment_term,
+				}
 			)
-			if payment_term_template:
-				allocate_payment_based_on_payment_terms = frappe.get_cached_value(
-					"Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms"
-				)
-				if allocate_payment_based_on_payment_terms:
-					payment_schedule = frappe.get_all(
-						"Payment Schedule", filters={"parent": d.voucher_no}, fields=["*"]
-					)
+		)
 
-					for payment_term in payment_schedule:
-						if payment_term.outstanding > 0.1:
-							doc_details = exc_rates.get(payment_term.parent, None)
-							is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
-								doc_details.party_account_currency != doc_details.company_currency
-							)
-							payment_term_outstanding = flt(payment_term.outstanding)
-							if not is_multi_currency_acc:
-								payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
-
-							invoice_ref_based_on_payment_terms.setdefault(idx, [])
-							invoice_ref_based_on_payment_terms[idx].append(
-								frappe._dict(
-									{
-										"due_date": d.due_date,
-										"currency": d.currency,
-										"voucher_no": d.voucher_no,
-										"voucher_type": d.voucher_type,
-										"posting_date": d.posting_date,
-										"invoice_amount": flt(d.invoice_amount),
-										"outstanding_amount": payment_term_outstanding
-										if payment_term_outstanding
-										else d.outstanding_amount,
-										"payment_term_outstanding": payment_term_outstanding,
-										"payment_amount": payment_term.payment_amount,
-										"payment_term": payment_term.payment_term,
-										"account": d.account,
-									}
-								)
-							)
-
-	outstanding_invoices_after_split = []
-	if invoice_ref_based_on_payment_terms:
-		for idx, ref in invoice_ref_based_on_payment_terms.items():
-			voucher_no = ref[0]["voucher_no"]
-			voucher_type = ref[0]["voucher_type"]
-
-			frappe.msgprint(
-				_("Spliting {} {} into {} row(s) as per Payment Terms").format(
-					voucher_type, voucher_no, len(ref)
-				),
-				alert=True,
-			)
-
-			outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]
-
-			existing_row = list(filter(lambda x: x.get("voucher_no") == voucher_no, outstanding_invoices))
-			index = outstanding_invoices.index(existing_row[0])
-			outstanding_invoices.pop(index)
-
-	outstanding_invoices_after_split += outstanding_invoices
-	return outstanding_invoices_after_split
+	return split_rows
 
 
 def get_orders_to_be_billed(
@@ -2638,3 +2635,8 @@
 	)
 
 	return doclist
+
+
+@erpnext.allow_regional
+def add_regional_gl_entries(gl_entries, doc):
+	return
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index edfec41..f4b0c55 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -6,10 +6,11 @@
 import frappe
 from frappe import qb
 from frappe.tests.utils import FrappeTestCase, change_settings
-from frappe.utils import flt, nowdate
+from frappe.utils import add_days, flt, nowdate
 
 from erpnext.accounts.doctype.payment_entry.payment_entry import (
 	InvalidPaymentEntry,
+	get_outstanding_reference_documents,
 	get_payment_entry,
 	get_reference_details,
 )
@@ -683,17 +684,6 @@
 		self.validate_gl_entries(pe.name, expected_gle)
 
 	def test_payment_against_negative_sales_invoice(self):
-		pe1 = frappe.new_doc("Payment Entry")
-		pe1.payment_type = "Pay"
-		pe1.company = "_Test Company"
-		pe1.party_type = "Customer"
-		pe1.party = "_Test Customer"
-		pe1.paid_from = "_Test Cash - _TC"
-		pe1.paid_amount = 100
-		pe1.received_amount = 100
-
-		self.assertRaises(InvalidPaymentEntry, pe1.validate)
-
 		si1 = create_sales_invoice()
 
 		# create full payment entry against si1
@@ -751,8 +741,6 @@
 
 		# pay more than outstanding against si1
 		pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
-		pe3.paid_amount = pe3.received_amount = 300
-		self.assertRaises(InvalidPaymentEntry, pe3.validate)
 
 		# pay negative outstanding against si1
 		pe3.paid_to = "Debtors - _TC"
@@ -1262,6 +1250,130 @@
 		so.reload()
 		self.assertEqual(so.advance_paid, so.rounded_total)
 
+	def test_outstanding_invoices_api(self):
+		"""
+		Test if `get_outstanding_reference_documents` fetches invoices in the right order.
+		"""
+		customer = create_customer("Max Mustermann", "INR")
+		create_payment_terms_template()
+
+		# SI has an earlier due date and SI2 has a later due date
+		si = create_sales_invoice(
+			qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4)
+		)
+		si2 = create_sales_invoice(do_not_save=1, qty=1, rate=100, customer=customer)
+		si2.payment_terms_template = "Test Receivable Template"
+		si2.submit()
+
+		args = {
+			"posting_date": nowdate(),
+			"company": "_Test Company",
+			"party_type": "Customer",
+			"payment_type": "Pay",
+			"party": customer,
+			"party_account": "Debtors - _TC",
+		}
+		args.update(
+			{
+				"get_outstanding_invoices": True,
+				"from_posting_date": add_days(nowdate(), -4),
+				"to_posting_date": add_days(nowdate(), 2),
+			}
+		)
+		references = get_outstanding_reference_documents(args)
+
+		self.assertEqual(len(references), 3)
+		self.assertEqual(references[0].voucher_no, si.name)
+		self.assertEqual(references[1].voucher_no, si2.name)
+		self.assertEqual(references[2].voucher_no, si2.name)
+		self.assertEqual(references[1].payment_term, "Basic Amount Receivable")
+		self.assertEqual(references[2].payment_term, "Tax Receivable")
+
+	def test_receive_payment_from_payable_party_type(self):
+		"""
+		Checks GL entries generated while receiving payments from a Payable Party Type.
+		"""
+		pe = create_payment_entry(
+			party_type="Supplier",
+			party="_Test Supplier",
+			payment_type="Receive",
+			paid_from="Creditors - _TC",
+			paid_to="_Test Cash - _TC",
+			save=True,
+			submit=True,
+		)
+		self.voucher_no = pe.name
+		self.expected_gle = [
+			{"account": "Creditors - _TC", "debit": 0.0, "credit": 1000.0},
+			{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
+		]
+		self.check_gl_entries()
+
+	def test_payment_against_partial_return_invoice(self):
+		"""
+		Checks GL entries generated for partial return invoice payments.
+		"""
+		si = create_sales_invoice(qty=10, rate=10, customer="_Test Customer")
+		credit_note = create_sales_invoice(
+			qty=-4, rate=10, customer="_Test Customer", is_return=1, return_against=si.name
+		)
+		pe = create_payment_entry(
+			party_type="Customer",
+			party="_Test Customer",
+			payment_type="Receive",
+			paid_from="Debtors - _TC",
+			paid_to="_Test Cash - _TC",
+		)
+		pe.set(
+			"references",
+			[
+				{
+					"reference_doctype": "Sales Invoice",
+					"reference_name": si.name,
+					"due_date": si.get("due_date"),
+					"total_amount": si.grand_total,
+					"outstanding_amount": si.outstanding_amount,
+					"allocated_amount": si.outstanding_amount,
+				},
+				{
+					"reference_doctype": "Sales Invoice",
+					"reference_name": credit_note.name,
+					"due_date": credit_note.get("due_date"),
+					"total_amount": credit_note.grand_total,
+					"outstanding_amount": credit_note.outstanding_amount,
+					"allocated_amount": credit_note.outstanding_amount,
+				},
+			],
+		)
+		pe.save()
+		pe.submit()
+		self.assertEqual(pe.total_allocated_amount, 60)
+		self.assertEqual(pe.unallocated_amount, 940)
+		self.voucher_no = pe.name
+		self.expected_gle = [
+			{"account": "Debtors - _TC", "debit": 40.0, "credit": 0.0},
+			{"account": "Debtors - _TC", "debit": 0.0, "credit": 940.0},
+			{"account": "Debtors - _TC", "debit": 0.0, "credit": 100.0},
+			{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
+		]
+		self.check_gl_entries()
+
+	def check_gl_entries(self):
+		gle = frappe.qb.DocType("GL Entry")
+		gl_entries = (
+			frappe.qb.from_(gle)
+			.select(
+				gle.account,
+				gle.debit,
+				gle.credit,
+			)
+			.where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0))
+			.orderby(gle.account, gle.debit, gle.credit, order=frappe.qb.desc)
+		).run(as_dict=True)
+		for row in range(len(self.expected_gle)):
+			for field in ["account", "debit", "credit"]:
+				self.assertEqual(self.expected_gle[row][field], gl_entries[row][field])
+
 
 def create_payment_entry(**args):
 	payment_entry = frappe.new_doc("Payment Entry")
@@ -1322,6 +1434,9 @@
 def create_payment_terms_template_with_discount(
 	name=None, discount_type=None, discount=None, template_name=None
 ):
+	"""
+	Create a Payment Terms Template with %  or amount discount.
+	"""
 	create_payment_term(name or "30 Credit Days with 10% Discount")
 	template_name = template_name or "Test Discount Template"
 
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
index b88791d..ccb9e64 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
@@ -212,9 +212,10 @@
  ],
  "hide_toolbar": 1,
  "icon": "icon-resize-horizontal",
+ "is_virtual": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-08-15 05:35:50.109290",
+ "modified": "2023-11-17 17:33:55.701726",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation",
@@ -239,6 +240,5 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
- "states": [],
- "track_changes": 1
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 43167be..6673e8d 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -29,6 +29,58 @@
 		self.accounting_dimension_filter_conditions = []
 		self.ple_posting_date_filter = []
 
+	def load_from_db(self):
+		# 'modified' attribute is required for `run_doc_method` to work properly.
+		doc_dict = frappe._dict(
+			{
+				"modified": None,
+				"company": None,
+				"party": None,
+				"party_type": None,
+				"receivable_payable_account": None,
+				"default_advance_account": None,
+				"from_invoice_date": None,
+				"to_invoice_date": None,
+				"invoice_limit": 50,
+				"from_payment_date": None,
+				"to_payment_date": None,
+				"payment_limit": 50,
+				"minimum_invoice_amount": None,
+				"minimum_payment_amount": None,
+				"maximum_invoice_amount": None,
+				"maximum_payment_amount": None,
+				"bank_cash_account": None,
+				"cost_center": None,
+				"payment_name": None,
+				"invoice_name": None,
+			}
+		)
+		super(Document, self).__init__(doc_dict)
+
+	def save(self):
+		return
+
+	@staticmethod
+	def get_list(args):
+		pass
+
+	@staticmethod
+	def get_count(args):
+		pass
+
+	@staticmethod
+	def get_stats(args):
+		pass
+
+	def db_insert(self, *args, **kwargs):
+		pass
+
+	def db_update(self, *args, **kwargs):
+		pass
+
+	def delete(self):
+		pass
+
 	@frappe.whitelist()
 	def get_unreconciled_entries(self):
 		self.get_nonreconciled_payment_entries()
diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
index 71bc498..d7a73f0 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
@@ -1137,6 +1137,40 @@
 		self.assertEqual(pay.unallocated_amount, 1000)
 		self.assertEqual(pay.difference_amount, 0)
 
+	def test_rounding_of_unallocated_amount(self):
+		self.supplier = "_Test Supplier USD"
+		pi = self.create_purchase_invoice(qty=1, rate=10, do_not_submit=True)
+		pi.supplier = self.supplier
+		pi.currency = "USD"
+		pi.conversion_rate = 80
+		pi.credit_to = self.creditors_usd
+		pi.save().submit()
+
+		pe = get_payment_entry(pi.doctype, pi.name)
+		pe.target_exchange_rate = 78.726500000
+		pe.received_amount = 26.75
+		pe.paid_amount = 2105.93
+		pe.references = []
+		pe.save().submit()
+
+		# unallocated_amount will have some rounding loss - 26.749950
+		self.assertNotEqual(pe.unallocated_amount, 26.75)
+
+		pr = frappe.get_doc("Payment Reconciliation")
+		pr.company = self.company
+		pr.party_type = "Supplier"
+		pr.party = self.supplier
+		pr.receivable_payable_account = self.creditors_usd
+		pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate()
+		pr.get_unreconciled_entries()
+
+		invoices = [invoice.as_dict() for invoice in pr.invoices]
+		payments = [payment.as_dict() for payment in pr.payments]
+		pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
+
+		# Should not raise frappe.exceptions.ValidationError: Payment Entry has been modified after you pulled it. Please pull it again.
+		pr.reconcile()
+
 
 def make_customer(customer_name, currency=None):
 	if not frappe.db.exists("Customer", customer_name):
diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
index 5b8556e..491c678 100644
--- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
@@ -159,9 +159,10 @@
    "label": "Difference Posting Date"
   }
  ],
+ "is_virtual": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-23 10:44:56.066303",
+ "modified": "2023-11-17 17:33:38.612615",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation Allocation",
diff --git a/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.json b/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.json
index c4dbd7e..7c9d49e 100644
--- a/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.json
+++ b/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.json
@@ -71,9 +71,10 @@
    "label": "Exchange Rate"
   }
  ],
+ "is_virtual": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-11-08 18:18:02.502149",
+ "modified": "2023-11-17 17:33:45.455166",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation Invoice",
diff --git a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json
index 17f3900..d199236 100644
--- a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json
+++ b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json
@@ -107,9 +107,10 @@
    "options": "Cost Center"
   }
  ],
+ "is_virtual": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-09-03 07:43:29.965353",
+ "modified": "2023-11-17 17:33:34.818530",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation Payment",
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 5f0b434..c2e01c4 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -175,13 +175,6 @@
 		if self.payment_url:
 			self.db_set("payment_url", self.payment_url)
 
-		if (
-			self.payment_url
-			or not self.payment_gateway_account
-			or (self.payment_gateway_account and self.payment_channel == "Phone")
-		):
-			self.db_set("status", "Initiated")
-
 	def get_payment_url(self):
 		if self.reference_doctype != "Fees":
 			data = frappe.db.get_value(
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index f604707..955b66a 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -18,6 +18,7 @@
   "is_pos",
   "is_return",
   "update_billed_amount_in_sales_order",
+  "update_billed_amount_in_delivery_note",
   "column_break1",
   "company",
   "posting_date",
@@ -1550,12 +1551,19 @@
    "fieldtype": "Currency",
    "label": "Amount Eligible for Commission",
    "read_only": 1
+  },
+  {
+   "default": "1",
+   "depends_on": "eval: doc.is_return && doc.return_against",
+   "fieldname": "update_billed_amount_in_delivery_note",
+   "fieldtype": "Check",
+   "label": "Update Billed Amount in Delivery Note"
   }
  ],
  "icon": "fa fa-file-text",
  "is_submittable": 1,
  "links": [],
- "modified": "2023-06-03 16:23:41.083409",
+ "modified": "2023-11-20 12:27:12.848149",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index e36e97b..9091a77 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -556,7 +556,7 @@
 		return bin_qty - pos_sales_qty, is_stock_item
 	else:
 		is_stock_item = True
-		if frappe.db.exists("Product Bundle", item_code):
+		if frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0}):
 			return get_bundle_availability(item_code, warehouse), is_stock_item
 		else:
 			is_stock_item = False
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 982bdc1..200b82a 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -6,7 +6,6 @@
 
 import frappe
 from frappe import _
-from frappe.utils import add_days, nowdate
 
 from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
 from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
@@ -126,64 +125,70 @@
 		self.assertEqual(inv.grand_total, 5474.0)
 
 	def test_tax_calculation_with_item_tax_template(self):
-		import json
+		inv = create_pos_invoice(qty=84, rate=4.6, do_not_save=1)
+		item_row = inv.get("items")[0]
 
-		from erpnext.stock.get_item_details import get_item_details
-
-		# set tax template in item
-		item = frappe.get_cached_doc("Item", "_Test Item")
-		item.set(
-			"taxes",
-			[
-				{
-					"item_tax_template": "_Test Account Excise Duty @ 15 - _TC",
-					"valid_from": add_days(nowdate(), -5),
-				}
-			],
-		)
-		item.save()
-
-		# create POS invoice with item
-		pos_inv = create_pos_invoice(qty=84, rate=4.6, do_not_save=True)
-		item_details = get_item_details(
-			doc=pos_inv,
-			args={
-				"item_code": item.item_code,
-				"company": pos_inv.company,
-				"doctype": "POS Invoice",
-				"conversion_rate": 1.0,
-			},
-		)
-		tax_map = json.loads(item_details.item_tax_rate)
-		for tax in tax_map:
-			pos_inv.append(
-				"taxes",
-				{
-					"charge_type": "On Net Total",
-					"account_head": tax,
-					"rate": tax_map[tax],
-					"description": "Test",
-					"cost_center": "_Test Cost Center - _TC",
-				},
-			)
-		pos_inv.submit()
-		pos_inv.load_from_db()
-
-		# check if correct tax values are applied from tax template
-		self.assertEqual(pos_inv.net_total, 386.4)
-
-		expected_taxes = [
-			{
-				"tax_amount": 57.96,
-				"total": 444.36,
-			},
+		add_items = [
+			(54, "_Test Account Excise Duty @ 12 - _TC"),
+			(288, "_Test Account Excise Duty @ 15 - _TC"),
+			(144, "_Test Account Excise Duty @ 20 - _TC"),
+			(430, "_Test Item Tax Template 1 - _TC"),
 		]
+		for qty, item_tax_template in add_items:
+			item_row_copy = copy.deepcopy(item_row)
+			item_row_copy.qty = qty
+			item_row_copy.item_tax_template = item_tax_template
+			inv.append("items", item_row_copy)
 
-		for i in range(len(expected_taxes)):
-			for key in expected_taxes[i]:
-				self.assertEqual(expected_taxes[i][key], pos_inv.get("taxes")[i].get(key))
+		inv.append(
+			"taxes",
+			{
+				"account_head": "_Test Account Excise Duty - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "Excise Duty",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 11,
+			},
+		)
+		inv.append(
+			"taxes",
+			{
+				"account_head": "_Test Account Education Cess - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "Education Cess",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 0,
+			},
+		)
+		inv.append(
+			"taxes",
+			{
+				"account_head": "_Test Account S&H Education Cess - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "S&H Education Cess",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 3,
+			},
+		)
+		inv.insert()
 
-		self.assertEqual(pos_inv.get("base_total_taxes_and_charges"), 57.96)
+		self.assertEqual(inv.net_total, 4600)
+
+		self.assertEqual(inv.get("taxes")[0].tax_amount, 502.41)
+		self.assertEqual(inv.get("taxes")[0].total, 5102.41)
+
+		self.assertEqual(inv.get("taxes")[1].tax_amount, 197.80)
+		self.assertEqual(inv.get("taxes")[1].total, 5300.21)
+
+		self.assertEqual(inv.get("taxes")[2].tax_amount, 375.36)
+		self.assertEqual(inv.get("taxes")[2].total, 5675.57)
+
+		self.assertEqual(inv.grand_total, 5675.57)
+		self.assertEqual(inv.rounding_adjustment, 0.43)
+		self.assertEqual(inv.rounded_total, 5676.0)
 
 	def test_tax_calculation_with_multiple_items_and_discount(self):
 		inv = create_pos_invoice(qty=1, rate=75, do_not_save=True)
diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
index cb0ed3d..5a281aa 100644
--- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
+++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
@@ -186,6 +186,7 @@
    "label": "Image"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -833,7 +834,7 @@
  ],
  "istable": 1,
  "links": [],
- "modified": "2023-03-12 13:36:40.160468",
+ "modified": "2023-11-14 18:33:22.585715",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Invoice Item",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 2eaa337..4b0df12 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -180,7 +180,7 @@
 		}
 
 		this.frm.set_df_property("tax_withholding_category", "hidden", doc.apply_tds ? 0 : 1);
-		erpnext.accounts.unreconcile_payments.add_unreconcile_btn(me.frm);
+		erpnext.accounts.unreconcile_payment.add_unreconcile_btn(me.frm);
 	}
 
 	unblock_invoice() {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 53c131a..e7d2972 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -13,6 +13,7 @@
 from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
 from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
 	validate_docs_for_deferred_accounting,
+	validate_docs_for_voucher_types,
 )
 from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
 	check_if_return_invoice_linked_with_payment_entry,
@@ -491,6 +492,7 @@
 	def validate_for_repost(self):
 		self.validate_write_off_account()
 		self.validate_expense_account()
+		validate_docs_for_voucher_types(["Purchase Invoice"])
 		validate_docs_for_deferred_accounting([], [self.name])
 
 	def on_submit(self):
@@ -525,7 +527,11 @@
 		if self.update_stock == 1:
 			self.repost_future_sle_and_gle()
 
-		self.update_project()
+		if (
+			frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
+		):
+			self.update_project()
+
 		update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
 		self.update_advance_tax_references()
 
@@ -1302,7 +1308,10 @@
 		if self.update_stock == 1:
 			self.repost_future_sle_and_gle()
 
-		self.update_project()
+		if (
+			frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
+		):
+			self.update_project()
 		self.db_set("status", "Cancelled")
 
 		unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
@@ -1321,13 +1330,21 @@
 		self.update_advance_tax_references(cancel=1)
 
 	def update_project(self):
-		project_list = []
+		projects = frappe._dict()
 		for d in self.items:
-			if d.project and d.project not in project_list:
-				project = frappe.get_doc("Project", d.project)
-				project.update_purchase_costing()
-				project.db_update()
-				project_list.append(d.project)
+			if d.project:
+				if self.docstatus == 1:
+					projects[d.project] = projects.get(d.project, 0) + d.base_net_amount
+				elif self.docstatus == 2:
+					projects[d.project] = projects.get(d.project, 0) - d.base_net_amount
+
+		pj = frappe.qb.DocType("Project")
+		for proj, value in projects.items():
+			res = (
+				frappe.qb.from_(pj).select(pj.total_purchase_cost).where(pj.name == proj).for_update().run()
+			)
+			current_purchase_cost = res and res[0][0] or 0
+			frappe.db.set_value("Project", proj, "total_purchase_cost", current_purchase_cost + value)
 
 	def validate_supplier_invoice(self):
 		if self.bill_date:
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 13593bc..171cc0c 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1783,9 +1783,14 @@
 		set_advance_flag(company="_Test Company", flag=0, default_account="")
 
 	def test_gl_entries_for_standalone_debit_note(self):
-		make_purchase_invoice(qty=5, rate=500, update_stock=True)
+		from erpnext.stock.doctype.item.test_item import make_item
 
-		returned_inv = make_purchase_invoice(qty=-5, rate=5, update_stock=True, is_return=True)
+		item_code = make_item(properties={"is_stock_item": 1})
+		make_purchase_invoice(item_code=item_code, qty=5, rate=500, update_stock=True)
+
+		returned_inv = make_purchase_invoice(
+			item_code=item_code, qty=-5, rate=5, update_stock=True, is_return=True
+		)
 
 		# override the rate with valuation rate
 		sle = frappe.get_all(
@@ -1795,7 +1800,7 @@
 		)[0]
 
 		rate = flt(sle.stock_value_difference) / flt(sle.actual_qty)
-		self.assertAlmostEqual(returned_inv.items[0].rate, rate)
+		self.assertAlmostEqual(rate, 500)
 
 	def test_payment_allocation_for_payment_terms(self):
 		from erpnext.buying.doctype.purchase_order.test_purchase_order import (
@@ -1898,6 +1903,12 @@
 		disable_dimension()
 
 	def test_repost_accounting_entries(self):
+		# update repost settings
+		settings = frappe.get_doc("Repost Accounting Ledger Settings")
+		if not [x for x in settings.allowed_types if x.document_type == "Purchase Invoice"]:
+			settings.append("allowed_types", {"document_type": "Purchase Invoice", "allowed": True})
+		settings.save()
+
 		pi = make_purchase_invoice(
 			rate=1000,
 			price_list_rate=1000,
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 424e942..71796c9 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -158,6 +158,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -497,6 +498,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "project",
    "fieldtype": "Link",
    "label": "Project",
@@ -504,6 +506,7 @@
    "print_hide": 1
   },
   {
+   "allow_on_submit": 1,
    "default": ":Company",
    "depends_on": "eval:!doc.is_fixed_asset",
    "fieldname": "cost_center",
@@ -915,7 +918,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-03 21:01:01.824892",
+ "modified": "2023-11-14 18:33:48.547297",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js
index 3a87a38..c7b7a14 100644
--- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js
+++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js
@@ -5,9 +5,7 @@
 	setup: function(frm) {
 		frm.fields_dict['vouchers'].grid.get_field('voucher_type').get_query = function(doc) {
 			return {
-				filters: {
-					name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']],
-				}
+				query: "erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger.get_repost_allowed_types"
 			}
 		}
 
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py
index dbb0971..1d72a46 100644
--- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py
+++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py
@@ -10,9 +10,7 @@
 class RepostAccountingLedger(Document):
 	def __init__(self, *args, **kwargs):
 		super(RepostAccountingLedger, self).__init__(*args, **kwargs)
-		self._allowed_types = set(
-			["Purchase Invoice", "Sales Invoice", "Payment Entry", "Journal Entry"]
-		)
+		self._allowed_types = get_allowed_types_from_settings()
 
 	def validate(self):
 		self.validate_vouchers()
@@ -53,15 +51,7 @@
 
 	def validate_vouchers(self):
 		if self.vouchers:
-			# Validate voucher types
-			voucher_types = set([x.voucher_type for x in self.vouchers])
-			if disallowed_types := voucher_types.difference(self._allowed_types):
-				frappe.throw(
-					_("{0} types are not allowed. Only {1} are.").format(
-						frappe.bold(comma_and(list(disallowed_types))),
-						frappe.bold(comma_and(list(self._allowed_types))),
-					)
-				)
+			validate_docs_for_voucher_types([x.voucher_type for x in self.vouchers])
 
 	def get_existing_ledger_entries(self):
 		vouchers = [x.voucher_no for x in self.vouchers]
@@ -157,7 +147,7 @@
 					doc.docstatus = 1
 					doc.make_gl_entries()
 
-				elif doc.doctype in ["Payment Entry", "Journal Entry"]:
+				elif doc.doctype in ["Payment Entry", "Journal Entry", "Expense Claim"]:
 					if not repost_doc.delete_cancelled_entries:
 						doc.make_gl_entries(1)
 					doc.make_gl_entries()
@@ -165,6 +155,15 @@
 				frappe.db.commit()
 
 
+def get_allowed_types_from_settings():
+	return [
+		x.document_type
+		for x in frappe.db.get_all(
+			"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"]
+		)
+	]
+
+
 def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):
 	docs_with_deferred_revenue = frappe.db.get_all(
 		"Sales Invoice Item",
@@ -186,3 +185,37 @@
 				frappe.bold(comma_and([x[0] for x in docs_with_deferred_expense + docs_with_deferred_revenue]))
 			)
 		)
+
+
+def validate_docs_for_voucher_types(doc_voucher_types):
+	allowed_types = get_allowed_types_from_settings()
+	# Validate voucher types
+	voucher_types = set(doc_voucher_types)
+	if disallowed_types := voucher_types.difference(allowed_types):
+		message = "are" if len(disallowed_types) > 1 else "is"
+		frappe.throw(
+			_("{0} {1} not allowed to be reposted. Modify {2} to enable reposting.").format(
+				frappe.bold(comma_and(list(disallowed_types))),
+				message,
+				frappe.bold(
+					frappe.utils.get_link_to_form(
+						"Repost Accounting Ledger Settings", "Repost Accounting Ledger Settings"
+					)
+				),
+			)
+		)
+
+
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def get_repost_allowed_types(doctype, txt, searchfield, start, page_len, filters):
+	filters = {"allowed": True}
+
+	if txt:
+		filters.update({"document_type": ("like", f"%{txt}%")})
+
+	if allowed_types := frappe.db.get_all(
+		"Repost Allowed Types", filters=filters, fields=["distinct(document_type)"], as_list=1
+	):
+		return allowed_types
+	return []
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py
index 0e75dd2..dda0ec7 100644
--- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py
+++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py
@@ -20,10 +20,18 @@
 		self.create_company()
 		self.create_customer()
 		self.create_item()
+		self.update_repost_settings()
 
 	def teadDown(self):
 		frappe.db.rollback()
 
+	def update_repost_settings(self):
+		allowed_types = ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]
+		repost_settings = frappe.get_doc("Repost Accounting Ledger Settings")
+		for x in allowed_types:
+			repost_settings.append("allowed_types", {"document_type": x, "allowed": True})
+			repost_settings.save()
+
 	def test_01_basic_functions(self):
 		si = create_sales_invoice(
 			item=self.item,
diff --git a/erpnext/accounts/doctype/unreconcile_payments/__init__.py b/erpnext/accounts/doctype/repost_accounting_ledger_settings/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/unreconcile_payments/__init__.py
copy to erpnext/accounts/doctype/repost_accounting_ledger_settings/__init__.py
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.js b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.js
new file mode 100644
index 0000000..8c83ca5
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+// frappe.ui.form.on("Repost Accounting Ledger Settings", {
+// 	refresh(frm) {
+
+// 	},
+// });
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json
new file mode 100644
index 0000000..8aa0a84
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json
@@ -0,0 +1,46 @@
+{
+ "actions": [],
+ "creation": "2023-11-07 09:57:20.619939",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "allowed_types"
+ ],
+ "fields": [
+  {
+   "fieldname": "allowed_types",
+   "fieldtype": "Table",
+   "label": "Allowed Doctypes",
+   "options": "Repost Allowed Types"
+  }
+ ],
+ "in_create": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2023-11-07 14:24:13.321522",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Repost Accounting Ledger Settings",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "role": "Administrator",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "read": 1,
+   "role": "System Manager",
+   "select": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.py b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.py
new file mode 100644
index 0000000..2b8230d
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class RepostAccountingLedgerSettings(Document):
+	pass
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_settings/test_repost_accounting_ledger_settings.py b/erpnext/accounts/doctype/repost_accounting_ledger_settings/test_repost_accounting_ledger_settings.py
new file mode 100644
index 0000000..ec4e87f
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_accounting_ledger_settings/test_repost_accounting_ledger_settings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestRepostAccountingLedgerSettings(FrappeTestCase):
+	pass
diff --git a/erpnext/accounts/doctype/unreconcile_payments/__init__.py b/erpnext/accounts/doctype/repost_allowed_types/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/unreconcile_payments/__init__.py
copy to erpnext/accounts/doctype/repost_allowed_types/__init__.py
diff --git a/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.json b/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.json
new file mode 100644
index 0000000..ede12fb
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.json
@@ -0,0 +1,45 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2023-11-07 09:58:03.595382",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "document_type",
+  "column_break_sfzb",
+  "allowed"
+ ],
+ "fields": [
+  {
+   "fieldname": "document_type",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Doctype",
+   "options": "DocType"
+  },
+  {
+   "default": "0",
+   "fieldname": "allowed",
+   "fieldtype": "Check",
+   "in_list_view": 1,
+   "label": "Allowed"
+  },
+  {
+   "fieldname": "column_break_sfzb",
+   "fieldtype": "Column Break"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2023-11-07 10:01:39.217861",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Repost Allowed Types",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.py b/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.py
new file mode 100644
index 0000000..0e4883b
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_allowed_types/repost_allowed_types.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class RepostAllowedTypes(Document):
+	pass
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index d4d9239..6763e44 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -37,7 +37,7 @@
 		super.onload();
 
 		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log',
-							  'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payments", "Unreconcile Payment Entries"];
+							  'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries"];
 
 		if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
 			// show debit_to in print format
@@ -184,10 +184,9 @@
 			}
 		}
 
-		erpnext.accounts.unreconcile_payments.add_unreconcile_btn(me.frm);
+		erpnext.accounts.unreconcile_payment.add_unreconcile_btn(me.frm);
 	}
 
-
 	make_maintenance_schedule() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
@@ -563,15 +562,6 @@
 	}
 }
 
-// Income Account in Details Table
-// --------------------------------
-cur_frm.set_query("income_account", "items", function(doc) {
-	return{
-		query: "erpnext.controllers.queries.get_income_account",
-		filters: {'company': doc.company}
-	}
-});
-
 // Cost Center in Details Table
 // -----------------------------
 cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
@@ -666,6 +656,16 @@
 			};
 		});
 
+		frm.set_query("income_account", "items", function() {
+			return{
+				query: "erpnext.controllers.queries.get_income_account",
+				filters: {
+					'company': frm.doc.company,
+					"disabled": 0
+				}
+			}
+		});
+
 		frm.custom_make_buttons = {
 			'Delivery Note': 'Delivery',
 			'Sales Invoice': 'Return / Credit Note',
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index cd725b9..f209487 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1615,7 +1615,8 @@
    "hide_seconds": 1,
    "label": "Inter Company Invoice Reference",
    "options": "Purchase Invoice",
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "customer_group",
@@ -2156,7 +2157,7 @@
    "label": "Use Company default Cost Center for Round off"
   },
   {
-   "default": "0",
+   "default": "1",
    "depends_on": "eval: doc.is_return",
    "fieldname": "update_billed_amount_in_delivery_note",
    "fieldtype": "Check",
@@ -2173,7 +2174,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2023-11-03 14:39:38.012346",
+ "modified": "2023-11-23 16:56:29.679499",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 87b40c0..cc81227 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -17,6 +17,7 @@
 )
 from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
 	validate_docs_for_deferred_accounting,
+	validate_docs_for_voucher_types,
 )
 from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
 	get_party_tax_withholding_details,
@@ -172,6 +173,7 @@
 		self.validate_write_off_account()
 		self.validate_account_for_change_amount()
 		self.validate_income_account()
+		validate_docs_for_voucher_types(["Sales Invoice"])
 		validate_docs_for_deferred_accounting([self.name], [])
 
 	def validate_fixed_asset(self):
@@ -395,7 +397,7 @@
 			"Repost Payment Ledger Items",
 			"Repost Accounting Ledger",
 			"Repost Accounting Ledger Items",
-			"Unreconcile Payments",
+			"Unreconcile Payment",
 			"Unreconcile Payment Entries",
 			"Payment Ledger Entry",
 			"Serial and Batch Bundle",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 21cc253..017bfa9 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -516,72 +516,70 @@
 		self.assertEqual(si.grand_total, 5474.0)
 
 	def test_tax_calculation_with_item_tax_template(self):
-		import json
-
-		from erpnext.stock.get_item_details import get_item_details
-
-		# set tax template in item
-		item = frappe.get_cached_doc("Item", "_Test Item")
-		item.set(
-			"taxes",
-			[
-				{
-					"item_tax_template": "_Test Item Tax Template 1 - _TC",
-					"valid_from": add_days(nowdate(), -5),
-				}
-			],
-		)
-		item.save()
-
-		# create sales invoice with item
 		si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
-		item_details = get_item_details(
-			doc=si,
-			args={
-				"item_code": item.item_code,
-				"company": si.company,
-				"doctype": "Sales Invoice",
-				"conversion_rate": 1.0,
+		item_row = si.get("items")[0]
+
+		add_items = [
+			(54, "_Test Account Excise Duty @ 12 - _TC"),
+			(288, "_Test Account Excise Duty @ 15 - _TC"),
+			(144, "_Test Account Excise Duty @ 20 - _TC"),
+			(430, "_Test Item Tax Template 1 - _TC"),
+		]
+		for qty, item_tax_template in add_items:
+			item_row_copy = copy.deepcopy(item_row)
+			item_row_copy.qty = qty
+			item_row_copy.item_tax_template = item_tax_template
+			si.append("items", item_row_copy)
+
+		si.append(
+			"taxes",
+			{
+				"account_head": "_Test Account Excise Duty - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "Excise Duty",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 11,
 			},
 		)
-		tax_map = json.loads(item_details.item_tax_rate)
-		for tax in tax_map:
-			si.append(
-				"taxes",
-				{
-					"charge_type": "On Net Total",
-					"account_head": tax,
-					"rate": tax_map[tax],
-					"description": "Test",
-					"cost_center": "_Test Cost Center - _TC",
-				},
-			)
-		si.submit()
-		si.load_from_db()
-
-		# check if correct tax values are applied from tax template
-		self.assertEqual(si.net_total, 386.4)
-
-		expected_taxes = [
+		si.append(
+			"taxes",
 			{
-				"tax_amount": 19.32,
-				"total": 405.72,
+				"account_head": "_Test Account Education Cess - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "Education Cess",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 0,
 			},
+		)
+		si.append(
+			"taxes",
 			{
-				"tax_amount": 38.64,
-				"total": 444.36,
+				"account_head": "_Test Account S&H Education Cess - _TC",
+				"charge_type": "On Net Total",
+				"cost_center": "_Test Cost Center - _TC",
+				"description": "S&H Education Cess",
+				"doctype": "Sales Taxes and Charges",
+				"rate": 3,
 			},
-			{
-				"tax_amount": 57.96,
-				"total": 502.32,
-			},
-		]
+		)
+		si.insert()
 
-		for i in range(len(expected_taxes)):
-			for key in expected_taxes[i]:
-				self.assertEqual(expected_taxes[i][key], si.get("taxes")[i].get(key))
+		self.assertEqual(si.net_total, 4600)
 
-		self.assertEqual(si.get("base_total_taxes_and_charges"), 115.92)
+		self.assertEqual(si.get("taxes")[0].tax_amount, 502.41)
+		self.assertEqual(si.get("taxes")[0].total, 5102.41)
+
+		self.assertEqual(si.get("taxes")[1].tax_amount, 197.80)
+		self.assertEqual(si.get("taxes")[1].total, 5300.21)
+
+		self.assertEqual(si.get("taxes")[2].tax_amount, 375.36)
+		self.assertEqual(si.get("taxes")[2].total, 5675.57)
+
+		self.assertEqual(si.grand_total, 5675.57)
+		self.assertEqual(si.rounding_adjustment, 0.43)
+		self.assertEqual(si.rounded_total, 5676.0)
 
 	def test_tax_calculation_with_multiple_items_and_discount(self):
 		si = create_sales_invoice(qty=1, rate=75, do_not_save=True)
@@ -791,6 +789,28 @@
 		w = self.make()
 		self.assertEqual(w.outstanding_amount, w.base_rounded_total)
 
+	def test_rounded_total_with_cash_discount(self):
+		si = frappe.copy_doc(test_records[2])
+
+		item = copy.deepcopy(si.get("items")[0])
+		item.update(
+			{
+				"qty": 1,
+				"rate": 14960.66,
+			}
+		)
+
+		si.set("items", [item])
+		si.set("taxes", [])
+		si.apply_discount_on = "Grand Total"
+		si.is_cash_or_non_trade_discount = 1
+		si.discount_amount = 1
+		si.insert()
+
+		self.assertEqual(si.grand_total, 14959.66)
+		self.assertEqual(si.rounded_total, 14960)
+		self.assertEqual(si.rounding_adjustment, 0.34)
+
 	def test_payment(self):
 		w = self.make()
 
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 5d2764b..a403b14 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -167,6 +167,7 @@
    "print_hide": 1
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -901,7 +902,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-07-26 12:53:22.404057",
+ "modified": "2023-11-14 18:34:10.479329",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice Item",
@@ -911,4 +912,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "states": []
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/unreconcile_payments/__init__.py b/erpnext/accounts/doctype/unreconcile_payment/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/unreconcile_payments/__init__.py
rename to erpnext/accounts/doctype/unreconcile_payment/__init__.py
diff --git a/erpnext/accounts/doctype/unreconcile_payments/test_unreconcile_payments.py b/erpnext/accounts/doctype/unreconcile_payment/test_unreconcile_payment.py
similarity index 96%
rename from erpnext/accounts/doctype/unreconcile_payments/test_unreconcile_payments.py
rename to erpnext/accounts/doctype/unreconcile_payment/test_unreconcile_payment.py
index 78e04bf..f404d99 100644
--- a/erpnext/accounts/doctype/unreconcile_payments/test_unreconcile_payments.py
+++ b/erpnext/accounts/doctype/unreconcile_payment/test_unreconcile_payment.py
@@ -10,7 +10,7 @@
 from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
 
 
-class TestUnreconcilePayments(AccountsTestMixin, FrappeTestCase):
+class TestUnreconcilePayment(AccountsTestMixin, FrappeTestCase):
 	def setUp(self):
 		self.create_company()
 		self.create_customer()
@@ -73,7 +73,7 @@
 
 		unreconcile = frappe.get_doc(
 			{
-				"doctype": "Unreconcile Payments",
+				"doctype": "Unreconcile Payment",
 				"company": self.company,
 				"voucher_type": pe.doctype,
 				"voucher_no": pe.name,
@@ -138,7 +138,7 @@
 
 		unreconcile = frappe.get_doc(
 			{
-				"doctype": "Unreconcile Payments",
+				"doctype": "Unreconcile Payment",
 				"company": self.company,
 				"voucher_type": pe2.doctype,
 				"voucher_no": pe2.name,
@@ -196,7 +196,7 @@
 
 		unreconcile = frappe.get_doc(
 			{
-				"doctype": "Unreconcile Payments",
+				"doctype": "Unreconcile Payment",
 				"company": self.company,
 				"voucher_type": pe.doctype,
 				"voucher_no": pe.name,
@@ -281,7 +281,7 @@
 
 		unreconcile = frappe.get_doc(
 			{
-				"doctype": "Unreconcile Payments",
+				"doctype": "Unreconcile Payment",
 				"company": self.company,
 				"voucher_type": pe2.doctype,
 				"voucher_no": pe2.name,
diff --git a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.js b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.js
similarity index 93%
rename from erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.js
rename to erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.js
index c522567..70cefb1 100644
--- a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.js
+++ b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.js
@@ -1,7 +1,7 @@
 // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
 
-frappe.ui.form.on("Unreconcile Payments", {
+frappe.ui.form.on("Unreconcile Payment", {
 	refresh(frm) {
 		frm.set_query("voucher_type", function() {
 			return {
diff --git a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.json b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.json
similarity index 95%
rename from erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.json
rename to erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.json
index f29e61b..f906dc6 100644
--- a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.json
+++ b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.json
@@ -21,7 +21,7 @@
    "fieldtype": "Link",
    "label": "Amended From",
    "no_copy": 1,
-   "options": "Unreconcile Payments",
+   "options": "Unreconcile Payment",
    "print_hide": 1,
    "read_only": 1
   },
@@ -61,7 +61,7 @@
  "modified": "2023-08-28 17:42:50.261377",
  "modified_by": "Administrator",
  "module": "Accounts",
- "name": "Unreconcile Payments",
+ "name": "Unreconcile Payment",
  "naming_rule": "Expression",
  "owner": "Administrator",
  "permissions": [
@@ -90,4 +90,4 @@
  "sort_order": "DESC",
  "states": [],
  "track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.py b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py
similarity index 97%
rename from erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.py
rename to erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py
index 4f9fb50..77906a7 100644
--- a/erpnext/accounts/doctype/unreconcile_payments/unreconcile_payments.py
+++ b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py
@@ -15,7 +15,7 @@
 )
 
 
-class UnreconcilePayments(Document):
+class UnreconcilePayment(Document):
 	def validate(self):
 		self.supported_types = ["Payment Entry", "Journal Entry"]
 		if not self.voucher_type in self.supported_types:
@@ -142,7 +142,7 @@
 		selections = frappe.json.loads(selections)
 		# assuming each row is a unique voucher
 		for row in selections:
-			unrecon = frappe.new_doc("Unreconcile Payments")
+			unrecon = frappe.new_doc("Unreconcile Payment")
 			unrecon.company = row.get("company")
 			unrecon.voucher_type = row.get("voucher_type")
 			unrecon.voucher_no = row.get("voucher_no")
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 16e73ea..5c18e50 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -31,7 +31,12 @@
 from erpnext.exceptions import InvalidAccountCurrency, PartyDisabled, PartyFrozen
 from erpnext.utilities.regional import temporary_flag
 
-PURCHASE_TRANSACTION_TYPES = {"Purchase Order", "Purchase Receipt", "Purchase Invoice"}
+PURCHASE_TRANSACTION_TYPES = {
+	"Supplier Quotation",
+	"Purchase Order",
+	"Purchase Receipt",
+	"Purchase Invoice",
+}
 SALES_TRANSACTION_TYPES = {
 	"Quotation",
 	"Sales Order",
@@ -231,7 +236,9 @@
 		if shipping_address:
 			party_details.update(
 				shipping_address=shipping_address,
-				shipping_address_display=render_address(shipping_address),
+				shipping_address_display=render_address(
+					shipping_address, check_permissions=not ignore_permissions
+				),
 				**get_fetch_values(doctype, "shipping_address", shipping_address)
 			)
 
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index eff705d..b608ebc 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -145,6 +145,16 @@
 			"fieldtype": "Check",
 		},
 		{
+			"fieldname": "in_party_currency",
+			"label": __("In Party Currency"),
+			"fieldtype": "Check",
+		},
+		{
+			"fieldname": "for_revaluation_journals",
+			"label": __("Revaluation Journals"),
+			"fieldtype": "Check",
+		},
+		{
 			"fieldname": "ignore_accounts",
 			"label": __("Group by Voucher"),
 			"fieldtype": "Check",
diff --git a/erpnext/accounts/report/accounts_payable/test_accounts_payable.py b/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
index 9f03d92..b4cb25f 100644
--- a/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
+++ b/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
@@ -40,6 +40,7 @@
 			"range2": 60,
 			"range3": 90,
 			"range4": 120,
+			"in_party_currency": 1,
 		}
 
 		data = execute(filters)
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 9e575e6..0f206b1 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -110,6 +110,11 @@
 			"fieldname":"based_on_payment_terms",
 			"label": __("Based On Payment Terms"),
 			"fieldtype": "Check",
+		},
+		{
+			"fieldname": "for_revaluation_journals",
+			"label": __("Revaluation Journals"),
+			"fieldtype": "Check",
 		}
 	],
 
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 786aad6..b4bc887 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -114,10 +114,13 @@
 			"reqd": 1
 		},
 		{
-			"fieldname": "customer_group",
+			"fieldname":"customer_group",
 			"label": __("Customer Group"),
-			"fieldtype": "Link",
-			"options": "Customer Group"
+			"fieldtype": "MultiSelectList",
+			"options": "Customer Group",
+			get_data: function(txt) {
+				return frappe.db.get_link_options('Customer Group', txt);
+			}
 		},
 		{
 			"fieldname": "payment_terms_template",
@@ -174,11 +177,22 @@
 			"fieldtype": "Check",
 		},
 		{
+			"fieldname": "in_party_currency",
+			"label": __("In Party Currency"),
+			"fieldtype": "Check",
+		},
+		{
+			"fieldname": "for_revaluation_journals",
+			"label": __("Revaluation Journals"),
+			"fieldtype": "Check",
+		},
+		{
 			"fieldname": "ignore_accounts",
 			"label": __("Group by Voucher"),
 			"fieldtype": "Check",
 		}
 
+
 	],
 
 	"formatter": function(value, row, column, data, default_formatter) {
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
old mode 100755
new mode 100644
index f24a24e..0e62ad6
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -7,14 +7,14 @@
 import frappe
 from frappe import _, qb, scrub
 from frappe.query_builder import Criterion
-from frappe.query_builder.functions import Date, Sum
+from frappe.query_builder.functions import Date, Substring, Sum
 from frappe.utils import cint, cstr, flt, getdate, nowdate
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_accounting_dimensions,
 	get_dimension_with_children,
 )
-from erpnext.accounts.utils import get_currency_precision
+from erpnext.accounts.utils import get_currency_precision, get_party_types_from_account_type
 
 #  This report gives a summary of all Outstanding Invoices considering the following
 
@@ -28,8 +28,8 @@
 #  6. Configurable Ageing Groups (0-30, 30-60 etc) can be set via filters
 #  7. For overpayment against an invoice with payment terms, there will be an additional row
 #  8. Invoice details like Sales Persons, Delivery Notes are also fetched comma separated
-#  9. Report amounts are in "Party Currency" if party is selected, or company currency for multi-party
-# 10. This reports is based on all GL Entries that are made against account_type "Receivable" or "Payable"
+#  9. Report amounts are in party currency if in_party_currency is selected, otherwise company currency
+# 10. This report is based on Payment Ledger Entries
 
 
 def execute(filters=None):
@@ -72,9 +72,7 @@
 		self.currency_precision = get_currency_precision() or 2
 		self.dr_or_cr = "debit" if self.filters.account_type == "Receivable" else "credit"
 		self.account_type = self.filters.account_type
-		self.party_type = frappe.db.get_all(
-			"Party Type", {"account_type": self.account_type}, pluck="name"
-		)
+		self.party_type = get_party_types_from_account_type(self.account_type)
 		self.party_details = {}
 		self.invoices = set()
 		self.skip_total_row = 0
@@ -84,6 +82,9 @@
 			self.total_row_map = {}
 			self.skip_total_row = 1
 
+		if self.filters.get("in_party_currency"):
+			self.skip_total_row = 1
+
 	def get_data(self):
 		self.get_ple_entries()
 		self.get_sales_invoices_or_customers_based_on_sales_person()
@@ -117,7 +118,7 @@
 		for ple in self.ple_entries:
 			# get the balance object for voucher_type
 
-			if self.filters.get("ingore_accounts"):
+			if self.filters.get("ignore_accounts"):
 				key = (ple.voucher_type, ple.voucher_no, ple.party)
 			else:
 				key = (ple.account, ple.voucher_type, ple.voucher_no, ple.party)
@@ -145,7 +146,7 @@
 			if self.filters.get("group_by_party"):
 				self.init_subtotal_row(ple.party)
 
-		if self.filters.get("group_by_party"):
+		if self.filters.get("group_by_party") and not self.filters.get("in_party_currency"):
 			self.init_subtotal_row("Total")
 
 	def get_invoices(self, ple):
@@ -188,7 +189,7 @@
 			):
 				return
 
-		if self.filters.get("ingore_accounts"):
+		if self.filters.get("ignore_accounts"):
 			key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
 		else:
 			key = (ple.account, ple.against_voucher_type, ple.against_voucher_no, ple.party)
@@ -200,7 +201,7 @@
 			if ple.against_voucher_no in self.return_entries:
 				return_against = self.return_entries.get(ple.against_voucher_no)
 				if return_against:
-					if self.filters.get("ingore_accounts"):
+					if self.filters.get("ignore_accounts"):
 						key = (ple.against_voucher_type, return_against, ple.party)
 					else:
 						key = (ple.account, ple.against_voucher_type, return_against, ple.party)
@@ -209,7 +210,7 @@
 
 		if not row:
 			# no invoice, this is an invoice / stand-alone payment / credit note
-			if self.filters.get("ingore_accounts"):
+			if self.filters.get("ignore_accounts"):
 				row = self.voucher_balance.get((ple.voucher_type, ple.voucher_no, ple.party))
 			else:
 				row = self.voucher_balance.get((ple.account, ple.voucher_type, ple.voucher_no, ple.party))
@@ -224,8 +225,7 @@
 		if not row:
 			return
 
-		# amount in "Party Currency", if its supplied. If not, amount in company currency
-		if self.filters.get("party_type") and self.filters.get("party"):
+		if self.filters.get("in_party_currency"):
 			amount = ple.amount_in_account_currency
 		else:
 			amount = ple.amount
@@ -256,8 +256,10 @@
 	def update_sub_total_row(self, row, party):
 		total_row = self.total_row_map.get(party)
 
-		for field in self.get_currency_fields():
-			total_row[field] += row.get(field, 0.0)
+		if total_row:
+			for field in self.get_currency_fields():
+				total_row[field] += row.get(field, 0.0)
+			total_row["currency"] = row.get("currency", "")
 
 	def append_subtotal_row(self, party):
 		sub_total_row = self.total_row_map.get(party)
@@ -281,11 +283,20 @@
 
 			row.invoice_grand_total = row.invoiced
 
-			if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
-				(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
-				or (row.voucher_no in self.err_journals)
-			):
+			must_consider = False
+			if self.filters.get("for_revaluation_journals"):
+				if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) or (
+					(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
+				):
+					must_consider = True
+			else:
+				if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
+					(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
+					or (row.voucher_no in self.err_journals)
+				):
+					must_consider = True
 
+			if must_consider:
 				# non-zero oustanding, we must consider this row
 
 				if self.is_invoice(row) and self.filters.based_on_payment_terms:
@@ -309,7 +320,7 @@
 		if self.filters.get("group_by_party"):
 			self.append_subtotal_row(self.previous_party)
 			if self.data:
-				self.data.append(self.total_row_map.get("Total"))
+				self.data.append(self.total_row_map.get("Total", {}))
 
 	def append_row(self, row):
 		self.allocate_future_payments(row)
@@ -440,7 +451,7 @@
 		party_details = self.get_party_details(row.party) or {}
 		row.update(party_details)
 
-		if self.filters.get("party_type") and self.filters.get("party"):
+		if self.filters.get("in_party_currency"):
 			row.currency = row.account_currency
 		else:
 			row.currency = self.company_currency
@@ -753,7 +764,12 @@
 		)
 
 		if self.filters.get("show_remarks"):
-			query = query.select(ple.remarks)
+			if remarks_length := frappe.db.get_single_value(
+				"Accounts Settings", "receivable_payable_remarks_length"
+			):
+				query = query.select(Substring(ple.remarks, 1, remarks_length).as_("remarks"))
+			else:
+				query = query.select(ple.remarks)
 
 		if self.filters.get("group_by_party"):
 			query = query.orderby(self.ple.party, self.ple.posting_date)
@@ -840,7 +856,13 @@
 		self.customer = qb.DocType("Customer")
 
 		if self.filters.get("customer_group"):
-			self.get_hierarchical_filters("Customer Group", "customer_group")
+			groups = get_customer_group_with_children(self.filters.customer_group)
+			customers = (
+				qb.from_(self.customer)
+				.select(self.customer.name)
+				.where(self.customer["customer_group"].isin(groups))
+			)
+			self.qb_selection_filter.append(self.ple.party.isin(customers))
 
 		if self.filters.get("territory"):
 			self.get_hierarchical_filters("Territory", "territory")
@@ -1132,3 +1154,19 @@
 			.run()
 		)
 		self.err_journals = [x[0] for x in results] if results else []
+
+
+def get_customer_group_with_children(customer_groups):
+	if not isinstance(customer_groups, list):
+		customer_groups = [d.strip() for d in customer_groups.strip().split(",") if d]
+
+	all_customer_groups = []
+	for d in customer_groups:
+		if frappe.db.exists("Customer Group", d):
+			lft, rgt = frappe.db.get_value("Customer Group", d, ["lft", "rgt"])
+			children = frappe.get_all("Customer Group", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
+			all_customer_groups += [c.name for c in children]
+		else:
+			frappe.throw(_("Customer Group: {0} does not exist").format(d))
+
+	return list(set(all_customer_groups))
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index cbeb6d3..dd0842d 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -475,6 +475,30 @@
 		report = execute(filters)[1]
 		self.assertEqual(len(report), 0)
 
+	def test_multi_customer_group_filter(self):
+		si = self.create_sales_invoice()
+		cus_group = frappe.db.get_value("Customer", self.customer, "customer_group")
+		# Create a list of customer groups, e.g., ["Group1", "Group2"]
+		cus_groups_list = [cus_group, "_Test Customer Group 1"]
+
+		filters = {
+			"company": self.company,
+			"report_date": today(),
+			"range1": 30,
+			"range2": 60,
+			"range3": 90,
+			"range4": 120,
+			"customer_group": cus_groups_list,  # Use the list of customer groups
+		}
+		report = execute(filters)[1]
+
+		# Assert that the report contains data for the specified customer groups
+		self.assertTrue(len(report) > 0)
+
+		for row in report:
+			# Assert that the customer group of each row is in the list of customer groups
+			self.assertIn(row.customer_group, cus_groups_list)
+
 	def test_party_account_filter(self):
 		si1 = self.create_sales_invoice()
 		self.customer2 = (
@@ -557,6 +581,7 @@
 			"range2": 60,
 			"range3": 90,
 			"range4": 120,
+			"in_party_currency": 1,
 		}
 
 		si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
index 5ad10c7..2f6d258 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -139,6 +139,11 @@
 			"label": __("Show GL Balance"),
 			"fieldtype": "Check",
 		},
+		{
+			"fieldname": "for_revaluation_journals",
+			"label": __("Revaluation Journals"),
+			"fieldtype": "Check",
+		}
 	],
 
 	onload: function(report) {
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index 60274cd..d50cf07 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -8,6 +8,7 @@
 
 from erpnext.accounts.party import get_partywise_advanced_payment_amount
 from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport
+from erpnext.accounts.utils import get_party_types_from_account_type
 
 
 def execute(filters=None):
@@ -22,9 +23,7 @@
 class AccountsReceivableSummary(ReceivablePayableReport):
 	def run(self, args):
 		self.account_type = args.get("account_type")
-		self.party_type = frappe.db.get_all(
-			"Party Type", {"account_type": self.account_type}, pluck="name"
-		)
+		self.party_type = get_party_types_from_account_type(self.account_type)
 		self.party_naming_by = frappe.db.get_value(
 			args.get("naming_by")[0], None, args.get("naming_by")[1]
 		)
diff --git a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.js b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.js
index 126cd03..12b9434 100644
--- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.js
+++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.js
@@ -32,16 +32,28 @@
 			"options": "Asset"
 		},
 		{
+			"fieldname":"asset_category",
+			"label": __("Asset Category"),
+			"fieldtype": "Link",
+			"options": "Asset Category"
+		},
+		{
+			"fieldname":"cost_center",
+			"label": __("Cost Center"),
+			"fieldtype": "Link",
+			"options": "Cost Center"
+		},
+		{
 			"fieldname":"finance_book",
 			"label": __("Finance Book"),
 			"fieldtype": "Link",
 			"options": "Finance Book"
 		},
 		{
-			"fieldname":"asset_category",
-			"label": __("Asset Category"),
-			"fieldtype": "Link",
-			"options": "Asset Category"
-		}
+			"fieldname": "include_default_book_assets",
+			"label": __("Include Default FB Assets"),
+			"fieldtype": "Check",
+			"default": 1
+		},
 	]
 }
diff --git a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.json b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.json
index 0ef9d85..9002e23 100644
--- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.json
+++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.json
@@ -1,15 +1,15 @@
 {
- "add_total_row": 1,
+ "add_total_row": 0,
  "columns": [],
  "creation": "2016-04-08 14:49:58.133098",
  "disabled": 0,
  "docstatus": 0,
  "doctype": "Report",
  "filters": [],
- "idx": 2,
+ "idx": 6,
  "is_standard": "Yes",
  "letterhead": null,
- "modified": "2023-07-26 21:05:33.554778",
+ "modified": "2023-11-08 20:17:05.774211",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Asset Depreciation Ledger",
diff --git a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py
index f21c94b..d285f28 100644
--- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py
+++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py
@@ -4,7 +4,7 @@
 
 import frappe
 from frappe import _
-from frappe.utils import flt
+from frappe.utils import cstr, flt
 
 
 def execute(filters=None):
@@ -32,7 +32,6 @@
 		filters_data.append(["against_voucher", "=", filters.get("asset")])
 
 	if filters.get("asset_category"):
-
 		assets = frappe.db.sql_list(
 			"""select name from tabAsset
 			where asset_category = %s and docstatus=1""",
@@ -41,12 +40,27 @@
 
 		filters_data.append(["against_voucher", "in", assets])
 
-	if filters.get("finance_book"):
-		filters_data.append(["finance_book", "in", ["", filters.get("finance_book")]])
+	company_fb = frappe.get_cached_value("Company", filters.get("company"), "default_finance_book")
+
+	if filters.get("include_default_book_assets") and company_fb:
+		if filters.get("finance_book") and cstr(filters.get("finance_book")) != cstr(company_fb):
+			frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Assets'"))
+		else:
+			finance_book = company_fb
+	elif filters.get("finance_book"):
+		finance_book = filters.get("finance_book")
+	else:
+		finance_book = None
+
+	if finance_book:
+		or_filters_data = [["finance_book", "in", ["", finance_book]], ["finance_book", "is", "not set"]]
+	else:
+		or_filters_data = [["finance_book", "in", [""]], ["finance_book", "is", "not set"]]
 
 	gl_entries = frappe.get_all(
 		"GL Entry",
 		filters=filters_data,
+		or_filters=or_filters_data,
 		fields=["against_voucher", "debit_in_account_currency as debit", "voucher_no", "posting_date"],
 		order_by="against_voucher, posting_date",
 	)
@@ -61,7 +75,9 @@
 		asset_data = assets_details.get(d.against_voucher)
 		if asset_data:
 			if not asset_data.get("accumulated_depreciation_amount"):
-				asset_data.accumulated_depreciation_amount = d.debit
+				asset_data.accumulated_depreciation_amount = d.debit + asset_data.get(
+					"opening_accumulated_depreciation"
+				)
 			else:
 				asset_data.accumulated_depreciation_amount += d.debit
 
@@ -70,7 +86,7 @@
 				{
 					"depreciation_amount": d.debit,
 					"depreciation_date": d.posting_date,
-					"amount_after_depreciation": (
+					"value_after_depreciation": (
 						flt(row.gross_purchase_amount) - flt(row.accumulated_depreciation_amount)
 					),
 					"depreciation_entry": d.voucher_no,
@@ -88,10 +104,12 @@
 	fields = [
 		"name as asset",
 		"gross_purchase_amount",
+		"opening_accumulated_depreciation",
 		"asset_category",
 		"status",
 		"depreciation_method",
 		"purchase_date",
+		"cost_center",
 	]
 
 	for d in frappe.get_all("Asset", fields=fields, filters={"name": ("in", assets)}):
@@ -122,6 +140,12 @@
 			"width": 120,
 		},
 		{
+			"label": _("Opening Accumulated Depreciation"),
+			"fieldname": "opening_accumulated_depreciation",
+			"fieldtype": "Currency",
+			"width": 140,
+		},
+		{
 			"label": _("Depreciation Amount"),
 			"fieldname": "depreciation_amount",
 			"fieldtype": "Currency",
@@ -134,8 +158,8 @@
 			"width": 210,
 		},
 		{
-			"label": _("Amount After Depreciation"),
-			"fieldname": "amount_after_depreciation",
+			"label": _("Value After Depreciation"),
+			"fieldname": "value_after_depreciation",
 			"fieldtype": "Currency",
 			"width": 180,
 		},
@@ -153,12 +177,13 @@
 			"options": "Asset Category",
 			"width": 120,
 		},
-		{"label": _("Current Status"), "fieldname": "status", "fieldtype": "Data", "width": 120},
 		{
-			"label": _("Depreciation Method"),
-			"fieldname": "depreciation_method",
-			"fieldtype": "Data",
-			"width": 130,
+			"label": _("Cost Center"),
+			"fieldtype": "Link",
+			"fieldname": "cost_center",
+			"options": "Cost Center",
+			"width": 100,
 		},
+		{"label": _("Current Status"), "fieldname": "status", "fieldtype": "Data", "width": 120},
 		{"label": _("Purchase Date"), "fieldname": "purchase_date", "fieldtype": "Date", "width": 120},
 	]
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.js b/erpnext/accounts/report/balance_sheet/balance_sheet.js
index c2b57f7..b05e744 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.js
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.js
@@ -17,7 +17,7 @@
 
 frappe.query_reports["Balance Sheet"]["filters"].push({
 	fieldname: "include_default_book_entries",
-	label: __("Include Default Book Entries"),
+	label: __("Include Default FB Entries"),
 	fieldtype: "Check",
 	default: 1,
 });
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.js b/erpnext/accounts/report/cash_flow/cash_flow.js
index 6b8ed27..ef17eb1 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.js
+++ b/erpnext/accounts/report/cash_flow/cash_flow.js
@@ -17,7 +17,7 @@
 frappe.query_reports["Cash Flow"]["filters"].push(
 	{
 		"fieldname": "include_default_book_entries",
-		"label": __("Include Default Book Entries"),
+		"label": __("Include Default FB Entries"),
 		"fieldtype": "Check",
 		"default": 1
 	}
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
index 590408c..0e0c42d 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
@@ -104,7 +104,7 @@
 		},
 		{
 			"fieldname": "include_default_book_entries",
-			"label": __("Include Default Book Entries"),
+			"label": __("Include Default FB Entries"),
 			"fieldtype": "Check",
 			"default": 1
 		},
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 693725d..096bb10 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -561,9 +561,7 @@
 			company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
 
 			if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
-				frappe.throw(
-					_("To use a different finance book, please uncheck 'Include Default Book Entries'")
-				)
+				frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
 
 			query = query.where(
 				(gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index c0b4f59..4cb443c 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -175,7 +175,7 @@
 		},
 		{
 			"fieldname": "include_default_book_entries",
-			"label": __("Include Default Book Entries"),
+			"label": __("Include Default FB Entries"),
 			"fieldtype": "Check",
 			"default": 1
 		},
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 5e484cf..fa557a1 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -164,7 +164,12 @@
 		credit_in_account_currency """
 
 	if filters.get("show_remarks"):
-		select_fields += """,remarks"""
+		if remarks_length := frappe.db.get_single_value(
+			"Accounts Settings", "general_ledger_remarks_length"
+		):
+			select_fields += f",substr(remarks, 1, {remarks_length}) as 'remarks'"
+		else:
+			select_fields += """,remarks"""
 
 	order_by_statement = "order by posting_date, account, creation"
 
@@ -259,9 +264,7 @@
 			if filters.get("company_fb") and cstr(filters.get("finance_book")) != cstr(
 				filters.get("company_fb")
 			):
-				frappe.throw(
-					_("To use a different finance book, please uncheck 'Include Default Book Entries'")
-				)
+				frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
 			else:
 				conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
 		else:
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
index e842d2e..f6c7bd3 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
@@ -184,6 +184,16 @@
 				"width": 180,
 			}
 		)
+	else:
+		columns.append(
+			{
+				"label": _(filters.get("party_type")),
+				"fieldname": "party",
+				"fieldtype": "Dynamic Link",
+				"options": "party_type",
+				"width": 180,
+			}
+		)
 
 	columns.extend(
 		[
@@ -316,7 +326,7 @@
 	if not tds_accounts:
 		frappe.throw(
 			_("No {0} Accounts found for this company.").format(frappe.bold("Tax Withholding")),
-			title="Accounts Missing Error",
+			title=_("Accounts Missing Error"),
 		)
 	gle = frappe.qb.DocType("GL Entry")
 	query = (
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index edd40b6..2c4c762 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -95,7 +95,7 @@
 		},
 		{
 			"fieldname": "include_default_book_entries",
-			"label": __("Include Default Book Entries"),
+			"label": __("Include Default FB Entries"),
 			"fieldtype": "Check",
 			"default": 1
 		},
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 2a8aa0c..8b7f0bb 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -275,9 +275,7 @@
 		company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
 
 		if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
-			frappe.throw(
-				_("To use a different finance book, please uncheck 'Include Default Book Entries'")
-			)
+			frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
 
 		opening_balance = opening_balance.where(
 			(closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 0edfc2a..380a044 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -53,6 +53,9 @@
 def get_fiscal_year(
 	date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False, boolean=False
 ):
+	if isinstance(boolean, str):
+		boolean = frappe.json.loads(boolean)
+
 	fiscal_years = get_fiscal_years(
 		date, fiscal_year, label, verbose, company, as_dict=as_dict, boolean=boolean
 	)
@@ -180,6 +183,7 @@
 	cost_center=None,
 	ignore_account_permission=False,
 	account_type=None,
+	start_date=None,
 ):
 	if not account and frappe.form_dict.get("account"):
 		account = frappe.form_dict.get("account")
@@ -193,6 +197,8 @@
 		cost_center = frappe.form_dict.get("cost_center")
 
 	cond = ["is_cancelled=0"]
+	if start_date:
+		cond.append("posting_date >= %s" % frappe.db.escape(cstr(start_date)))
 	if date:
 		cond.append("posting_date <= %s" % frappe.db.escape(cstr(date)))
 	else:
@@ -1831,6 +1837,28 @@
 					Table("outstanding").amount_in_account_currency >= self.max_outstanding
 				)
 
+		if self.limit and self.get_invoices:
+			outstanding_vouchers = (
+				qb.from_(ple)
+				.select(
+					ple.against_voucher_no.as_("voucher_no"),
+					Sum(ple.amount_in_account_currency).as_("amount_in_account_currency"),
+				)
+				.where(ple.delinked == 0)
+				.where(Criterion.all(filter_on_against_voucher_no))
+				.where(Criterion.all(self.common_filter))
+				.groupby(ple.against_voucher_type, ple.against_voucher_no, ple.party_type, ple.party)
+				.orderby(ple.posting_date, ple.voucher_no)
+				.having(qb.Field("amount_in_account_currency") > 0)
+				.limit(self.limit)
+				.run()
+			)
+			if outstanding_vouchers:
+				filter_on_voucher_no.append(ple.voucher_no.isin([x[0] for x in outstanding_vouchers]))
+				filter_on_against_voucher_no.append(
+					ple.against_voucher_no.isin([x[0] for x in outstanding_vouchers])
+				)
+
 		# build query for voucher amount
 		query_voucher_amount = (
 			qb.from_(ple)
@@ -2047,3 +2075,7 @@
 	journal_entry.save()
 	journal_entry.submit()
 	return journal_entry.name
+
+
+def get_party_types_from_account_type(account_type):
+	return frappe.db.get_all("Party Type", {"account_type": account_type}, pluck="name")
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 40f51ab..540a4f5 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -481,11 +481,11 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval.doc.asset_quantity",
+   "default": "1",
    "fieldname": "asset_quantity",
    "fieldtype": "Int",
    "label": "Asset Quantity",
-   "read_only": 1
+   "read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
   },
   {
    "fieldname": "depr_entry_posting_status",
@@ -572,7 +572,7 @@
    "link_fieldname": "target_asset"
   }
  ],
- "modified": "2023-10-27 17:03:46.629617",
+ "modified": "2023-11-20 20:57:37.010467",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 8908d8e..12dcc5b 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -46,12 +46,28 @@
 		self.validate_item()
 		self.validate_cost_center()
 		self.set_missing_values()
-		self.validate_finance_books()
-		if not self.split_from:
-			self.prepare_depreciation_data()
-			update_draft_asset_depr_schedules(self)
 		self.validate_gross_and_purchase_amount()
 		self.validate_expected_value_after_useful_life()
+		self.validate_finance_books()
+
+		if not self.split_from:
+			self.prepare_depreciation_data()
+
+			if self.calculate_depreciation:
+				update_draft_asset_depr_schedules(self)
+
+				if frappe.db.exists("Asset", self.name):
+					asset_depr_schedules_names = make_draft_asset_depr_schedules_if_not_present(self)
+
+					if asset_depr_schedules_names:
+						asset_depr_schedules_links = get_comma_separated_links(
+							asset_depr_schedules_names, "Asset Depreciation Schedule"
+						)
+						frappe.msgprint(
+							_(
+								"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
+							).format(asset_depr_schedules_links)
+						)
 
 		self.status = self.get_status()
 
@@ -61,17 +77,7 @@
 		if not self.booked_fixed_asset and self.validate_make_gl_entry():
 			self.make_gl_entries()
 		if self.calculate_depreciation and not self.split_from:
-			asset_depr_schedules_names = make_draft_asset_depr_schedules_if_not_present(self)
 			convert_draft_asset_depr_schedules_into_active(self)
-			if asset_depr_schedules_names:
-				asset_depr_schedules_links = get_comma_separated_links(
-					asset_depr_schedules_names, "Asset Depreciation Schedule"
-				)
-				frappe.msgprint(
-					_(
-						"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
-					).format(asset_depr_schedules_links)
-				)
 		self.set_status()
 		add_asset_activity(self.name, _("Asset submitted"))
 
@@ -827,6 +833,7 @@
 				"expected_value_after_useful_life": flt(gross_purchase_amount)
 				* flt(d.salvage_value_percentage / 100),
 				"depreciation_start_date": d.depreciation_start_date or nowdate(),
+				"rate_of_depreciation": d.rate_of_depreciation,
 			}
 		)
 
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 84a428c..66930c0 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -509,6 +509,9 @@
 
 
 def depreciate_asset(asset_doc, date, notes):
+	if not asset_doc.calculate_depreciation:
+		return
+
 	asset_doc.flags.ignore_validate_update_after_submit = True
 
 	make_new_active_asset_depr_schedules_and_cancel_current_ones(
@@ -521,6 +524,9 @@
 
 
 def reset_depreciation_schedule(asset_doc, date, notes):
+	if not asset_doc.calculate_depreciation:
+		return
+
 	asset_doc.flags.ignore_validate_update_after_submit = True
 
 	make_new_active_asset_depr_schedules_and_cancel_current_ones(
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
index 48d3331..812b7f7 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
@@ -52,7 +52,7 @@
 		},
 		{
 			"fieldname": "include_default_book_assets",
-			"label": __("Include Default Book Assets"),
+			"label": __("Include Default FB Assets"),
 			"fieldtype": "Check",
 			"default": 1
 		},
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index 383be97..45811a9 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -223,7 +223,7 @@
 		company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
 
 		if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
-			frappe.throw(_("To use a different finance book, please uncheck 'Include Default Book Assets'"))
+			frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Assets'"))
 
 		query = query.where(
 			(afb.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.js b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.js
index 0073170..dc54d60 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.js
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.js
@@ -1,30 +1,21 @@
-// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
 
-frappe.ui.form.on('Bulk Transaction Log', {
-
-	refresh: function(frm) {
-		frm.disable_save();
-		frm.add_custom_button(__('Retry Failed Transactions'), ()=>{
-			frappe.confirm(__("Retry Failing Transactions ?"), ()=>{
-				query(frm, 1);
-			}
-			);
-		});
-	}
+frappe.ui.form.on("Bulk Transaction Log", {
+	refresh(frm) {
+		frm.add_custom_button(__('Succeeded Entries'), function() {
+			frappe.set_route('List', 'Bulk Transaction Log Detail', {'date': frm.doc.date, 'transaction_status': "Success"});
+		}, __("View"));
+		frm.add_custom_button(__('Failed Entries'), function() {
+			frappe.set_route('List', 'Bulk Transaction Log Detail', {'date': frm.doc.date, 'transaction_status': "Failed"});
+		}, __("View"));
+		if (frm.doc.failed) {
+			frm.add_custom_button(__('Retry Failed Transactions'), function() {
+				frappe.call({
+					method: "erpnext.utilities.bulk_transaction.retry",
+					args: {date: frm.doc.date}
+				});
+			});
+		}
+	},
 });
-
-function query(frm) {
-	frappe.call({
-		method: "erpnext.bulk_transaction.doctype.bulk_transaction_log.bulk_transaction_log.retry_failing_transaction",
-		args: {
-			log_date: frm.doc.log_date
-		}
-	}).then((r) => {
-		if (r.message === "No Failed Records") {
-			frappe.show_alert(__(r.message), 5);
-		} else {
-			frappe.show_alert(__("Retrying Failed Transactions"), 5);
-		}
-	});
-}
\ No newline at end of file
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.json b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.json
index da42cf1..75cb358 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.json
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.json
@@ -1,31 +1,64 @@
 {
  "actions": [],
- "allow_rename": 1,
- "creation": "2021-11-30 13:41:16.343827",
+ "allow_copy": 1,
+ "creation": "2023-11-09 20:14:45.139593",
+ "default_view": "List",
  "doctype": "DocType",
- "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "log_date",
-  "logger_data"
+  "date",
+  "column_break_bsan",
+  "log_entries",
+  "section_break_mdmv",
+  "succeeded",
+  "column_break_qryp",
+  "failed"
  ],
  "fields": [
   {
-   "fieldname": "log_date",
+   "fieldname": "date",
    "fieldtype": "Date",
-   "label": "Log Date",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Date",
    "read_only": 1
   },
   {
-   "fieldname": "logger_data",
-   "fieldtype": "Table",
-   "label": "Logger Data",
-   "options": "Bulk Transaction Log Detail"
+   "fieldname": "log_entries",
+   "fieldtype": "Int",
+   "in_list_view": 1,
+   "label": "Log Entries",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_bsan",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break_mdmv",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "succeeded",
+   "fieldtype": "Int",
+   "label": "Succeeded",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_qryp",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "failed",
+   "fieldtype": "Int",
+   "label": "Failed",
+   "read_only": 1
   }
  ],
- "index_web_pages_for_search": 1,
+ "in_create": 1,
+ "is_virtual": 1,
  "links": [],
- "modified": "2022-02-03 17:23:02.935325",
+ "modified": "2023-11-11 04:52:49.347376",
  "modified_by": "Administrator",
  "module": "Bulk Transaction",
  "name": "Bulk Transaction Log",
@@ -47,5 +80,5 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "states": [],
- "track_changes": 1
+ "title_field": "date"
 }
\ No newline at end of file
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.py b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.py
index 0596be4..712caf1 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.py
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.py
@@ -1,67 +1,112 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-from datetime import date
-
 import frappe
+from frappe import qb
 from frappe.model.document import Document
-
-from erpnext.utilities.bulk_transaction import task, update_logger
+from frappe.query_builder.functions import Count
+from frappe.utils import cint
+from pypika import Order
 
 
 class BulkTransactionLog(Document):
-	pass
+	def db_insert(self, *args, **kwargs):
+		pass
 
+	def load_from_db(self):
+		log_detail = qb.DocType("Bulk Transaction Log Detail")
 
-@frappe.whitelist()
-def retry_failing_transaction(log_date=None):
-	if not log_date:
-		log_date = str(date.today())
-	btp = frappe.qb.DocType("Bulk Transaction Log Detail")
-	data = (
-		frappe.qb.from_(btp)
-		.select(btp.transaction_name, btp.from_doctype, btp.to_doctype)
-		.distinct()
-		.where(btp.retried != 1)
-		.where(btp.transaction_status == "Failed")
-		.where(btp.date == log_date)
-	).run(as_dict=True)
+		has_records = frappe.db.sql(
+			f"select exists (select * from `tabBulk Transaction Log Detail` where date = '{self.name}');"
+		)[0][0]
+		if not has_records:
+			raise frappe.DoesNotExistError
 
-	if data:
-		if len(data) > 10:
-			frappe.enqueue(job, queue="long", job_name="bulk_retry", data=data, log_date=log_date)
-		else:
-			job(data, log_date)
-	else:
-		return "No Failed Records"
+		succeeded_logs = (
+			qb.from_(log_detail)
+			.select(Count(log_detail.date).as_("count"))
+			.where((log_detail.date == self.name) & (log_detail.transaction_status == "Success"))
+			.run()
+		)[0][0] or 0
+		failed_logs = (
+			qb.from_(log_detail)
+			.select(Count(log_detail.date).as_("count"))
+			.where((log_detail.date == self.name) & (log_detail.transaction_status == "Failed"))
+			.run()
+		)[0][0] or 0
+		total_logs = succeeded_logs + failed_logs
+		transaction_log = frappe._dict(
+			{
+				"date": self.name,
+				"count": total_logs,
+				"succeeded": succeeded_logs,
+				"failed": failed_logs,
+			}
+		)
+		super(Document, self).__init__(serialize_transaction_log(transaction_log))
 
+	@staticmethod
+	def get_list(args):
+		filter_date = parse_list_filters(args)
+		limit = cint(args.get("page_length")) or 20
+		log_detail = qb.DocType("Bulk Transaction Log Detail")
 
-def job(data, log_date):
-	for d in data:
-		failed = []
-		try:
-			frappe.db.savepoint("before_creation_of_record")
-			task(d.transaction_name, d.from_doctype, d.to_doctype)
-		except Exception as e:
-			frappe.db.rollback(save_point="before_creation_of_record")
-			failed.append(e)
-			update_logger(
-				d.transaction_name,
-				e,
-				d.from_doctype,
-				d.to_doctype,
-				status="Failed",
-				log_date=log_date,
-				restarted=1,
+		dates_query = (
+			qb.from_(log_detail)
+			.select(log_detail.date)
+			.distinct()
+			.orderby(log_detail.date, order=Order.desc)
+			.limit(limit)
+		)
+		if filter_date:
+			dates_query = dates_query.where(log_detail.date == filter_date)
+		dates = dates_query.run()
+
+		transaction_logs = []
+		if dates:
+			transaction_logs_query = (
+				qb.from_(log_detail)
+				.select(log_detail.date.as_("date"), Count(log_detail.date).as_("count"))
+				.where(log_detail.date.isin(dates))
+				.orderby(log_detail.date, order=Order.desc)
+				.groupby(log_detail.date)
+				.limit(limit)
 			)
+			transaction_logs = transaction_logs_query.run(as_dict=True)
 
-		if not failed:
-			update_logger(
-				d.transaction_name,
-				None,
-				d.from_doctype,
-				d.to_doctype,
-				status="Success",
-				log_date=log_date,
-				restarted=1,
-			)
+		return [serialize_transaction_log(x) for x in transaction_logs]
+
+	@staticmethod
+	def get_count(args):
+		pass
+
+	@staticmethod
+	def get_stats(args):
+		pass
+
+	def db_update(self, *args, **kwargs):
+		pass
+
+	def delete(self):
+		pass
+
+
+def serialize_transaction_log(data):
+	return frappe._dict(
+		name=data.date,
+		date=data.date,
+		log_entries=data.count,
+		succeeded=data.succeeded,
+		failed=data.failed,
+	)
+
+
+def parse_list_filters(args):
+	# parse date filter
+	filter_date = None
+	for fil in args.get("filters"):
+		if isinstance(fil, list):
+			for elem in fil:
+				if elem == "date":
+					filter_date = fil[3]
+	return filter_date
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py b/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
index c673be8..01bb615 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
@@ -1,79 +1,9 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
 
-import unittest
-from datetime import date
-
-import frappe
-
-from erpnext.utilities.bulk_transaction import transaction_processing
+# import frappe
+from frappe.tests.utils import FrappeTestCase
 
 
-class TestBulkTransactionLog(unittest.TestCase):
-	def setUp(self):
-		create_company()
-		create_customer()
-		create_item()
-
-	def test_entry_in_log(self):
-		so_name = create_so()
-		transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
-		doc = frappe.get_doc("Bulk Transaction Log", str(date.today()))
-		for d in doc.get("logger_data"):
-			if d.transaction_name == so_name:
-				self.assertEqual(d.transaction_name, so_name)
-				self.assertEqual(d.transaction_status, "Success")
-				self.assertEqual(d.from_doctype, "Sales Order")
-				self.assertEqual(d.to_doctype, "Sales Invoice")
-				self.assertEqual(d.retried, 0)
-
-
-def create_company():
-	if not frappe.db.exists("Company", "_Test Company"):
-		frappe.get_doc(
-			{
-				"doctype": "Company",
-				"company_name": "_Test Company",
-				"country": "India",
-				"default_currency": "INR",
-			}
-		).insert()
-
-
-def create_customer():
-	if not frappe.db.exists("Customer", "Bulk Customer"):
-		frappe.get_doc({"doctype": "Customer", "customer_name": "Bulk Customer"}).insert()
-
-
-def create_item():
-	if not frappe.db.exists("Item", "MK"):
-		frappe.get_doc(
-			{
-				"doctype": "Item",
-				"item_code": "MK",
-				"item_name": "Milk",
-				"description": "Milk",
-				"item_group": "Products",
-			}
-		).insert()
-
-
-def create_so(intent=None):
-	so = frappe.new_doc("Sales Order")
-	so.customer = "Bulk Customer"
-	so.company = "_Test Company"
-	so.transaction_date = date.today()
-
-	so.set_warehouse = "Finished Goods - _TC"
-	so.append(
-		"items",
-		{
-			"item_code": "MK",
-			"delivery_date": date.today(),
-			"qty": 10,
-			"rate": 80,
-		},
-	)
-	so.insert()
-	so.submit()
-	return so.name
+class TestBulkTransactionLog(FrappeTestCase):
+	pass
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.js b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.js
new file mode 100644
index 0000000..5669601
--- /dev/null
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+// frappe.ui.form.on("Bulk Transaction Log Detail", {
+// 	refresh(frm) {
+
+// 	},
+// });
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.json b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.json
index 8262caa..9590325 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.json
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/bulk_transaction_log_detail.json
@@ -6,12 +6,12 @@
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
+  "from_doctype",
   "transaction_name",
   "date",
   "time",
   "transaction_status",
   "error_description",
-  "from_doctype",
   "to_doctype",
   "retried"
  ],
@@ -20,8 +20,11 @@
    "fieldname": "transaction_name",
    "fieldtype": "Dynamic Link",
    "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Name",
-   "options": "from_doctype"
+   "options": "from_doctype",
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "transaction_status",
@@ -39,9 +42,11 @@
   {
    "fieldname": "from_doctype",
    "fieldtype": "Link",
+   "in_standard_filter": 1,
    "label": "From Doctype",
    "options": "DocType",
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "to_doctype",
@@ -54,8 +59,10 @@
    "fieldname": "date",
    "fieldtype": "Date",
    "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Date ",
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "time",
@@ -66,19 +73,33 @@
   {
    "fieldname": "retried",
    "fieldtype": "Int",
+   "in_list_view": 1,
    "label": "Retried",
    "read_only": 1
   }
  ],
+ "in_create": 1,
  "index_web_pages_for_search": 1,
- "istable": 1,
  "links": [],
- "modified": "2022-02-03 19:57:31.650359",
+ "modified": "2023-11-10 11:44:10.758342",
  "modified_by": "Administrator",
  "module": "Bulk Transaction",
  "name": "Bulk Transaction Log Detail",
  "owner": "Administrator",
- "permissions": [],
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
  "sort_field": "modified",
  "sort_order": "DESC",
  "states": [],
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/test_bulk_transaction_log_detail.py b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/test_bulk_transaction_log_detail.py
new file mode 100644
index 0000000..5217b60
--- /dev/null
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log_detail/test_bulk_transaction_log_detail.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestBulkTransactionLogDetail(FrappeTestCase):
+	pass
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 0599992..0af93bf 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -17,6 +17,7 @@
   "po_required",
   "pr_required",
   "blanket_order_allowance",
+  "project_update_frequency",
   "column_break_12",
   "maintain_same_rate",
   "set_landed_cost_based_on_purchase_invoice_rate",
@@ -172,6 +173,14 @@
    "fieldname": "blanket_order_allowance",
    "fieldtype": "Float",
    "label": "Blanket Order Allowance (%)"
+  },
+  {
+   "default": "Each Transaction",
+   "description": "How often should Project be updated of Total Purchase Cost ?",
+   "fieldname": "project_update_frequency",
+   "fieldtype": "Select",
+   "label": "Update frequency of Project",
+   "options": "Each Transaction\nManual"
   }
  ],
  "icon": "fa fa-cog",
@@ -179,7 +188,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-10-25 14:03:32.520418",
+ "modified": "2023-11-24 10:55:51.287327",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Buying Settings",
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index b1da97d..2d706f4 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -189,6 +189,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -470,6 +471,7 @@
    "fieldname": "material_request",
    "fieldtype": "Link",
    "label": "Material Request",
+   "mandatory_depends_on": "eval: doc.material_request_item",
    "no_copy": 1,
    "oldfieldname": "prevdoc_docname",
    "oldfieldtype": "Link",
@@ -485,6 +487,7 @@
    "fieldtype": "Data",
    "hidden": 1,
    "label": "Material Request Item",
+   "mandatory_depends_on": "eval: doc.material_request",
    "no_copy": 1,
    "oldfieldname": "prevdoc_detail_docname",
    "oldfieldtype": "Data",
@@ -914,7 +917,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-27 15:50:42.655573",
+ "modified": "2023-11-14 18:34:27.267382",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index 06dbd86..fd73f77 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -9,6 +9,8 @@
  "field_order": [
   "naming_series",
   "company",
+  "billing_address",
+  "billing_address_display",
   "vendor",
   "column_break1",
   "transaction_date",
@@ -292,13 +294,25 @@
    "fieldtype": "Check",
    "label": "Send Document Print",
    "print_hide": 1
+  },
+  {
+   "fieldname": "billing_address",
+   "fieldtype": "Link",
+   "label": "Company Billing Address",
+   "options": "Address"
+  },
+  {
+   "fieldname": "billing_address_display",
+   "fieldtype": "Small Text",
+   "label": "Billing Address Details",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-shopping-cart",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-08-09 12:20:26.850623",
+ "modified": "2023-11-06 12:45:28.898706",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Request for Quotation",
diff --git a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
index 82fcfa2..6cdd2ba 100644
--- a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
+++ b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json
@@ -87,6 +87,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -260,13 +261,15 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-09-24 17:26:46.276934",
+ "modified": "2023-11-14 18:34:48.327224",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Request for Quotation Item",
+ "naming_rule": "Random",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 31bf439..b052f56 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -165,16 +165,17 @@
 @frappe.validate_and_sanitize_search_inputs
 def get_supplier_primary_contact(doctype, txt, searchfield, start, page_len, filters):
 	supplier = filters.get("supplier")
-	return frappe.db.sql(
-		"""
-		SELECT
-			`tabContact`.name from `tabContact`,
-			`tabDynamic Link`
-		WHERE
-			`tabContact`.name = `tabDynamic Link`.parent
-			and `tabDynamic Link`.link_name = %(supplier)s
-			and `tabDynamic Link`.link_doctype = 'Supplier'
-			and `tabContact`.name like %(txt)s
-		""",
-		{"supplier": supplier, "txt": "%%%s%%" % txt},
-	)
+	contact = frappe.qb.DocType("Contact")
+	dynamic_link = frappe.qb.DocType("Dynamic Link")
+
+	return (
+		frappe.qb.from_(contact)
+		.join(dynamic_link)
+		.on(contact.name == dynamic_link.parent)
+		.select(contact.name, contact.email_id)
+		.where(
+			(dynamic_link.link_name == supplier)
+			& (dynamic_link.link_doctype == "Supplier")
+			& (contact.name.like("%{0}%".format(txt)))
+		)
+	).run(as_dict=False)
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 7b635b3..1891261 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -20,6 +20,10 @@
   "valid_till",
   "quotation_number",
   "amended_from",
+  "accounting_dimensions_section",
+  "cost_center",
+  "dimension_col_break",
+  "project",
   "currency_and_price_list",
   "currency",
   "conversion_rate",
@@ -79,6 +83,7 @@
   "pricing_rule_details",
   "pricing_rules",
   "address_and_contact_tab",
+  "supplier_address_section",
   "supplier_address",
   "address_display",
   "column_break_72",
@@ -86,6 +91,14 @@
   "contact_display",
   "contact_mobile",
   "contact_email",
+  "shipping_address_section",
+  "shipping_address",
+  "column_break_zjaq",
+  "shipping_address_display",
+  "company_billing_address_section",
+  "billing_address",
+  "column_break_gcth",
+  "billing_address_display",
   "terms_tab",
   "tc_name",
   "terms",
@@ -838,6 +851,76 @@
    "fieldname": "named_place",
    "fieldtype": "Data",
    "label": "Named Place"
+  },
+  {
+   "fieldname": "shipping_address",
+   "fieldtype": "Link",
+   "label": "Shipping Address",
+   "options": "Address",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "column_break_zjaq",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "shipping_address_display",
+   "fieldtype": "Small Text",
+   "label": "Shipping Address Details",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "shipping_address_section",
+   "fieldtype": "Section Break",
+   "label": "Shipping Address"
+  },
+  {
+   "fieldname": "supplier_address_section",
+   "fieldtype": "Section Break",
+   "label": "Supplier Address"
+  },
+  {
+   "fieldname": "company_billing_address_section",
+   "fieldtype": "Section Break",
+   "label": "Company Billing Address"
+  },
+  {
+   "fieldname": "billing_address",
+   "fieldtype": "Link",
+   "label": "Company Billing Address",
+   "options": "Address"
+  },
+  {
+   "fieldname": "column_break_gcth",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "billing_address_display",
+   "fieldtype": "Small Text",
+   "label": "Billing Address Details",
+   "read_only": 1
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "project",
+   "fieldtype": "Link",
+   "label": "Project",
+   "options": "Project"
+  },
+  {
+   "fieldname": "dimension_col_break",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
   }
  ],
  "icon": "fa fa-shopping-cart",
@@ -845,7 +928,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-06-03 16:20:15.880114",
+ "modified": "2023-11-17 12:34:30.083077",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier Quotation",
diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
index 8d491fb..a6229b5 100644
--- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
+++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
@@ -68,6 +68,8 @@
   "column_break_15",
   "manufacturer_part_no",
   "ad_sec_break",
+  "cost_center",
+  "dimension_col_break",
   "project",
   "section_break_44",
   "page_break"
@@ -553,19 +555,31 @@
    "fieldname": "expected_delivery_date",
    "fieldtype": "Date",
    "label": "Expected Delivery Date"
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "dimension_col_break",
+   "fieldtype": "Column Break"
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-10-19 12:36:26.913211",
+ "modified": "2023-11-17 12:25:26.235367",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier Quotation Item",
+ "naming_rule": "Random",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c9c248c..154d490 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -239,7 +239,7 @@
 				references_map.setdefault(x.parent, []).append(x.name)
 
 			for doc, rows in references_map.items():
-				unreconcile_doc = frappe.get_doc("Unreconcile Payments", doc)
+				unreconcile_doc = frappe.get_doc("Unreconcile Payment", doc)
 				for row in rows:
 					unreconcile_doc.remove(unreconcile_doc.get("allocations", {"name": row})[0])
 
@@ -248,9 +248,9 @@
 				unreconcile_doc.save(ignore_permissions=True)
 
 		# delete docs upon parent doc deletion
-		unreconcile_docs = frappe.db.get_all("Unreconcile Payments", filters={"voucher_no": self.name})
+		unreconcile_docs = frappe.db.get_all("Unreconcile Payment", filters={"voucher_no": self.name})
 		for x in unreconcile_docs:
-			_doc = frappe.get_doc("Unreconcile Payments", x.name)
+			_doc = frappe.get_doc("Unreconcile Payment", x.name)
 			if _doc.docstatus == 1:
 				_doc.cancel()
 			_doc.delete()
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 3a802bd..68ad97d 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -105,26 +105,26 @@
 	def set_rate_for_standalone_debit_note(self):
 		if self.get("is_return") and self.get("update_stock") and not self.return_against:
 			for row in self.items:
+				if row.rate <= 0:
+					# override the rate with valuation rate
+					row.rate = get_incoming_rate(
+						{
+							"item_code": row.item_code,
+							"warehouse": row.warehouse,
+							"posting_date": self.get("posting_date"),
+							"posting_time": self.get("posting_time"),
+							"qty": row.qty,
+							"serial_and_batch_bundle": row.get("serial_and_batch_bundle"),
+							"company": self.company,
+							"voucher_type": self.doctype,
+							"voucher_no": self.name,
+						},
+						raise_error_if_no_rate=False,
+					)
 
-				# override the rate with valuation rate
-				row.rate = get_incoming_rate(
-					{
-						"item_code": row.item_code,
-						"warehouse": row.warehouse,
-						"posting_date": self.get("posting_date"),
-						"posting_time": self.get("posting_time"),
-						"qty": row.qty,
-						"serial_and_batch_bundle": row.get("serial_and_batch_bundle"),
-						"company": self.company,
-						"voucher_type": self.doctype,
-						"voucher_no": self.name,
-					},
-					raise_error_if_no_rate=False,
-				)
-
-				row.discount_percentage = 0.0
-				row.discount_amount = 0.0
-				row.margin_rate_or_amount = 0.0
+					row.discount_percentage = 0.0
+					row.discount_amount = 0.0
+					row.margin_rate_or_amount = 0.0
 
 	def set_missing_values(self, for_validate=False):
 		super(BuyingController, self).set_missing_values(for_validate)
@@ -365,7 +365,7 @@
 						{
 							"item_code": d.item_code,
 							"warehouse": d.get("from_warehouse"),
-							"posting_date": self.get("posting_date") or self.get("transation_date"),
+							"posting_date": self.get("posting_date") or self.get("transaction_date"),
 							"posting_time": posting_time,
 							"qty": -1 * flt(d.get("stock_qty")),
 							"serial_and_batch_bundle": d.get("serial_and_batch_bundle"),
@@ -758,7 +758,7 @@
 				"calculate_depreciation": 0,
 				"purchase_receipt_amount": purchase_amount,
 				"gross_purchase_amount": purchase_amount,
-				"asset_quantity": row.qty if is_grouped_asset else 0,
+				"asset_quantity": row.qty if is_grouped_asset else 1,
 				"purchase_receipt": self.name if self.doctype == "Purchase Receipt" else None,
 				"purchase_invoice": self.name if self.doctype == "Purchase Invoice" else None,
 			}
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 5ec2474..199732b 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -611,6 +611,8 @@
 	if filters.get("company"):
 		condition += "and tabAccount.company = %(company)s"
 
+	condition += f"and tabAccount.disabled = {filters.get('disabled', 0)}"
+
 	return frappe.db.sql(
 		"""select tabAccount.name from `tabAccount`
 			where (tabAccount.report_type = "Profit and Loss"
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 165e17b..e91212b 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -356,6 +356,7 @@
 			if doc.doctype == "Sales Invoice" or doc.doctype == "POS Invoice":
 				doc.consolidated_invoice = ""
 				doc.set("payments", [])
+				doc.update_billed_amount_in_delivery_note = True
 				for data in source.payments:
 					paid_amount = 0.00
 					base_paid_amount = 0.00
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index d34fbeb..5575a24 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -350,11 +350,12 @@
 		return il
 
 	def has_product_bundle(self, item_code):
-		return frappe.db.sql(
-			"""select name from `tabProduct Bundle`
-			where new_item_code=%s and docstatus != 2""",
-			item_code,
-		)
+		product_bundle = frappe.qb.DocType("Product Bundle")
+		return (
+			frappe.qb.from_(product_bundle)
+			.select(product_bundle.name)
+			.where((product_bundle.new_item_code == item_code) & (product_bundle.disabled == 0))
+		).run()
 
 	def get_already_delivered_qty(self, current_docname, so, so_detail):
 		delivered_via_dn = frappe.db.sql(
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 5fa66b1..3d55a08 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -626,6 +626,18 @@
 						(row.item_code, row.get(self.subcontract_data.order_field))
 					] -= row.qty
 
+	def __set_rate_for_serial_and_batch_bundle(self):
+		if self.doctype != "Subcontracting Receipt":
+			return
+
+		for row in self.get(self.raw_material_table):
+			if not row.get("serial_and_batch_bundle"):
+				continue
+
+			row.rate = frappe.get_cached_value(
+				"Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"
+			)
+
 	def __modify_serial_and_batch_bundle(self):
 		if self.is_new():
 			return
@@ -681,6 +693,7 @@
 		self.__remove_changed_rows()
 		self.__set_supplied_items()
 		self.__modify_serial_and_batch_bundle()
+		self.__set_rate_for_serial_and_batch_bundle()
 
 	def __validate_batch_no(self, row, key):
 		if row.get("batch_no") and row.get("batch_no") not in self.__transferred_items.get(key).get(
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 96284d6..f9f68a1 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -54,6 +54,7 @@
 		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.doc.rounding_adjustment = self.doc.base_rounding_adjustment = 0.0
 			self.set_rounded_total()
 
 		self.calculate_shipping_charges()
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index e897ba4..fdec88d 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -7,6 +7,8 @@
 	delete_contact_and_address,
 	load_address_and_contact,
 )
+from frappe.contacts.doctype.address.address import get_default_address
+from frappe.contacts.doctype.contact.contact import get_default_contact
 from frappe.email.inbox import link_communication_to_document
 from frappe.model.mapper import get_mapped_doc
 from frappe.utils import comma_and, get_link_to_form, has_gravatar, validate_email_address
@@ -251,6 +253,13 @@
 
 		target.customer_group = frappe.db.get_default("Customer Group")
 
+		address = get_default_address("Lead", source.name)
+		contact = get_default_contact("Lead", source.name)
+		if address:
+			target.customer_primary_address = address
+		if contact:
+			target.customer_primary_contact = contact
+
 	doclist = get_mapped_doc(
 		"Lead",
 		source_name,
diff --git a/erpnext/crm/doctype/opportunity_item/opportunity_item.json b/erpnext/crm/doctype/opportunity_item/opportunity_item.json
index 1b4973c..732f80d 100644
--- a/erpnext/crm/doctype/opportunity_item/opportunity_item.json
+++ b/erpnext/crm/doctype/opportunity_item/opportunity_item.json
@@ -103,6 +103,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -165,7 +166,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-07-30 16:39:09.775720",
+ "modified": "2023-11-14 18:35:30.887278",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Opportunity Item",
@@ -173,5 +174,6 @@
  "permissions": [],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5483a10..c6ab6f1 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -421,7 +421,7 @@
 	"hourly_long": [
 		"erpnext.accounts.doctype.process_subscription.process_subscription.create_subscription_process",
 		"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries",
-		"erpnext.bulk_transaction.doctype.bulk_transaction_log.bulk_transaction_log.retry_failing_transaction",
+		"erpnext.utilities.bulk_transaction.retry",
 	],
 	"daily": [
 		"erpnext.support.doctype.issue.issue.auto_close_tickets",
@@ -539,6 +539,8 @@
 	"Subcontracting Receipt",
 	"Subcontracting Receipt Item",
 	"Account Closing Balance",
+	"Supplier Quotation",
+	"Supplier Quotation Item",
 ]
 
 get_matching_queries = (
diff --git a/erpnext/manufacturing/doctype/bom_creator/bom_creator.js b/erpnext/manufacturing/doctype/bom_creator/bom_creator.js
index 0cf2b51..243e52d 100644
--- a/erpnext/manufacturing/doctype/bom_creator/bom_creator.js
+++ b/erpnext/manufacturing/doctype/bom_creator/bom_creator.js
@@ -15,7 +15,7 @@
 				|| frappe.bom_configurator.bom_configurator !== frm.doc.name)) {
 				frm.trigger("build_tree");
 			}
-		} else {
+		} else if (!frm.doc.items?.length ) {
 			let $parent = $(frm.fields_dict["bom_creator"].wrapper);
 			$parent.empty();
 			frm.trigger("make_new_entry");
diff --git a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py
index 058caa3..49041a0 100644
--- a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py
+++ b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py
@@ -6,7 +6,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import flt
+from frappe.utils import cint, flt
 
 from erpnext.manufacturing.doctype.bom.bom import get_bom_item_rate
 
@@ -91,11 +91,19 @@
 		parent_reference = {row.idx: row.name for row in self.items}
 
 		for row in self.items:
-			if row.fg_reference_id:
+			ref_id = ""
+
+			if row.parent_row_no:
+				ref_id = parent_reference.get(cint(row.parent_row_no))
+
+			# Check whether the reference id of the FG Item has correct or not
+			if row.fg_reference_id and row.fg_reference_id == ref_id:
 				continue
 
 			if row.parent_row_no:
-				row.fg_reference_id = parent_reference.get(row.parent_row_no)
+				row.fg_reference_id = ref_id
+			elif row.fg_item == self.item_code:
+				row.fg_reference_id = self.name
 
 	@frappe.whitelist()
 	def add_boms(self):
diff --git a/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json b/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
index fdb5d3a..56acd8a 100644
--- a/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
+++ b/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
@@ -215,7 +215,6 @@
    "fieldname": "parent_row_no",
    "fieldtype": "Data",
    "label": "Parent Row No",
-   "no_copy": 1,
    "print_hide": 1
   },
   {
@@ -231,7 +230,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-08-07 11:52:30.492233",
+ "modified": "2023-11-16 13:34:06.321061",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM Creator Item",
diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
index 9b1db63..c75ac32 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
@@ -85,6 +85,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -169,7 +170,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-05-27 13:42:23.305455",
+ "modified": "2023-11-14 18:35:40.856895",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM Explosion Item",
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json
index c526611..cb58af1 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -111,6 +111,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -289,7 +290,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-07-28 10:20:51.559010",
+ "modified": "2023-11-14 18:35:51.378513",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM Item",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 72438dd..dd102b0 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -89,10 +89,6 @@
 			frm.trigger("show_progress");
 
 			if (frm.doc.status !== "Completed") {
-				frm.add_custom_button(__("Work Order Tree"), ()=> {
-					frappe.set_route('Tree', 'Work Order', {production_plan: frm.doc.name});
-				}, __('View'));
-
 				frm.add_custom_button(__("Production Plan Summary"), ()=> {
 					frappe.set_route('query-report', 'Production Plan Summary', {production_plan: frm.doc.name});
 				}, __('View'));
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 6b12a29..6efb762 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -828,8 +828,6 @@
 			# Combine subassembly items
 			sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
 
-		sub_assembly_items_store.sort(key=lambda d: d.bom_level, reverse=True)  # sort by bom level
-
 		for idx, row in enumerate(sub_assembly_items_store):
 			row.idx = idx + 1
 			self.append("sub_assembly_items", row)
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index e9c6ee3..dd32c34 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -664,49 +664,6 @@
 
 		frappe.db.rollback()
 
-	def test_subassmebly_sorting(self):
-		"Test subassembly sorting in case of multiple items with nested BOMs."
-		from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
-
-		prefix = "_TestLevel_"
-		boms = {
-			"Assembly": {
-				"SubAssembly1": {
-					"ChildPart1": {},
-					"ChildPart2": {},
-				},
-				"ChildPart6": {},
-				"SubAssembly4": {"SubSubAssy2": {"ChildPart7": {}}},
-			},
-			"MegaDeepAssy": {
-				"SecretSubassy": {
-					"SecretPart": {"VerySecret": {"SuperSecret": {"Classified": {}}}},
-				},
-				# ^ assert that this is
-				# first item in subassy table
-			},
-		}
-		create_nested_bom(boms, prefix=prefix)
-
-		items = [prefix + item_code for item_code in boms.keys()]
-		plan = create_production_plan(item_code=items[0], do_not_save=True)
-		plan.append(
-			"po_items",
-			{
-				"use_multi_level_bom": 1,
-				"item_code": items[1],
-				"bom_no": frappe.db.get_value("Item", items[1], "default_bom"),
-				"planned_qty": 1,
-				"planned_start_date": now_datetime(),
-			},
-		)
-		plan.get_sub_assembly_items()
-
-		bom_level_order = [d.bom_level for d in plan.sub_assembly_items]
-		self.assertEqual(bom_level_order, sorted(bom_level_order, reverse=True))
-		# lowest most level of subassembly should be first
-		self.assertIn("SuperSecret", plan.sub_assembly_items[0].production_item)
-
 	def test_multiple_work_order_for_production_plan_item(self):
 		"Test producing Prod Plan (making WO) in parts."
 
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 58945bb..d9cc212 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -710,7 +710,7 @@
 		return new Promise((resolve, reject) => {
 			frappe.prompt({
 				fieldtype: 'Float',
-				label: __('Qty for {0}', [purpose]),
+				label: __('Qty for {0}', [__(purpose)]),
 				fieldname: 'qty',
 				description: __('Max: {0}', [max]),
 				default: max
diff --git a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js
index 521543a..afe4a6e 100644
--- a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js
+++ b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js
@@ -22,9 +22,9 @@
 	"formatter": function(value, row, column, data, default_formatter) {
 		value = default_formatter(value, row, column, data);
 
-		if (column.fieldname == "document_name") {
+		if (column.fieldname == "item_code") {
 			var color = data.pending_qty > 0 ? 'red': 'green';
-			value = `<a style='color:${color}' href="#Form/${data['document_type']}/${data['document_name']}" data-doctype="${data['document_type']}">${data['document_name']}</a>`;
+			value = `<a style='color:${color}' href="/app/item/${data['item_code']}" data-doctype="Item">${data['item_code']}</a>`;
 		}
 
 		return value;
diff --git a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
index 2c8f82f..076690f 100644
--- a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
+++ b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py
@@ -44,6 +44,7 @@
 			{
 				"indent": 0,
 				"item_code": row.item_code,
+				"sales_order": row.get("sales_order"),
 				"item_name": frappe.get_cached_value("Item", row.item_code, "item_name"),
 				"qty": row.planned_qty,
 				"document_type": "Work Order",
@@ -80,7 +81,7 @@
 
 			data.append(
 				{
-					"indent": 1,
+					"indent": 1 + item.indent,
 					"item_code": item.production_item,
 					"item_name": item.item_name,
 					"qty": item.qty,
@@ -98,7 +99,7 @@
 	for row in frappe.get_all(
 		"Work Order",
 		filters={"production_plan": filters.get("production_plan")},
-		fields=["name", "produced_qty", "production_plan", "production_item"],
+		fields=["name", "produced_qty", "production_plan", "production_item", "sales_order"],
 	):
 		order_details.setdefault((row.name, row.production_item), row)
 
@@ -118,10 +119,17 @@
 			"label": _("Finished Good"),
 			"fieldtype": "Link",
 			"fieldname": "item_code",
-			"width": 300,
+			"width": 240,
 			"options": "Item",
 		},
-		{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 100},
+		{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 150},
+		{
+			"label": _("Sales Order"),
+			"options": "Sales Order",
+			"fieldtype": "Link",
+			"fieldname": "sales_order",
+			"width": 100,
+		},
 		{
 			"label": _("Document Type"),
 			"fieldtype": "Link",
@@ -133,10 +141,16 @@
 			"label": _("Document Name"),
 			"fieldtype": "Dynamic Link",
 			"fieldname": "document_name",
-			"width": 150,
+			"options": "document_type",
+			"width": 180,
 		},
 		{"label": _("BOM Level"), "fieldtype": "Int", "fieldname": "bom_level", "width": 100},
 		{"label": _("Order Qty"), "fieldtype": "Float", "fieldname": "qty", "width": 120},
-		{"label": _("Received Qty"), "fieldtype": "Float", "fieldname": "produced_qty", "width": 160},
+		{
+			"label": _("Produced / Received Qty"),
+			"fieldtype": "Float",
+			"fieldname": "produced_qty",
+			"width": 200,
+		},
 		{"label": _("Pending Qty"), "fieldtype": "Float", "fieldname": "pending_qty", "width": 110},
 	]
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e0f32c5..a73502d 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -259,6 +259,7 @@
 erpnext.patches.v15_0.saudi_depreciation_warning
 erpnext.patches.v15_0.delete_saudi_doctypes
 erpnext.patches.v14_0.show_loan_management_deprecation_warning
+erpnext.patches.v14_0.clear_reconciliation_values_from_singles
 execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
 
 [post_model_sync]
@@ -338,15 +339,18 @@
 erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults
 erpnext.patches.v14_0.update_invoicing_period_in_subscription
 execute:frappe.delete_doc("Page", "welcome-to-erpnext")
+erpnext.patches.v15_0.migrate_payment_request_status
 erpnext.patches.v15_0.delete_payment_gateway_doctypes
 erpnext.patches.v14_0.create_accounting_dimensions_in_sales_order_item
 erpnext.patches.v15_0.update_sre_from_voucher_details
 erpnext.patches.v14_0.rename_over_order_allowance_field
 erpnext.patches.v14_0.migrate_delivery_stop_lock_field
-execute:frappe.db.set_single_value("Payment Reconciliation", "invoice_limit", 50)
-execute:frappe.db.set_single_value("Payment Reconciliation", "payment_limit", 50)
+erpnext.patches.v14_0.add_default_for_repost_settings
 erpnext.patches.v15_0.rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month
 erpnext.patches.v15_0.rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based
 erpnext.patches.v15_0.set_reserved_stock_in_bin
+erpnext.patches.v14_0.create_accounting_dimensions_in_supplier_quotation
+erpnext.patches.v14_0.update_zero_asset_quantity_field
+execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction")
 # below migration patch should always run last
 erpnext.patches.v14_0.migrate_gl_to_payment_ledger
diff --git a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
index e53bdf8..08ddbbf 100644
--- a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
+++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
@@ -21,6 +21,9 @@
 	params = set({x.casefold(): x for x in params}.values())
 
 	for parameter in params:
+		if frappe.db.exists("Quality Inspection Parameter", parameter):
+			continue
+
 		frappe.get_doc(
 			{"doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter}
 		).insert(ignore_permissions=True)
diff --git a/erpnext/patches/v14_0/add_default_for_repost_settings.py b/erpnext/patches/v14_0/add_default_for_repost_settings.py
new file mode 100644
index 0000000..6cafc66
--- /dev/null
+++ b/erpnext/patches/v14_0/add_default_for_repost_settings.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+	"""
+	Update Repost Accounting Ledger Settings with default values
+	"""
+	allowed_types = ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]
+	repost_settings = frappe.get_doc("Repost Accounting Ledger Settings")
+	for x in allowed_types:
+		repost_settings.append("allowed_types", {"document_type": x, "allowed": True})
+	repost_settings.save()
diff --git a/erpnext/patches/v14_0/clear_reconciliation_values_from_singles.py b/erpnext/patches/v14_0/clear_reconciliation_values_from_singles.py
new file mode 100644
index 0000000..c1f5b60
--- /dev/null
+++ b/erpnext/patches/v14_0/clear_reconciliation_values_from_singles.py
@@ -0,0 +1,17 @@
+from frappe import qb
+
+
+def execute():
+	"""
+	Clear `tabSingles` and Payment Reconciliation tables of values
+	"""
+	singles = qb.DocType("Singles")
+	qb.from_(singles).delete().where(singles.doctype == "Payment Reconciliation").run()
+	doctypes = [
+		"Payment Reconciliation Invoice",
+		"Payment Reconciliation Payment",
+		"Payment Reconciliation Allocation",
+	]
+	for x in doctypes:
+		dt = qb.DocType(x)
+		qb.from_(dt).delete().run()
diff --git a/erpnext/patches/v14_0/create_accounting_dimensions_in_supplier_quotation.py b/erpnext/patches/v14_0/create_accounting_dimensions_in_supplier_quotation.py
new file mode 100644
index 0000000..6966db1
--- /dev/null
+++ b/erpnext/patches/v14_0/create_accounting_dimensions_in_supplier_quotation.py
@@ -0,0 +1,8 @@
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
+	create_accounting_dimensions_for_doctype,
+)
+
+
+def execute():
+	create_accounting_dimensions_for_doctype(doctype="Supplier Quotation")
+	create_accounting_dimensions_for_doctype(doctype="Supplier Quotation Item")
diff --git a/erpnext/patches/v14_0/update_zero_asset_quantity_field.py b/erpnext/patches/v14_0/update_zero_asset_quantity_field.py
new file mode 100644
index 0000000..0480f9b
--- /dev/null
+++ b/erpnext/patches/v14_0/update_zero_asset_quantity_field.py
@@ -0,0 +1,6 @@
+import frappe
+
+
+def execute():
+	asset = frappe.qb.DocType("Asset")
+	frappe.qb.update(asset).set(asset.asset_quantity, 1).where(asset.asset_quantity == 0).run()
diff --git a/erpnext/patches/v15_0/migrate_payment_request_status.py b/erpnext/patches/v15_0/migrate_payment_request_status.py
new file mode 100644
index 0000000..9f0de56
--- /dev/null
+++ b/erpnext/patches/v15_0/migrate_payment_request_status.py
@@ -0,0 +1,13 @@
+import frappe
+
+
+def execute():
+	"""
+	Description:
+	Change Inward Payment Requests from statut 'Initiated' to correct status 'Requested'.
+	Status 'Initiated' is reserved for Outward Payment Requests and was a semantic error in previour versions.
+	"""
+	so = frappe.qb.DocType("Payment Request")
+	frappe.qb.update(so).set(so.status, "Requested").where(so.payment_request_type == "Inward").where(
+		so.status == "Initiated"
+	).run()
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index f366f77..2dac399 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -68,6 +68,10 @@
 				frm.events.create_duplicate(frm);
 			}, __("Actions"));
 
+			frm.add_custom_button(__('Update Total Purchase Cost'), () => {
+				frm.events.update_total_purchase_cost(frm);
+			}, __("Actions"));
+
 			frm.trigger("set_project_status_button");
 
 
@@ -92,6 +96,22 @@
 
 	},
 
+	update_total_purchase_cost: function(frm) {
+		frappe.call({
+			method: "erpnext.projects.doctype.project.project.recalculate_project_total_purchase_cost",
+			args: {project: frm.doc.name},
+			freeze: true,
+			freeze_message: __('Recalculating Purchase Cost against this Project...'),
+			callback: function(r) {
+				if (r && !r.exc) {
+					frappe.msgprint(__('Total Purchase Cost has been updated'));
+					frm.refresh();
+				}
+			}
+
+		});
+	},
+
 	set_project_status_button: function(frm) {
 		frm.add_custom_button(__('Set Project Status'), () => {
 			let d = new frappe.ui.Dialog({
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index e9aed1a..4f2e395 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -4,11 +4,11 @@
 
 import frappe
 from email_reply_parser import EmailReplyParser
-from frappe import _
+from frappe import _, qb
 from frappe.desk.reportview import get_match_cond
 from frappe.model.document import Document
 from frappe.query_builder import Interval
-from frappe.query_builder.functions import Count, CurDate, Date, UnixTimestamp
+from frappe.query_builder.functions import Count, CurDate, Date, Sum, UnixTimestamp
 from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
 from frappe.utils.user import is_website_user
 
@@ -249,12 +249,7 @@
 			self.per_gross_margin = (self.gross_margin / flt(self.total_billed_amount)) * 100
 
 	def update_purchase_costing(self):
-		total_purchase_cost = frappe.db.sql(
-			"""select sum(base_net_amount)
-			from `tabPurchase Invoice Item` where project = %s and docstatus=1""",
-			self.name,
-		)
-
+		total_purchase_cost = calculate_total_purchase_cost(self.name)
 		self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
 
 	def update_sales_amount(self):
@@ -695,3 +690,29 @@
 
 def get_users_email(doc):
 	return [d.email for d in doc.users if frappe.db.get_value("User", d.user, "enabled")]
+
+
+def calculate_total_purchase_cost(project: str | None = None):
+	if project:
+		pitem = qb.DocType("Purchase Invoice Item")
+		frappe.qb.DocType("Purchase Invoice Item")
+		total_purchase_cost = (
+			qb.from_(pitem)
+			.select(Sum(pitem.base_net_amount))
+			.where((pitem.project == project) & (pitem.docstatus == 1))
+			.run(as_list=True)
+		)
+		return total_purchase_cost
+	return None
+
+
+@frappe.whitelist()
+def recalculate_project_total_purchase_cost(project: str | None = None):
+	if project:
+		total_purchase_cost = calculate_total_purchase_cost(project)
+		frappe.db.set_value(
+			"Project",
+			project,
+			"total_purchase_cost",
+			(total_purchase_cost and total_purchase_cost[0][0] or 0),
+		)
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 25a5455..4d2d225 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -57,6 +57,7 @@
  ],
  "fields": [
   {
+   "allow_in_quick_entry": 1,
    "fieldname": "subject",
    "fieldtype": "Data",
    "in_global_search": 1,
@@ -66,6 +67,7 @@
    "search_index": 1
   },
   {
+   "allow_in_quick_entry": 1,
    "bold": 1,
    "fieldname": "project",
    "fieldtype": "Link",
@@ -396,7 +398,7 @@
  "is_tree": 1,
  "links": [],
  "max_attachments": 5,
- "modified": "2023-09-28 13:52:05.861175",
+ "modified": "2023-11-20 11:42:41.884069",
  "modified_by": "Administrator",
  "module": "Projects",
  "name": "Task",
@@ -416,6 +418,7 @@
    "write": 1
   }
  ],
+ "quick_entry": 1,
  "search_fields": "subject",
  "show_name_in_global_search": 1,
  "show_preview_popup": 1,
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index d1d07a7..eb7a97e 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -111,6 +111,7 @@
 
 		frm.trigger('setup_filters');
 		frm.trigger('set_dynamic_field_label');
+		frm.trigger('set_route_options_for_new_task');
 	},
 
 	customer: function(frm) {
@@ -172,6 +173,14 @@
 		frm.refresh_fields();
 	},
 
+	set_route_options_for_new_task: (frm) => {
+		let task_field = frm.get_docfield('time_logs', 'task');
+
+		if (task_field) {
+			task_field.get_route_options_for_new_doc = (row) => ({'project': row.doc.project});
+		}
+	},
+
 	make_invoice: function(frm) {
 		let fields = [{
 			"fieldtype": "Link",
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 11156f4..b9d801c 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -71,6 +71,12 @@
 		if args.is_billable:
 			if flt(args.billing_hours) == 0.0:
 				args.billing_hours = args.hours
+			elif flt(args.billing_hours) > flt(args.hours):
+				frappe.msgprint(
+					_("Warning - Row {0}: Billing Hours are more than Actual Hours").format(args.idx),
+					indicator="orange",
+					alert=True,
+				)
 		else:
 			args.billing_hours = 0
 
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 6b613ce..d24c4e6 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -43,6 +43,9 @@
 		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;
+			this.frm.doc.rounding_adjustment = 0;
+			this.frm.doc.base_rounding_adjustment = 0;
+			this.set_rounded_total();
 		}
 
 		await this.calculate_shipping_charges();
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index b0a9e40..2c40f49 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1772,7 +1772,7 @@
 			if(frappe.meta.has_field(me.frm.doc.doctype, fieldname) &&  !["Purchase Order","Purchase Invoice"].includes(me.frm.doc.doctype)) {
 				if (!me.frm.doc[fieldname]) {
 					frappe.msgprint(__("Please specify") + ": " +
-						frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
+						__(frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name)) +
 						". " + __("It is needed to fetch Item Details."));
 					valid = false;
 				}
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 907a775..1b10d8a 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -139,7 +139,6 @@
 			"label": __("Start Year"),
 			"fieldtype": "Link",
 			"options": "Fiscal Year",
-			"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
 			"reqd": 1,
 			"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
 		},
@@ -148,7 +147,6 @@
 			"label": __("End Year"),
 			"fieldtype": "Link",
 			"options": "Fiscal Year",
-			"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
 			"reqd": 1,
 			"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
 		},
@@ -197,5 +195,13 @@
 		}
 	]
 
+	// Dynamically set 'default' values for fiscal year filters
+	let fy_filters = filters.filter(x=>{return ["from_fiscal_year", "to_fiscal_year"].includes(x.fieldname);})
+	let fiscal_year = erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), false, true);
+	if (fiscal_year) {
+		let fy = erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), false, false);
+		fy_filters.forEach(x=>{x.default = fy;})
+	}
+
 	return filters;
 }
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index d435711..25fc754 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -404,7 +404,7 @@
 		});
 	},
 
-	get_fiscal_year: function(date, with_dates=false) {
+	get_fiscal_year: function(date, with_dates=false, boolean=false) {
 		if(!date) {
 			date = frappe.datetime.get_today();
 		}
@@ -413,7 +413,8 @@
 		frappe.call({
 			method: "erpnext.accounts.utils.get_fiscal_year",
 			args: {
-				date: date
+				date: date,
+				boolean: boolean
 			},
 			async: false,
 			callback: function(r) {
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 5c41aa0..cba615c 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -4,7 +4,7 @@
 frappe.provide("erpnext.utils");
 
 const SALES_DOCTYPES = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice'];
-const PURCHASE_DOCTYPES = ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'];
+const PURCHASE_DOCTYPES = ['Supplier Quotation','Purchase Order', 'Purchase Receipt', 'Purchase Invoice'];
 
 erpnext.utils.get_party_details = function(frm, method, args, callback) {
 	if (!method) {
diff --git a/erpnext/public/js/utils/unreconcile.js b/erpnext/public/js/utils/unreconcile.js
index fa00ed2..79490a1 100644
--- a/erpnext/public/js/utils/unreconcile.js
+++ b/erpnext/public/js/utils/unreconcile.js
@@ -1,6 +1,6 @@
 frappe.provide('erpnext.accounts');
 
-erpnext.accounts.unreconcile_payments = {
+erpnext.accounts.unreconcile_payment = {
 	add_unreconcile_btn(frm) {
 		if (frm.doc.docstatus == 1) {
 			if(((frm.doc.doctype == "Journal Entry") && (frm.doc.voucher_type != "Journal Entry"))
@@ -10,7 +10,7 @@
 			}
 
 			frappe.call({
-				"method": "erpnext.accounts.doctype.unreconcile_payments.unreconcile_payments.doc_has_references",
+				"method": "erpnext.accounts.doctype.unreconcile_payment.unreconcile_payment.doc_has_references",
 				"args": {
 					"doctype": frm.doc.doctype,
 					"docname": frm.doc.name
@@ -18,7 +18,7 @@
 				callback: function(r) {
 					if (r.message) {
 						frm.add_custom_button(__("UnReconcile"), function() {
-							erpnext.accounts.unreconcile_payments.build_unreconcile_dialog(frm);
+							erpnext.accounts.unreconcile_payment.build_unreconcile_dialog(frm);
 						}, __('Actions'));
 					}
 				}
@@ -74,7 +74,7 @@
 
 			// get linked payments
 			frappe.call({
-				"method": "erpnext.accounts.doctype.unreconcile_payments.unreconcile_payments.get_linked_payments_for_doc",
+				"method": "erpnext.accounts.doctype.unreconcile_payment.unreconcile_payment.get_linked_payments_for_doc",
 				"args": {
 					"company": frm.doc.company,
 					"doctype": frm.doc.doctype,
@@ -96,8 +96,8 @@
 
 								let selected_allocations = values.allocations.filter(x=>x.__checked);
 								if (selected_allocations.length > 0) {
-									let selection_map = erpnext.accounts.unreconcile_payments.build_selection_map(frm, selected_allocations);
-									erpnext.accounts.unreconcile_payments.create_unreconcile_docs(selection_map);
+									let selection_map = erpnext.accounts.unreconcile_payment.build_selection_map(frm, selected_allocations);
+									erpnext.accounts.unreconcile_payment.create_unreconcile_docs(selection_map);
 									d.hide();
 
 								} else {
@@ -115,7 +115,7 @@
 
 	create_unreconcile_docs(selection_map) {
 		frappe.call({
-			"method": "erpnext.accounts.doctype.unreconcile_payments.unreconcile_payments.create_unreconcile_doc_for_selection",
+			"method": "erpnext.accounts.doctype.unreconcile_payment.unreconcile_payment.create_unreconcile_doc_for_selection",
 			"args": {
 				"selections": selection_map
 			},
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
index fd2b6a4..79fd2eb 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.js
@@ -3,10 +3,10 @@
 
 frappe.ui.form.on('Quality Procedure', {
 	refresh: function(frm) {
-		frm.set_query("procedure","processes", (frm) =>{
+		frm.set_query('procedure', 'processes', (frm) =>{
 			return {
 				filters: {
-					name: ["not in", [frm.parent_quality_procedure, frm.name]]
+					name: ['not in', [frm.parent_quality_procedure, frm.name]]
 				}
 			};
 		});
@@ -14,7 +14,8 @@
 		frm.set_query('parent_quality_procedure', function(){
 			return {
 				filters: {
-					is_group: 1
+					is_group: 1,
+					name: ['!=', frm.doc.name]
 				}
 			};
 		});
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index e860408..6834abc 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -16,16 +16,13 @@
 	def on_update(self):
 		NestedSet.on_update(self)
 		self.set_parent()
+		self.remove_parent_from_old_child()
+		self.add_child_to_parent()
+		self.remove_child_from_old_parent()
 
 	def after_insert(self):
 		self.set_parent()
-
-		# add child to parent if missing
-		if self.parent_quality_procedure:
-			parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
-			if not [d for d in parent.processes if d.procedure == self.name]:
-				parent.append("processes", {"procedure": self.name, "process_description": self.name})
-				parent.save()
+		self.add_child_to_parent()
 
 	def on_trash(self):
 		# clear from child table (sub procedures)
@@ -36,15 +33,6 @@
 		)
 		NestedSet.on_trash(self, allow_root_deletion=True)
 
-	def set_parent(self):
-		for process in self.processes:
-			# Set parent for only those children who don't have a parent
-			has_parent = frappe.db.get_value(
-				"Quality Procedure", process.procedure, "parent_quality_procedure"
-			)
-			if not has_parent and process.procedure:
-				frappe.db.set_value(self.doctype, process.procedure, "parent_quality_procedure", self.name)
-
 	def check_for_incorrect_child(self):
 		for process in self.processes:
 			if process.procedure:
@@ -61,6 +49,48 @@
 						title=_("Invalid Child Procedure"),
 					)
 
+	def set_parent(self):
+		"""Set `Parent Procedure` in `Child Procedures`"""
+
+		for process in self.processes:
+			if process.procedure:
+				if not frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure"):
+					frappe.db.set_value(
+						"Quality Procedure", process.procedure, "parent_quality_procedure", self.name
+					)
+
+	def remove_parent_from_old_child(self):
+		"""Remove `Parent Procedure` from `Old Child Procedures`"""
+
+		if old_doc := self.get_doc_before_save():
+			if old_child_procedures := set([d.procedure for d in old_doc.processes if d.procedure]):
+				current_child_procedures = set([d.procedure for d in self.processes if d.procedure])
+
+				if removed_child_procedures := list(old_child_procedures.difference(current_child_procedures)):
+					for child_procedure in removed_child_procedures:
+						frappe.db.set_value("Quality Procedure", child_procedure, "parent_quality_procedure", None)
+
+	def add_child_to_parent(self):
+		"""Add `Child Procedure` to `Parent Procedure`"""
+
+		if self.parent_quality_procedure:
+			parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
+			if not [d for d in parent.processes if d.procedure == self.name]:
+				parent.append("processes", {"procedure": self.name, "process_description": self.name})
+				parent.save()
+
+	def remove_child_from_old_parent(self):
+		"""Remove `Child Procedure` from `Old Parent Procedure`"""
+
+		if old_doc := self.get_doc_before_save():
+			if old_parent := old_doc.parent_quality_procedure:
+				if self.parent_quality_procedure != old_parent:
+					parent = frappe.get_doc("Quality Procedure", old_parent)
+					for process in parent.processes:
+						if process.procedure == self.name:
+							parent.remove(process)
+					parent.save()
+
 
 @frappe.whitelist()
 def get_children(doctype, parent=None, parent_quality_procedure=None, is_root=False):
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
index 04e8211..467186d 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -1,56 +1,107 @@
 # Copyright (c) 2018, Frappe and Contributors
 # See license.txt
 
-import unittest
-
 import frappe
+from frappe.tests.utils import FrappeTestCase
 
 from .quality_procedure import add_node
 
 
-class TestQualityProcedure(unittest.TestCase):
+class TestQualityProcedure(FrappeTestCase):
 	def test_add_node(self):
-		try:
-			procedure = frappe.get_doc(
-				dict(
-					doctype="Quality Procedure",
-					quality_procedure_name="Test Procedure 1",
-					processes=[dict(process_description="Test Step 1")],
-				)
-			).insert()
-
-			frappe.local.form_dict = frappe._dict(
-				doctype="Quality Procedure",
-				quality_procedure_name="Test Child 1",
-				parent_quality_procedure=procedure.name,
-				cmd="test",
-				is_root="false",
-			)
-			node = add_node()
-
-			procedure.reload()
-
-			self.assertEqual(procedure.is_group, 1)
-
-			# child row created
-			self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
-
-			node.delete()
-			procedure.reload()
-
-			# child unset
-			self.assertFalse([d for d in procedure.processes if d.name == node.name])
-
-		finally:
-			procedure.delete()
-
-
-def create_procedure():
-	return frappe.get_doc(
-		dict(
-			doctype="Quality Procedure",
-			quality_procedure_name="Test Procedure 1",
-			is_group=1,
-			processes=[dict(process_description="Test Step 1")],
+		procedure = create_procedure(
+			{
+				"quality_procedure_name": "Test Procedure 1",
+				"is_group": 1,
+				"processes": [dict(process_description="Test Step 1")],
+			}
 		)
-	).insert()
+
+		frappe.local.form_dict = frappe._dict(
+			doctype="Quality Procedure",
+			quality_procedure_name="Test Child 1",
+			parent_quality_procedure=procedure.name,
+			cmd="test",
+			is_root="false",
+		)
+		node = add_node()
+
+		procedure.reload()
+
+		self.assertEqual(procedure.is_group, 1)
+
+		# child row created
+		self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
+
+		node.delete()
+		procedure.reload()
+
+		# child unset
+		self.assertFalse([d for d in procedure.processes if d.name == node.name])
+
+	def test_remove_parent_from_old_child(self):
+		child_qp = create_procedure(
+			{
+				"quality_procedure_name": "Test Child 1",
+				"is_group": 0,
+			}
+		)
+		group_qp = create_procedure(
+			{
+				"quality_procedure_name": "Test Group",
+				"is_group": 1,
+				"processes": [dict(procedure=child_qp.name)],
+			}
+		)
+
+		child_qp.reload()
+		self.assertEqual(child_qp.parent_quality_procedure, group_qp.name)
+
+		group_qp.reload()
+		del group_qp.processes[0]
+		group_qp.save()
+
+		child_qp.reload()
+		self.assertEqual(child_qp.parent_quality_procedure, None)
+
+	def remove_child_from_old_parent(self):
+		child_qp = create_procedure(
+			{
+				"quality_procedure_name": "Test Child 1",
+				"is_group": 0,
+			}
+		)
+		group_qp = create_procedure(
+			{
+				"quality_procedure_name": "Test Group",
+				"is_group": 1,
+				"processes": [dict(procedure=child_qp.name)],
+			}
+		)
+
+		group_qp.reload()
+		self.assertTrue([d for d in group_qp.processes if d.procedure == child_qp.name])
+
+		child_qp.reload()
+		self.assertEqual(child_qp.parent_quality_procedure, group_qp.name)
+
+		child_qp.parent_quality_procedure = None
+		child_qp.save()
+
+		group_qp.reload()
+		self.assertFalse([d for d in group_qp.processes if d.procedure == child_qp.name])
+
+
+def create_procedure(kwargs=None):
+	kwargs = frappe._dict(kwargs or {})
+
+	doc = frappe.new_doc("Quality Procedure")
+	doc.quality_procedure_name = kwargs.quality_procedure_name or "_Test Procedure"
+	doc.is_group = kwargs.is_group or 0
+
+	for process in kwargs.processes or []:
+		doc.append("processes", process)
+
+	doc.insert()
+
+	return doc
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index 42932ad..ddc7e2a 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -3,17 +3,32 @@
 
 frappe.ui.form.on("Customer", {
 	setup: function(frm) {
-
+		frm.custom_make_buttons = {
+			"Opportunity": "Opportunity",
+			"Quotation": "Quotation",
+			"Sales Order": "Sales Order",
+			"Pricing Rule": "Pricing Rule",
+		};
 		frm.make_methods = {
-			'Quotation': () => frappe.model.open_mapped_doc({
-				method: "erpnext.selling.doctype.customer.customer.make_quotation",
-				frm: cur_frm
-			}),
-			'Opportunity': () => frappe.model.open_mapped_doc({
-				method: "erpnext.selling.doctype.customer.customer.make_opportunity",
-				frm: cur_frm
-			})
-		}
+			"Quotation": () =>
+				frappe.model.open_mapped_doc({
+					method: "erpnext.selling.doctype.customer.customer.make_quotation",
+					frm: frm,
+				}),
+			"Sales Order": () =>
+				frappe.model.with_doctype("Sales Order", function () {
+					var so = frappe.model.get_new_doc("Sales Order");
+					so.customer = frm.doc.name; // Set the current customer as the SO customer
+					frappe.set_route("Form", "Sales Order", so.name);
+				}),
+			"Opportunity": () =>
+				frappe.model.open_mapped_doc({
+					method: "erpnext.selling.doctype.customer.customer.make_opportunity",
+					frm: frm,
+				}),
+			"Pricing Rule": () =>
+				erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name),
+		};
 
 		frm.add_fetch('lead_name', 'company_name', 'customer_name');
 		frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate');
@@ -146,9 +161,9 @@
 					{party_type: 'Customer', party: frm.doc.name, party_name: frm.doc.customer_name});
 			}, __('View'));
 
-			frm.add_custom_button(__('Pricing Rule'), function () {
-				erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name);
-			}, __('Create'));
+			for (const doctype in frm.make_methods) {
+				frm.add_custom_button(__(doctype), frm.make_methods[doctype], __("Create"));
+			}
 
 			frm.add_custom_button(__('Get Customer Group Details'), function () {
 				frm.trigger("get_customer_group_details");
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index a7a1aa2..88ed1c6 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -186,6 +186,8 @@
 				self.db_set("customer_primary_contact", contact.name)
 				self.db_set("mobile_no", self.mobile_no)
 				self.db_set("email_id", self.email_id)
+		elif self.customer_primary_contact:
+			frappe.set_value("Contact", self.customer_primary_contact, "is_primary_contact", 1)  # ensure
 
 	def create_primary_address(self):
 		from frappe.contacts.doctype.address.address import get_address_display
@@ -196,6 +198,8 @@
 
 			self.db_set("customer_primary_address", address.name)
 			self.db_set("primary_address", address_display)
+		elif self.customer_primary_address:
+			frappe.set_value("Address", self.customer_primary_address, "is_primary_address", 1)  # ensure
 
 	def update_lead_status(self):
 		"""If Customer created from Lead, update lead status to "Converted"
@@ -303,22 +307,6 @@
 			)
 
 
-def create_contact(contact, party_type, party, email):
-	"""Create contact based on given contact name"""
-	contact = contact.split(" ")
-
-	contact = frappe.get_doc(
-		{
-			"doctype": "Contact",
-			"first_name": contact[0],
-			"last_name": len(contact) > 1 and contact[1] or "",
-		}
-	)
-	contact.append("email_ids", dict(email_id=email, is_primary=1))
-	contact.append("links", dict(link_doctype=party_type, link_name=party))
-	contact.insert()
-
-
 @frappe.whitelist()
 def make_quotation(source_name, target_doc=None):
 	def set_missing_values(source, target):
@@ -495,6 +483,7 @@
 				primary_action={
 					"label": "Send Email",
 					"server_action": "erpnext.selling.doctype.customer.customer.send_emails",
+					"hide_on_success": True,
 					"args": {
 						"customer": customer,
 						"customer_outstanding": customer_outstanding,
@@ -635,24 +624,47 @@
 
 
 def make_contact(args, is_primary_contact=1):
-	contact = frappe.get_doc(
-		{
-			"doctype": "Contact",
-			"first_name": args.get("name"),
-			"is_primary_contact": is_primary_contact,
-			"links": [{"link_doctype": args.get("doctype"), "link_name": args.get("name")}],
-		}
-	)
+	values = {
+		"doctype": "Contact",
+		"is_primary_contact": is_primary_contact,
+		"links": [{"link_doctype": args.get("doctype"), "link_name": args.get("name")}],
+	}
+
+	party_type = args.customer_type if args.doctype == "Customer" else args.supplier_type
+	party_name_key = "customer_name" if args.doctype == "Customer" else "supplier_name"
+
+	if party_type == "Individual":
+		first, middle, last = parse_full_name(args.get(party_name_key))
+		values.update(
+			{
+				"first_name": first,
+				"middle_name": middle,
+				"last_name": last,
+			}
+		)
+	else:
+		values.update(
+			{
+				"company_name": args.get(party_name_key),
+			}
+		)
+
+	contact = frappe.get_doc(values)
+
 	if args.get("email_id"):
 		contact.add_email(args.get("email_id"), is_primary=True)
 	if args.get("mobile_no"):
 		contact.add_phone(args.get("mobile_no"), is_primary_mobile_no=True)
-	contact.insert()
+
+	if flags := args.get("flags"):
+		contact.insert(ignore_permissions=flags.get("ignore_permissions"))
+	else:
+		contact.insert()
 
 	return contact
 
 
-def make_address(args, is_primary_address=1):
+def make_address(args, is_primary_address=1, is_shipping_address=1):
 	reqd_fields = []
 	for field in ["city", "country"]:
 		if not args.get(field):
@@ -665,19 +677,28 @@
 			title=_("Missing Values Required"),
 		)
 
+	party_name_key = "customer_name" if args.doctype == "Customer" else "supplier_name"
+
 	address = frappe.get_doc(
 		{
 			"doctype": "Address",
-			"address_title": args.get("name"),
+			"address_title": args.get(party_name_key),
 			"address_line1": args.get("address_line1"),
 			"address_line2": args.get("address_line2"),
 			"city": args.get("city"),
 			"state": args.get("state"),
 			"pincode": args.get("pincode"),
 			"country": args.get("country"),
+			"is_primary_address": is_primary_address,
+			"is_shipping_address": is_shipping_address,
 			"links": [{"link_doctype": args.get("doctype"), "link_name": args.get("name")}],
 		}
-	).insert()
+	)
+
+	if flags := args.get("flags"):
+		address.insert(ignore_permissions=flags.get("ignore_permissions"))
+	else:
+		address.insert()
 
 	return address
 
@@ -698,3 +719,13 @@
 		.where((dlink.link_name == customer) & (con.name.like(f"%{txt}%")))
 		.run()
 	)
+
+
+def parse_full_name(full_name: str) -> tuple[str, str | None, str | None]:
+	"""Parse full name into first name, middle name and last name"""
+	names = full_name.split()
+	first_name = names[0]
+	middle_name = " ".join(names[1:-1]) if len(names) > 2 else None
+	last_name = names[-1] if len(names) > 1 else None
+
+	return first_name, middle_name, last_name
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 6e737e4..29dbd4f 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -10,7 +10,11 @@
 
 from erpnext.accounts.party import get_due_date
 from erpnext.exceptions import PartyDisabled, PartyFrozen
-from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
+from erpnext.selling.doctype.customer.customer import (
+	get_credit_limit,
+	get_customer_outstanding,
+	parse_full_name,
+)
 from erpnext.tests.utils import create_test_contact_and_address
 
 test_ignore = ["Price List"]
@@ -373,6 +377,22 @@
 
 		frappe.db.set_single_value("Selling Settings", "cust_master_name", "Customer Name")
 
+	def test_parse_full_name(self):
+		first, middle, last = parse_full_name("John")
+		self.assertEqual(first, "John")
+		self.assertEqual(middle, None)
+		self.assertEqual(last, None)
+
+		first, middle, last = parse_full_name("John Doe")
+		self.assertEqual(first, "John")
+		self.assertEqual(middle, None)
+		self.assertEqual(last, "Doe")
+
+		first, middle, last = parse_full_name("John Michael Doe")
+		self.assertEqual(first, "John")
+		self.assertEqual(middle, "Michael")
+		self.assertEqual(last, "Doe")
+
 
 def get_customer_dict(customer_name):
 	return {
diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.json b/erpnext/selling/doctype/product_bundle/product_bundle.json
index 56155fb..c4f21b6 100644
--- a/erpnext/selling/doctype/product_bundle/product_bundle.json
+++ b/erpnext/selling/doctype/product_bundle/product_bundle.json
@@ -1,315 +1,119 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2013-06-20 11:53:21", 
- "custom": 0, 
- "description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials", 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 0, 
+ "actions": [],
+ "allow_import": 1,
+ "creation": "2013-06-20 11:53:21",
+ "description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "basic_section",
+  "new_item_code",
+  "description",
+  "column_break_eonk",
+  "disabled",
+  "item_section",
+  "items",
+  "section_break_4",
+  "about"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "basic_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "basic_section",
+   "fieldtype": "Section Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "new_item_code", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Parent Item", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "new_item_code", 
-   "oldfieldtype": "Data", 
-   "options": "Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "new_item_code",
+   "fieldtype": "Link",
+   "in_global_search": 1,
+   "in_list_view": 1,
+   "label": "Parent Item",
+   "no_copy": 1,
+   "oldfieldname": "new_item_code",
+   "oldfieldtype": "Data",
+   "options": "Item",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "description", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Description", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "description",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Description"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "List items that form the package.", 
-   "fieldname": "item_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "description": "List items that form the package.",
+   "fieldname": "item_section",
+   "fieldtype": "Section Break",
+   "label": "Items"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "items", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "sales_bom_items", 
-   "oldfieldtype": "Table", 
-   "options": "Product Bundle Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "items",
+   "fieldtype": "Table",
+   "label": "Items",
+   "oldfieldname": "sales_bom_items",
+   "oldfieldtype": "Table",
+   "options": "Product Bundle Item",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_4", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "section_break_4",
+   "fieldtype": "Section Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "about", 
-   "fieldtype": "HTML", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "<h3>About Product Bundle</h3>\n\n<p>Aggregate group of <b>Items</b> into another <b>Item</b>. This is useful if you are bundling a certain <b>Items</b> into a package and you maintain stock of the packed <b>Items</b> and not the aggregate <b>Item</b>.</p>\n<p>The package <b>Item</b> will have <code>Is Stock Item</code> as <b>No</b> and <code>Is Sales Item</code> as <b>Yes</b>.</p>\n<h4>Example:</h4>\n<p>If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.</p>", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "fieldname": "about",
+   "fieldtype": "HTML",
+   "options": "<h3>About Product Bundle</h3>\n\n<p>Aggregate group of <b>Items</b> into another <b>Item</b>. This is useful if you are bundling a certain <b>Items</b> into a package and you maintain stock of the packed <b>Items</b> and not the aggregate <b>Item</b>.</p>\n<p>The package <b>Item</b> will have <code>Is Stock Item</code> as <b>No</b> and <code>Is Sales Item</code> as <b>Yes</b>.</p>\n<h4>Example:</h4>\n<p>If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.</p>"
+  },
+  {
+   "default": "0",
+   "fieldname": "disabled",
+   "fieldtype": "Check",
+   "label": "Disabled"
+  },
+  {
+   "fieldname": "column_break_eonk",
+   "fieldtype": "Column Break"
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-sitemap", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Selling", 
- "name": "Product Bundle", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-sitemap",
+ "idx": 1,
+ "links": [],
+ "modified": "2023-11-22 15:20:46.805114",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Product Bundle",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Stock Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Stock User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock User"
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Sales User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales User",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_order": "ASC", 
- "track_changes": 0, 
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py
index ac83c0f..2fd9cc1 100644
--- a/erpnext/selling/doctype/product_bundle/product_bundle.py
+++ b/erpnext/selling/doctype/product_bundle/product_bundle.py
@@ -59,10 +59,12 @@
 		"""Validates, main Item is not a stock item"""
 		if frappe.db.get_value("Item", self.new_item_code, "is_stock_item"):
 			frappe.throw(_("Parent Item {0} must not be a Stock Item").format(self.new_item_code))
+		if frappe.db.get_value("Item", self.new_item_code, "is_fixed_asset"):
+			frappe.throw(_("Parent Item {0} must not be a Fixed Asset").format(self.new_item_code))
 
 	def validate_child_items(self):
 		for item in self.items:
-			if frappe.db.exists("Product Bundle", item.item_code):
+			if frappe.db.exists("Product Bundle", {"name": item.item_code, "disabled": 0}):
 				frappe.throw(
 					_(
 						"Row #{0}: Child Item should not be a Product Bundle. Please remove Item {1} and Save"
@@ -73,12 +75,17 @@
 @frappe.whitelist()
 @frappe.validate_and_sanitize_search_inputs
 def get_new_item_code(doctype, txt, searchfield, start, page_len, filters):
-	from erpnext.controllers.queries import get_match_cond
-
-	return frappe.db.sql(
-		"""select name, item_name, description from tabItem
-		where is_stock_item=0 and name not in (select name from `tabProduct Bundle`)
-		and %s like %s %s limit %s offset %s"""
-		% (searchfield, "%s", get_match_cond(doctype), "%s", "%s"),
-		("%%%s%%" % txt, page_len, start),
-	)
+	product_bundles = frappe.db.get_list("Product Bundle", {"disabled": 0}, pluck="name")
+	item = frappe.qb.DocType("Item")
+	return (
+		frappe.qb.from_(item)
+		.select("*")
+		.where(
+			(item.is_stock_item == 0)
+			& (item.is_fixed_asset == 0)
+			& (item.name.notin(product_bundles))
+			& (item[searchfield].like(f"%{txt}%"))
+		)
+		.limit(page_len)
+		.offset(start)
+	).run()
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 5016f1f..0e25313 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -135,6 +135,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -666,7 +667,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-09-26 13:42:11.410294",
+ "modified": "2023-11-14 18:24:24.619832",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Quotation Item",
@@ -676,4 +677,4 @@
  "sort_order": "DESC",
  "states": [],
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index e4f1a28..a23599b 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -688,7 +688,9 @@
 			"Sales Order Item": {
 				"doctype": "Material Request Item",
 				"field_map": {"name": "sales_order_item", "parent": "sales_order"},
-				"condition": lambda item: not frappe.db.exists("Product Bundle", item.item_code)
+				"condition": lambda item: not frappe.db.exists(
+					"Product Bundle", {"name": item.item_code, "disabled": 0}
+				)
 				and get_remaining_qty(item) > 0,
 				"postprocess": update_item,
 			},
@@ -767,8 +769,11 @@
 		if target.company_address:
 			target.update(get_fetch_values("Delivery Note", "company_address", target.company_address))
 
-		# set target items names to ensure proper linking with packed_items
-		target.set_new_name()
+		# if invoked in bulk creation, validations are ignored and thus this method is nerver invoked
+		if frappe.flags.bulk_transaction:
+			# set target items names to ensure proper linking with packed_items
+			target.set_new_name()
+
 		make_packing_list(target)
 
 	def condition(doc):
@@ -1306,7 +1311,7 @@
 
 
 def is_product_bundle(item_code):
-	return frappe.db.exists("Product Bundle", item_code)
+	return frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0})
 
 
 @frappe.whitelist()
@@ -1518,7 +1523,7 @@
 		product_bundle_parents = [
 			pb.new_item_code
 			for pb in frappe.get_all(
-				"Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"]
+				"Product Bundle", {"new_item_code": ["in", item_codes], "disabled": 0}, ["new_item_code"]
 			)
 		]
 
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index f82047f..b4f7300 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -68,7 +68,6 @@
   "total_weight",
   "column_break_21",
   "weight_uom",
-  "accounting_dimensions_section",
   "warehouse_and_reference",
   "warehouse",
   "target_warehouse",
@@ -177,6 +176,7 @@
    "print_hide": 1
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -890,18 +890,12 @@
    "label": "Production Plan Qty",
    "no_copy": 1,
    "read_only": 1
-  },
-  {
-   "collapsible": 1,
-   "fieldname": "accounting_dimensions_section",
-   "fieldtype": "Section Break",
-   "label": "Accounting Dimensions"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-17 18:18:26.475259",
+ "modified": "2023-11-14 18:37:12.787893",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order Item",
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index db6255a..feecd9c 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -548,6 +548,14 @@
 				if (!item_code)
 					return;
 
+				if (rate == undefined || rate == 0) {
+					frappe.show_alert({
+						message: __('Price is not set for the item.'),
+						indicator: 'orange'
+					});
+					frappe.utils.play_sound("error");
+					return;
+				}
 				const new_item = { item_code, batch_no, rate, uom, [field]: value };
 
 				if (serial_no) {
@@ -601,11 +609,12 @@
 			// if item is clicked twice from item selector
 			// then "item_code, batch_no, uom, rate" will help in getting the exact item
 			// to increase the qty by one
-			const has_batch_no = batch_no;
+			const has_batch_no = (batch_no !== 'null' && batch_no !== null);
 			item_row = this.frm.doc.items.find(
 				i => i.item_code === item_code
 					&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
 					&& (i.uom === uom)
+					&& (i.rate === flt(rate))
 			);
 		}
 
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 89ce61ab..63711c5 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -203,7 +203,7 @@
 			const paid_amount = doc.paid_amount;
 			const items = doc.items;
 
-			if (paid_amount == 0 || !items.length) {
+			if (!items.length || (paid_amount == 0 && doc.additional_discount_percentage != 100)) {
 				const message = items.length ? __("You cannot submit the order without payment.") : __("You cannot submit empty order.");
 				frappe.show_alert({ message, indicator: "orange" });
 				frappe.utils.play_sound("error");
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
index 4542bdf..0a29d43 100644
--- a/erpnext/selling/report/address_and_contacts/address_and_contacts.py
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
@@ -26,7 +26,7 @@
 def get_columns(filters):
 	party_type = filters.get("party_type")
 	party_type_value = get_party_group(party_type)
-	return [
+	columns = [
 		"{party_type}:Link/{party_type}".format(party_type=party_type),
 		"{party_value_type}::150".format(party_value_type=frappe.unscrub(str(party_type_value))),
 		"Address Line 1",
@@ -43,6 +43,15 @@
 		"Email Id",
 		"Is Primary Contact:Check",
 	]
+	if filters.get("party_type") == "Supplier" and frappe.db.get_single_value(
+		"Buying Settings", "supp_master_name"
+	) == ["Naming Series", "Auto Name"]:
+		columns.insert(1, "Supplier Name:Data:150")
+	if filters.get("party_type") == "Customer" and frappe.db.get_single_value(
+		"Selling Settings", "cust_master_name"
+	) == ["Naming Series", "Auto Name"]:
+		columns.insert(1, "Customer Name:Data:150")
+	return columns
 
 
 def get_data(filters):
@@ -50,27 +59,33 @@
 	party = filters.get("party_name")
 	party_group = get_party_group(party_type)
 
-	return get_party_addresses_and_contact(party_type, party, party_group)
+	return get_party_addresses_and_contact(party_type, party, party_group, filters)
 
 
-def get_party_addresses_and_contact(party_type, party, party_group):
+def get_party_addresses_and_contact(party_type, party, party_group, filters):
 	data = []
-	filters = None
+	query_filters = None
 	party_details = frappe._dict()
 
 	if not party_type:
 		return []
 
 	if party:
-		filters = {"name": party}
+		query_filters = {"name": party}
+	if filters.get("party_type") in ["Customer", "Supplier"]:
+		field = filters.get("party_type").lower() + "_name"
+	else:
+		field = "partner_name"
 
 	fetch_party_list = frappe.get_list(
-		party_type, filters=filters, fields=["name", party_group], as_list=True
+		party_type, filters=query_filters, fields=["name", party_group, field], as_list=True
 	)
 	party_list = [d[0] for d in fetch_party_list]
 	party_groups = {}
+	party_name_map = {}
 	for d in fetch_party_list:
 		party_groups[d[0]] = d[1]
+		party_name_map[d[0]] = d[2]
 
 	for d in party_list:
 		party_details.setdefault(d, frappe._dict())
@@ -84,6 +99,8 @@
 		if not any([addresses, contacts]):
 			result = [party]
 			result.append(party_groups[party])
+			if filters.get("party_type") in ["Customer", "Supplier"]:
+				result.append(party_name_map[party])
 			result.extend(add_blank_columns_for("Contact"))
 			result.extend(add_blank_columns_for("Address"))
 			data.append(result)
@@ -95,11 +112,12 @@
 			for idx in range(0, max_length):
 				result = [party]
 				result.append(party_groups[party])
+				if filters.get("party_type") in ["Customer", "Supplier"]:
+					result.append(party_name_map[party])
 				address = addresses[idx] if idx < len(addresses) else add_blank_columns_for("Address")
 				contact = contacts[idx] if idx < len(contacts) else add_blank_columns_for("Contact")
 				result.extend(address)
 				result.extend(contact)
-
 				data.append(result)
 	return data
 
@@ -115,7 +133,6 @@
 	for d in records:
 		details = party_details.get(d[0])
 		details.setdefault(frappe.scrub(doctype), []).append(d[1:])
-
 	return party_details
 
 
diff --git a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
index 5dfc1db..ecb63d8 100644
--- a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
+++ b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
@@ -80,7 +80,7 @@
 
 		territory_orders = []
 		if t_quotation_names and sales_orders:
-			list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
+			territory_orders = list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
 		t_order_names = []
 		if territory_orders:
 			t_order_names = [t.name for t in territory_orders]
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 4fc20e6..6ed44ff 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -382,9 +382,10 @@
 		"""Get income to date"""
 		balance = 0.0
 		count = 0
+		fy_start_date = get_fiscal_year(self.future_to_date)[1]
 
 		for account in self.get_root_type_accounts(root_type):
-			balance += get_balance_on(account, date=self.future_to_date)
+			balance += get_balance_on(account, date=self.future_to_date, start_date=fy_start_date)
 			count += get_count_on(account, fieldname, date=self.future_to_date)
 
 		if fieldname == "income":
diff --git a/erpnext/setup/doctype/employee/employee.js b/erpnext/setup/doctype/employee/employee.js
index 39a215f..efc3fd1 100755
--- a/erpnext/setup/doctype/employee/employee.js
+++ b/erpnext/setup/doctype/employee/employee.js
@@ -81,8 +81,10 @@
 				employee: frm.doc.name,
 				email: frm.doc.prefered_email
 			},
+			freeze: true,
+			freeze_message: __("Creating User..."),
 			callback: function (r) {
-				frm.set_value("user_id", r.message);
+				frm.reload_doc();
 			}
 		});
 	}
diff --git a/erpnext/setup/doctype/employee/employee.py b/erpnext/setup/doctype/employee/employee.py
index 78fb4df..6f9176c 100755
--- a/erpnext/setup/doctype/employee/employee.py
+++ b/erpnext/setup/doctype/employee/employee.py
@@ -48,6 +48,9 @@
 		else:
 			existing_user_id = frappe.db.get_value("Employee", self.name, "user_id")
 			if existing_user_id:
+				user = frappe.get_doc("User", existing_user_id)
+				validate_employee_role(user, ignore_emp_check=True)
+				user.save(ignore_permissions=True)
 				remove_user_permission("Employee", self.name, existing_user_id)
 
 	def after_rename(self, old, new, merge):
@@ -230,12 +233,26 @@
 			frappe.cache().hdel("employees_with_number", prev_number)
 
 
-def validate_employee_role(doc, method):
+def validate_employee_role(doc, method=None, ignore_emp_check=False):
 	# called via User hook
-	if "Employee" in [d.role for d in doc.get("roles")]:
-		if not frappe.db.get_value("Employee", {"user_id": doc.name}):
-			frappe.msgprint(_("Please set User ID field in an Employee record to set Employee Role"))
-			doc.get("roles").remove(doc.get("roles", {"role": "Employee"})[0])
+	if not ignore_emp_check:
+		if frappe.db.get_value("Employee", {"user_id": doc.name}):
+			return
+
+	user_roles = [d.role for d in doc.get("roles")]
+	if "Employee" in user_roles:
+		frappe.msgprint(
+			_("User {0}: Removed Employee role as there is no mapped employee.").format(doc.name)
+		)
+		doc.get("roles").remove(doc.get("roles", {"role": "Employee"})[0])
+
+	if "Employee Self Service" in user_roles:
+		frappe.msgprint(
+			_("User {0}: Removed Employee Self Service role as there is no mapped employee.").format(
+				doc.name
+			)
+		)
+		doc.get("roles").remove(doc.get("roles", {"role": "Employee Self Service"})[0])
 
 
 def update_user_permissions(doc, method):
@@ -347,6 +364,8 @@
 		}
 	)
 	user.insert()
+	emp.user_id = user.name
+	emp.save()
 	return user.name
 
 
diff --git a/erpnext/setup/doctype/employee/test_employee.py b/erpnext/setup/doctype/employee/test_employee.py
index 5a693c5..9b70683 100644
--- a/erpnext/setup/doctype/employee/test_employee.py
+++ b/erpnext/setup/doctype/employee/test_employee.py
@@ -25,6 +25,15 @@
 		employee1_doc.status = "Left"
 		self.assertRaises(InactiveEmployeeStatusError, employee1_doc.save)
 
+	def test_user_has_employee(self):
+		employee = make_employee("test_emp_user_creation@company.com")
+		employee_doc = frappe.get_doc("Employee", employee)
+		user = employee_doc.user_id
+		self.assertTrue("Employee" in frappe.get_roles(user))
+		employee_doc.user_id = ""
+		employee_doc.save()
+		self.assertTrue("Employee" not in frappe.get_roles(user))
+
 	def tearDown(self):
 		frappe.db.rollback()
 
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 481a3a5..d266285 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -108,7 +108,16 @@
 
 				if no_of_docs > 0:
 					self.delete_version_log(docfield["parent"], docfield["fieldname"])
-					self.delete_communications(docfield["parent"], docfield["fieldname"])
+
+					reference_docs = frappe.get_all(
+						docfield["parent"], filters={docfield["fieldname"]: self.company}
+					)
+					reference_doc_names = [r.name for r in reference_docs]
+
+					self.delete_communications(docfield["parent"], reference_doc_names)
+					self.delete_comments(docfield["parent"], reference_doc_names)
+					self.unlink_attachments(docfield["parent"], reference_doc_names)
+
 					self.populate_doctypes_table(tables, docfield["parent"], no_of_docs)
 
 					self.delete_child_tables(docfield["parent"], docfield["fieldname"])
@@ -197,19 +206,49 @@
 					(versions.ref_doctype == doctype) & (versions.docname.isin(batch))
 				).run()
 
-	def delete_communications(self, doctype, company_fieldname):
-		reference_docs = frappe.get_all(doctype, filters={company_fieldname: self.company})
-		reference_doc_names = [r.name for r in reference_docs]
-
+	def delete_communications(self, doctype, reference_doc_names):
 		communications = frappe.get_all(
 			"Communication",
 			filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
 		)
 		communication_names = [c.name for c in communications]
 
+		if not communication_names:
+			return
+
 		for batch in create_batch(communication_names, self.batch_size):
 			frappe.delete_doc("Communication", batch, ignore_permissions=True)
 
+	def delete_comments(self, doctype, reference_doc_names):
+		comments = frappe.get_all(
+			"Comment",
+			filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
+		)
+		comment_names = [c.name for c in comments]
+
+		if not comment_names:
+			return
+
+		for batch in create_batch(comment_names, self.batch_size):
+			frappe.delete_doc("Comment", batch, ignore_permissions=True)
+
+	def unlink_attachments(self, doctype, reference_doc_names):
+		files = frappe.get_all(
+			"File",
+			filters={"attached_to_doctype": doctype, "attached_to_name": ["in", reference_doc_names]},
+		)
+		file_names = [c.name for c in files]
+
+		if not file_names:
+			return
+
+		file = qb.DocType("File")
+
+		for batch in create_batch(file_names, self.batch_size):
+			qb.update(file).set(file.attached_to_doctype, None).set(file.attached_to_name, None).where(
+				file.name.isin(batch)
+			).run()
+
 
 @frappe.whitelist()
 def get_doctypes_to_be_ignored():
diff --git a/erpnext/stock/doctype/batch/batch.json b/erpnext/stock/doctype/batch/batch.json
index e6cb351..e20030a 100644
--- a/erpnext/stock/doctype/batch/batch.json
+++ b/erpnext/stock/doctype/batch/batch.json
@@ -61,6 +61,7 @@
    "oldfieldname": "item",
    "oldfieldtype": "Link",
    "options": "Item",
+   "read_only_depends_on": "eval:!doc.__islocal",
    "reqd": 1
   },
   {
@@ -207,7 +208,7 @@
  "image_field": "image",
  "links": [],
  "max_attachments": 5,
- "modified": "2023-03-12 15:56:09.516586",
+ "modified": "2023-11-09 12:17:28.339975",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Batch",
@@ -224,7 +225,6 @@
    "read": 1,
    "report": 1,
    "role": "Item Manager",
-   "set_user_permissions": 1,
    "share": 1,
    "write": 1
   }
diff --git a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.json b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.json
index 225da6d..0c4757f 100644
--- a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.json
+++ b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.json
@@ -104,15 +104,6 @@
    "read_only": 1
   },
   {
-   "fieldname": "amended_from",
-   "fieldtype": "Link",
-   "label": "Amended From",
-   "no_copy": 1,
-   "options": "Closing Stock Balance",
-   "print_hide": 1,
-   "read_only": 1
-  },
-  {
    "fieldname": "include_uom",
    "fieldtype": "Link",
    "label": "Include UOM",
@@ -145,4 +136,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "states": []
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 66dd33a..f240136 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -615,7 +615,7 @@
 		items_list = [item.item_code for item in self.items]
 		return frappe.db.get_all(
 			"Product Bundle",
-			filters={"new_item_code": ["in", items_list]},
+			filters={"new_item_code": ["in", items_list], "disabled": 0},
 			pluck="name",
 		)
 
@@ -938,7 +938,7 @@
 				},
 				"postprocess": update_item,
 				"condition": lambda item: (
-					not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code})
+					not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code, "disabled": 0})
 					and flt(item.packed_qty) < flt(item.qty)
 				),
 			},
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 6148950..a44b9ac 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -168,6 +168,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -893,7 +894,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-16 16:18:18.013379",
+ "modified": "2023-11-14 18:37:38.638144",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index c13d3eb..13f3be8 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -504,7 +504,7 @@
    "fieldtype": "Table",
    "hidden": 1,
    "label": "Variant Attributes",
-   "mandatory_depends_on": "has_variants",
+   "mandatory_depends_on": "eval:(doc.has_variants || doc.variant_of) && doc.variant_based_on==='Item Attribute'",
    "options": "Item Variant Attribute"
   },
   {
@@ -888,7 +888,7 @@
  "index_web_pages_for_search": 1,
  "links": [],
  "make_attachments_public": 1,
- "modified": "2023-09-11 13:46:32.688051",
+ "modified": "2023-09-18 15:41:32.688051",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index d8935fe..cb34497 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -512,8 +512,12 @@
 
 	def validate_duplicate_product_bundles_before_merge(self, old_name, new_name):
 		"Block merge if both old and new items have product bundles."
-		old_bundle = frappe.get_value("Product Bundle", filters={"new_item_code": old_name})
-		new_bundle = frappe.get_value("Product Bundle", filters={"new_item_code": new_name})
+		old_bundle = frappe.get_value(
+			"Product Bundle", filters={"new_item_code": old_name, "disabled": 0}
+		)
+		new_bundle = frappe.get_value(
+			"Product Bundle", filters={"new_item_code": new_name, "disabled": 0}
+		)
 
 		if old_bundle and new_bundle:
 			bundle_link = get_link_to_form("Product Bundle", old_bundle)
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 09d3dd1..a942f58 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -163,7 +163,7 @@
 			{
 				"item_code": "_Test Item With Item Tax Template",
 				"tax_category": "_Test Tax Category 2",
-				"item_tax_template": "",
+				"item_tax_template": None,
 			},
 			{
 				"item_code": "_Test Item Inherit Group Item Tax Template 1",
@@ -178,7 +178,7 @@
 			{
 				"item_code": "_Test Item Inherit Group Item Tax Template 1",
 				"tax_category": "_Test Tax Category 2",
-				"item_tax_template": "",
+				"item_tax_template": None,
 			},
 			{
 				"item_code": "_Test Item Inherit Group Item Tax Template 2",
@@ -193,7 +193,7 @@
 			{
 				"item_code": "_Test Item Inherit Group Item Tax Template 2",
 				"tax_category": "_Test Tax Category 2",
-				"item_tax_template": "",
+				"item_tax_template": None,
 			},
 			{
 				"item_code": "_Test Item Override Group Item Tax Template",
@@ -208,12 +208,12 @@
 			{
 				"item_code": "_Test Item Override Group Item Tax Template",
 				"tax_category": "_Test Tax Category 2",
-				"item_tax_template": "",
+				"item_tax_template": None,
 			},
 		]
 
 		expected_item_tax_map = {
-			"": {},
+			None: {},
 			"_Test Account Excise Duty @ 10 - _TC": {"_Test Account Excise Duty - _TC": 10},
 			"_Test Account Excise Duty @ 12 - _TC": {"_Test Account Excise Duty - _TC": 12},
 			"_Test Account Excise Duty @ 15 - _TC": {"_Test Account Excise Duty - _TC": 15},
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index 9912be1..5dc07c9 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -110,6 +110,7 @@
    "width": "250px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach Image",
    "label": "Image",
@@ -478,7 +479,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-27 15:53:41.444236",
+ "modified": "2023-11-14 18:37:59.599115",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Material Request Item",
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index a9e9ad1..35701c9 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -55,7 +55,7 @@
 
 
 def is_product_bundle(item_code: str) -> bool:
-	return bool(frappe.db.exists("Product Bundle", {"new_item_code": item_code}))
+	return bool(frappe.db.exists("Product Bundle", {"new_item_code": item_code, "disabled": 0}))
 
 
 def get_indexed_packed_items_table(doc):
@@ -111,7 +111,7 @@
 			product_bundle_item.uom,
 			product_bundle_item.description,
 		)
-		.where(product_bundle.new_item_code == item_code)
+		.where((product_bundle.new_item_code == item_code) & (product_bundle.disabled == 0))
 		.orderby(product_bundle_item.idx)
 	)
 	return query.run(as_dict=True)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index ed20209..644df3d 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -368,7 +368,9 @@
 				frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx))
 			if not cint(
 				frappe.get_cached_value("Item", item.item_code, "is_stock_item")
-			) and not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code}):
+			) and not frappe.db.exists(
+				"Product Bundle", {"new_item_code": item.item_code, "disabled": 0}
+			):
 				continue
 			item_code = item.item_code
 			reference = item.sales_order_item or item.material_request_item
@@ -507,7 +509,9 @@
 		# bundle_item_code: Dict[component, qty]
 		product_bundle_qty_map = {}
 		for bundle_item_code in bundles:
-			bundle = frappe.get_last_doc("Product Bundle", {"new_item_code": bundle_item_code})
+			bundle = frappe.get_last_doc(
+				"Product Bundle", {"new_item_code": bundle_item_code, "disabled": 0}
+			)
 			product_bundle_qty_map[bundle_item_code] = {item.item_code: item.qty for item in bundle.items}
 		return product_bundle_qty_map
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 1fcde44..e02dfed 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -7,7 +7,7 @@
 from frappe.desk.notifications import clear_doctype_notifications
 from frappe.model.mapper import get_mapped_doc
 from frappe.query_builder.functions import CombineDatetime
-from frappe.utils import cint, flt, getdate, nowdate
+from frappe.utils import cint, flt, get_datetime, getdate, nowdate
 from pypika import functions as fn
 
 import erpnext
@@ -734,12 +734,18 @@
 
 	def update_assets(self, item, valuation_rate):
 		assets = frappe.db.get_all(
-			"Asset", filters={"purchase_receipt": self.name, "item_code": item.item_code}
+			"Asset",
+			filters={"purchase_receipt": self.name, "item_code": item.item_code},
+			fields=["name", "asset_quantity"],
 		)
 
 		for asset in assets:
-			frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(valuation_rate))
-			frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(valuation_rate))
+			frappe.db.set_value(
+				"Asset", asset.name, "gross_purchase_amount", flt(valuation_rate) * asset.asset_quantity
+			)
+			frappe.db.set_value(
+				"Asset", asset.name, "purchase_receipt_amount", flt(valuation_rate) * asset.asset_quantity
+			)
 
 	def update_status(self, status):
 		self.set_status(update=True, status=status)
@@ -763,8 +769,12 @@
 			update_billing_percentage(pr_doc, update_modified=update_modified)
 
 	def reserve_stock_for_sales_order(self):
-		if self.is_return or not cint(
-			frappe.db.get_single_value("Stock Settings", "auto_reserve_stock_for_sales_order_on_purchase")
+		if (
+			self.is_return
+			or not frappe.db.get_single_value("Stock Settings", "enable_stock_reservation")
+			or not frappe.db.get_single_value(
+				"Stock Settings", "auto_reserve_stock_for_sales_order_on_purchase"
+			)
 		):
 			return
 
@@ -785,6 +795,11 @@
 				so_items_details_map.setdefault(item.sales_order, []).append(item_details)
 
 		if so_items_details_map:
+			if get_datetime("{} {}".format(self.posting_date, self.posting_time)) > get_datetime():
+				return frappe.msgprint(
+					_("Cannot create Stock Reservation Entries for future dated Purchase Receipts.")
+				)
+
 			for so, items_details in so_items_details_map.items():
 				so_doc = frappe.get_doc("Sales Order", so)
 				so_doc.create_stock_reservation_entries(
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 718f007..ce2e5d7 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -192,6 +192,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -1090,7 +1091,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-10-30 17:32:24.560337",
+ "modified": "2023-11-14 18:38:15.251994",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index f2bbf2b..abdbeb4 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -246,7 +246,7 @@
 				valuation_field = "rate"
 				child_table = "Subcontracting Receipt Supplied Item"
 			else:
-				valuation_field = "rm_supp_cost"
+				valuation_field = "rate"
 				child_table = "Subcontracting Receipt Item"
 
 		precision = frappe.get_precision(child_table, valuation_field) or 2
@@ -406,7 +406,7 @@
 
 		if abs(abs(flt(self.total_qty, precision)) - abs(flt(row.get(qty_field), precision))) > 0.01:
 			self.throw_error_message(
-				f"Total quantity {abs(self.total_qty)} in the Serial and Batch Bundle {bold(self.name)} does not match with the quantity {abs(row.get(qty_field))} for the Item {bold(self.item_code)} in the {self.voucher_type} # {self.voucher_no}"
+				f"Total quantity {abs(flt(self.total_qty))} in the Serial and Batch Bundle {bold(self.name)} does not match with the quantity {abs(flt(row.get(qty_field)))} for the Item {bold(self.item_code)} in the {self.voucher_type} # {self.voucher_no}"
 			)
 
 	def set_is_outward(self):
@@ -1604,6 +1604,9 @@
 	)
 
 	for key, val in kwargs.items():
+		if not val:
+			continue
+
 		if key in ["get_subcontracted_item"]:
 			continue
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index e87658b..b9e1af5 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -161,7 +161,7 @@
 		if self.is_enqueue_action():
 			frappe.msgprint(
 				_(
-					"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Draft stage"
+					"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Draft stage"
 				)
 			)
 			self.queue_action("submit", timeout=2000)
@@ -172,7 +172,7 @@
 		if self.is_enqueue_action():
 			frappe.msgprint(
 				_(
-					"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Submitted stage"
+					"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Submitted stage"
 				)
 			)
 			self.queue_action("cancel", timeout=2000)
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 569f58a..be37994 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -11,6 +11,8 @@
   "warehouse",
   "posting_date",
   "posting_time",
+  "is_adjustment_entry",
+  "auto_created_serial_and_batch_bundle",
   "column_break_6",
   "voucher_type",
   "voucher_no",
@@ -333,6 +335,19 @@
    "fieldname": "has_serial_no",
    "fieldtype": "Check",
    "label": "Has Serial No"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_adjustment_entry",
+   "fieldtype": "Check",
+   "label": "Is Adjustment Entry"
+  },
+  {
+   "default": "0",
+   "depends_on": "serial_and_batch_bundle",
+   "fieldname": "auto_created_serial_and_batch_bundle",
+   "fieldtype": "Check",
+   "label": "Auto Created Serial and Batch Bundle"
   }
  ],
  "hide_toolbar": 1,
@@ -341,7 +356,7 @@
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2023-04-03 16:33:16.270722",
+ "modified": "2023-11-14 16:47:39.791967",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Ledger Entry",
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 323ad4f..1bf143b 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -442,6 +442,11 @@
 
 		sl_entries = []
 		for row in self.items:
+
+			if not row.qty and not row.valuation_rate and not row.current_qty:
+				self.make_adjustment_entry(row, sl_entries)
+				continue
+
 			item = frappe.get_cached_value(
 				"Item", row.item_code, ["has_serial_no", "has_batch_no"], as_dict=1
 			)
@@ -492,6 +497,21 @@
 			)
 			self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
 
+	def make_adjustment_entry(self, row, sl_entries):
+		from erpnext.stock.stock_ledger import get_stock_value_difference
+
+		difference_amount = get_stock_value_difference(
+			row.item_code, row.warehouse, self.posting_date, self.posting_time
+		)
+
+		if not difference_amount:
+			return
+
+		args = self.get_sle_for_items(row)
+		args.update({"stock_value_difference": -1 * difference_amount, "is_adjustment_entry": 1})
+
+		sl_entries.append(args)
+
 	def get_sle_for_serialized_items(self, row, sl_entries):
 		if row.current_serial_and_batch_bundle:
 			args = self.get_sle_for_items(row)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index e29fc88..d1a9cf2 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -149,7 +149,7 @@
 
 
 def set_valuation_rate(out, args):
-	if frappe.db.exists("Product Bundle", args.item_code, cache=True):
+	if frappe.db.exists("Product Bundle", {"name": args.item_code, "disabled": 0}, cache=True):
 		valuation_rate = 0.0
 		bundled_items = frappe.get_doc("Product Bundle", args.item_code)
 
@@ -610,7 +610,6 @@
 
 	# all templates have validity and no template is valid
 	if not taxes_with_validity and (not taxes_with_no_validity):
-		out["item_tax_template"] = ""
 		return None
 
 	# do not change if already a valid template
diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py
index ab47b4a..a53a9f2 100644
--- a/erpnext/stock/report/item_prices/item_prices.py
+++ b/erpnext/stock/report/item_prices/item_prices.py
@@ -202,7 +202,7 @@
 	bin_data = (
 		frappe.qb.from_(bin)
 		.select(
-			bin.item_code, Sum(bin.actual_qty * bin.valuation_rate) / Sum(bin.actual_qty).as_("val_rate")
+			bin.item_code, (Sum(bin.actual_qty * bin.valuation_rate) / Sum(bin.actual_qty)).as_("val_rate")
 		)
 		.where(bin.actual_qty > 0)
 		.groupby(bin.item_code)
diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py
index 5998274..da98455 100644
--- a/erpnext/stock/serial_batch_bundle.py
+++ b/erpnext/stock/serial_batch_bundle.py
@@ -129,7 +129,9 @@
 			frappe.throw(_(error_msg))
 
 	def set_serial_and_batch_bundle(self, sn_doc):
-		self.sle.db_set("serial_and_batch_bundle", sn_doc.name)
+		self.sle.db_set(
+			{"serial_and_batch_bundle": sn_doc.name, "auto_created_serial_and_batch_bundle": 1}
+		)
 
 		if sn_doc.is_rejected:
 			frappe.db.set_value(
@@ -143,6 +145,12 @@
 	@property
 	def child_doctype(self):
 		child_doctype = self.sle.voucher_type + " Item"
+
+		if (
+			self.sle.voucher_type == "Subcontracting Receipt" and self.sle.dependant_sle_voucher_detail_no
+		):
+			child_doctype = "Subcontracting Receipt Supplied Item"
+
 		if self.sle.voucher_type == "Stock Entry":
 			child_doctype = "Stock Entry Detail"
 
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index e9381d4..9142a27 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -759,12 +759,16 @@
 		sle.valuation_rate = self.wh_data.valuation_rate
 		sle.stock_value = self.wh_data.stock_value
 		sle.stock_queue = json.dumps(self.wh_data.stock_queue)
-		sle.stock_value_difference = stock_value_difference
-		sle.doctype = "Stock Ledger Entry"
 
+		if not sle.is_adjustment_entry or not self.args.get("sle_id"):
+			sle.stock_value_difference = stock_value_difference
+
+		sle.doctype = "Stock Ledger Entry"
 		frappe.get_doc(sle).db_update()
 
-		if not self.args.get("sle_id"):
+		if not self.args.get("sle_id") or (
+			sle.serial_and_batch_bundle and sle.auto_created_serial_and_batch_bundle
+		):
 			self.update_outgoing_rate_on_transaction(sle)
 
 	def reset_actual_qty_for_stock_reco(self, sle):
@@ -1939,3 +1943,27 @@
 
 	if data.is_internal_supplier and data.represents_company == data.company:
 		return True
+
+
+def get_stock_value_difference(item_code, warehouse, posting_date, posting_time, voucher_no=None):
+	table = frappe.qb.DocType("Stock Ledger Entry")
+
+	query = (
+		frappe.qb.from_(table)
+		.select(Sum(table.stock_value_difference).as_("value"))
+		.where(
+			(table.is_cancelled == 0)
+			& (table.item_code == item_code)
+			& (table.warehouse == warehouse)
+			& (
+				(table.posting_date < posting_date)
+				| ((table.posting_date == posting_date) & (table.posting_time <= posting_time))
+			)
+		)
+	)
+
+	if voucher_no:
+		query = query.where(table.voucher_no != voucher_no)
+
+	difference_amount = query.run()
+	return flt(difference_amount[0][0]) if difference_amount else 0
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 d77e774..46c229b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -112,6 +112,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -337,7 +338,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-01-20 23:25:45.363281",
+ "modified": "2023-11-14 18:38:37.640677",
  "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 19a1c93..36001eb 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -13,6 +13,16 @@
 		frm.trigger('set_queries');
 	},
 
+	on_submit(frm) {
+		frm.events.refresh_serial_batch_bundle_field(frm);
+	},
+
+	refresh_serial_batch_bundle_field(frm) {
+		frappe.route_hooks.after_submit = (frm_obj) => {
+			frm_obj.reload_doc();
+		}
+	},
+
 	refresh: (frm) => {
 		if (frm.doc.docstatus > 0) {
 			frm.add_custom_button(__('Stock Ledger'), () => {
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
index 8be1c1b..383a83b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
@@ -11,6 +11,7 @@
   "naming_series",
   "supplier",
   "supplier_name",
+  "supplier_delivery_note",
   "column_break1",
   "company",
   "posting_date",
@@ -634,12 +635,17 @@
    "fieldtype": "Button",
    "label": "Get Scrap Items",
    "options": "get_scrap_items"
+  },
+  {
+   "fieldname": "supplier_delivery_note",
+   "fieldtype": "Data",
+   "label": "Supplier Delivery Note"
   }
  ],
  "in_create": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-08-26 10:52:04.050829",
+ "modified": "2023-11-16 13:04:00.710534",
  "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 7e06444..8d705aa 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -148,6 +148,8 @@
 		if (
 			frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
 			== "BOM"
+			and self.supplied_items
+			and not any(item.serial_and_batch_bundle for item in self.supplied_items)
 		):
 			self.supplied_items = []
 
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index 1828f696..f0e4e00 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -6,7 +6,7 @@
 
 import frappe
 from frappe.tests.utils import FrappeTestCase
-from frappe.utils import add_days, cint, cstr, flt, today
+from frappe.utils import add_days, cint, cstr, flt, nowtime, today
 
 import erpnext
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
@@ -26,6 +26,10 @@
 from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
+from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import (
+	get_batch_from_bundle,
+	make_serial_batch_bundle,
+)
 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,
@@ -507,6 +511,260 @@
 		self.assertNotEqual(scr.supplied_items[0].rate, prev_cost)
 		self.assertEqual(scr.supplied_items[0].rate, sr.items[0].valuation_rate)
 
+	def test_subcontracting_receipt_for_batch_raw_materials_without_material_transfer(self):
+		set_backflush_based_on("BOM")
+
+		fg_item = make_item(properties={"is_stock_item": 1, "is_sub_contracted_item": 1}).name
+		rm_item1 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+			}
+		).name
+
+		bom = make_bom(item=fg_item, raw_materials=[rm_item1])
+
+		rm_batch_no = None
+		for row in bom.items:
+			se = make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=300,
+			)
+
+			se.reload()
+			rm_batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 1",
+				"qty": 1,
+				"rate": 100,
+				"fg_item": fg_item,
+				"fg_item_qty": 1,
+			},
+		]
+		sco = get_subcontracting_order(service_items=service_items)
+		scr = make_subcontracting_receipt(sco.name)
+		scr.save()
+		scr.reload()
+
+		bundle_doc = make_serial_batch_bundle(
+			{
+				"item_code": scr.supplied_items[0].rm_item_code,
+				"warehouse": "_Test Warehouse 1 - _TC",
+				"voucher_type": "Subcontracting Receipt",
+				"posting_date": today(),
+				"posting_time": nowtime(),
+				"qty": -1,
+				"batches": frappe._dict({rm_batch_no: 1}),
+				"type_of_transaction": "Outward",
+				"do_not_submit": True,
+			}
+		)
+
+		scr.supplied_items[0].serial_and_batch_bundle = bundle_doc.name
+		scr.submit()
+		scr.reload()
+
+		batch_no = get_batch_from_bundle(scr.supplied_items[0].serial_and_batch_bundle)
+		self.assertEqual(batch_no, rm_batch_no)
+		self.assertEqual(scr.items[0].rm_cost_per_qty, 300)
+		self.assertEqual(scr.items[0].service_cost_per_qty, 100)
+
+	def test_subcontracting_receipt_valuation_with_auto_created_serial_batch_bundle(self):
+		set_backflush_based_on("BOM")
+
+		fg_item = make_item(properties={"is_stock_item": 1, "is_sub_contracted_item": 1}).name
+		rm_item1 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+			}
+		).name
+
+		rm_item2 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"has_serial_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+				"serial_no_series": "BNSS-.####",
+			}
+		).name
+
+		rm_item3 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_serial_no": 1,
+				"serial_no_series": "BSSSS-.####",
+			}
+		).name
+
+		bom = make_bom(item=fg_item, raw_materials=[rm_item1, rm_item2, rm_item3])
+
+		rm_batch_no = None
+		for row in bom.items:
+			make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=300,
+			)
+
+			make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=400,
+			)
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 1",
+				"qty": 1,
+				"rate": 100,
+				"fg_item": fg_item,
+				"fg_item_qty": 1,
+			},
+		]
+		sco = get_subcontracting_order(service_items=service_items)
+
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1
+		)
+		scr = make_subcontracting_receipt(sco.name)
+		scr.save()
+		for row in scr.supplied_items:
+			self.assertNotEqual(row.rate, 300.00)
+			self.assertFalse(row.serial_and_batch_bundle)
+
+		scr.submit()
+		scr.reload()
+
+		for row in scr.supplied_items:
+			self.assertEqual(row.rate, 300.00)
+			self.assertTrue(row.serial_and_batch_bundle)
+			auto_created_serial_batch = frappe.db.get_value(
+				"Stock Ledger Entry",
+				{"voucher_no": scr.name, "voucher_detail_no": row.name},
+				"auto_created_serial_and_batch_bundle",
+			)
+
+			self.assertTrue(auto_created_serial_batch)
+
+		self.assertEqual(scr.items[0].rm_cost_per_qty, 900)
+		self.assertEqual(scr.items[0].service_cost_per_qty, 100)
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 0
+		)
+
+	def test_subcontracting_receipt_valuation_for_fg_with_auto_created_serial_batch_bundle(self):
+		set_backflush_based_on("BOM")
+
+		fg_item = make_item(
+			properties={
+				"is_stock_item": 1,
+				"is_sub_contracted_item": 1,
+				"has_batch_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BSSNGS-.####",
+			}
+		).name
+
+		rm_item1 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+			}
+		).name
+
+		rm_item2 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"has_serial_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+				"serial_no_series": "BNSS-.####",
+			}
+		).name
+
+		rm_item3 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_serial_no": 1,
+				"serial_no_series": "BSSSS-.####",
+			}
+		).name
+
+		bom = make_bom(item=fg_item, raw_materials=[rm_item1, rm_item2, rm_item3])
+
+		rm_batch_no = None
+		for row in bom.items:
+			make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=300,
+			)
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 1",
+				"qty": 1,
+				"rate": 100,
+				"fg_item": fg_item,
+				"fg_item_qty": 1,
+			},
+		]
+		sco = get_subcontracting_order(service_items=service_items)
+
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1
+		)
+		scr = make_subcontracting_receipt(sco.name)
+		scr.save()
+		scr.submit()
+		scr.reload()
+
+		for row in scr.supplied_items:
+			self.assertEqual(row.rate, 300.00)
+			self.assertTrue(row.serial_and_batch_bundle)
+			auto_created_serial_batch = frappe.db.get_value(
+				"Stock Ledger Entry",
+				{"voucher_no": scr.name, "voucher_detail_no": row.name},
+				"auto_created_serial_and_batch_bundle",
+			)
+
+			self.assertTrue(auto_created_serial_batch)
+
+		self.assertEqual(scr.items[0].rm_cost_per_qty, 900)
+		self.assertEqual(scr.items[0].service_cost_per_qty, 100)
+		self.assertEqual(scr.items[0].rate, 1000)
+		valuation_rate = frappe.db.get_value(
+			"Stock Ledger Entry",
+			{"voucher_no": scr.name, "voucher_detail_no": scr.items[0].name},
+			"valuation_rate",
+		)
+
+		self.assertEqual(flt(valuation_rate), flt(1000))
+
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 0
+		)
+
 	def test_subcontracting_receipt_raw_material_rate(self):
 		# Step - 1: Set Backflush Based On as "BOM"
 		set_backflush_based_on("BOM")
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 38432be..26a29dd 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -109,6 +109,7 @@
    "width": "300px"
   },
   {
+   "fetch_from": "item_code.image",
    "fieldname": "image",
    "fieldtype": "Attach",
    "hidden": 1,
@@ -521,7 +522,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-09-03 17:04:21.214316",
+ "modified": "2023-11-14 18:38:26.459669",
  "modified_by": "Administrator",
  "module": "Subcontracting",
  "name": "Subcontracting Receipt Item",
diff --git a/erpnext/translations/af.csv b/erpnext/translations/af.csv
index f457314..ee77d98 100644
--- a/erpnext/translations/af.csv
+++ b/erpnext/translations/af.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",In die geval van &#39;n multi-vlak program sal kliënte outomaties toegewys word aan die betrokke vlak volgens hul besteding,
 Inactive,onaktiewe,
 Incentives,aansporings,
-Include Default Book Entries,Sluit standaardboekinskrywings in,
+Include Default FB Entries,Sluit standaardboekinskrywings in,
 Include Exploded Items,Sluit ontplofte items in,
 Include POS Transactions,Sluit POS-transaksies in,
 Include UOM,Sluit UOM in,
diff --git a/erpnext/translations/am.csv b/erpnext/translations/am.csv
index 0453d5d..a5f09a7 100644
--- a/erpnext/translations/am.csv
+++ b/erpnext/translations/am.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","በባለብዙ ደረጃ መርሃግብር ሁኔታ, ደንበኞች በተጠቀሱት ወጪ መሰረት ለተሰጣቸው ደረጃ ደረጃ በራስ መተላለፍ ይኖራቸዋል",
 Inactive,ገባሪ አይደለም,
 Incentives,ማበረታቻዎች,
-Include Default Book Entries,ነባሪ የመጽሐፍ ግቤቶችን አካትት።,
+Include Default FB Entries,ነባሪ የመጽሐፍ ግቤቶችን አካትት።,
 Include Exploded Items,የተበተኑ ንጥሎችን አካት,
 Include POS Transactions,የ POS ሽግግሮችን አክል,
 Include UOM,UOM አካት,
diff --git a/erpnext/translations/ar.csv b/erpnext/translations/ar.csv
index 67b409e..195b9c7 100644
--- a/erpnext/translations/ar.csv
+++ b/erpnext/translations/ar.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",في حالة البرنامج متعدد المستويات ، سيتم تعيين العملاء تلقائيًا إلى الطبقة المعنية وفقًا للإنفاق,
 Inactive,غير نشط,
 Incentives,الحوافز,
-Include Default Book Entries,تضمين إدخالات دفتر افتراضي,
+Include Default FB Entries,تضمين إدخالات دفتر افتراضي,
 Include Exploded Items,تشمل البنود المستبعدة,
 Include POS Transactions,تشمل معاملات نقطه البيع,
 Include UOM,تضمين UOM,
diff --git a/erpnext/translations/bg.csv b/erpnext/translations/bg.csv
index 787f81e..c2bacf4 100644
--- a/erpnext/translations/bg.csv
+++ b/erpnext/translations/bg.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","В случай на многостепенна програма, клиентите ще бъдат автоматично зададени на съответния подреждан по тяхна сметка",
 Inactive,неактивен,
 Incentives,Стимули,
-Include Default Book Entries,Включете записи по подразбиране на книги,
+Include Default FB Entries,Включете записи по подразбиране на книги,
 Include Exploded Items,Включете експлодираните елементи,
 Include POS Transactions,Включете POS транзакции,
 Include UOM,Включете UOM,
diff --git a/erpnext/translations/bn.csv b/erpnext/translations/bn.csv
index 69fd08c..d7366e1 100644
--- a/erpnext/translations/bn.csv
+++ b/erpnext/translations/bn.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","মাল্টি-টিয়ার প্রোগ্রামের ক্ষেত্রে, গ্রাহকরা তাদের ব্যয় অনুযায়ী সংশ্লিষ্ট টায়ারে স্বয়ংক্রিয়ভাবে নিয়োগ পাবেন",
 Inactive,নিষ্ক্রিয়,
 Incentives,ইনসেনটিভ,
-Include Default Book Entries,ডিফল্ট বুক এন্ট্রি অন্তর্ভুক্ত করুন,
+Include Default FB Entries,ডিফল্ট বুক এন্ট্রি অন্তর্ভুক্ত করুন,
 Include Exploded Items,বিস্ফোরিত আইটেম অন্তর্ভুক্ত করুন,
 Include POS Transactions,পিওএস লেনদেন অন্তর্ভুক্ত করুন,
 Include UOM,UOM অন্তর্ভুক্ত করুন,
diff --git a/erpnext/translations/bs.csv b/erpnext/translations/bs.csv
index ef680a3..df4083e 100644
--- a/erpnext/translations/bs.csv
+++ b/erpnext/translations/bs.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","U slučaju višeslojnog programa, Korisnici će automatski biti dodeljeni za dotičnu grupu po njihovom trošenju",
 Inactive,Neaktivan,
 Incentives,Poticaji,
-Include Default Book Entries,Uključite zadane unose knjiga,
+Include Default FB Entries,Uključite zadane unose knjiga,
 Include Exploded Items,Uključite eksplodirane predmete,
 Include POS Transactions,Uključite POS transakcije,
 Include UOM,Uključite UOM,
diff --git a/erpnext/translations/ca.csv b/erpnext/translations/ca.csv
index fa545a4..b3cf2c5 100644
--- a/erpnext/translations/ca.csv
+++ b/erpnext/translations/ca.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","En el cas del programa de diversos nivells, els clients seran assignats automàticament al nivell corresponent segons el seu gastat",
 Inactive,Inactiu,
 Incentives,Incentius,
-Include Default Book Entries,Inclou les entrades de llibres predeterminats,
+Include Default FB Entries,Inclou les entrades de llibres predeterminats,
 Include Exploded Items,Inclou articles explotats,
 Include POS Transactions,Inclou transaccions de POS,
 Include UOM,Inclou UOM,
diff --git a/erpnext/translations/cs.csv b/erpnext/translations/cs.csv
index 7fb1679..b6deaa4 100644
--- a/erpnext/translations/cs.csv
+++ b/erpnext/translations/cs.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",V případě víceúrovňového programu budou zákazníci automaticky přiděleni danému vrstvě podle svých vynaložených nákladů,
 Inactive,Neaktivní,
 Incentives,Pobídky,
-Include Default Book Entries,Zahrnout výchozí položky knihy,
+Include Default FB Entries,Zahrnout výchozí položky knihy,
 Include Exploded Items,Zahrnout výbušné položky,
 Include POS Transactions,Zahrnout POS transakce,
 Include UOM,Zahrnout UOM,
diff --git a/erpnext/translations/da.csv b/erpnext/translations/da.csv
index 4eb3960..4bcc307 100644
--- a/erpnext/translations/da.csv
+++ b/erpnext/translations/da.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","I tilfælde af multi-tier program, vil kunder automatisk blive tildelt den pågældende tier som per deres brugt",
 Inactive,inaktive,
 Incentives,Incitamenter,
-Include Default Book Entries,Inkluder standardbogsindlæg,
+Include Default FB Entries,Inkluder standardbogsindlæg,
 Include Exploded Items,Inkluder eksploderede elementer,
 Include POS Transactions,Inkluder POS-transaktioner,
 Include UOM,Inkluder UOM,
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index c627f81..73755be 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -533,6 +533,7 @@
 Company is manadatory for company account,Bitte gib ein Unternehmen für dieses Unternehmenskonto an.,
 Company name not same,Firma nicht gleich,
 Company {0} does not exist,Unternehmen {0} existiert nicht,
+Competitor,Konkurrent,
 Compensatory leave request days not in valid holidays,"Tage des Ausgleichsurlaubs, die nicht in den gültigen Feiertagen sind",
 Complaint,Beschwerde,
 Completion Date,Fertigstellungstermin,
@@ -1160,7 +1161,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",Im Falle eines mehrstufigen Programms werden Kunden automatisch der betroffenen Ebene entsprechend ihrer Ausgaben zugewiesen,
 Inactive,Inaktiv,
 Incentives,Anreize,
-Include Default Book Entries,Standardbucheinträge einschließen,
+Include Default FB Entries,Standardbucheinträge einschließen,
 Include Exploded Items,Unterartikel einbeziehen,
 Include POS Transactions,POS-Transaktionen einschließen,
 Include UOM,Fügen Sie UOM hinzu,
@@ -5073,7 +5074,7 @@
 PUR-ORD-.YYYY.-,PUR-ORD-.YYYY.-,
 Get Items from Open Material Requests,Hole Artikel von offenen Material  Anfragen,
 Fetch items based on Default Supplier.,Abrufen von Elementen basierend auf dem Standardlieferanten.,
-Required By,Benötigt von,
+Required By,Benötigt bis,
 Order Confirmation No,Auftragsbestätigung Nr,
 Order Confirmation Date,Auftragsbestätigungsdatum,
 Customer Mobile No,Mobilnummer des Kunden,
diff --git a/erpnext/translations/el.csv b/erpnext/translations/el.csv
index 21fb435..e67eaff 100644
--- a/erpnext/translations/el.csv
+++ b/erpnext/translations/el.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Στην περίπτωση προγράμματος πολλαπλών βαθμίδων, οι Πελάτες θα αντιστοιχούν αυτόματα στη σχετική βαθμίδα σύμφωνα με το ποσό που δαπανώνται",
 Inactive,Αδρανής,
 Incentives,Κίνητρα,
-Include Default Book Entries,Συμπεριλάβετε τις προεπιλεγμένες καταχωρίσεις βιβλίων,
+Include Default FB Entries,Συμπεριλάβετε τις προεπιλεγμένες καταχωρίσεις βιβλίων,
 Include Exploded Items,Συμπεριλάβετε εκραγμένα στοιχεία,
 Include POS Transactions,Συμπεριλάβετε τις συναλλαγές POS,
 Include UOM,Συμπεριλάβετε UOM,
diff --git a/erpnext/translations/es.csv b/erpnext/translations/es.csv
index 2abe418..0c90694 100644
--- a/erpnext/translations/es.csv
+++ b/erpnext/translations/es.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","En el caso del programa de varios niveles, los Clientes se asignarán automáticamente al nivel correspondiente según su gasto",
 Inactive,Inactivo,
 Incentives,Incentivos,
-Include Default Book Entries,Incluir entradas de libro predeterminadas,
+Include Default FB Entries,Incluir entradas de libro predeterminadas,
 Include Exploded Items,Incluir Elementos Estallados,
 Include POS Transactions,Incluir transacciones POS,
 Include UOM,Incluir UOM,
diff --git a/erpnext/translations/et.csv b/erpnext/translations/et.csv
index a4a8736..69a89d9 100644
--- a/erpnext/translations/et.csv
+++ b/erpnext/translations/et.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",Mitmekordsete programmide korral määratakse Kliendid automaatselt asjaomasele tasemele vastavalt nende kasutatud kuludele,
 Inactive,Mitteaktiivne,
 Incentives,Soodustused,
-Include Default Book Entries,Lisage vaikeraamatu kanded,
+Include Default FB Entries,Lisage vaikeraamatu kanded,
 Include Exploded Items,Kaasa lõhutud esemed,
 Include POS Transactions,Kaasa POS-tehingud,
 Include UOM,Lisa UOM,
diff --git a/erpnext/translations/fa.csv b/erpnext/translations/fa.csv
index bd40c8b..cddabfb 100644
--- a/erpnext/translations/fa.csv
+++ b/erpnext/translations/fa.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",در مورد برنامه چند لایه، مشتریان به صورت خودکار به سطر مربوطه اختصاص داده می شوند، همانطور که در هزینه های خود هستند,
 Inactive,غیر فعال,
 Incentives,انگیزه,
-Include Default Book Entries,شامل ورودی های پیش فرض کتاب,
+Include Default FB Entries,شامل ورودی های پیش فرض کتاب,
 Include Exploded Items,شامل موارد انفجار,
 Include POS Transactions,شامل معاملات POS,
 Include UOM,شامل UOM,
diff --git a/erpnext/translations/fi.csv b/erpnext/translations/fi.csv
index 33cf157..eae6053 100644
--- a/erpnext/translations/fi.csv
+++ b/erpnext/translations/fi.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",Monitasoisen ohjelman tapauksessa asiakkaat määräytyvät automaattisesti kyseiselle tasolle niiden kulutuksen mukaan,
 Inactive,Epäaktiivinen,
 Incentives,kannustimet/bonukset,
-Include Default Book Entries,Sisällytä oletustiedot,
+Include Default FB Entries,Sisällytä oletustiedot,
 Include Exploded Items,Sisällytä räjähtämättömiä kohteita,
 Include POS Transactions,Sisällytä POS-tapahtumia,
 Include UOM,Sisällytä UOM,
diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv
index d15af74..5c34759 100644
--- a/erpnext/translations/fr.csv
+++ b/erpnext/translations/fr.csv
@@ -1058,7 +1058,7 @@
 In Value,En valeur,
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Dans le cas d'un programme à plusieurs échelons, les clients seront automatiquement affectés au niveau approprié en fonction de leurs dépenses",
 Incentives,Incitations,
-Include Default Book Entries,Inclure les entrées de livre par défaut,
+Include Default FB Entries,Inclure les entrées de livre par défaut,
 Include Exploded Items,Inclure les articles éclatés,
 Include POS Transactions,Inclure les transactions du point de vente,
 Include UOM,Inclure UdM,
diff --git a/erpnext/translations/gu.csv b/erpnext/translations/gu.csv
index 06a3cc6..604ec41 100644
--- a/erpnext/translations/gu.csv
+++ b/erpnext/translations/gu.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","મલ્ટિ-ટાયર પ્રોગ્રામના કિસ્સામાં, ગ્રાહક તેમના ખર્ચ મુજબ સંબંધિત ટાયરમાં ઓટો હશે",
 Inactive,નિષ્ક્રિય,
 Incentives,ઇનસેન્ટીવ્સ,
-Include Default Book Entries,ડિફaultલ્ટ બુક એન્ટ્રીઓ શામેલ કરો,
+Include Default FB Entries,ડિફaultલ્ટ બુક એન્ટ્રીઓ શામેલ કરો,
 Include Exploded Items,વિસ્ફોટ થયેલ આઇટમ્સ શામેલ કરો,
 Include POS Transactions,POS વ્યવહારો શામેલ કરો,
 Include UOM,યુએમએમ શામેલ કરો,
diff --git a/erpnext/translations/he.csv b/erpnext/translations/he.csv
index d5fcab6..5407578 100644
--- a/erpnext/translations/he.csv
+++ b/erpnext/translations/he.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","במקרה של תוכנית רב-שכבתית, הלקוחות יוקצו אוטומטית לשכבה הנוגעת בדבר שהוצאו",
 Inactive,לֹא פָּעִיל,
 Incentives,תמריצים,
-Include Default Book Entries,כלול רשומות ברירת מחדל לספרים,
+Include Default FB Entries,כלול רשומות ברירת מחדל לספרים,
 Include Exploded Items,כלול פריטים מפוצצים,
 Include POS Transactions,כלול עסקאות קופה,
 Include UOM,כלול UOM,
diff --git a/erpnext/translations/hi.csv b/erpnext/translations/hi.csv
index a5caa66..00532df 100644
--- a/erpnext/translations/hi.csv
+++ b/erpnext/translations/hi.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","मल्टी-स्तरीय कार्यक्रम के मामले में, ग्राहक अपने खर्च के अनुसार संबंधित स्तर को स्वचालित रूप से सौंपा जाएगा",
 Inactive,निष्क्रिय,
 Incentives,प्रोत्साहन,
-Include Default Book Entries,डिफ़ॉल्ट बुक प्रविष्टियाँ शामिल करें,
+Include Default FB Entries,डिफ़ॉल्ट बुक प्रविष्टियाँ शामिल करें,
 Include Exploded Items,विस्फोट किए गए आइटम शामिल करें,
 Include POS Transactions,पीओएस लेनदेन शामिल करें,
 Include UOM,यूओएम शामिल करें,
diff --git a/erpnext/translations/hr.csv b/erpnext/translations/hr.csv
index 2834602..3cc9ef3 100644
--- a/erpnext/translations/hr.csv
+++ b/erpnext/translations/hr.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","U slučaju višerazinskog programa, Kupci će biti automatski dodijeljeni odgovarajućem stupcu po njihovu potrošenom",
 Inactive,neaktivan,
 Incentives,poticaji,
-Include Default Book Entries,Uključite zadane unose u knjige,
+Include Default FB Entries,Uključite zadane unose u knjige,
 Include Exploded Items,Uključi eksplodirane predmete,
 Include POS Transactions,Uključi POS transakcije,
 Include UOM,Uključi UOM,
diff --git a/erpnext/translations/hu.csv b/erpnext/translations/hu.csv
index a262c8a..42175bb 100644
--- a/erpnext/translations/hu.csv
+++ b/erpnext/translations/hu.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Többszintű program esetében az ügyfeleket automatikusan az adott kategóriába sorolják, az általuk elköltöttek szerint",
 Inactive,Inaktív,
 Incentives,Ösztönzők,
-Include Default Book Entries,Tartalmazza az alapértelmezett könyvbejegyzéseket,
+Include Default FB Entries,Tartalmazza az alapértelmezett könyvbejegyzéseket,
 Include Exploded Items,Tartalmazza a robbantott elemeket,
 Include POS Transactions,Tartalmazza a POS kassza tranzakciókat,
 Include UOM,Ide tartozik az ANYJ,
diff --git a/erpnext/translations/id.csv b/erpnext/translations/id.csv
index c4e50fd..d69eef3 100644
--- a/erpnext/translations/id.csv
+++ b/erpnext/translations/id.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Dalam kasus program multi-tier, Pelanggan akan ditugaskan secara otomatis ke tingkat yang bersangkutan sesuai yang mereka habiskan",
 Inactive,Tidak aktif,
 Incentives,Insentif,
-Include Default Book Entries,Sertakan Entri Buku Default,
+Include Default FB Entries,Sertakan Entri Buku Default,
 Include Exploded Items,Sertakan barang yang meledak,
 Include POS Transactions,Sertakan Transaksi POS,
 Include UOM,Termasuk UOM,
diff --git a/erpnext/translations/is.csv b/erpnext/translations/is.csv
index 50c06ec..1acefbb 100644
--- a/erpnext/translations/is.csv
+++ b/erpnext/translations/is.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Þegar um er að ræða fjölþættaráætlun, verða viðskiptavinir sjálfkrafa tengdir viðkomandi flokka eftir því sem þeir eru í",
 Inactive,Óvirkt,
 Incentives,Incentives,
-Include Default Book Entries,Hafa sjálfgefnar bókarfærslur með,
+Include Default FB Entries,Hafa sjálfgefnar bókarfærslur með,
 Include Exploded Items,Inniheldur sprauta hluti,
 Include POS Transactions,Innifalið POS-viðskipti,
 Include UOM,Innifalið UOM,
diff --git a/erpnext/translations/it.csv b/erpnext/translations/it.csv
index 3760895..e6e6425 100644
--- a/erpnext/translations/it.csv
+++ b/erpnext/translations/it.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Nel caso di un programma multilivello, i clienti verranno assegnati automaticamente al livello interessato come da loro speso",
 Inactive,Inattivo,
 Incentives,Incentivi,
-Include Default Book Entries,Includi voci di libro predefinite,
+Include Default FB Entries,Includi voci di libro predefinite,
 Include Exploded Items,Includi elementi esplosi,
 Include POS Transactions,Includi transazioni POS,
 Include UOM,Includi UOM,
diff --git a/erpnext/translations/ja.csv b/erpnext/translations/ja.csv
index 888ec80..dd5820a 100644
--- a/erpnext/translations/ja.csv
+++ b/erpnext/translations/ja.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",マルチティアプログラムの場合、顧客は、消費されるごとに自動的に関係する層に割り当てられます,
 Inactive,非アクティブ,
 Incentives,インセンティブ,
-Include Default Book Entries,デフォルトのブックエントリを含める,
+Include Default FB Entries,デフォルトのブックエントリを含める,
 Include Exploded Items,分解された項目を含める,
 Include POS Transactions,POSトランザクションを含める,
 Include UOM,UOMを含める,
diff --git a/erpnext/translations/km.csv b/erpnext/translations/km.csv
index d2003c0..2740d7f 100644
--- a/erpnext/translations/km.csv
+++ b/erpnext/translations/km.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",ក្នុងករណីមានកម្មវិធីពហុលំដាប់អតិថិជននឹងត្រូវបានចាត់តាំងដោយខ្លួនឯងទៅថ្នាក់ដែលពាក់ព័ន្ធដោយចំណាយរបស់ពួកគេ,
 Inactive,អសកម្ម,
 Incentives,ការលើកទឹកចិត្ត,
-Include Default Book Entries,រួមបញ្ចូលធាតុសៀវភៅលំនាំដើម។,
+Include Default FB Entries,រួមបញ្ចូលធាតុសៀវភៅលំនាំដើម។,
 Include Exploded Items,រួមបញ្ចូលធាតុផ្ទុះ,
 Include POS Transactions,បញ្ចូលប្រតិបត្តិការ POS,
 Include UOM,រួមបញ្ចូល UOM,
diff --git a/erpnext/translations/kn.csv b/erpnext/translations/kn.csv
index 7206671..8b27168 100644
--- a/erpnext/translations/kn.csv
+++ b/erpnext/translations/kn.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","ಮಲ್ಟಿ-ಟೈರ್ ಪ್ರೋಗ್ರಾಂನ ಸಂದರ್ಭದಲ್ಲಿ, ಗ್ರಾಹಕರು ತಮ್ಮ ಖರ್ಚುಗೆ ಅನುಗುಣವಾಗಿ ಆಯಾ ಶ್ರೇಣಿಗೆ ಸ್ವಯಂ ನಿಯೋಜಿಸಲಾಗುವುದು",
 Inactive,ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ,
 Incentives,ಪ್ರೋತ್ಸಾಹ,
-Include Default Book Entries,ಡೀಫಾಲ್ಟ್ ಪುಸ್ತಕ ನಮೂದುಗಳನ್ನು ಸೇರಿಸಿ,
+Include Default FB Entries,ಡೀಫಾಲ್ಟ್ ಪುಸ್ತಕ ನಮೂದುಗಳನ್ನು ಸೇರಿಸಿ,
 Include Exploded Items,ಸ್ಫೋಟಗೊಂಡ ವಸ್ತುಗಳನ್ನು ಸೇರಿಸಿ,
 Include POS Transactions,ಪಿಒಎಸ್ ಟ್ರಾನ್ಸಾಕ್ಷನ್ಸ್ ಸೇರಿಸಿ,
 Include UOM,UOM ಸೇರಿಸಿ,
diff --git a/erpnext/translations/ko.csv b/erpnext/translations/ko.csv
index 9911925..edd3f27 100644
--- a/erpnext/translations/ko.csv
+++ b/erpnext/translations/ko.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",다중 계층 프로그램의 경우 고객은 지출 한대로 해당 계층에 자동으로 할당됩니다.,
 Inactive,비활성,
 Incentives,장려책,
-Include Default Book Entries,기본 도서 항목 포함,
+Include Default FB Entries,기본 도서 항목 포함,
 Include Exploded Items,분해 된 항목 포함,
 Include POS Transactions,POS 트랜잭션 포함,
 Include UOM,UOM 포함,
diff --git a/erpnext/translations/ku.csv b/erpnext/translations/ku.csv
index 8fec059..e18ce45 100644
--- a/erpnext/translations/ku.csv
+++ b/erpnext/translations/ku.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Di rewşê de bernameya pir-tier, Ewrûpa dê ji hêla xercê xwe ve girêdayî xerîb be",
 Inactive,Bêkar,
 Incentives,aborîve,
-Include Default Book Entries,Navnîşanên Pirtûka Pêvek Bawer bikin,
+Include Default FB Entries,Navnîşanên Pirtûka Pêvek Bawer bikin,
 Include Exploded Items,Included Dead Items,
 Include POS Transactions,Têkiliyên POSê de,
 Include UOM,UOM,
diff --git a/erpnext/translations/lo.csv b/erpnext/translations/lo.csv
index 0831788..46acd22 100644
--- a/erpnext/translations/lo.csv
+++ b/erpnext/translations/lo.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","ໃນກໍລະນີຂອງໂຄງການຫຼາຍຂັ້ນ, ລູກຄ້າຈະໄດ້ຮັບການມອບຫມາຍໂດຍອັດຕະໂນມັດໃຫ້ກັບຂັ້ນຕອນທີ່ກ່ຽວຂ້ອງຕາມການໃຊ້ຈ່າຍຂອງເຂົາເຈົ້າ",
 Inactive,Inactive,
 Incentives,ສິ່ງຈູງໃຈ,
-Include Default Book Entries,ລວມທັງການອອກສຽງປື້ມແບບເລີ່ມຕົ້ນ,
+Include Default FB Entries,ລວມທັງການອອກສຽງປື້ມແບບເລີ່ມຕົ້ນ,
 Include Exploded Items,ລວມເອົາສິ່ງທີ່ເກີດຂື້ນ,
 Include POS Transactions,ລວມທຸລະກໍາ POS,
 Include UOM,ລວມ UOM,
diff --git a/erpnext/translations/lt.csv b/erpnext/translations/lt.csv
index 8215275..292c9d8 100644
--- a/erpnext/translations/lt.csv
+++ b/erpnext/translations/lt.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Kalbant apie daugiapakopę programą, klientai bus automatiškai priskirti atitinkamam lygmeniui, atsižvelgiant į jų išleidimą",
 Inactive,Neaktyvus,
 Incentives,Paskatos,
-Include Default Book Entries,Įtraukite numatytuosius knygų įrašus,
+Include Default FB Entries,Įtraukite numatytuosius knygų įrašus,
 Include Exploded Items,Įtraukti sprogus elementus,
 Include POS Transactions,Įtraukti POS operacijas,
 Include UOM,Įtraukti UOM,
diff --git a/erpnext/translations/lv.csv b/erpnext/translations/lv.csv
index 8c4526c..52641b2 100644
--- a/erpnext/translations/lv.csv
+++ b/erpnext/translations/lv.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Daudzpakāpju programmas gadījumā Klienti tiks automātiski piešķirti attiecīgajam līmenim, salīdzinot ar viņu iztērēto",
 Inactive,Neaktīvs,
 Incentives,Stimuli,
-Include Default Book Entries,Iekļaujiet noklusējuma grāmatas ierakstus,
+Include Default FB Entries,Iekļaujiet noklusējuma grāmatas ierakstus,
 Include Exploded Items,Iekļaut izpūstas preces,
 Include POS Transactions,Iekļaut POS darījumus,
 Include UOM,Iekļaut UOM,
diff --git a/erpnext/translations/mk.csv b/erpnext/translations/mk.csv
index a622524..0a29019 100644
--- a/erpnext/translations/mk.csv
+++ b/erpnext/translations/mk.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Во случај на повеќеслојна програма, корисниците ќе бидат автоматски доделени на засегнатите нивоа, како на нивните потрошени",
 Inactive,Неактивен,
 Incentives,Стимулации,
-Include Default Book Entries,Вклучете стандардни записи за книги,
+Include Default FB Entries,Вклучете стандардни записи за книги,
 Include Exploded Items,Вклучи експлодирани елементи,
 Include POS Transactions,Вклучете POS-трансакции,
 Include UOM,Вклучете UOM,
diff --git a/erpnext/translations/ml.csv b/erpnext/translations/ml.csv
index 777d5c6..04af8ab 100644
--- a/erpnext/translations/ml.csv
+++ b/erpnext/translations/ml.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","മൾട്ടി-ടയർ പരിപാടിയുടെ കാര്യത്തിൽ, കസ്റ്റമർമാർ ചെലവഴിച്ച തുക പ്രകാരം ബന്ധപ്പെട്ട ടീമിൽ ഓട്ടോ നിർണ്ണയിക്കും",
 Inactive,നിഷ്ക്രിയം,
 Incentives,ഇൻസെന്റീവ്സ്,
-Include Default Book Entries,സ്ഥിരസ്ഥിതി പുസ്തക എൻ‌ട്രികൾ‌ ഉൾ‌പ്പെടുത്തുക,
+Include Default FB Entries,സ്ഥിരസ്ഥിതി പുസ്തക എൻ‌ട്രികൾ‌ ഉൾ‌പ്പെടുത്തുക,
 Include Exploded Items,എക്സ്പ്ലോഡഡ് ഇനങ്ങൾ ഉൾപ്പെടുത്തുക,
 Include POS Transactions,POS ഇടപാടുകൾ ഉൾപ്പെടുത്തുക,
 Include UOM,UOM ഉൾപ്പെടുത്തുക,
diff --git a/erpnext/translations/mr.csv b/erpnext/translations/mr.csv
index 624f1ab..785ab65 100644
--- a/erpnext/translations/mr.csv
+++ b/erpnext/translations/mr.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",बहु-स्तरीय कार्यक्रमाच्या बाबतीत ग्राहक त्यांच्या खर्चानुसार संबंधित टायरला स्वयंचलितरित्या नियुक्त केले जातील,
 Inactive,निष्क्रिय,
 Incentives,प्रोत्साहन,
-Include Default Book Entries,डीफॉल्ट पुस्तक नोंदी समाविष्ट करा,
+Include Default FB Entries,डीफॉल्ट पुस्तक नोंदी समाविष्ट करा,
 Include Exploded Items,विस्फोट केलेल्या वस्तू समाविष्ट करा,
 Include POS Transactions,पीओएस व्यवहार समाविष्ट करा,
 Include UOM,यूओएम समाविष्ट करा,
diff --git a/erpnext/translations/ms.csv b/erpnext/translations/ms.csv
index 75e150a..db20d3c 100644
--- a/erpnext/translations/ms.csv
+++ b/erpnext/translations/ms.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Dalam hal program multi-tier, Pelanggan akan ditugaskan secara automatik ke peringkat yang bersangkutan seperti yang dibelanjakannya",
 Inactive,Tidak aktif,
 Incentives,Insentif,
-Include Default Book Entries,Sertakan Penyertaan Buku Lalai,
+Include Default FB Entries,Sertakan Penyertaan Buku Lalai,
 Include Exploded Items,Termasuk Item Meletup,
 Include POS Transactions,Termasuk Transaksi POS,
 Include UOM,Termasuk UOM,
diff --git a/erpnext/translations/my.csv b/erpnext/translations/my.csv
index 36cd874..f4b8676 100644
--- a/erpnext/translations/my.csv
+++ b/erpnext/translations/my.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Multi-tier အစီအစဉ်၏အမှု၌, Customer များအလိုအလျောက်သူတို့ရဲ့သုံးစွဲနှုန်းအတိုင်းစိုးရိမ်ပူပန်ဆင့်မှတာဝန်ပေးအပ်ပါလိမ့်မည်",
 Inactive,မလှုပ်ရှားတတ်သော,
 Incentives,မက်လုံးတွေပေးပြီး,
-Include Default Book Entries,ပုံမှန်စာအုပ် Entries Include,
+Include Default FB Entries,ပုံမှန်စာအုပ် Entries Include,
 Include Exploded Items,ပေါက်ကွဲပစ္စည်းများ Include,
 Include POS Transactions,POS အရောင်းအဝယ် Include,
 Include UOM,UOM Include,
diff --git a/erpnext/translations/nl.csv b/erpnext/translations/nl.csv
index 5859833..1778c80 100644
--- a/erpnext/translations/nl.csv
+++ b/erpnext/translations/nl.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",In het geval van een meerlagig programma worden klanten automatisch toegewezen aan de betreffende laag op basis van hun bestede tijd,
 Inactive,Inactief,
 Incentives,Incentives,
-Include Default Book Entries,Standaard boekvermeldingen opnemen,
+Include Default FB Entries,Standaard boekvermeldingen opnemen,
 Include Exploded Items,Exploded Items opnemen,
 Include POS Transactions,POS-transacties opnemen,
 Include UOM,Inclusief UOM,
diff --git a/erpnext/translations/no.csv b/erpnext/translations/no.csv
index a3236ac..542217a 100644
--- a/erpnext/translations/no.csv
+++ b/erpnext/translations/no.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Når det gjelder flerlagsprogram, vil kundene automatisk bli tilordnet den aktuelle delen som brukt",
 Inactive,inaktiv,
 Incentives,Motivasjon,
-Include Default Book Entries,Inkluder standardbokoppføringer,
+Include Default FB Entries,Inkluder standardbokoppføringer,
 Include Exploded Items,Inkluder eksploderte elementer,
 Include POS Transactions,Inkluder POS-transaksjoner,
 Include UOM,Inkluder UOM,
diff --git a/erpnext/translations/pl.csv b/erpnext/translations/pl.csv
index df41e39..247d0ba 100644
--- a/erpnext/translations/pl.csv
+++ b/erpnext/translations/pl.csv
@@ -1151,7 +1151,7 @@
 In Value,w polu Wartość,
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","W przypadku programu wielowarstwowego Klienci zostaną automatycznie przypisani do danego poziomu, zgodnie z wydatkami",
 Inactive,Nieaktywny,
-Include Default Book Entries,Dołącz domyślne wpisy książki,
+Include Default FB Entries,Dołącz domyślne wpisy książki,
 Include Exploded Items,Dołącz rozstrzelone przedmioty,
 Include POS Transactions,Uwzględnij transakcje POS,
 Include UOM,Dołącz UOM,
diff --git a/erpnext/translations/ps.csv b/erpnext/translations/ps.csv
index 5a0b2a5..09d4df3 100644
--- a/erpnext/translations/ps.csv
+++ b/erpnext/translations/ps.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",د څو اړخیز پروګرام په صورت کې، پیرودونکي به د خپل مصرف په اساس اړوند ټیټ ته ګمارل کیږي,
 Inactive,غیر فعال,
 Incentives,هڅوونکي,
-Include Default Book Entries,د ډیفالټ کتاب ننوتل شامل کړئ,
+Include Default FB Entries,د ډیفالټ کتاب ننوتل شامل کړئ,
 Include Exploded Items,چاودیدونکي توکي شامل کړئ,
 Include POS Transactions,د POS تعاملات شامل کړئ,
 Include UOM,UOM شامل کړئ,
diff --git a/erpnext/translations/pt-BR.csv b/erpnext/translations/pt-BR.csv
index bc5b616..92845b0 100644
--- a/erpnext/translations/pt-BR.csv
+++ b/erpnext/translations/pt-BR.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","No caso do programa multicamadas, os Clientes serão atribuídos automaticamente ao nível em questão de acordo com o gasto",
 Inactive,Inativo,
 Incentives,Incentivos,
-Include Default Book Entries,Incluir Entradas de Livro Padrão,
+Include Default FB Entries,Incluir Entradas de Livro Padrão,
 Include Exploded Items,Incluir Itens Explodidos,
 Include POS Transactions,Incluir Transações PDV,
 Include UOM,Incluir UDM,
diff --git a/erpnext/translations/pt.csv b/erpnext/translations/pt.csv
index e6846c6..58cf6c8 100644
--- a/erpnext/translations/pt.csv
+++ b/erpnext/translations/pt.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","No caso do programa multicamadas, os Clientes serão atribuídos automaticamente ao nível em questão de acordo com o gasto",
 Inactive,Inativo,
 Incentives,Incentivos,
-Include Default Book Entries,Incluir entradas de livro padrão,
+Include Default FB Entries,Incluir entradas de livro padrão,
 Include Exploded Items,Incluir itens explodidos,
 Include POS Transactions,Incluir transações POS,
 Include UOM,Incluir UOM,
diff --git a/erpnext/translations/ro.csv b/erpnext/translations/ro.csv
index ac7e598..935b1e6 100644
--- a/erpnext/translations/ro.csv
+++ b/erpnext/translations/ro.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","În cazul unui program cu mai multe niveluri, Clienții vor fi automat alocați nivelului respectiv în funcție de cheltuielile efectuate",
 Inactive,Inactiv,
 Incentives,stimulente,
-Include Default Book Entries,Includeți intrări implicite în cărți,
+Include Default FB Entries,Includeți intrări implicite în cărți,
 Include Exploded Items,Includeți articole explodate,
 Include POS Transactions,Includeți tranzacțiile POS,
 Include UOM,Includeți UOM,
diff --git a/erpnext/translations/ru.csv b/erpnext/translations/ru.csv
index 52c2998..2f6f361 100644
--- a/erpnext/translations/ru.csv
+++ b/erpnext/translations/ru.csv
@@ -1151,7 +1151,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",В случае многоуровневой программы Клиенты будут автоматически назначены соответствующему уровню в соответствии с затраченными,
 Inactive,Неактивный,
 Incentives,Стимулирование,
-Include Default Book Entries,Включить записи в книгу по умолчанию,
+Include Default FB Entries,Включить записи в книгу по умолчанию,
 Include Exploded Items,Включить раздробленные элементы,
 Include POS Transactions,Включить POS-транзакции,
 Include UOM,Включить UOM,
diff --git a/erpnext/translations/rw.csv b/erpnext/translations/rw.csv
index f035d57..59362a1 100644
--- a/erpnext/translations/rw.csv
+++ b/erpnext/translations/rw.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Kubijyanye na gahunda yo mu byiciro byinshi, Abakiriya bazahabwa imodoka bashinzwe urwego bireba nkuko bakoresheje",
 Inactive,Kudakora,
 Incentives,Inkunga,
-Include Default Book Entries,Shyiramo Ibisanzwe Byanditswe,
+Include Default FB Entries,Shyiramo Ibisanzwe Byanditswe,
 Include Exploded Items,Shyiramo Ibintu Biturika,
 Include POS Transactions,Shyiramo ibikorwa bya POS,
 Include UOM,Shyiramo UOM,
diff --git a/erpnext/translations/si.csv b/erpnext/translations/si.csv
index 4047263..dd2acc4 100644
--- a/erpnext/translations/si.csv
+++ b/erpnext/translations/si.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","බහු ස්ථරයේ වැඩසටහනක දී, පාරිභෝගිකයින් විසින් වැය කරනු ලබන පරිදි පාරිභෝගිකයින්ට අදාල ස්ථානයට ස්වයංක්රීයව පවරනු ලැබේ",
 Inactive,අක්රියයි,
 Incentives,සහන,
-Include Default Book Entries,පෙරනිමි පොත් ඇතුළත් කිරීම් ඇතුළත් කරන්න,
+Include Default FB Entries,පෙරනිමි පොත් ඇතුළත් කිරීම් ඇතුළත් කරන්න,
 Include Exploded Items,පුපුරණ ද්රව්ය අඩංගු කරන්න,
 Include POS Transactions,POS ගනුදෙනු,
 Include UOM,UOM ඇතුළත් කරන්න,
diff --git a/erpnext/translations/sk.csv b/erpnext/translations/sk.csv
index 98e1663..025c8b7 100644
--- a/erpnext/translations/sk.csv
+++ b/erpnext/translations/sk.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",V prípade viacvrstvového programu budú zákazníci automaticky priradení príslušnému vrstvu podľa ich vynaložených prostriedkov,
 Inactive,neaktívne,
 Incentives,Pobídky,
-Include Default Book Entries,Zahrnúť predvolené položky knihy,
+Include Default FB Entries,Zahrnúť predvolené položky knihy,
 Include Exploded Items,Zahrňte explodované položky,
 Include POS Transactions,Zahrňte POS transakcie,
 Include UOM,Zahrňte UOM,
diff --git a/erpnext/translations/sl.csv b/erpnext/translations/sl.csv
index 5380714..86b5e58 100644
--- a/erpnext/translations/sl.csv
+++ b/erpnext/translations/sl.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",V primeru večstopenjskega programa bodo stranke samodejno dodeljene zadevni stopnji glede na porabljene,
 Inactive,Neaktivno,
 Incentives,Spodbude,
-Include Default Book Entries,Vključi privzete vnose v knjige,
+Include Default FB Entries,Vključi privzete vnose v knjige,
 Include Exploded Items,Vključi eksplodirane elemente,
 Include POS Transactions,Vključite POS transakcije,
 Include UOM,Vključi UOM,
diff --git a/erpnext/translations/sq.csv b/erpnext/translations/sq.csv
index 2a893d2..3cfa429 100644
--- a/erpnext/translations/sq.csv
+++ b/erpnext/translations/sq.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Në rastin e programit multi-shtresor, Konsumatorët do të caktohen automatikisht në nivelin përkatës sipas shpenzimeve të tyre",
 Inactive,joaktiv,
 Incentives,Nxitjet,
-Include Default Book Entries,Përfshini hyrje të librave të paracaktuar,
+Include Default FB Entries,Përfshini hyrje të librave të paracaktuar,
 Include Exploded Items,Përfshirja e artikujve të eksploduar,
 Include POS Transactions,Përfshi transaksione POS,
 Include UOM,Përfshi UOM,
diff --git a/erpnext/translations/sr.csv b/erpnext/translations/sr.csv
index c1e5eb0..621772f 100644
--- a/erpnext/translations/sr.csv
+++ b/erpnext/translations/sr.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","У случају мулти-тиер програма, Корисници ће аутоматски бити додијељени за одређени ниво према њиховом потрошеном",
 Inactive,Неактиван,
 Incentives,Подстицаји,
-Include Default Book Entries,Укључивање заданих уноса у књиге,
+Include Default FB Entries,Укључивање заданих уноса у књиге,
 Include Exploded Items,Укључите експлодиране ставке,
 Include POS Transactions,Укључите ПОС трансакције,
 Include UOM,Укључите УОМ,
diff --git a/erpnext/translations/sv.csv b/erpnext/translations/sv.csv
index 8b4ab06..4fef88b 100644
--- a/erpnext/translations/sv.csv
+++ b/erpnext/translations/sv.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",När det gäller program med flera nivåer kommer kunderna automatiskt att tilldelas den aktuella tiern enligt deras tillbringade,
 Inactive,Inaktiv,
 Incentives,Sporen,
-Include Default Book Entries,Inkludera standardbokposter,
+Include Default FB Entries,Inkludera standardbokposter,
 Include Exploded Items,Inkludera explosiva artiklar,
 Include POS Transactions,Inkludera POS-transaktioner,
 Include UOM,Inkludera UOM,
diff --git a/erpnext/translations/sw.csv b/erpnext/translations/sw.csv
index fa2287c..3b4d8ae 100644
--- a/erpnext/translations/sw.csv
+++ b/erpnext/translations/sw.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Katika kesi ya mpango wa mipango mbalimbali, Wateja watapatiwa auto kwa tier husika kama kwa matumizi yao",
 Inactive,Haikufanya kazi,
 Incentives,Vidokezo,
-Include Default Book Entries,Jumuisha Ingizo Mbadala za Kitabu,
+Include Default FB Entries,Jumuisha Ingizo Mbadala za Kitabu,
 Include Exploded Items,Jumuisha Vipengee Vipengee,
 Include POS Transactions,Jumuisha Shughuli za POS,
 Include UOM,Jumuisha UOM,
diff --git a/erpnext/translations/ta.csv b/erpnext/translations/ta.csv
index 6eaae34..f40e512 100644
--- a/erpnext/translations/ta.csv
+++ b/erpnext/translations/ta.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","பல அடுக்கு திட்டத்தின் விஷயத்தில், வாடிக்கையாளர்கள் தங்கள் செலவினங்களின்படி சம்பந்தப்பட்ட அடுக்குக்கு கார் ஒதுக்கப்படுவார்கள்",
 Inactive,செயல்படா,
 Incentives,செயல் தூண்டுதல்,
-Include Default Book Entries,இயல்புநிலை புத்தக உள்ளீடுகளைச் சேர்க்கவும்,
+Include Default FB Entries,இயல்புநிலை புத்தக உள்ளீடுகளைச் சேர்க்கவும்,
 Include Exploded Items,வெடித்துள்ள பொருட்கள் அடங்கும்,
 Include POS Transactions,POS பரிமாற்றங்களைச் சேர்க்கவும்,
 Include UOM,UOM ஐ சேர்க்கவும்,
diff --git a/erpnext/translations/te.csv b/erpnext/translations/te.csv
index d3f739a..22fd7d7 100644
--- a/erpnext/translations/te.csv
+++ b/erpnext/translations/te.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","మల్టీ-టైర్ ప్రోగ్రామ్ విషయంలో, కస్టమర్లు వారి గడువు ప్రకారం, సంబంధిత స్థాయికి కేటాయించబడతారు",
 Inactive,క్రియారహిత,
 Incentives,ఇన్సెంటివ్స్,
-Include Default Book Entries,డిఫాల్ట్ బుక్ ఎంట్రీలను చేర్చండి,
+Include Default FB Entries,డిఫాల్ట్ బుక్ ఎంట్రీలను చేర్చండి,
 Include Exploded Items,ఎక్స్ప్లోడ్ ఐటెమ్లను చేర్చండి,
 Include POS Transactions,POS లావాదేవీలను చేర్చండి,
 Include UOM,UOM ని చేర్చండి,
diff --git a/erpnext/translations/th.csv b/erpnext/translations/th.csv
index a065595..5dfb93c 100644
--- a/erpnext/translations/th.csv
+++ b/erpnext/translations/th.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",ในกรณีของโปรแกรมแบบหลายชั้นลูกค้าจะได้รับการกำหนดให้โดยอัตโนมัติตามระดับที่เกี่ยวข้องตามการใช้จ่าย,
 Inactive,เฉื่อยชา,
 Incentives,แรงจูงใจ,
-Include Default Book Entries,รวมรายการหนังสือเริ่มต้น,
+Include Default FB Entries,รวมรายการหนังสือเริ่มต้น,
 Include Exploded Items,รวมรายการที่ระเบิดแล้ว,
 Include POS Transactions,รวมธุรกรรม POS,
 Include UOM,รวม UOM,
diff --git a/erpnext/translations/tr.csv b/erpnext/translations/tr.csv
index 9e916f0..82d2824 100644
--- a/erpnext/translations/tr.csv
+++ b/erpnext/translations/tr.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Çok katmanlı program söz konusu olduğunda, Müşteriler harcanan esasa göre ilgili kademeye otomatik olarak atanacaktır.",
 Inactive,etkisiz,
 Incentives,Teşvikler,
-Include Default Book Entries,Varsayılan Defter Girişlerini Dahil et,
+Include Default FB Entries,Varsayılan Defter Girişlerini Dahil et,
 Include Exploded Items,Patlatılmış Öğeleri Dahil et,
 Include POS Transactions,POS İşlemlerini Dahil et,
 Include UOM,Birimi Dahil et,
diff --git a/erpnext/translations/uk.csv b/erpnext/translations/uk.csv
index 8d1fb04..f77c6da 100644
--- a/erpnext/translations/uk.csv
+++ b/erpnext/translations/uk.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","У випадку багаторівневої програми, Клієнти будуть автоматично призначені для відповідного рівня відповідно до витрачених ними витрат",
 Inactive,Неактивний,
 Incentives,Стимули,
-Include Default Book Entries,Включити записи за замовчуванням,
+Include Default FB Entries,Включити записи за замовчуванням,
 Include Exploded Items,Включити вибухнуті елементи,
 Include POS Transactions,Включити POS-транзакції,
 Include UOM,Включити UOM,
diff --git a/erpnext/translations/ur.csv b/erpnext/translations/ur.csv
index 649c1c7..4dc872b 100644
--- a/erpnext/translations/ur.csv
+++ b/erpnext/translations/ur.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",کثیر درجے کے پروگرام کے معاملے میں، صارفین اپنے اخراجات کے مطابق متعلقہ درجے کو خود کار طریقے سے تفویض کریں گے,
 Inactive,غیر فعال,
 Incentives,ترغیبات,
-Include Default Book Entries,ڈیفالٹ کتاب اندراجات شامل کریں۔,
+Include Default FB Entries,ڈیفالٹ کتاب اندراجات شامل کریں۔,
 Include Exploded Items,دھماکہ خیز اشیاء شامل کریں,
 Include POS Transactions,پی او ایس کے لین دین میں شامل کریں,
 Include UOM,UOM شامل کریں,
diff --git a/erpnext/translations/uz.csv b/erpnext/translations/uz.csv
index 5ca51cc..c09aa89 100644
--- a/erpnext/translations/uz.csv
+++ b/erpnext/translations/uz.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",Ko&#39;p qatlamli dasturda mijozlar o&#39;zlari sarflagan xarajatlariga muvofiq tegishli darajaga avtomatik tarzda topshiriladi,
 Inactive,Faol emas,
 Incentives,Rag&#39;batlantirish,
-Include Default Book Entries,Odatiy kitob yozuvlarini qo&#39;shing,
+Include Default FB Entries,Odatiy kitob yozuvlarini qo&#39;shing,
 Include Exploded Items,Portlatilgan narsalarni qo&#39;shish,
 Include POS Transactions,Qalin operatsiyalarni qo&#39;shish,
 Include UOM,UOM ni qo&#39;shing,
diff --git a/erpnext/translations/vi.csv b/erpnext/translations/vi.csv
index 7a005fa..eb251a5 100644
--- a/erpnext/translations/vi.csv
+++ b/erpnext/translations/vi.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent","Trong trường hợp chương trình nhiều tầng, Khách hàng sẽ được tự động chỉ định cho cấp có liên quan theo mức chi tiêu của họ",
 Inactive,Không hoạt động,
 Incentives,Ưu đãi,
-Include Default Book Entries,Bao gồm các mục sách mặc định,
+Include Default FB Entries,Bao gồm các mục sách mặc định,
 Include Exploded Items,Bao gồm các mục đã Phát hiện,
 Include POS Transactions,Bao gồm giao dịch POS,
 Include UOM,Bao gồm UOM,
diff --git a/erpnext/translations/zh.csv b/erpnext/translations/zh.csv
index cf89dc6..08f8d33 100644
--- a/erpnext/translations/zh.csv
+++ b/erpnext/translations/zh.csv
@@ -1153,7 +1153,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",在多层程序的情况下,客户将根据其花费自动分配到相关层,
 Inactive,非活动的,
 Incentives,激励政策,
-Include Default Book Entries,包括默认工作簿条目,
+Include Default FB Entries,包括默认工作簿条目,
 Include Exploded Items,包含爆炸物料,
 Include POS Transactions,包括POS交易,
 Include UOM,包括基本计量单位,
diff --git a/erpnext/translations/zh_tw.csv b/erpnext/translations/zh_tw.csv
index 8ecbaaa..dd683c5 100644
--- a/erpnext/translations/zh_tw.csv
+++ b/erpnext/translations/zh_tw.csv
@@ -1166,7 +1166,7 @@
 "In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent",在多層程序的情況下,客戶將根據其花費自動分配到相關層,
 Inactive,待用,
 Incentives,獎勵,
-Include Default Book Entries,包括默認工作簿條目,
+Include Default FB Entries,包括默認工作簿條目,
 Include Exploded Items,包含爆炸物品,
 Include UOM,包括UOM,
 Included in Gross Profit,包含在毛利潤中,
diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py
index 5e57b31..df21b61 100644
--- a/erpnext/utilities/bulk_transaction.py
+++ b/erpnext/utilities/bulk_transaction.py
@@ -3,6 +3,7 @@
 
 import frappe
 from frappe import _
+from frappe.utils import get_link_to_form, today
 
 
 @frappe.whitelist()
@@ -28,6 +29,51 @@
 		job(deserialized_data, from_doctype, to_doctype)
 
 
+@frappe.whitelist()
+def retry(date: str | None = None):
+	if not date:
+		date = today()
+
+	if date:
+		failed_docs = frappe.db.get_all(
+			"Bulk Transaction Log Detail",
+			filters={"date": date, "transaction_status": "Failed", "retried": 0},
+			fields=["name", "transaction_name", "from_doctype", "to_doctype"],
+		)
+		if not failed_docs:
+			frappe.msgprint(_("There are no Failed transactions"))
+		else:
+			job = frappe.enqueue(
+				retry_failed_transactions,
+				failed_docs=failed_docs,
+			)
+			frappe.msgprint(
+				_("Job: {0} has been triggered for processing failed transactions").format(
+					get_link_to_form("RQ Job", job.id)
+				)
+			)
+
+
+def retry_failed_transactions(failed_docs: list | None):
+	if failed_docs:
+		for log in failed_docs:
+			try:
+				frappe.db.savepoint("before_creation_state")
+				task(log.transaction_name, log.from_doctype, log.to_doctype)
+			except Exception as e:
+				frappe.db.rollback(save_point="before_creation_state")
+				update_log(log.name, "Failed", 1, str(frappe.get_traceback()))
+			else:
+				update_log(log.name, "Success", 1)
+
+
+def update_log(log_name, status, retried, err=None):
+	frappe.db.set_value("Bulk Transaction Log Detail", log_name, "transaction_status", status)
+	frappe.db.set_value("Bulk Transaction Log Detail", log_name, "retried", retried)
+	if err:
+		frappe.db.set_value("Bulk Transaction Log Detail", log_name, "error_description", err)
+
+
 def job(deserialized_data, from_doctype, to_doctype):
 	fail_count = 0
 	for d in deserialized_data:
@@ -38,7 +84,7 @@
 		except Exception as e:
 			frappe.db.rollback(save_point="before_creation_state")
 			fail_count += 1
-			update_logger(
+			create_log(
 				doc_name,
 				str(frappe.get_traceback()),
 				from_doctype,
@@ -47,7 +93,7 @@
 				log_date=str(date.today()),
 			)
 		else:
-			update_logger(
+			create_log(
 				doc_name, None, from_doctype, to_doctype, status="Success", log_date=str(date.today())
 			)
 
@@ -98,6 +144,7 @@
 		},
 		"Purchase Receipt": {"Purchase Invoice": purchase_receipt.make_purchase_invoice},
 	}
+	frappe.flags.bulk_transaction = True
 	if to_doctype in ["Payment Entry"]:
 		obj = mapper[from_doctype][to_doctype](from_doctype, doc_name)
 	else:
@@ -106,47 +153,21 @@
 	obj.flags.ignore_validate = True
 	obj.set_title_field()
 	obj.insert(ignore_mandatory=True)
+	del frappe.flags.bulk_transaction
 
 
-def check_logger_doc_exists(log_date):
-	return frappe.db.exists("Bulk Transaction Log", log_date)
-
-
-def get_logger_doc(log_date):
-	return frappe.get_doc("Bulk Transaction Log", log_date)
-
-
-def create_logger_doc():
-	log_doc = frappe.new_doc("Bulk Transaction Log")
-	log_doc.set_new_name(set_name=str(date.today()))
-	log_doc.log_date = date.today()
-
-	return log_doc
-
-
-def append_data_to_logger(log_doc, doc_name, error, from_doctype, to_doctype, status, restarted):
-	row = log_doc.append("logger_data", {})
-	row.transaction_name = doc_name
-	row.date = date.today()
+def create_log(doc_name, e, from_doctype, to_doctype, status, log_date=None, restarted=0):
+	transaction_log = frappe.new_doc("Bulk Transaction Log Detail")
+	transaction_log.transaction_name = doc_name
+	transaction_log.date = today()
 	now = datetime.now()
-	row.time = now.strftime("%H:%M:%S")
-	row.transaction_status = status
-	row.error_description = str(error)
-	row.from_doctype = from_doctype
-	row.to_doctype = to_doctype
-	row.retried = restarted
-
-
-def update_logger(doc_name, e, from_doctype, to_doctype, status, log_date=None, restarted=0):
-	if not check_logger_doc_exists(log_date):
-		log_doc = create_logger_doc()
-		append_data_to_logger(log_doc, doc_name, e, from_doctype, to_doctype, status, restarted)
-		log_doc.insert()
-	else:
-		log_doc = get_logger_doc(log_date)
-		if record_exists(log_doc, doc_name, status):
-			append_data_to_logger(log_doc, doc_name, e, from_doctype, to_doctype, status, restarted)
-			log_doc.save()
+	transaction_log.time = now.strftime("%H:%M:%S")
+	transaction_log.transaction_status = status
+	transaction_log.error_description = str(e)
+	transaction_log.from_doctype = from_doctype
+	transaction_log.to_doctype = to_doctype
+	transaction_log.retried = restarted
+	transaction_log.save()
 
 
 def show_job_status(fail_count, deserialized_data_count, to_doctype):
@@ -176,25 +197,3 @@
 			title="Failed",
 			indicator="red",
 		)
-
-
-def record_exists(log_doc, doc_name, status):
-	record = mark_retrired_transaction(log_doc, doc_name)
-	if record and status == "Failed":
-		return False
-	elif record and status == "Success":
-		return True
-	else:
-		return True
-
-
-def mark_retrired_transaction(log_doc, doc_name):
-	record = 0
-	for d in log_doc.get("logger_data"):
-		if d.transaction_name == doc_name and d.transaction_status == "Failed":
-			d.retried = 1
-			record = record + 1
-
-	log_doc.save()
-
-	return record
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 7eba35d..b083614 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -98,6 +98,7 @@
 				"Selling Settings", "None", ["maintain_same_rate_action", "role_to_override_stop_action"]
 			)
 
+		stop_actions = []
 		for ref_dt, ref_dn_field, ref_link_field in ref_details:
 			reference_names = [d.get(ref_link_field) for d in self.get("items") if d.get(ref_link_field)]
 			reference_details = self.get_reference_details(reference_names, ref_dt + " Item")
@@ -108,7 +109,7 @@
 					if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= 0.01:
 						if action == "Stop":
 							if role_allowed_to_override not in frappe.get_roles():
-								frappe.throw(
+								stop_actions.append(
 									_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
 										d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate
 									)
@@ -121,6 +122,8 @@
 								title=_("Warning"),
 								indicator="orange",
 							)
+		if stop_actions:
+			frappe.throw(stop_actions, as_list=True)
 
 	def get_reference_details(self, reference_names, reference_doctype):
 		return frappe._dict(