Merge pull request #37294 from ruthra-kumar/restrict_payment_as_ref_in_je_from_ui

refactor: block Payment Entry as ref in Journals from UI
diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py
index c7404d1..2a18830 100644
--- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py
@@ -35,13 +35,13 @@
 		from lending.loan_management.doctype.loan.test_loan import (
 			create_loan,
 			create_loan_accounts,
-			create_loan_type,
+			create_loan_product,
 			create_repayment_entry,
 			make_loan_disbursement_entry,
 		)
 
 		def create_loan_masters():
-			create_loan_type(
+			create_loan_product(
 				"Clearance Loan",
 				2000000,
 				13.5,
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index 0c328ff..2a504f6 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -410,7 +410,7 @@
 def create_loan_and_repayment():
 	from lending.loan_management.doctype.loan.test_loan import (
 		create_loan,
-		create_loan_type,
+		create_loan_product,
 		create_repayment_entry,
 		make_loan_disbursement_entry,
 	)
@@ -420,7 +420,7 @@
 
 	from erpnext.setup.doctype.employee.test_employee import make_employee
 
-	create_loan_type(
+	create_loan_product(
 		"Personal Loan",
 		500000,
 		8.4,
@@ -441,7 +441,7 @@
 			"applicant_type": "Employee",
 			"company": "_Test Company",
 			"applicant": applicant,
-			"loan_type": "Personal Loan",
+			"loan_product": "Personal Loan",
 			"loan_amount": 5000,
 			"repayment_method": "Repay Fixed Amount per Period",
 			"monthly_repayment_amount": 500,
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json
index 5ffd718..66b5c4b 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.json
+++ b/erpnext/accounts/doctype/payment_request/payment_request.json
@@ -268,8 +268,7 @@
    "fieldname": "email_to",
    "fieldtype": "Data",
    "in_global_search": 1,
-   "label": "To",
-   "options": "Email"
+   "label": "To"
   },
   {
    "depends_on": "eval: doc.payment_channel != \"Phone\"",
@@ -340,8 +339,8 @@
   },
   {
    "fieldname": "payment_url",
-   "hidden": 1,
    "fieldtype": "Data",
+   "hidden": 1,
    "length": 500,
    "options": "URL",
    "read_only": 1
@@ -396,7 +395,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-09-16 14:15:02.510890",
+ "modified": "2023-09-27 09:51:42.277638",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Request",
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json
index 54a76b3..624b5f8 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json
@@ -8,6 +8,7 @@
   "transaction_date",
   "posting_date",
   "fiscal_year",
+  "year_start_date",
   "amended_from",
   "company",
   "column_break1",
@@ -100,16 +101,22 @@
    "fieldtype": "Text",
    "label": "Error Message",
    "read_only": 1
+  },
+  {
+   "fieldname": "year_start_date",
+   "fieldtype": "Date",
+   "label": "Year Start Date"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-07-20 14:51:04.714154",
+ "modified": "2023-09-11 20:19:11.810533",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Period Closing Voucher",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -144,5 +151,6 @@
  "search_fields": "posting_date, fiscal_year",
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "title_field": "closing_account_head"
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index d984d86..674db6c 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -95,15 +95,23 @@
 
 		self.check_if_previous_year_closed()
 
-		pce = frappe.db.sql(
-			"""select name from `tabPeriod Closing Voucher`
-			where posting_date > %s and fiscal_year = %s and docstatus = 1 and company = %s""",
-			(self.posting_date, self.fiscal_year, self.company),
+		pcv = frappe.qb.DocType("Period Closing Voucher")
+		existing_entry = (
+			frappe.qb.from_(pcv)
+			.select(pcv.name)
+			.where(
+				(pcv.posting_date >= self.posting_date)
+				& (pcv.fiscal_year == self.fiscal_year)
+				& (pcv.docstatus == 1)
+				& (pcv.company == self.company)
+			)
+			.run()
 		)
-		if pce and pce[0][0]:
+
+		if existing_entry and existing_entry[0][0]:
 			frappe.throw(
 				_("Another Period Closing Entry {0} has been made after {1}").format(
-					pce[0][0], self.posting_date
+					existing_entry[0][0], self.posting_date
 				)
 			)
 
@@ -130,18 +138,27 @@
 			frappe.enqueue(
 				process_gl_entries,
 				gl_entries=gl_entries,
+				voucher_name=self.name,
+				timeout=3000,
+			)
+
+			frappe.enqueue(
+				process_closing_entries,
+				gl_entries=gl_entries,
 				closing_entries=closing_entries,
 				voucher_name=self.name,
 				company=self.company,
 				closing_date=self.posting_date,
-				queue="long",
+				timeout=3000,
 			)
+
 			frappe.msgprint(
 				_("The GL Entries will be processed in the background, it can take a few minutes."),
 				alert=True,
 			)
 		else:
-			process_gl_entries(gl_entries, closing_entries, self.name, self.company, self.posting_date)
+			process_gl_entries(gl_entries, self.name)
+			process_closing_entries(gl_entries, closing_entries, self.name, self.company, self.posting_date)
 
 	def get_grouped_gl_entries(self, get_opening_entries=False):
 		closing_entries = []
@@ -322,17 +339,12 @@
 		return query.run(as_dict=1)
 
 
-def process_gl_entries(gl_entries, closing_entries, voucher_name, company, closing_date):
-	from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
-		make_closing_entries,
-	)
+def process_gl_entries(gl_entries, voucher_name):
 	from erpnext.accounts.general_ledger import make_gl_entries
 
 	try:
 		if gl_entries:
 			make_gl_entries(gl_entries, merge_entries=False)
-
-		make_closing_entries(gl_entries + closing_entries, voucher_name, company, closing_date)
 		frappe.db.set_value("Period Closing Voucher", voucher_name, "gle_processing_status", "Completed")
 	except Exception as e:
 		frappe.db.rollback()
@@ -340,6 +352,19 @@
 		frappe.db.set_value("Period Closing Voucher", voucher_name, "gle_processing_status", "Failed")
 
 
+def process_closing_entries(gl_entries, closing_entries, voucher_name, company, closing_date):
+	from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
+		make_closing_entries,
+	)
+
+	try:
+		if gl_entries + closing_entries:
+			make_closing_entries(gl_entries + closing_entries, voucher_name, company, closing_date)
+	except Exception as e:
+		frappe.db.rollback()
+		frappe.log_error(e)
+
+
 def make_reverse_gl_entries(voucher_type, voucher_no):
 	from erpnext.accounts.general_ledger import make_reverse_gl_entries
 
diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
index 5d08e8d..1bd565e 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
@@ -10,7 +10,7 @@
 from erpnext.accounts.doctype.finance_book.test_finance_book import create_finance_book
 from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-from erpnext.accounts.utils import get_fiscal_year, now
+from erpnext.accounts.utils import get_fiscal_year
 
 
 class TestPeriodClosingVoucher(unittest.TestCase):
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 9a5ad35..52ae951 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -145,7 +145,8 @@
 def get_ar_filters(doc, entry):
 	return {
 		"report_date": doc.posting_date if doc.posting_date else None,
-		"customer": entry.customer,
+		"party_type": "Customer",
+		"party": [entry.customer],
 		"customer_name": entry.customer_name if entry.customer_name else None,
 		"payment_terms_template": doc.payment_terms_template if doc.payment_terms_template else None,
 		"sales_partner": doc.sales_partner if doc.sales_partner else None,
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 095617d..2eaa337 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -479,6 +479,12 @@
 	}
 });
 
+cur_frm.set_query("wip_composite_asset", "items", function() {
+	return {
+		filters: {'is_composite_asset': 1, 'docstatus': 0 }
+	}
+});
+
 cur_frm.cscript.expense_account = function(doc, cdt, cdn){
 	var d = locals[cdt][cdn];
 	if(d.idx == 1 && d.expense_account){
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index f3c0181..e489882 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1385,6 +1385,7 @@
    "depends_on": "eval:doc.is_subcontracted",
    "fieldname": "supplier_warehouse",
    "fieldtype": "Link",
+   "ignore_user_permissions": 1,
    "label": "Supplier Warehouse",
    "no_copy": 1,
    "options": "Warehouse",
@@ -1593,7 +1594,7 @@
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-09-21 12:22:04.545106",
+ "modified": "2023-10-01 21:01:47.282533",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
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 3690142..424e942 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -77,6 +77,7 @@
   "manufacturer_part_no",
   "accounting",
   "expense_account",
+  "wip_composite_asset",
   "col_break5",
   "is_fixed_asset",
   "asset_location",
@@ -903,12 +904,18 @@
    "no_copy": 1,
    "options": "Serial and Batch Bundle",
    "print_hide": 1
+  },
+  {
+   "fieldname": "wip_composite_asset",
+   "fieldtype": "Link",
+   "label": "WIP Composite Asset",
+   "options": "Asset"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-07-26 12:54:53.178156",
+ "modified": "2023-10-03 21:01:01.824892",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 27a8570..9c73cbb 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -95,30 +95,27 @@
 			"options": "Payment Terms Template"
 		},
 		{
-			"fieldname": "party_type",
+			"fieldname":"party_type",
 			"label": __("Party Type"),
-			"fieldtype": "Link",
-			"options": "Party Type",
-			get_query: () => {
-				return {
-					filters: {
-						'account_type': 'Payable'
-					}
-				};
-			},
-			on_change: () => {
+			"fieldtype": "Autocomplete",
+			options: get_party_type_options(),
+			on_change: function() {
 				frappe.query_report.set_filter_value('party', "");
-				let party_type = frappe.query_report.get_filter_value('party_type');
 				frappe.query_report.toggle_filter_display('supplier_group', frappe.query_report.get_filter_value('party_type') !== "Supplier");
-
 			}
-
 		},
 		{
 			"fieldname":"party",
 			"label": __("Party"),
-			"fieldtype": "Dynamic Link",
-			"options": "party_type",
+			"fieldtype": "MultiSelectList",
+			get_data: function(txt) {
+				if (!frappe.query_report.filters) return;
+
+				let party_type = frappe.query_report.get_filter_value('party_type');
+				if (!party_type) return;
+
+				return frappe.db.get_link_options(party_type, txt);
+			},
 		},
 		{
 			"fieldname": "supplier_group",
@@ -167,3 +164,15 @@
 }
 
 erpnext.utils.add_dimensions('Accounts Payable', 9);
+
+function get_party_type_options() {
+	let options = [];
+	frappe.db.get_list(
+		"Party Type", {filters:{"account_type": "Payable"}, fields:['name']}
+	).then((res) => {
+		res.forEach((party_type) => {
+			options.push(party_type.name);
+		});
+	});
+	return options;
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_payable/test_accounts_payable.py b/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
index 3cf93cc..9f03d92 100644
--- a/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
+++ b/erpnext/accounts/report/accounts_payable/test_accounts_payable.py
@@ -34,7 +34,7 @@
 		filters = {
 			"company": self.company,
 			"party_type": "Supplier",
-			"party": self.supplier,
+			"party": [self.supplier],
 			"report_date": today(),
 			"range1": 30,
 			"range2": 60,
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 ea20072..9e575e6 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -72,10 +72,27 @@
 			}
 		},
 		{
-			"fieldname":"supplier",
-			"label": __("Supplier"),
-			"fieldtype": "Link",
-			"options": "Supplier"
+			"fieldname":"party_type",
+			"label": __("Party Type"),
+			"fieldtype": "Autocomplete",
+			options: get_party_type_options(),
+			on_change: function() {
+				frappe.query_report.set_filter_value('party', "");
+				frappe.query_report.toggle_filter_display('supplier_group', frappe.query_report.get_filter_value('party_type') !== "Supplier");
+			}
+		},
+		{
+			"fieldname":"party",
+			"label": __("Party"),
+			"fieldtype": "MultiSelectList",
+			get_data: function(txt) {
+				if (!frappe.query_report.filters) return;
+
+				let party_type = frappe.query_report.get_filter_value('party_type');
+				if (!party_type) return;
+
+				return frappe.db.get_link_options(party_type, txt);
+			},
 		},
 		{
 			"fieldname":"payment_terms_template",
@@ -105,3 +122,15 @@
 }
 
 erpnext.utils.add_dimensions('Accounts Payable Summary', 9);
+
+function get_party_type_options() {
+	let options = [];
+	frappe.db.get_list(
+		"Party Type", {filters:{"account_type": "Payable"}, fields:['name']}
+	).then((res) => {
+		res.forEach((party_type) => {
+			options.push(party_type.name);
+		});
+	});
+	return options;
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index bb00d61..1073be0 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
+frappe.provide("erpnext.utils");
+
 frappe.query_reports["Accounts Receivable"] = {
 	"filters": [
 		{
@@ -38,30 +40,27 @@
 			}
 		},
 		{
-			"fieldname": "party_type",
+			"fieldname":"party_type",
 			"label": __("Party Type"),
-			"fieldtype": "Link",
-			"options": "Party Type",
-			"Default": "Customer",
-			get_query: () => {
-				return {
-					filters: {
-						'account_type': 'Receivable'
-					}
-				};
-			},
-			on_change: () => {
+			"fieldtype": "Autocomplete",
+			options: get_party_type_options(),
+			on_change: function() {
 				frappe.query_report.set_filter_value('party', "");
-				let party_type = frappe.query_report.get_filter_value('party_type');
 				frappe.query_report.toggle_filter_display('customer_group', frappe.query_report.get_filter_value('party_type') !== "Customer");
-
 			}
 		},
 		{
 			"fieldname":"party",
 			"label": __("Party"),
-			"fieldtype": "Dynamic Link",
-			"options": "party_type",
+			"fieldtype": "MultiSelectList",
+			get_data: function(txt) {
+				if (!frappe.query_report.filters) return;
+
+				let party_type = frappe.query_report.get_filter_value('party_type');
+				if (!party_type) return;
+
+				return frappe.db.get_link_options(party_type, txt);
+			},
 		},
 		{
 			"fieldname": "party_account",
@@ -194,3 +193,16 @@
 }
 
 erpnext.utils.add_dimensions('Accounts Receivable', 9);
+
+
+function get_party_type_options() {
+	let options = [];
+	frappe.db.get_list(
+		"Party Type", {filters:{"account_type": "Receivable"}, fields:['name']}
+	).then((res) => {
+		res.forEach((party_type) => {
+			options.push(party_type.name);
+		});
+	});
+	return options;
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 7942402..e3b671f 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -801,7 +801,7 @@
 			self.qb_selection_filter.append(self.filters.party_type == self.ple.party_type)
 
 		if self.filters.get("party"):
-			self.qb_selection_filter.append(self.filters.party == self.ple.party)
+			self.qb_selection_filter.append(self.ple.party.isin(self.filters.party))
 
 		if self.filters.party_account:
 			self.qb_selection_filter.append(self.ple.account == self.filters.party_account)
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index b98916e..4307689 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -573,7 +573,7 @@
 		filters = {
 			"company": self.company,
 			"party_type": "Customer",
-			"party": self.customer,
+			"party": [self.customer],
 			"report_date": today(),
 			"range1": 30,
 			"range2": 60,
@@ -605,3 +605,41 @@
 		for field in expected:
 			with self.subTest(field=field):
 				self.assertEqual(report_output.get(field), expected.get(field))
+
+	def test_multi_select_party_filter(self):
+		self.customer1 = self.customer
+		self.create_customer("_Test Customer 2")
+		self.customer2 = self.customer
+		self.create_customer("_Test Customer 3")
+		self.customer3 = self.customer
+
+		filters = {
+			"company": self.company,
+			"party_type": "Customer",
+			"party": [self.customer1, self.customer3],
+			"report_date": today(),
+			"range1": 30,
+			"range2": 60,
+			"range3": 90,
+			"range4": 120,
+		}
+
+		si1 = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
+		si1.customer = self.customer1
+		si1.save().submit()
+
+		si2 = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
+		si2.customer = self.customer2
+		si2.save().submit()
+
+		si3 = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
+		si3.customer = self.customer3
+		si3.save().submit()
+
+		# check invoice grand total and invoiced column's value for 3 payment terms
+		report = execute(filters)
+
+		expected_output = {self.customer1, self.customer3}
+		self.assertEqual(len(report[1]), 2)
+		output_for = set([x.party for x in report[1]])
+		self.assertEqual(output_for, expected_output)
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 715cd64..5ad10c7 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -72,10 +72,27 @@
 			}
 		},
 		{
-			"fieldname":"customer",
-			"label": __("Customer"),
-			"fieldtype": "Link",
-			"options": "Customer"
+			"fieldname":"party_type",
+			"label": __("Party Type"),
+			"fieldtype": "Autocomplete",
+			options: get_party_type_options(),
+			on_change: function() {
+				frappe.query_report.set_filter_value('party', "");
+				frappe.query_report.toggle_filter_display('customer_group', frappe.query_report.get_filter_value('party_type') !== "Customer");
+			}
+		},
+		{
+			"fieldname":"party",
+			"label": __("Party"),
+			"fieldtype": "MultiSelectList",
+			get_data: function(txt) {
+				if (!frappe.query_report.filters) return;
+
+				let party_type = frappe.query_report.get_filter_value('party_type');
+				if (!party_type) return;
+
+				return frappe.db.get_link_options(party_type, txt);
+			},
 		},
 		{
 			"fieldname":"customer_group",
@@ -133,3 +150,15 @@
 }
 
 erpnext.utils.add_dimensions('Accounts Receivable Summary', 9);
+
+function get_party_type_options() {
+	let options = [];
+	frappe.db.get_list(
+		"Party Type", {filters:{"account_type": "Receivable"}, fields:['name']}
+	).then((res) => {
+		res.forEach((party_type) => {
+			options.push(party_type.name);
+		});
+	});
+	return options;
+}
\ No newline at end of file
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 cffc878..60274cd 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -99,13 +99,11 @@
 
 			# Add all amount columns
 			for k in list(self.party_total[d.party]):
-				if k not in ["currency", "sales_person"]:
-
-					self.party_total[d.party][k] += d.get(k, 0.0)
+				if isinstance(self.party_total[d.party][k], float):
+					self.party_total[d.party][k] += d.get(k) or 0.0
 
 			# set territory, customer_group, sales person etc
 			self.set_party_details(d)
-			self.party_total[d.party].update({"party_type": d.party_type})
 
 	def init_party_total(self, row):
 		self.party_total.setdefault(
@@ -124,6 +122,7 @@
 					"total_due": 0.0,
 					"future_amount": 0.0,
 					"sales_person": [],
+					"party_type": row.party_type,
 				}
 			),
 		)
@@ -133,13 +132,12 @@
 
 		for key in ("territory", "customer_group", "supplier_group"):
 			if row.get(key):
-				self.party_total[row.party][key] = row.get(key)
-
+				self.party_total[row.party][key] = row.get(key, "")
 		if row.sales_person:
-			self.party_total[row.party].sales_person.append(row.sales_person)
+			self.party_total[row.party].sales_person.append(row.get("sales_person", ""))
 
 		if self.filters.sales_partner:
-			self.party_total[row.party]["default_sales_partner"] = row.get("default_sales_partner")
+			self.party_total[row.party]["default_sales_partner"] = row.get("default_sales_partner", "")
 
 	def get_columns(self):
 		self.columns = []
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
index c9accef..ebd0ec1 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js
@@ -112,7 +112,7 @@
 				"to_fiscal_year": data.fiscal_year
 			};
 
-			if(data.based_on == 'cost_center'){
+			if(data.based_on == 'Cost Center'){
 				frappe.route_options["cost_center"] = data.account
 			} else {
 				frappe.route_options["project"] = data.account
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 962292b..5395f15 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -148,6 +148,15 @@
 
 		if (frm.doc.docstatus == 0) {
 			frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
+
+			if (frm.doc.is_composite_asset && !frm.doc.capitalized_in) {
+				$('.primary-action').prop('hidden', true);
+				$('.form-message').text('Capitalize this asset to confirm');
+
+				frm.add_custom_button(__("Capitalize Asset"), function() {
+					frm.trigger("create_asset_capitalization");
+				});
+			}
 		}
 	},
 
@@ -169,7 +178,7 @@
 			frm.set_df_property('purchase_invoice', 'read_only', 1);
 			frm.set_df_property('purchase_receipt', 'read_only', 1);
 		}
-		else if (frm.doc.is_existing_asset) {
+		else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
 			frm.toggle_reqd('purchase_receipt', 0);
 			frm.toggle_reqd('purchase_invoice', 0);
 		}
@@ -239,7 +248,7 @@
 
 		datatable.style.setStyle(`.dt-scrollable`, {'font-size': '0.75rem', 'margin-bottom': '1rem', 'margin-left': '0.35rem', 'margin-right': '0.35rem'});
 		datatable.style.setStyle(`.dt-header`, {'margin-left': '0.35rem', 'margin-right': '0.35rem'});
-		datatable.style.setStyle(`.dt-cell--header`, {'color': 'var(--text-muted)'});
+		datatable.style.setStyle(`.dt-cell--header .dt-cell__content`, {'color': 'var(--gray-600)', 'font-size': 'var(--text-sm)'});
 		datatable.style.setStyle(`.dt-cell`, {'color': 'var(--text-color)'});
 		datatable.style.setStyle(`.dt-cell--col-1`, {'text-align': 'center'});
 		datatable.style.setStyle(`.dt-cell--col-2`, {'font-weight': 600});
@@ -340,7 +349,8 @@
 			method: "erpnext.assets.doctype.asset.asset.get_item_details",
 			args: {
 				item_code: frm.doc.item_code,
-				asset_category: frm.doc.asset_category
+				asset_category: frm.doc.asset_category,
+				gross_purchase_amount: frm.doc.gross_purchase_amount
 			},
 			callback: function(r, rt) {
 				if(r.message) {
@@ -352,7 +362,17 @@
 
 	is_existing_asset: function(frm) {
 		frm.trigger("toggle_reference_doc");
-		// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
+	},
+
+	is_composite_asset: function(frm) {
+		if(frm.doc.is_composite_asset) {
+			frm.set_value('gross_purchase_amount', 0);
+			frm.set_df_property('gross_purchase_amount', 'read_only', 1);
+		} else {
+			frm.set_df_property('gross_purchase_amount', 'read_only', 0);
+		}
+
+		frm.trigger("toggle_reference_doc");
 	},
 
 	make_sales_invoice: function(frm) {
@@ -402,6 +422,19 @@
 		});
 	},
 
+	create_asset_capitalization: function(frm) {
+		frappe.call({
+			args: {
+				"asset": frm.doc.name,
+			},
+			method: "erpnext.assets.doctype.asset.asset.create_asset_capitalization",
+			callback: function(r) {
+				var doclist = frappe.model.sync(r.message);
+				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+			}
+		});
+	},
+
 	split_asset: function(frm) {
 		const title = __('Split Asset');
 
@@ -465,9 +498,11 @@
 	},
 
 	gross_purchase_amount: function(frm) {
-		frm.doc.finance_books.forEach(d => {
-			frm.events.set_depreciation_rate(frm, d);
-		})
+		if (frm.doc.finance_books) {
+			frm.doc.finance_books.forEach(d => {
+				frm.events.set_depreciation_rate(frm, d);
+			})
+		}
 	},
 
 	purchase_receipt: (frm) => {
@@ -546,7 +581,21 @@
 				}
 			});
 		}
-	}
+	},
+
+	set_salvage_value_percentage_or_expected_value_after_useful_life: function(frm, row, salvage_value_percentage_changed, expected_value_after_useful_life_changed) {
+		if (expected_value_after_useful_life_changed) {
+			frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
+			const new_salvage_value_percentage = flt((row.expected_value_after_useful_life * 100) / frm.doc.gross_purchase_amount, precision("salvage_value_percentage", row));
+			frappe.model.set_value(row.doctype, row.name, "salvage_value_percentage", new_salvage_value_percentage);
+			frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
+		} else if (salvage_value_percentage_changed) {
+			frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
+			const new_expected_value_after_useful_life = flt(frm.doc.gross_purchase_amount * (row.salvage_value_percentage / 100), precision('gross_purchase_amount'));
+			frappe.model.set_value(row.doctype, row.name, "expected_value_after_useful_life", new_expected_value_after_useful_life);
+			frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
+		}
+	},
 });
 
 frappe.ui.form.on('Asset Finance Book', {
@@ -557,9 +606,19 @@
 
 	expected_value_after_useful_life: function(frm, cdt, cdn) {
 		const row = locals[cdt][cdn];
+		if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
+			frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, false, true);
+		}
 		frm.events.set_depreciation_rate(frm, row);
 	},
 
+	salvage_value_percentage: function(frm, cdt, cdn) {
+		const row = locals[cdt][cdn];
+		if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
+			frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, true, false);
+		}
+	},
+
 	frequency_of_depreciation: function(frm, cdt, cdn) {
 		const row = locals[cdt][cdn];
 		frm.events.set_depreciation_rate(frm, row);
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index befb524..c7d08e2 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -14,6 +14,7 @@
   "asset_owner",
   "asset_owner_company",
   "is_existing_asset",
+  "is_composite_asset",
   "supplier",
   "customer",
   "image",
@@ -72,7 +73,8 @@
   "purchase_receipt_amount",
   "default_finance_book",
   "depr_entry_posting_status",
-  "amended_from"
+  "amended_from",
+  "capitalized_in"
  ],
  "fields": [
   {
@@ -199,7 +201,7 @@
    "fieldtype": "Date",
    "label": "Purchase Date",
    "read_only": 1,
-   "read_only_depends_on": "eval:!doc.is_existing_asset",
+   "read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
    "reqd": 1
   },
   {
@@ -237,10 +239,12 @@
    "default": "0",
    "fieldname": "calculate_depreciation",
    "fieldtype": "Check",
-   "label": "Calculate Depreciation"
+   "label": "Calculate Depreciation",
+   "read_only_depends_on": "eval:doc.is_composite_asset && !doc.gross_purchase_amount"
   },
   {
    "default": "0",
+   "depends_on": "eval:!doc.is_composite_asset",
    "fieldname": "is_existing_asset",
    "fieldtype": "Check",
    "label": "Is Existing Asset"
@@ -478,7 +482,7 @@
    "fieldname": "asset_quantity",
    "fieldtype": "Int",
    "label": "Asset Quantity",
-   "read_only_depends_on": "eval:!doc.is_existing_asset"
+   "read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
   },
   {
    "fieldname": "depr_entry_posting_status",
@@ -507,6 +511,21 @@
    "fieldname": "is_fully_depreciated",
    "fieldtype": "Check",
    "label": "Is Fully Depreciated"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:!doc.is_existing_asset",
+   "fieldname": "is_composite_asset",
+   "fieldtype": "Check",
+   "label": "Is Composite Asset"
+  },
+  {
+   "fieldname": "capitalized_in",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Capitalized In",
+   "options": "Asset Capitalization",
+   "read_only": 1
   }
  ],
  "idx": 72,
@@ -545,7 +564,7 @@
    "table_fieldname": "accounts"
   }
  ],
- "modified": "2023-07-28 20:12:44.819616",
+ "modified": "2023-10-03 23:28:26.732269",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 0dbed87..9d35634 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -198,7 +198,9 @@
 			self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
 
 		if self.item_code and not self.get("finance_books"):
-			finance_books = get_item_details(self.item_code, self.asset_category)
+			finance_books = get_item_details(
+				self.item_code, self.asset_category, self.gross_purchase_amount
+			)
 			self.set("finance_books", finance_books)
 
 	def validate_finance_books(self):
@@ -226,7 +228,7 @@
 		if not self.asset_category:
 			self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
 
-		if not flt(self.gross_purchase_amount):
+		if not flt(self.gross_purchase_amount) and not self.is_composite_asset:
 			frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
 
 		if is_cwip_accounting_enabled(self.asset_category):
@@ -767,6 +769,15 @@
 
 
 @frappe.whitelist()
+def create_asset_capitalization(asset):
+	asset_capitalization = frappe.new_doc("Asset Capitalization")
+	asset_capitalization.update(
+		{"target_asset": asset, "capitalization_method": "Choose a WIP composite asset"}
+	)
+	return asset_capitalization
+
+
+@frappe.whitelist()
 def create_asset_value_adjustment(asset, asset_category, company):
 	asset_value_adjustment = frappe.new_doc("Asset Value Adjustment")
 	asset_value_adjustment.update(
@@ -797,7 +808,7 @@
 
 
 @frappe.whitelist()
-def get_item_details(item_code, asset_category):
+def get_item_details(item_code, asset_category, gross_purchase_amount):
 	asset_category_doc = frappe.get_doc("Asset Category", asset_category)
 	books = []
 	for d in asset_category_doc.finance_books:
@@ -807,7 +818,11 @@
 				"depreciation_method": d.depreciation_method,
 				"total_number_of_depreciations": d.total_number_of_depreciations,
 				"frequency_of_depreciation": d.frequency_of_depreciation,
-				"start_date": nowdate(),
+				"daily_depreciation": d.daily_depreciation,
+				"salvage_value_percentage": d.salvage_value_percentage,
+				"expected_value_after_useful_life": flt(gross_purchase_amount)
+				* flt(d.salvage_value_percentage / 100),
+				"depreciation_start_date": d.depreciation_start_date or nowdate(),
 			}
 		)
 
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 39fcb21..88ef69c 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -1744,6 +1744,7 @@
 			"location": args.location or "Test Location",
 			"asset_owner": args.asset_owner or "Company",
 			"is_existing_asset": args.is_existing_asset or 1,
+			"is_composite_asset": args.is_composite_asset or 0,
 			"asset_quantity": args.get("asset_quantity") or 1,
 			"depr_entry_posting_status": args.depr_entry_posting_status or "",
 		}
diff --git a/erpnext/assets/doctype/asset_activity/asset_activity.json b/erpnext/assets/doctype/asset_activity/asset_activity.json
index 476fb27..00992e2 100644
--- a/erpnext/assets/doctype/asset_activity/asset_activity.json
+++ b/erpnext/assets/doctype/asset_activity/asset_activity.json
@@ -75,13 +75,14 @@
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2023-08-01 11:09:52.584482",
+ "modified": "2023-09-29 15:56:17.608643",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset Activity",
  "owner": "Administrator",
  "permissions": [
   {
+   "delete": 1,
    "email": 1,
    "read": 1,
    "report": 1,
@@ -89,6 +90,7 @@
    "share": 1
   },
   {
+   "delete": 1,
    "email": 1,
    "read": 1,
    "report": 1,
@@ -96,6 +98,7 @@
    "share": 1
   },
   {
+   "delete": 1,
    "email": 1,
    "read": 1,
    "report": 1,
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
index 6d55d77..be78d9e 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
@@ -16,9 +16,15 @@
 
 	refresh() {
 		this.show_general_ledger();
+
 		if ((this.frm.doc.stock_items && this.frm.doc.stock_items.length) || !this.frm.doc.target_is_fixed_asset) {
 			this.show_stock_ledger();
 		}
+
+		if (this.frm.doc.stock_items && !this.frm.doc.stock_items.length && this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
+			this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
+			this.get_target_asset_details();
+		}
 	}
 
 	setup_queries() {
@@ -35,18 +41,9 @@
 		});
 
 		me.frm.set_query("target_asset", function() {
-			var filters = {};
-
-			if (me.frm.doc.target_item_code) {
-				filters['item_code'] = me.frm.doc.target_item_code;
-			}
-
-			filters['status'] = ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]];
-			filters['docstatus'] = 1;
-
 			return {
-				filters: filters
-			};
+				filters: {'is_composite_asset': 1, 'docstatus': 0 }
+			}
 		});
 
 		me.frm.set_query("asset", "asset_items", function() {
@@ -128,6 +125,39 @@
 		return this.get_target_item_details();
 	}
 
+	target_asset() {
+		if (this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
+			this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
+			this.get_target_asset_details();
+		}
+	}
+
+	set_consumed_stock_items_tagged_to_wip_composite_asset(asset) {
+		var me = this;
+
+		if (asset) {
+			return me.frm.call({
+				method: "erpnext.assets.doctype.asset_capitalization.asset_capitalization.get_items_tagged_to_wip_composite_asset",
+				args: {
+					asset: asset,
+				},
+				callback: function (r) {
+					if (!r.exc && r.message) {
+						me.frm.clear_table("stock_items");
+
+						for (let item of r.message) {
+							me.frm.add_child("stock_items", item);
+						}
+
+						refresh_field("stock_items");
+
+						me.calculate_totals();
+					}
+				}
+			});
+		}
+	}
+
 	item_code(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		if (cdt === "Asset Capitalization Stock Item") {
@@ -242,6 +272,26 @@
 		}
 	}
 
+	get_target_asset_details() {
+		var me = this;
+
+		if (me.frm.doc.target_asset) {
+			return me.frm.call({
+				method: "erpnext.assets.doctype.asset_capitalization.asset_capitalization.get_target_asset_details",
+				child: me.frm.doc,
+				args: {
+					asset: me.frm.doc.target_asset,
+					company: me.frm.doc.company,
+				},
+				callback: function (r) {
+					if (!r.exc) {
+						me.frm.refresh_fields();
+					}
+				}
+			});
+		}
+	}
+
 	get_consumed_stock_item_details(row) {
 		var me = this;
 
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
index 04b0c4e..9ddc442 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
@@ -8,24 +8,25 @@
  "engine": "InnoDB",
  "field_order": [
   "title",
+  "company",
   "naming_series",
   "entry_type",
-  "target_item_code",
-  "target_asset",
   "target_item_name",
   "target_is_fixed_asset",
   "target_has_batch_no",
   "target_has_serial_no",
   "column_break_9",
-  "target_asset_name",
+  "capitalization_method",
+  "target_item_code",
   "target_asset_location",
+  "target_asset",
+  "target_asset_name",
   "target_warehouse",
   "target_qty",
   "target_stock_uom",
   "target_batch_no",
   "target_serial_no",
   "column_break_5",
-  "company",
   "finance_book",
   "posting_date",
   "posting_time",
@@ -57,12 +58,13 @@
    "label": "Title"
   },
   {
+   "depends_on": "eval:(doc.target_item_code && !doc.__islocal && doc.capitalization_method !== 'Choose a WIP composite asset') || ((doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset') || doc.entry_type=='Decapitalization')",
    "fieldname": "target_item_code",
    "fieldtype": "Link",
    "in_standard_filter": 1,
    "label": "Target Item Code",
-   "options": "Item",
-   "reqd": 1
+   "mandatory_depends_on": "eval:(doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset') || doc.entry_type=='Decapitalization'",
+   "options": "Item"
   },
   {
    "depends_on": "eval:doc.target_item_code && doc.target_item_name != doc.target_item_code",
@@ -86,16 +88,18 @@
    "fieldtype": "Column Break"
   },
   {
+   "depends_on": "eval:(doc.target_asset && !doc.__islocal) || (doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset')",
    "fieldname": "target_asset",
    "fieldtype": "Link",
    "in_standard_filter": 1,
    "label": "Target Asset",
+   "mandatory_depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset'",
    "no_copy": 1,
    "options": "Asset",
-   "read_only": 1
+   "read_only_depends_on": "eval:(doc.entry_type=='Decapitalization') || (doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset')"
   },
   {
-   "depends_on": "eval:doc.entry_type=='Capitalization'",
+   "depends_on": "eval:(doc.target_asset_name && !doc.__islocal) || (doc.target_asset && doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset')",
    "fetch_from": "target_asset.asset_name",
    "fieldname": "target_asset_name",
    "fieldtype": "Data",
@@ -186,12 +190,14 @@
   },
   {
    "default": "1",
+   "depends_on": "eval:doc.entry_type=='Decapitalization'",
    "fieldname": "target_qty",
    "fieldtype": "Float",
    "label": "Target Qty",
    "read_only_depends_on": "eval:doc.entry_type=='Capitalization'"
   },
   {
+   "depends_on": "eval:doc.entry_type=='Decapitalization'",
    "fetch_from": "target_item_code.stock_uom",
    "fieldname": "target_stock_uom",
    "fieldtype": "Link",
@@ -331,18 +337,26 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval:doc.entry_type=='Capitalization'",
+   "depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset'",
    "fieldname": "target_asset_location",
    "fieldtype": "Link",
    "label": "Target Asset Location",
-   "mandatory_depends_on": "eval:doc.entry_type=='Capitalization'",
+   "mandatory_depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset'",
    "options": "Location"
+  },
+  {
+   "depends_on": "eval:doc.entry_type=='Capitalization'",
+   "fieldname": "capitalization_method",
+   "fieldtype": "Select",
+   "label": "Capitalization Method",
+   "mandatory_depends_on": "eval:doc.entry_type=='Capitalization'",
+   "options": "\nCreate a new composite asset\nChoose a WIP composite asset"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-06-22 14:17:07.995120",
+ "modified": "2023-10-03 22:55:59.461456",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset Capitalization",
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 662e4b9..0d6f6b4 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -53,6 +53,7 @@
 		self.validate_posting_time()
 		self.set_missing_values(for_validate=True)
 		self.validate_target_item()
+		self.validate_target_asset()
 		self.validate_consumed_stock_item()
 		self.validate_consumed_asset_item()
 		self.validate_service_item()
@@ -67,12 +68,12 @@
 
 	def before_submit(self):
 		self.validate_source_mandatory()
-		if self.entry_type == "Capitalization":
-			self.create_target_asset()
+		self.create_target_asset()
 
 	def on_submit(self):
 		self.update_stock_ledger()
 		self.make_gl_entries()
+		self.update_target_asset()
 
 	def on_cancel(self):
 		self.ignore_linked_doctypes = (
@@ -94,6 +95,11 @@
 			if self.meta.has_field(k) and (not self.get(k) or k in force_fields):
 				self.set(k, v)
 
+		target_asset_details = get_target_asset_details(self.target_asset, self.company)
+		for k, v in target_asset_details.items():
+			if self.meta.has_field(k) and (not self.get(k) or k in force_fields):
+				self.set(k, v)
+
 		for d in self.stock_items:
 			args = self.as_dict()
 			args.update(d.as_dict())
@@ -155,6 +161,33 @@
 
 		self.validate_item(target_item)
 
+	def validate_target_asset(self):
+		if self.target_asset:
+			target_asset = self.get_asset_for_validation(self.target_asset)
+
+			if not target_asset.is_composite_asset:
+				frappe.throw(_("Target Asset {0} needs to be composite asset").format(target_asset.name))
+
+			if target_asset.item_code != self.target_item_code:
+				frappe.throw(
+					_("Asset {0} does not belong to Item {1}").format(self.target_asset, self.target_item_code)
+				)
+
+			if target_asset.status in ("Scrapped", "Sold", "Capitalized", "Decapitalized"):
+				frappe.throw(
+					_("Target Asset {0} cannot be {1}").format(target_asset.name, target_asset.status)
+				)
+
+			if target_asset.docstatus == 1:
+				frappe.throw(_("Target Asset {0} cannot be submitted").format(target_asset.name))
+			elif target_asset.docstatus == 2:
+				frappe.throw(_("Target Asset {0} cannot be cancelled").format(target_asset.name))
+
+			if target_asset.company != self.company:
+				frappe.throw(
+					_("Target Asset {0} does not belong to company {1}").format(target_asset.name, self.company)
+				)
+
 	def validate_consumed_stock_item(self):
 		for d in self.stock_items:
 			if d.item_code:
@@ -179,7 +212,23 @@
 					)
 
 				asset = self.get_asset_for_validation(d.asset)
-				self.validate_asset(asset)
+
+				if asset.status in ("Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"):
+					frappe.throw(
+						_("Row #{0}: Consumed Asset {1} cannot be {2}").format(d.idx, asset.name, asset.status)
+					)
+
+				if asset.docstatus == 0:
+					frappe.throw(_("Row #{0}: Consumed Asset {1} cannot be Draft").format(d.idx, asset.name))
+				elif asset.docstatus == 2:
+					frappe.throw(_("Row #{0}: Consumed Asset {1} cannot be cancelled").format(d.idx, asset.name))
+
+				if asset.company != self.company:
+					frappe.throw(
+						_("Row #{0}: Consumed Asset {1} does not belong to company {2}").format(
+							d.idx, asset.name, self.company
+						)
+					)
 
 	def validate_service_item(self):
 		for d in self.service_items:
@@ -214,21 +263,12 @@
 
 	def get_asset_for_validation(self, asset):
 		return frappe.db.get_value(
-			"Asset", asset, ["name", "item_code", "company", "status", "docstatus"], as_dict=1
+			"Asset",
+			asset,
+			["name", "item_code", "company", "status", "docstatus", "is_composite_asset"],
+			as_dict=1,
 		)
 
-	def validate_asset(self, asset):
-		if asset.status in ("Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"):
-			frappe.throw(_("Asset {0} is {1}").format(asset.name, asset.status))
-
-		if asset.docstatus == 0:
-			frappe.throw(_("Asset {0} is Draft").format(asset.name))
-		if asset.docstatus == 2:
-			frappe.throw(_("Asset {0} is cancelled").format(asset.name))
-
-		if asset.company != self.company:
-			frappe.throw(_("Asset {0} does not belong to company {1}").format(asset.name, self.company))
-
 	@frappe.whitelist()
 	def set_warehouse_details(self):
 		for d in self.get("stock_items"):
@@ -495,16 +535,25 @@
 				)
 
 	def create_target_asset(self):
+		if (
+			self.entry_type != "Capitalization"
+			or self.capitalization_method != "Create a new composite asset"
+		):
+			return
+
 		total_target_asset_value = flt(self.total_value, self.precision("total_value"))
+
 		asset_doc = frappe.new_doc("Asset")
 		asset_doc.company = self.company
 		asset_doc.item_code = self.target_item_code
-		asset_doc.is_existing_asset = 1
+		asset_doc.is_composite_asset = 1
 		asset_doc.location = self.target_asset_location
 		asset_doc.available_for_use_date = self.posting_date
 		asset_doc.purchase_date = self.posting_date
 		asset_doc.gross_purchase_amount = total_target_asset_value
 		asset_doc.purchase_receipt_amount = total_target_asset_value
+		asset_doc.purchase_receipt_amount = total_target_asset_value
+		asset_doc.capitalized_in = self.name
 		asset_doc.flags.ignore_validate = True
 		asset_doc.flags.asset_created_via_asset_capitalization = True
 		asset_doc.insert()
@@ -528,6 +577,28 @@
 			).format(get_link_to_form("Asset", asset_doc.name))
 		)
 
+	def update_target_asset(self):
+		if (
+			self.entry_type != "Capitalization"
+			or self.capitalization_method != "Choose a WIP composite asset"
+		):
+			return
+
+		total_target_asset_value = flt(self.total_value, self.precision("total_value"))
+
+		asset_doc = frappe.get_doc("Asset", self.target_asset)
+		asset_doc.gross_purchase_amount = total_target_asset_value
+		asset_doc.purchase_receipt_amount = total_target_asset_value
+		asset_doc.capitalized_in = self.name
+		asset_doc.flags.ignore_validate = True
+		asset_doc.save()
+
+		frappe.msgprint(
+			_(
+				"Asset {0} has been updated. Please set the depreciation details if any and submit it."
+			).format(get_link_to_form("Asset", asset_doc.name))
+		)
+
 	def restore_consumed_asset_items(self):
 		for item in self.asset_items:
 			asset = frappe.get_doc("Asset", item.asset)
@@ -613,6 +684,33 @@
 
 
 @frappe.whitelist()
+def get_target_asset_details(asset=None, company=None):
+	out = frappe._dict()
+
+	# Get Asset Details
+	asset_details = frappe._dict()
+	if asset:
+		asset_details = frappe.db.get_value("Asset", asset, ["asset_name", "item_code"], as_dict=1)
+		if not asset_details:
+			frappe.throw(_("Asset {0} does not exist").format(asset))
+
+		# Re-set item code from Asset
+		out.target_item_code = asset_details.item_code
+
+	# Set Asset Details
+	out.asset_name = asset_details.asset_name
+
+	if asset_details.item_code:
+		out.target_fixed_asset_account = get_asset_category_account(
+			"fixed_asset_account", item=asset_details.item_code, company=company
+		)
+	else:
+		out.target_fixed_asset_account = None
+
+	return out
+
+
+@frappe.whitelist()
 def get_consumed_stock_item_details(args):
 	if isinstance(args, str):
 		args = json.loads(args)
@@ -760,3 +858,30 @@
 	)
 
 	return out
+
+
+@frappe.whitelist()
+def get_items_tagged_to_wip_composite_asset(asset):
+	fields = [
+		"item_code",
+		"item_name",
+		"batch_no",
+		"serial_no",
+		"stock_qty",
+		"stock_uom",
+		"warehouse",
+		"cost_center",
+		"qty",
+		"valuation_rate",
+		"amount",
+	]
+
+	pi_items = frappe.get_all(
+		"Purchase Invoice Item", filters={"wip_composite_asset": asset}, fields=fields
+	)
+
+	pr_items = frappe.get_all(
+		"Purchase Receipt Item", filters={"wip_composite_asset": asset}, fields=fields
+	)
+
+	return pi_items + pr_items
diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
index 6e0a685..ac7c90d 100644
--- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
@@ -58,6 +58,7 @@
 		# Create and submit Asset Captitalization
 		asset_capitalization = create_asset_capitalization(
 			entry_type="Capitalization",
+			capitalization_method="Create a new composite asset",
 			target_item_code="Macbook Pro",
 			target_asset_location="Test Location",
 			stock_qty=stock_qty,
@@ -147,6 +148,7 @@
 		# Create and submit Asset Captitalization
 		asset_capitalization = create_asset_capitalization(
 			entry_type="Capitalization",
+			capitalization_method="Create a new composite asset",
 			target_item_code="Macbook Pro",
 			target_asset_location="Test Location",
 			stock_qty=stock_qty,
@@ -211,6 +213,77 @@
 		self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
 		self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
 
+	def test_capitalization_with_wip_composite_asset(self):
+		company = "_Test Company with perpetual inventory"
+		set_depreciation_settings_in_company(company=company)
+
+		stock_rate = 1000
+		stock_qty = 2
+		stock_amount = 2000
+
+		total_amount = 2000
+
+		wip_composite_asset = create_asset(
+			asset_name="Asset Capitalization WIP Composite Asset",
+			is_composite_asset=1,
+			warehouse="Stores - TCP1",
+			company=company,
+		)
+
+		# Create and submit Asset Captitalization
+		asset_capitalization = create_asset_capitalization(
+			entry_type="Capitalization",
+			capitalization_method="Choose a WIP composite asset",
+			target_asset=wip_composite_asset.name,
+			target_asset_location="Test Location",
+			stock_qty=stock_qty,
+			stock_rate=stock_rate,
+			service_expense_account="Expenses Included In Asset Valuation - TCP1",
+			company=company,
+			submit=1,
+		)
+
+		# Test Asset Capitalization values
+		self.assertEqual(asset_capitalization.entry_type, "Capitalization")
+		self.assertEqual(asset_capitalization.capitalization_method, "Choose a WIP composite asset")
+		self.assertEqual(asset_capitalization.target_qty, 1)
+
+		self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate)
+		self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount)
+		self.assertEqual(asset_capitalization.stock_items_total, stock_amount)
+
+		self.assertEqual(asset_capitalization.total_value, total_amount)
+		self.assertEqual(asset_capitalization.target_incoming_rate, total_amount)
+
+		# Test Target Asset values
+		target_asset = frappe.get_doc("Asset", asset_capitalization.target_asset)
+		self.assertEqual(target_asset.gross_purchase_amount, total_amount)
+		self.assertEqual(target_asset.purchase_receipt_amount, total_amount)
+
+		# Test General Ledger Entries
+		expected_gle = {
+			"_Test Fixed Asset - TCP1": 2000,
+			"_Test Warehouse - TCP1": -2000,
+		}
+		actual_gle = get_actual_gle_dict(asset_capitalization.name)
+
+		self.assertEqual(actual_gle, expected_gle)
+
+		# Test Stock Ledger Entries
+		expected_sle = {
+			("Capitalization Source Stock Item", "_Test Warehouse - TCP1"): {
+				"actual_qty": -stock_qty,
+				"stock_value_difference": -stock_amount,
+			}
+		}
+		actual_sle = get_actual_sle_dict(asset_capitalization.name)
+		self.assertEqual(actual_sle, expected_sle)
+
+		# Cancel Asset Capitalization and make test entries and status are reversed
+		asset_capitalization.cancel()
+		self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
+		self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
+
 	def test_decapitalization_with_depreciation(self):
 		# Variables
 		purchase_date = "2020-01-01"
@@ -347,6 +420,7 @@
 	asset_capitalization.update(
 		{
 			"entry_type": args.entry_type or "Capitalization",
+			"capitalization_method": args.capitalization_method or None,
 			"company": company,
 			"posting_date": args.posting_date or now.strftime("%Y-%m-%d"),
 			"posting_time": args.posting_time or now.strftime("%H:%M:%S.%f"),
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index 4121302..2c27dc9 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -12,6 +12,7 @@
   "column_break_5",
   "frequency_of_depreciation",
   "depreciation_start_date",
+  "salvage_value_percentage",
   "expected_value_after_useful_life",
   "value_after_depreciation",
   "rate_of_depreciation"
@@ -91,12 +92,17 @@
    "fieldname": "daily_depreciation",
    "fieldtype": "Check",
    "label": "Daily Depreciation"
+  },
+  {
+   "fieldname": "salvage_value_percentage",
+   "fieldtype": "Percent",
+   "label": "Salvage Value Percentage"
   }
  ],
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-08-10 22:10:36.576199",
+ "modified": "2023-09-29 15:39:52.740594",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset Finance Book",
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 7e95cb2..9c2b8bc 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -177,7 +177,7 @@
 					"item_code": stock_item.item_code,
 					"qty": stock_item.consumed_quantity,
 					"basic_rate": stock_item.valuation_rate,
-					"serial_no": stock_item.serial_and_batch_bundle,
+					"serial_and_batch_bundle": stock_item.serial_and_batch_bundle,
 					"cost_center": self.cost_center,
 					"project": self.project,
 				},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 5b5cc2b..f74df66 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -477,6 +477,7 @@
    "depends_on": "eval:doc.is_subcontracted",
    "fieldname": "supplier_warehouse",
    "fieldtype": "Link",
+   "ignore_user_permissions": 1,
    "label": "Supplier Warehouse",
    "options": "Warehouse"
   },
@@ -1274,7 +1275,7 @@
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-09-13 16:21:07.361700",
+ "modified": "2023-10-01 20:58:07.851037",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order",
diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js
index 08dc44c..70d2782 100644
--- a/erpnext/buying/doctype/supplier/supplier.js
+++ b/erpnext/buying/doctype/supplier/supplier.js
@@ -88,7 +88,7 @@
 			}, __("View"));
 
 			frm.add_custom_button(__('Accounts Payable'), function () {
-				frappe.set_route('query-report', 'Accounts Payable', { supplier: frm.doc.name });
+				frappe.set_route('query-report', 'Accounts Payable', { party_type: "Supplier", party: frm.doc.name });
 			}, __("View"));
 
 			frm.add_custom_button(__('Bank Account'), function () {
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
index a728290..01ff28d 100644
--- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
@@ -35,8 +35,12 @@
 			sq_item.parent,
 			sq_item.item_code,
 			sq_item.qty,
+			sq.currency,
 			sq_item.stock_qty,
 			sq_item.amount,
+			sq_item.base_rate,
+			sq_item.base_amount,
+			sq.price_list_currency,
 			sq_item.uom,
 			sq_item.stock_uom,
 			sq_item.request_for_quotation,
@@ -105,7 +109,11 @@
 			"qty": data.get("qty"),
 			"price": flt(data.get("amount") * exchange_rate, float_precision),
 			"uom": data.get("uom"),
+			"price_list_currency": data.get("price_list_currency"),
+			"currency": data.get("currency"),
 			"stock_uom": data.get("stock_uom"),
+			"base_amount": flt(data.get("base_amount"), float_precision),
+			"base_rate": flt(data.get("base_rate"), float_precision),
 			"request_for_quotation": data.get("request_for_quotation"),
 			"valid_till": data.get("valid_till"),
 			"lead_time_days": data.get("lead_time_days"),
@@ -183,6 +191,8 @@
 
 
 def get_columns(filters):
+	currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency")
+
 	group_by_columns = [
 		{
 			"fieldname": "supplier_name",
@@ -204,10 +214,17 @@
 		{"fieldname": "uom", "label": _("UOM"), "fieldtype": "Link", "options": "UOM", "width": 90},
 		{"fieldname": "qty", "label": _("Quantity"), "fieldtype": "Float", "width": 80},
 		{
+			"fieldname": "currency",
+			"label": _("Currency"),
+			"fieldtype": "Link",
+			"options": "Currency",
+			"width": 110,
+		},
+		{
 			"fieldname": "price",
 			"label": _("Price"),
 			"fieldtype": "Currency",
-			"options": "Company:company:default_currency",
+			"options": "currency",
 			"width": 110,
 		},
 		{
@@ -221,10 +238,24 @@
 			"fieldname": "price_per_unit",
 			"label": _("Price per Unit (Stock UOM)"),
 			"fieldtype": "Currency",
-			"options": "Company:company:default_currency",
+			"options": "currency",
 			"width": 120,
 		},
 		{
+			"fieldname": "base_amount",
+			"label": _("Price ({0})").format(currency),
+			"fieldtype": "Currency",
+			"options": "price_list_currency",
+			"width": 180,
+		},
+		{
+			"fieldname": "base_rate",
+			"label": _("Price Per Unit ({0})").format(currency),
+			"fieldtype": "Currency",
+			"options": "price_list_currency",
+			"width": 180,
+		},
+		{
 			"fieldname": "quotation",
 			"label": _("Supplier Quotation"),
 			"fieldtype": "Link",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 6efa09b..6812940 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1491,7 +1491,7 @@
 						"account": self.additional_discount_account,
 						"against": supplier_or_customer,
 						dr_or_cr: self.base_discount_amount,
-						"cost_center": self.cost_center,
+						"cost_center": self.cost_center or erpnext.get_default_cost_center(self.company),
 					},
 					item=self,
 				)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 0d0fd5e..4a00416 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -228,7 +228,7 @@
   },
   {
    "default": "0",
-   "description": "If enabled, the system won't create material requests for the available items.",
+   "description": "If enabled, the system will create material requests even if the stock exists in the 'Raw Materials Warehouse'.",
    "fieldname": "ignore_existing_ordered_qty",
    "fieldtype": "Check",
    "label": "Ignore Available Stock"
@@ -422,7 +422,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-07-28 13:37:43.926686",
+ "modified": "2023-09-29 11:41:03.246059",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index e88b791..deef020 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -8,6 +8,7 @@
 import frappe
 from frappe import _, msgprint
 from frappe.model.document import Document
+from frappe.query_builder import Case
 from frappe.query_builder.functions import IfNull, Sum
 from frappe.utils import (
 	add_days,
@@ -1509,6 +1510,10 @@
 def get_materials_from_other_locations(item, warehouses, new_mr_items, company):
 	from erpnext.stock.doctype.pick_list.pick_list import get_available_item_locations
 
+	stock_uom, purchase_uom = frappe.db.get_value(
+		"Item", item.get("item_code"), ["stock_uom", "purchase_uom"]
+	)
+
 	locations = get_available_item_locations(
 		item.get("item_code"), warehouses, item.get("quantity"), company, ignore_validation=True
 	)
@@ -1519,6 +1524,10 @@
 		if required_qty <= 0:
 			return
 
+		conversion_factor = 1.0
+		if purchase_uom != stock_uom and purchase_uom == item["uom"]:
+			conversion_factor = get_uom_conversion_factor(item["item_code"], item["uom"])
+
 		new_dict = copy.deepcopy(item)
 		quantity = required_qty if d.get("qty") > required_qty else d.get("qty")
 
@@ -1531,25 +1540,14 @@
 			}
 		)
 
-		required_qty -= quantity
+		required_qty -= quantity / conversion_factor
 		new_mr_items.append(new_dict)
 
 	# raise purchase request for remaining qty
-	if required_qty:
-		stock_uom, purchase_uom = frappe.db.get_value(
-			"Item", item["item_code"], ["stock_uom", "purchase_uom"]
-		)
 
-		if purchase_uom != stock_uom and purchase_uom == item["uom"]:
-			conversion_factor = get_uom_conversion_factor(item["item_code"], item["uom"])
-			if not (conversion_factor or frappe.flags.show_qty_in_stock_uom):
-				frappe.throw(
-					_("UOM Conversion factor ({0} -> {1}) not found for item: {2}").format(
-						purchase_uom, stock_uom, item["item_code"]
-					)
-				)
-
-			required_qty = required_qty / conversion_factor
+	precision = frappe.get_precision("Material Request Plan Item", "quantity")
+	if flt(required_qty, precision) > 0:
+		required_qty = required_qty
 
 		if frappe.db.get_value("UOM", purchase_uom, "must_be_whole_number"):
 			required_qty = ceil(required_qty)
@@ -1620,18 +1618,33 @@
 	table = frappe.qb.DocType("Production Plan")
 	child = frappe.qb.DocType("Material Request Plan Item")
 
+	completed_production_plans = get_completed_production_plans()
+
+	case = Case()
 	query = (
 		frappe.qb.from_(table)
 		.inner_join(child)
 		.on(table.name == child.parent)
-		.select(Sum(child.quantity * IfNull(child.conversion_factor, 1.0)))
+		.select(
+			Sum(
+				child.quantity
+				* IfNull(
+					case.when(child.material_request_type == "Purchase", child.conversion_factor).else_(1.0), 1.0
+				)
+			)
+		)
 		.where(
 			(table.docstatus == 1)
 			& (child.item_code == item_code)
 			& (child.warehouse == warehouse)
 			& (table.status.notin(["Completed", "Closed"]))
 		)
-	).run()
+	)
+
+	if completed_production_plans:
+		query = query.where(table.name.notin(completed_production_plans))
+
+	query = query.run()
 
 	if not query:
 		return 0.0
@@ -1639,7 +1652,9 @@
 	reserved_qty_for_production_plan = flt(query[0][0])
 
 	reserved_qty_for_production = flt(
-		get_reserved_qty_for_production(item_code, warehouse, check_production_plan=True)
+		get_reserved_qty_for_production(
+			item_code, warehouse, completed_production_plans, check_production_plan=True
+		)
 	)
 
 	if reserved_qty_for_production > reserved_qty_for_production_plan:
@@ -1648,6 +1663,25 @@
 	return reserved_qty_for_production_plan - reserved_qty_for_production
 
 
+def get_completed_production_plans():
+	table = frappe.qb.DocType("Production Plan")
+	child = frappe.qb.DocType("Production Plan Item")
+
+	query = (
+		frappe.qb.from_(table)
+		.inner_join(child)
+		.on(table.name == child.parent)
+		.select(table.name)
+		.where(
+			(table.docstatus == 1)
+			& (table.status.notin(["Completed", "Closed"]))
+			& (child.ordered_qty >= child.planned_qty)
+		)
+	).run(as_dict=True)
+
+	return list(set([d.name for d in query]))
+
+
 def get_raw_materials_of_sub_assembly_items(
 	item_details, company, bom_no, include_non_stock_items, sub_assembly_items, planned_qty=1
 ):
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 2348d2b..4ff9d29 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -6,6 +6,7 @@
 
 from erpnext.controllers.item_variant import create_variant
 from erpnext.manufacturing.doctype.production_plan.production_plan import (
+	get_completed_production_plans,
 	get_items_for_material_requests,
 	get_sales_orders,
 	get_warehouse_list,
@@ -1103,6 +1104,49 @@
 
 			self.assertEqual(after_qty, before_qty)
 
+	def test_resered_qty_for_production_plan_for_less_rm_qty(self):
+		from erpnext.stock.utils import get_or_make_bin
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		before_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		pln = create_production_plan(item_code="Test Production Item 1", planned_qty=10)
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		self.assertEqual(after_qty - before_qty, 10)
+
+		pln.make_work_order()
+
+		plans = []
+		for row in frappe.get_all("Work Order", filters={"production_plan": pln.name}, fields=["name"]):
+			wo_doc = frappe.get_doc("Work Order", row.name)
+			wo_doc.source_warehouse = "_Test Warehouse - _TC"
+			wo_doc.wip_warehouse = "_Test Warehouse 1 - _TC"
+			wo_doc.fg_warehouse = "_Test Warehouse - _TC"
+			for d in wo_doc.required_items:
+				d.source_warehouse = "_Test Warehouse - _TC"
+				d.required_qty -= 5
+				make_stock_entry(
+					item_code=d.item_code,
+					qty=d.required_qty,
+					rate=100,
+					target="_Test Warehouse - _TC",
+				)
+
+			wo_doc.submit()
+			plans.append(pln.name)
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		self.assertEqual(after_qty, before_qty)
+
+		completed_plans = get_completed_production_plans()
+		for plan in plans:
+			self.assertTrue(plan in completed_plans)
+
 	def test_resered_qty_for_production_plan_for_material_requests_with_multi_UOM(self):
 		from erpnext.stock.utils import get_or_make_bin
 
@@ -1230,6 +1274,64 @@
 			if row.item_code == "SubAssembly2 For SUB Test":
 				self.assertEqual(row.quantity, 10)
 
+	def test_transfer_and_purchase_mrp_for_purchase_uom(self):
+		from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
+		from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+
+		bom_tree = {
+			"Test FG Item INK PEN": {
+				"Test RM Item INK": {},
+			}
+		}
+
+		parent_bom = create_nested_bom(bom_tree, prefix="")
+		if not frappe.db.exists("UOM Conversion Detail", {"parent": "Test RM Item INK", "uom": "Kg"}):
+			doc = frappe.get_doc("Item", "Test RM Item INK")
+			doc.purchase_uom = "Kg"
+			doc.append("uoms", {"uom": "Kg", "conversion_factor": 0.5})
+			doc.save()
+
+		wh1 = create_warehouse("PNE Warehouse", company="_Test Company")
+		wh2 = create_warehouse("MBE Warehouse", company="_Test Company")
+		mrp_warhouse = create_warehouse("MRPBE Warehouse", company="_Test Company")
+
+		make_stock_entry(
+			item_code="Test RM Item INK",
+			qty=2,
+			rate=100,
+			target=wh1,
+		)
+
+		make_stock_entry(
+			item_code="Test RM Item INK",
+			qty=2,
+			rate=100,
+			target=wh2,
+		)
+
+		plan = create_production_plan(
+			item_code=parent_bom.item,
+			planned_qty=10,
+			do_not_submit=1,
+			warehouse="_Test Warehouse - _TC",
+		)
+
+		plan.for_warehouse = mrp_warhouse
+
+		items = get_items_for_material_requests(
+			plan.as_dict(), warehouses=[{"warehouse": wh1}, {"warehouse": wh2}]
+		)
+
+		for row in items:
+			row = frappe._dict(row)
+			if row.material_request_type == "Material Transfer":
+				self.assertTrue(row.from_warehouse in [wh1, wh2])
+				self.assertEqual(row.quantity, 2)
+
+			if row.material_request_type == "Purchase":
+				self.assertTrue(row.warehouse == mrp_warhouse)
+				self.assertEqual(row.quantity, 12)
+
 
 def create_production_plan(**args):
 	"""
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index d8fc220..3dc33ac 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -358,10 +358,10 @@
 		else:
 			self.update_work_order_qty_in_so()
 
+		self.update_ordered_qty()
 		self.update_reserved_qty_for_production()
 		self.update_completed_qty_in_material_request()
 		self.update_planned_qty()
-		self.update_ordered_qty()
 		self.create_job_card()
 
 	def on_cancel(self):
@@ -1513,7 +1513,10 @@
 
 
 def get_reserved_qty_for_production(
-	item_code: str, warehouse: str, check_production_plan: bool = False
+	item_code: str,
+	warehouse: str,
+	completed_production_plans: list = None,
+	check_production_plan: bool = False,
 ) -> float:
 	"""Get total reserved quantity for any item in specified warehouse"""
 	wo = frappe.qb.DocType("Work Order")
@@ -1546,6 +1549,9 @@
 	if check_production_plan:
 		query = query.where(wo.production_plan.isnotnull())
 
+	if completed_production_plans:
+		query = query.where(wo.production_plan.notin(completed_production_plans))
+
 	return query.run()[0][0] or 0.0
 
 
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 05a70c3..25a5455 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -60,7 +60,6 @@
    "fieldname": "subject",
    "fieldtype": "Data",
    "in_global_search": 1,
-   "in_list_view": 1,
    "in_standard_filter": 1,
    "label": "Subject",
    "reqd": 1,
@@ -140,7 +139,6 @@
    "fieldname": "parent_task",
    "fieldtype": "Link",
    "ignore_user_permissions": 1,
-   "in_list_view": 1,
    "label": "Parent Task",
    "options": "Task",
    "search_index": 1
@@ -398,7 +396,7 @@
  "is_tree": 1,
  "links": [],
  "max_attachments": 5,
- "modified": "2023-09-06 13:52:05.861175",
+ "modified": "2023-09-28 13:52:05.861175",
  "modified_by": "Administrator",
  "module": "Projects",
  "name": "Task",
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 959cf50..907a775 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -6,8 +6,10 @@
 		if (data && column.fieldname=="account") {
 			value = data.account_name || value;
 
-			column.link_onclick =
-				"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
+			if (data.account) {
+				column.link_onclick =
+					"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
+			}
 			column.is_tree = true;
 		}
 
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index ec2db81..bd5d540 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -10,7 +10,7 @@
 
 def check_deletion_permission(doc, method):
 	region = get_region(doc.company)
-	if region in ["Nepal", "France"] and doc.docstatus != 0:
+	if region in ["Nepal"] and doc.docstatus != 0:
 		frappe.throw(_("Deletion is not permitted for country {0}").format(region))
 
 
@@ -20,7 +20,7 @@
 	Called on submit of Sales Invoice and Payment Entry.
 	"""
 	region = get_region()
-	if region not in ["France", "Germany"]:
+	if region not in ["Germany"]:
 		return
 
 	data = str(doc.as_dict())
diff --git a/erpnext/regional/address_template/templates/france.html b/erpnext/regional/address_template/templates/france.html
deleted file mode 100644
index 752331e..0000000
--- a/erpnext/regional/address_template/templates/france.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% if address_line1 %}{{ address_line1 }}{% endif -%}
-{% if address_line2 %}<br>{{ address_line2 }}{% endif -%}
-{% if pincode %}<br>{{ pincode }}{% endif -%}
-{% if city %} {{ city }}{% endif -%}
-{% if country %}<br>{{ country }}{% endif -%}
diff --git a/erpnext/regional/france/__init__.py b/erpnext/regional/france/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/france/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/france/setup.py b/erpnext/regional/france/setup.py
deleted file mode 100644
index da772d6..0000000
--- a/erpnext/regional/france/setup.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-
-def setup(company=None, patch=True):
-	make_custom_fields()
-	add_custom_roles_for_reports()
-
-
-def make_custom_fields():
-	custom_fields = {
-		"Company": [
-			dict(fieldname="siren_number", label="SIREN Number", fieldtype="Data", insert_after="website")
-		]
-	}
-
-	create_custom_fields(custom_fields)
-
-
-def add_custom_roles_for_reports():
-	report_name = "Fichier des Ecritures Comptables [FEC]"
-
-	if not frappe.db.get_value("Custom Role", dict(report=report_name)):
-		frappe.get_doc(
-			dict(doctype="Custom Role", report=report_name, roles=[dict(role="Accounts Manager")])
-		).insert()
diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py
deleted file mode 100644
index 65dfd2d..0000000
--- a/erpnext/regional/france/utils.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and contributors
-# For license information, please see license.txt
-
-
-# don't remove this function it is used in tests
-def test_method():
-	"""test function"""
-	return "overridden"
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/__init__.py" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/__init__.py"
deleted file mode 100644
index e69de29..0000000
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/__init__.py"
+++ /dev/null
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js"
deleted file mode 100644
index b85b58f..0000000
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js"
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.query_reports["Fichier des Ecritures Comptables [FEC]"] = {
-	"filters": [
-		{
-			"fieldname": "company",
-			"label": __("Company"),
-			"fieldtype": "Link",
-			"options": "Company",
-			"default": frappe.defaults.get_user_default("Company"),
-			"reqd": 1
-		},
-		{
-			"fieldname": "fiscal_year",
-			"label": __("Fiscal Year"),
-			"fieldtype": "Link",
-			"options": "Fiscal Year",
-			"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
-			"reqd": 1
-		}
-	],
-	onload: function(query_report) {
-		query_report.page.add_inner_button(__("Export"), function() {
-			fec_export(query_report);
-		});
-
-		query_report.add_make_chart_button = function() {
-			//
-		};
-
-		query_report.export_report = function() {
-			fec_export(query_report);
-		};
-	}
-};
-
-let fec_export = function(query_report) {
-	const fiscal_year = query_report.get_values().fiscal_year;
-	const company = query_report.get_values().company;
-
-	frappe.db.get_value("Company", company, "siren_number", (value) => {
-		const company_data = value.siren_number;
-		if (company_data === null || company_data === undefined) {
-			frappe.msgprint(__("Please register the SIREN number in the company information file"));
-		} else {
-			frappe.db.get_value("Fiscal Year", fiscal_year, "year_end_date", (r) => {
-				const fy = r.year_end_date;
-				const title = company_data + "FEC" + moment(fy).format('YYYYMMDD');
-				const column_row = query_report.columns.map(col => col.label);
-				const column_data = query_report.get_data_for_csv(false);
-				const result = [column_row].concat(column_data);
-				downloadify(result, null, title);
-			});
-
-		}
-	});
-};
-
-let downloadify = function(data, roles, title) {
-	if (roles && roles.length && !has_common(roles, roles)) {
-		frappe.msgprint(__("Export not allowed. You need {0} role to export.", [frappe.utils.comma_or(roles)]));
-		return;
-	}
-
-	const filename = title + ".txt";
-	let csv_data = to_tab_csv(data);
-	const a = document.createElement('a');
-
-	if ("download" in a) {
-		// Used Blob object, because it can handle large files
-		let blob_object = new Blob([csv_data], {
-			type: 'text/csv;charset=UTF-8'
-		});
-		a.href = URL.createObjectURL(blob_object);
-		a.download = filename;
-
-	} else {
-		// use old method
-		a.href = 'data:attachment/csv,' + encodeURIComponent(csv_data);
-		a.download = filename;
-		a.target = "_blank";
-	}
-
-	document.body.appendChild(a);
-	a.click();
-
-	document.body.removeChild(a);
-};
-
-let to_tab_csv = function(data) {
-	let res = [];
-	$.each(data, function(i, row) {
-		res.push(row.join("\t"));
-	});
-	return res.join("\n");
-};
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.json" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.json"
deleted file mode 100644
index 9b48e11..0000000
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.json"
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "add_total_row": 0, 
- "apply_user_permissions": 0, 
- "creation": "2018-01-10 15:10:16.650129", 
- "disabled": 0, 
- "docstatus": 0, 
- "doctype": "Report", 
- "idx": 0, 
- "is_standard": "Yes", 
- "modified": "2018-01-11 10:27:25.595485", 
- "modified_by": "Administrator", 
- "module": "Regional", 
- "name": "Fichier des Ecritures Comptables [FEC]", 
- "owner": "Administrator", 
- "ref_doctype": "GL Entry", 
- "report_name": "Fichier des Ecritures Comptables [FEC]", 
- "report_type": "Script Report", 
- "roles": []
-}
\ No newline at end of file
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py"
deleted file mode 100644
index 6717989..0000000
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py"
+++ /dev/null
@@ -1,339 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-import re
-
-import frappe
-from frappe import _
-from frappe.utils import format_datetime
-
-COLUMNS = [
-	{
-		"label": "JournalCode",
-		"fieldname": "JournalCode",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "JournalLib",
-		"fieldname": "JournalLib",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "EcritureNum",
-		"fieldname": "EcritureNum",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "EcritureDate",
-		"fieldname": "EcritureDate",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "CompteNum",
-		"fieldname": "CompteNum",
-		"fieldtype": "Link",
-		"options": "Account",
-		"width": 100,
-	},
-	{
-		"label": "CompteLib",
-		"fieldname": "CompteLib",
-		"fieldtype": "Link",
-		"options": "Account",
-		"width": 200,
-	},
-	{
-		"label": "CompAuxNum",
-		"fieldname": "CompAuxNum",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "CompAuxLib",
-		"fieldname": "CompAuxLib",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "PieceRef",
-		"fieldname": "PieceRef",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "PieceDate",
-		"fieldname": "PieceDate",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "EcritureLib",
-		"fieldname": "EcritureLib",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "Debit",
-		"fieldname": "Debit",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "Credit",
-		"fieldname": "Credit",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "EcritureLet",
-		"fieldname": "EcritureLet",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "DateLet",
-		"fieldname": "DateLet",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "ValidDate",
-		"fieldname": "ValidDate",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "Montantdevise",
-		"fieldname": "Montantdevise",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-	{
-		"label": "Idevise",
-		"fieldname": "Idevise",
-		"fieldtype": "Data",
-		"width": 90,
-	},
-]
-
-
-def execute(filters=None):
-	validate_filters(filters)
-	return COLUMNS, get_result(
-		company=filters["company"],
-		fiscal_year=filters["fiscal_year"],
-	)
-
-
-def validate_filters(filters):
-	if not filters.get("company"):
-		frappe.throw(_("{0} is mandatory").format(_("Company")))
-
-	if not filters.get("fiscal_year"):
-		frappe.throw(_("{0} is mandatory").format(_("Fiscal Year")))
-
-
-def get_gl_entries(company, fiscal_year):
-	gle = frappe.qb.DocType("GL Entry")
-	sales_invoice = frappe.qb.DocType("Sales Invoice")
-	purchase_invoice = frappe.qb.DocType("Purchase Invoice")
-	journal_entry = frappe.qb.DocType("Journal Entry")
-	payment_entry = frappe.qb.DocType("Payment Entry")
-	customer = frappe.qb.DocType("Customer")
-	supplier = frappe.qb.DocType("Supplier")
-	employee = frappe.qb.DocType("Employee")
-
-	debit = frappe.query_builder.functions.Sum(gle.debit).as_("debit")
-	credit = frappe.query_builder.functions.Sum(gle.credit).as_("credit")
-	debit_currency = frappe.query_builder.functions.Sum(gle.debit_in_account_currency).as_(
-		"debitCurr"
-	)
-	credit_currency = frappe.query_builder.functions.Sum(gle.credit_in_account_currency).as_(
-		"creditCurr"
-	)
-
-	query = (
-		frappe.qb.from_(gle)
-		.left_join(sales_invoice)
-		.on(gle.voucher_no == sales_invoice.name)
-		.left_join(purchase_invoice)
-		.on(gle.voucher_no == purchase_invoice.name)
-		.left_join(journal_entry)
-		.on(gle.voucher_no == journal_entry.name)
-		.left_join(payment_entry)
-		.on(gle.voucher_no == payment_entry.name)
-		.left_join(customer)
-		.on(gle.party == customer.name)
-		.left_join(supplier)
-		.on(gle.party == supplier.name)
-		.left_join(employee)
-		.on(gle.party == employee.name)
-		.select(
-			gle.posting_date.as_("GlPostDate"),
-			gle.name.as_("GlName"),
-			gle.account,
-			gle.transaction_date,
-			debit,
-			credit,
-			debit_currency,
-			credit_currency,
-			gle.voucher_type,
-			gle.voucher_no,
-			gle.against_voucher_type,
-			gle.against_voucher,
-			gle.account_currency,
-			gle.against,
-			gle.party_type,
-			gle.party,
-			sales_invoice.name.as_("InvName"),
-			sales_invoice.title.as_("InvTitle"),
-			sales_invoice.posting_date.as_("InvPostDate"),
-			purchase_invoice.name.as_("PurName"),
-			purchase_invoice.title.as_("PurTitle"),
-			purchase_invoice.posting_date.as_("PurPostDate"),
-			journal_entry.cheque_no.as_("JnlRef"),
-			journal_entry.posting_date.as_("JnlPostDate"),
-			journal_entry.title.as_("JnlTitle"),
-			payment_entry.name.as_("PayName"),
-			payment_entry.posting_date.as_("PayPostDate"),
-			payment_entry.title.as_("PayTitle"),
-			customer.customer_name,
-			customer.name.as_("cusName"),
-			supplier.supplier_name,
-			supplier.name.as_("supName"),
-			employee.employee_name,
-			employee.name.as_("empName"),
-		)
-		.where((gle.company == company) & (gle.fiscal_year == fiscal_year))
-		.groupby(gle.voucher_type, gle.voucher_no, gle.account)
-		.orderby(gle.posting_date, gle.voucher_no)
-	)
-
-	return query.run(as_dict=True)
-
-
-def get_result(company, fiscal_year):
-	data = get_gl_entries(company, fiscal_year)
-
-	result = []
-
-	company_currency = frappe.get_cached_value("Company", company, "default_currency")
-	accounts = frappe.get_all(
-		"Account", filters={"Company": company}, fields=["name", "account_number"]
-	)
-
-	for d in data:
-		JournalCode = re.split("-|/|[0-9]", d.get("voucher_no"))[0]
-
-		if d.get("voucher_no").startswith("{0}-".format(JournalCode)) or d.get("voucher_no").startswith(
-			"{0}/".format(JournalCode)
-		):
-			EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
-		else:
-			EcritureNum = re.search(r"{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE)[1]
-
-		EcritureDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
-
-		account_number = [
-			account.account_number for account in accounts if account.name == d.get("account")
-		]
-		if account_number[0] is not None:
-			CompteNum = account_number[0]
-		else:
-			frappe.throw(
-				_(
-					"Account number for account {0} is not available.<br> Please setup your Chart of Accounts correctly."
-				).format(d.get("account"))
-			)
-
-		if d.get("party_type") == "Customer":
-			CompAuxNum = d.get("cusName")
-			CompAuxLib = d.get("customer_name")
-
-		elif d.get("party_type") == "Supplier":
-			CompAuxNum = d.get("supName")
-			CompAuxLib = d.get("supplier_name")
-
-		elif d.get("party_type") == "Employee":
-			CompAuxNum = d.get("empName")
-			CompAuxLib = d.get("employee_name")
-
-		elif d.get("party_type") == "Student":
-			CompAuxNum = d.get("stuName")
-			CompAuxLib = d.get("student_name")
-
-		elif d.get("party_type") == "Member":
-			CompAuxNum = d.get("memName")
-			CompAuxLib = d.get("member_name")
-
-		else:
-			CompAuxNum = ""
-			CompAuxLib = ""
-
-		ValidDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
-
-		PieceRef = d.get("voucher_no") or "Sans Reference"
-
-		# EcritureLib is the reference title unless it is an opening entry
-		if d.get("is_opening") == "Yes":
-			EcritureLib = _("Opening Entry Journal")
-		if d.get("voucher_type") == "Sales Invoice":
-			EcritureLib = d.get("InvTitle")
-		elif d.get("voucher_type") == "Purchase Invoice":
-			EcritureLib = d.get("PurTitle")
-		elif d.get("voucher_type") == "Journal Entry":
-			EcritureLib = d.get("JnlTitle")
-		elif d.get("voucher_type") == "Payment Entry":
-			EcritureLib = d.get("PayTitle")
-		else:
-			EcritureLib = d.get("voucher_type")
-
-		PieceDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
-
-		debit = "{:.2f}".format(d.get("debit")).replace(".", ",")
-
-		credit = "{:.2f}".format(d.get("credit")).replace(".", ",")
-
-		Idevise = d.get("account_currency")
-
-		if Idevise != company_currency:
-			Montantdevise = (
-				"{:.2f}".format(d.get("debitCurr")).replace(".", ",")
-				if d.get("debitCurr") != 0
-				else "{:.2f}".format(d.get("creditCurr")).replace(".", ",")
-			)
-		else:
-			Montantdevise = (
-				"{:.2f}".format(d.get("debit")).replace(".", ",")
-				if d.get("debit") != 0
-				else "{:.2f}".format(d.get("credit")).replace(".", ",")
-			)
-
-		row = [
-			JournalCode,
-			d.get("voucher_type"),
-			EcritureNum,
-			EcritureDate,
-			CompteNum,
-			d.get("account"),
-			CompAuxNum,
-			CompAuxLib,
-			PieceRef,
-			PieceDate,
-			EcritureLib,
-			debit,
-			credit,
-			"",
-			"",
-			ValidDate,
-			Montantdevise,
-			Idevise,
-		]
-
-		result.append(row)
-
-	return result
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index e274a52..42932ad 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -138,7 +138,7 @@
 			// custom buttons
 
 			frm.add_custom_button(__('Accounts Receivable'), function () {
-				frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name});
+				frappe.set_route('query-report', 'Accounts Receivable', { party_type: "Customer", party: frm.doc.name });
 			}, __('View'));
 
 			frm.add_custom_button(__('Accounting Ledger'), function () {
diff --git a/erpnext/setup/doctype/employee/employee.json b/erpnext/setup/doctype/employee/employee.json
index 6cb4292..1143ccb 100644
--- a/erpnext/setup/doctype/employee/employee.json
+++ b/erpnext/setup/doctype/employee/employee.json
@@ -616,6 +616,7 @@
    "fieldname": "relieving_date",
    "fieldtype": "Date",
    "label": "Relieving Date",
+   "no_copy": 1,
    "mandatory_depends_on": "eval:doc.status == \"Left\"",
    "oldfieldname": "relieving_date",
    "oldfieldtype": "Date"
@@ -822,7 +823,7 @@
  "idx": 24,
  "image_field": "image",
  "links": [],
- "modified": "2023-03-30 15:57:05.174592",
+ "modified": "2023-10-04 10:57:05.174592",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Employee",
@@ -870,4 +871,4 @@
  "sort_order": "DESC",
  "states": [],
  "title_field": "employee_name"
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 2bb479b..6552cd7 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -37,6 +37,12 @@
 			}
 		});
 
+		frm.set_query("wip_composite_asset", "items", function() {
+			return {
+				filters: {'is_composite_asset': 1, 'docstatus': 0 }
+			}
+		});
+
 		frm.set_query("taxes_and_charges", function() {
 			return {
 				filters: {'company': frm.doc.company }
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 912b908..c8a9e3e 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -464,6 +464,7 @@
    "depends_on": "eval:doc.is_subcontracted",
    "fieldname": "supplier_warehouse",
    "fieldtype": "Link",
+   "ignore_user_permissions": 1,
    "label": "Supplier Warehouse",
    "no_copy": 1,
    "oldfieldname": "supplier_warehouse",
@@ -1241,7 +1242,7 @@
  "idx": 261,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-07-04 17:23:17.025390",
+ "modified": "2023-10-01 21:00:44.556816",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt",
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 5eb3656..d7419dc 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -117,6 +117,7 @@
   "accounting_details_section",
   "expense_account",
   "item_tax_rate",
+  "wip_composite_asset",
   "column_break_102",
   "provisional_expense_account",
   "accounting_dimensions_section",
@@ -1056,12 +1057,18 @@
    "fieldname": "add_serial_batch_bundle",
    "fieldtype": "Button",
    "label": "Add Serial / Batch No"
+  },
+  {
+   "fieldname": "wip_composite_asset",
+   "fieldtype": "Link",
+   "label": "WIP Composite Asset",
+   "options": "Asset"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-08-11 16:16:16.504549",
+ "modified": "2023-10-03 21:11:50.547261",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index db71fe2..d3807b0 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -1464,8 +1464,6 @@
 	if not company:
 		company = frappe.get_cached_value("Warehouse", warehouse, "company")
 
-	last_valuation_rate = None
-
 	# Get moving average rate of a specific batch number
 	if warehouse and serial_and_batch_bundle:
 		batch_obj = BatchNoValuation(
@@ -1482,21 +1480,18 @@
 		return batch_obj.get_incoming_rate()
 
 	# Get valuation rate from last sle for the same item and warehouse
-	if not last_valuation_rate or last_valuation_rate[0][0] is None:
-		last_valuation_rate = frappe.db.sql(
-			"""select valuation_rate
-			from `tabStock Ledger Entry` force index (item_warehouse)
-			where
-				item_code = %s
-				AND warehouse = %s
-				AND valuation_rate >= 0
-				AND is_cancelled = 0
-				AND NOT (voucher_no = %s AND voucher_type = %s)
-			order by posting_date desc, posting_time desc, name desc limit 1""",
-			(item_code, warehouse, voucher_no, voucher_type),
-		)
-
-	if last_valuation_rate:
+	if last_valuation_rate := frappe.db.sql(
+		"""select valuation_rate
+		from `tabStock Ledger Entry` force index (item_warehouse)
+		where
+			item_code = %s
+			AND warehouse = %s
+			AND valuation_rate >= 0
+			AND is_cancelled = 0
+			AND NOT (voucher_no = %s AND voucher_type = %s)
+		order by posting_date desc, posting_time desc, name desc limit 1""",
+		(item_code, warehouse, voucher_no, voucher_type),
+	):
 		return flt(last_valuation_rate[0][0])
 
 	# If negative stock allowed, and item delivered without any incoming entry,
diff --git a/erpnext/tests/test_regional.py b/erpnext/tests/test_regional.py
index 2c16def..55c8bb7 100644
--- a/erpnext/tests/test_regional.py
+++ b/erpnext/tests/test_regional.py
@@ -14,6 +14,3 @@
 	def test_regional_overrides(self):
 		frappe.flags.country = "Maldives"
 		self.assertEqual(test_method(), "original")
-
-		frappe.flags.country = "France"
-		self.assertEqual(test_method(), "overridden")