Merge pull request #35091 from ruthra-kumar/cost_center_allocation_splits_roundoff

refactor: button to toggle parent doc cost center preference for rounding adjustment amount
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index f9c9173..3a360c4 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -297,7 +297,7 @@
 		# fixed asset depreciation
 		["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
 		["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
-		["_Test Depreciations", "Expenses", 0, None, None],
+		["_Test Depreciations", "Expenses", 0, "Depreciation", None],
 		["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],
 		# Receivable / Payable Account
 		["_Test Receivable", "Current Assets", 0, "Receivable", None],
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
index 0817187..8ad0bd1 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
@@ -56,7 +56,7 @@
 			select
 				"Payment Entry" as payment_document, name as payment_entry,
 				reference_no as cheque_number, reference_date as cheque_date,
-				if(paid_from=%(account)s, paid_amount, 0) as credit,
+				if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
 				if(paid_from=%(account)s, 0, received_amount) as debit,
 				posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
 				if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index fcbaf32..b441af9 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -281,10 +281,13 @@
 		)
 
 	elif payment_entry.payment_document == "Journal Entry":
-		return frappe.db.get_value(
-			"Journal Entry Account",
-			{"parent": payment_entry.payment_entry, "account": gl_bank_account},
-			"sum(credit_in_account_currency)",
+		return abs(
+			frappe.db.get_value(
+				"Journal Entry Account",
+				{"parent": payment_entry.payment_entry, "account": gl_bank_account},
+				"sum(debit_in_account_currency-credit_in_account_currency)",
+			)
+			or 0
 		)
 
 	elif payment_entry.payment_document == "Expense Claim":
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 089f20b..b31cc32 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -8,7 +8,7 @@
 frappe.ui.form.on("Journal Entry", {
 	setup: function(frm) {
 		frm.add_fetch("bank_account", "account", "account");
-		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger"];
+		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset Depreciation Schedule'];
 	},
 
 	refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 0f8ae4f..34a753f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -69,6 +69,7 @@
 		self.validate_empty_accounts_table()
 		self.set_account_and_party_balance()
 		self.validate_inter_company_accounts()
+		self.validate_depr_entry_voucher_type()
 
 		if self.docstatus == 0:
 			self.apply_tax_withholding()
@@ -130,6 +131,13 @@
 				if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
 					frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
 
+	def validate_depr_entry_voucher_type(self):
+		if (
+			any(d.account_type == "Depreciation" for d in self.get("accounts"))
+			and self.voucher_type != "Depreciation Entry"
+		):
+			frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
+
 	def validate_stock_accounts(self):
 		stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
 		for account in stock_accounts:
@@ -233,25 +241,30 @@
 			self.remove(d)
 
 	def update_asset_value(self):
-		if self.voucher_type != "Depreciation Entry":
+		if self.flags.planned_depr_entry or self.voucher_type != "Depreciation Entry":
 			return
 
-		processed_assets = []
-
 		for d in self.get("accounts"):
 			if (
-				d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets
+				d.reference_type == "Asset"
+				and d.reference_name
+				and d.account_type == "Depreciation"
+				and d.debit
 			):
-				processed_assets.append(d.reference_name)
-
 				asset = frappe.get_doc("Asset", d.reference_name)
 
 				if asset.calculate_depreciation:
-					continue
-
-				depr_value = d.debit or d.credit
-
-				asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value)
+					fb_idx = 1
+					if self.finance_book:
+						for fb_row in asset.get("finance_books"):
+							if fb_row.finance_book == self.finance_book:
+								fb_idx = fb_row.idx
+								break
+					fb_row = asset.get("finance_books")[fb_idx - 1]
+					fb_row.value_after_depreciation -= d.debit
+					fb_row.db_update()
+				else:
+					asset.db_set("value_after_depreciation", asset.value_after_depreciation - d.debit)
 
 				asset.set_status()
 
@@ -316,42 +329,47 @@
 		if self.voucher_type != "Depreciation Entry":
 			return
 
-		processed_assets = []
-
 		for d in self.get("accounts"):
 			if (
-				d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets
+				d.reference_type == "Asset"
+				and d.reference_name
+				and d.account_type == "Depreciation"
+				and d.debit
 			):
-				processed_assets.append(d.reference_name)
-
 				asset = frappe.get_doc("Asset", d.reference_name)
 
 				if asset.calculate_depreciation:
 					je_found = False
 
-					for row in asset.get("finance_books"):
+					for fb_row in asset.get("finance_books"):
 						if je_found:
 							break
 
-						depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
+						depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book)
 
 						for s in depr_schedule or []:
 							if s.journal_entry == self.name:
 								s.db_set("journal_entry", None)
 
-								row.value_after_depreciation += s.depreciation_amount
-								row.db_update()
-
-								asset.set_status()
+								fb_row.value_after_depreciation += d.debit
+								fb_row.db_update()
 
 								je_found = True
 								break
+					if not je_found:
+						fb_idx = 1
+						if self.finance_book:
+							for fb_row in asset.get("finance_books"):
+								if fb_row.finance_book == self.finance_book:
+									fb_idx = fb_row.idx
+									break
+
+						fb_row = asset.get("finance_books")[fb_idx - 1]
+						fb_row.value_after_depreciation += d.debit
+						fb_row.db_update()
 				else:
-					depr_value = d.debit or d.credit
-
-					asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value)
-
-					asset.set_status()
+					asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit)
+				asset.set_status()
 
 	def unlink_inter_company_jv(self):
 		if (
diff --git a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
index 88f1c90..5ebdf61 100644
--- a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
+++ b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.js
@@ -2,6 +2,21 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on("Journal Entry Template", {
+	onload: function(frm) {
+		if(frm.is_new()) {
+			frappe.call({
+				type: "GET",
+				method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
+				callback: function(r){
+					if(r.message) {
+						frm.set_df_property("naming_series", "options", r.message.split("\n"));
+						frm.set_value("naming_series", r.message.split("\n")[0]);
+						frm.refresh_field("naming_series");
+					}
+				}
+			});
+		}
+	},
 	refresh: function(frm) {
 		frappe.model.set_default_values(frm.doc);
 
@@ -19,18 +34,6 @@
 
 			return { filters: filters };
 		});
-
-		frappe.call({
-			type: "GET",
-			method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
-			callback: function(r){
-				if(r.message){
-					frm.set_df_property("naming_series", "options", r.message.split("\n"));
-					frm.set_value("naming_series", r.message.split("\n")[0]);
-					frm.refresh_field("naming_series");
-				}
-			}
-		});
 	},
 	voucher_type: function(frm) {
 		var add_accounts = function(doc, r) {
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index ee4d4d2..24d257f 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -654,6 +654,28 @@
 				self.precision("base_received_amount"),
 			)
 
+	def calculate_base_allocated_amount_for_reference(self, d) -> float:
+		base_allocated_amount = 0
+		if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
+			# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
+			# This is so there are no Exchange Gain/Loss generated for such doctypes
+
+			exchange_rate = 1
+			if self.payment_type == "Receive":
+				exchange_rate = self.source_exchange_rate
+			elif self.payment_type == "Pay":
+				exchange_rate = self.target_exchange_rate
+
+			base_allocated_amount += flt(
+				flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount")
+			)
+		else:
+			base_allocated_amount += flt(
+				flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
+			)
+
+		return base_allocated_amount
+
 	def set_total_allocated_amount(self):
 		if self.payment_type == "Internal Transfer":
 			return
@@ -662,9 +684,7 @@
 		for d in self.get("references"):
 			if d.allocated_amount:
 				total_allocated_amount += flt(d.allocated_amount)
-				base_total_allocated_amount += flt(
-					flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
-				)
+				base_total_allocated_amount += self.calculate_base_allocated_amount_for_reference(d)
 
 		self.total_allocated_amount = abs(total_allocated_amount)
 		self.base_total_allocated_amount = abs(base_total_allocated_amount)
@@ -881,9 +901,7 @@
 					}
 				)
 
-				allocated_amount_in_company_currency = flt(
-					flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("paid_amount")
-				)
+				allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
 
 				gle.update(
 					{
@@ -1693,7 +1711,10 @@
 ):
 	reference_doc = None
 	doc = frappe.get_doc(dt, dn)
-	if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= 99.99:
+	over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
+	if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (
+		100.0 + over_billing_allowance
+	):
 		frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
 
 	if not party_type:
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 67049c4..68f333d 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -51,6 +51,38 @@
 		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
 		self.assertEqual(so_advance_paid, 0)
 
+	def test_payment_against_sales_order_usd_to_inr(self):
+		so = make_sales_order(
+			customer="_Test Customer USD", currency="USD", qty=1, rate=100, do_not_submit=True
+		)
+		so.conversion_rate = 50
+		so.submit()
+		pe = get_payment_entry("Sales Order", so.name)
+		pe.source_exchange_rate = 55
+		pe.received_amount = 5500
+		pe.insert()
+		pe.submit()
+
+		# there should be no difference amount
+		pe.reload()
+		self.assertEqual(pe.difference_amount, 0)
+		self.assertEqual(pe.deductions, [])
+
+		expected_gle = dict(
+			(d[0], d)
+			for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], ["Cash - _TC", 5500.0, 0, None]]
+		)
+
+		self.validate_gl_entries(pe.name, expected_gle)
+
+		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+		self.assertEqual(so_advance_paid, 100)
+
+		pe.cancel()
+
+		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+		self.assertEqual(so_advance_paid, 0)
+
 	def test_payment_entry_for_blocked_supplier_invoice(self):
 		supplier = frappe.get_doc("Supplier", "_Test Supplier")
 		supplier.on_hold = 1
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 62ae857..5d08e8d 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
@@ -205,7 +205,7 @@
 
 		self.assertRaises(frappe.ValidationError, jv1.submit)
 
-	def test_closing_balance_with_dimensions(self):
+	def test_closing_balance_with_dimensions_and_test_reposting_entry(self):
 		frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
 		frappe.db.sql("delete from `tabPeriod Closing Voucher` where company='Test PCV Company'")
 		frappe.db.sql("delete from `tabAccount Closing Balance` where company='Test PCV Company'")
@@ -299,6 +299,24 @@
 		self.assertEqual(cc2_closing_balance.credit, 500)
 		self.assertEqual(cc2_closing_balance.credit_in_account_currency, 500)
 
+		warehouse = frappe.db.get_value("Warehouse", {"company": company}, "name")
+
+		repost_doc = frappe.get_doc(
+			{
+				"doctype": "Repost Item Valuation",
+				"company": company,
+				"posting_date": "2020-03-15",
+				"based_on": "Item and Warehouse",
+				"item_code": "Test Item 1",
+				"warehouse": warehouse,
+			}
+		)
+
+		self.assertRaises(frappe.ValidationError, repost_doc.save)
+
+		repost_doc.posting_date = today()
+		repost_doc.save()
+
 	def make_period_closing_voucher(self, posting_date=None, submit=True):
 		surplus_account = create_account()
 		cost_center = create_cost_center("Test Cost Center 1")
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index b9680df..03abc93 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -15,7 +15,12 @@
 	</div>
 	<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
 	<div>
-		<h5 style="float: left;">{{ _("Customer: ") }} <b>{{filters.party_name[0] }}</b></h5>
+		{% if filters.party[0] == filters.party_name[0] %}
+			<h5 style="float: left;">{{ _("Customer: ") }} <b>{{ filters.party_name[0] }}</b></h5>
+		{% else %}
+			<h5 style="float: left;">{{ _("Customer: ") }} <b>{{ filters.party[0] }}</b></h5>
+			<h5 style="float: left; margin-left:15px">{{ _("Customer Name: ") }} <b>{{filters.party_name[0] }}</b></h5>
+		{% endif %}
 		<h5 style="float: right;">
 			{{ _("Date: ") }}
 			<b>{{ frappe.format(filters.from_date, 'Date')}}
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index 16602d3..e23620f 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -36,6 +36,8 @@
   "terms_and_conditions",
   "section_break_1",
   "enable_auto_email",
+  "column_break_ocfq",
+  "sender",
   "section_break_18",
   "frequency",
   "filter_duration",
@@ -298,10 +300,20 @@
    "fieldname": "show_net_values_in_party_account",
    "fieldtype": "Check",
    "label": "Show Net Values in Party Account"
+  },
+  {
+   "fieldname": "sender",
+   "fieldtype": "Link",
+   "label": "Sender",
+   "options": "Email Account"
+  },
+  {
+   "fieldname": "column_break_ocfq",
+   "fieldtype": "Column Break"
   }
  ],
  "links": [],
- "modified": "2022-11-10 17:44:17.165991",
+ "modified": "2023-04-26 12:46:43.645455",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Process Statement Of Accounts",
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 a482931..b36f33b 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
@@ -334,7 +334,7 @@
 				queue="short",
 				method=frappe.sendmail,
 				recipients=recipients,
-				sender=frappe.session.user,
+				sender=doc.sender or frappe.session.user,
 				cc=cc,
 				subject=subject,
 				message=message,
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json
index 8bffd6a..1749d72 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.json
@@ -27,7 +27,7 @@
   },
   {
    "fieldname": "billing_email",
-   "fieldtype": "Read Only",
+   "fieldtype": "Data",
    "in_list_view": 1,
    "label": "Billing Email"
   },
@@ -41,7 +41,7 @@
  ],
  "istable": 1,
  "links": [],
- "modified": "2023-03-13 00:12:34.508086",
+ "modified": "2023-04-26 13:02:41.964499",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Process Statement Of Accounts Customer",
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index f0146ea..ad3477e 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -215,7 +215,7 @@
 	}
 
 
-def get_lower_deduction_certificate(tax_details, pan_no):
+def get_lower_deduction_certificate(company, tax_details, pan_no):
 	ldc_name = frappe.db.get_value(
 		"Lower Deduction Certificate",
 		{
@@ -223,6 +223,7 @@
 			"tax_withholding_category": tax_details.tax_withholding_category,
 			"valid_from": (">=", tax_details.from_date),
 			"valid_upto": ("<=", tax_details.to_date),
+			"company": company,
 		},
 		"name",
 	)
@@ -255,7 +256,7 @@
 	tax_amount = 0
 
 	if party_type == "Supplier":
-		ldc = get_lower_deduction_certificate(tax_details, pan_no)
+		ldc = get_lower_deduction_certificate(inv.company, tax_details, pan_no)
 		if tax_deducted:
 			net_total = inv.tax_withholding_net_total
 			if ldc:
diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
index 5827697..d67eee3 100644
--- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
+++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
@@ -114,28 +114,6 @@
 			   sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
 			   sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
 		from (SELECT a.asset_category,
-				   ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
-								   ds.depreciation_amount
-							  else
-								   0
-							  end), 0) as accumulated_depreciation_as_on_from_date,
-				   ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
-										and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
-								   ds.depreciation_amount
-							  else
-								   0
-							  end), 0) as depreciation_eliminated_during_the_period,
-				   ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
-										and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
-								   ds.depreciation_amount
-							  else
-								   0
-							  end), 0) as depreciation_amount_during_the_period
-			from `tabAsset` a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
-			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and ads.asset = a.name and ads.docstatus=1 and ads.name = ds.parent and ifnull(ds.journal_entry, '') != ''
-			group by a.asset_category
-			union
-			SELECT a.asset_category,
 				   ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
 								   gle.debit
 							  else
@@ -160,7 +138,7 @@
 				aca.parent = a.asset_category and aca.company_name = %(company)s
 			join `tabCompany` company on
 				company.name = %(company)s
-			where a.docstatus=1 and a.company=%(company)s and a.calculate_depreciation=0 and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
+			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
 			group by a.asset_category
 			union
 			SELECT a.asset_category,
diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
index 306af72..2d68bb7 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
@@ -80,7 +80,7 @@
 	payment_entries = frappe.db.sql(
 		"""SELECT
 			"Payment Entry", name, posting_date, reference_no, clearance_date, party,
-			if(paid_from=%(account)s, paid_amount * -1, received_amount)
+			if(paid_from=%(account)s, ((paid_amount * -1) - total_taxes_and_charges) , received_amount)
 		FROM
 			`tabPayment Entry`
 		WHERE
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js
index e89d429..53921dc 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.js
+++ b/erpnext/accounts/report/gross_profit/gross_profit.js
@@ -73,7 +73,7 @@
 		if (column.fieldname == "sales_invoice" && column.options == "Item" && data && data.indent == 0) {
 			column._options = "Sales Invoice";
 		} else {
-			column._options = "Item";
+			column._options = "";
 		}
 		value = default_formatter(value, row, column, data);
 
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 01fee28..81f5928 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -250,7 +250,7 @@
 				"label": _("Warehouse"),
 				"fieldname": "warehouse",
 				"fieldtype": "Link",
-				"options": "warehouse",
+				"options": "Warehouse",
 				"width": 100,
 			},
 			"qty": {"label": _("Qty"), "fieldname": "qty", "fieldtype": "Float", "width": 80},
@@ -305,7 +305,8 @@
 			"sales_person": {
 				"label": _("Sales Person"),
 				"fieldname": "sales_person",
-				"fieldtype": "Data",
+				"fieldtype": "Link",
+				"options": "Sales Person",
 				"width": 100,
 			},
 			"allocated_amount": {
@@ -326,14 +327,14 @@
 				"label": _("Customer Group"),
 				"fieldname": "customer_group",
 				"fieldtype": "Link",
-				"options": "customer",
+				"options": "Customer Group",
 				"width": 100,
 			},
 			"territory": {
 				"label": _("Territory"),
 				"fieldname": "territory",
 				"fieldtype": "Link",
-				"options": "territory",
+				"options": "Territory",
 				"width": 100,
 			},
 			"monthly": {
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 890872f..0ee06e8 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -1374,10 +1374,7 @@
 		if wh_details.account == account and not wh_details.is_group
 	]
 
-	total_stock_value = 0.0
-	for warehouse in related_warehouses:
-		value = get_stock_value_on(warehouse, posting_date)
-		total_stock_value += value
+	total_stock_value = get_stock_value_on(related_warehouses, posting_date)
 
 	precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
 	return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 6001254..42f5311 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -783,7 +783,7 @@
 	je.voucher_type = "Depreciation Entry"
 	je.naming_series = depreciation_series
 	je.company = asset.company
-	je.remark = "Depreciation Entry against asset {0}".format(asset_name)
+	je.remark = _("Depreciation Entry against asset {0}").format(asset_name)
 
 	je.append(
 		"accounts",
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 028e3d6..f23ae2f 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -157,6 +157,7 @@
 			je.append("accounts", debit_entry)
 
 			je.flags.ignore_permissions = True
+			je.flags.planned_depr_entry = True
 			je.save()
 			if not je.meta.get_workflow():
 				je.submit()
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index cde0280..203612f 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -1511,7 +1511,7 @@
 		)
 
 		self.assertEqual(asset.status, "Submitted")
-		self.assertEqual(asset.get("value_after_depreciation"), 100000)
+		self.assertEqual(asset.get_value_after_depreciation(), 100000)
 
 		jv = make_journal_entry(
 			"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
@@ -1524,12 +1524,68 @@
 		jv.submit()
 
 		asset.reload()
-		self.assertEqual(asset.get("value_after_depreciation"), 99900)
+		self.assertEqual(asset.get_value_after_depreciation(), 99900)
 
 		jv.cancel()
 
 		asset.reload()
-		self.assertEqual(asset.get("value_after_depreciation"), 100000)
+		self.assertEqual(asset.get_value_after_depreciation(), 100000)
+
+	def test_manual_depreciation_for_depreciable_asset(self):
+		asset = create_asset(
+			item_code="Macbook Pro",
+			calculate_depreciation=1,
+			purchase_date="2020-01-30",
+			available_for_use_date="2020-01-30",
+			expected_value_after_useful_life=10000,
+			total_number_of_depreciations=10,
+			frequency_of_depreciation=1,
+			submit=1,
+		)
+
+		self.assertEqual(asset.status, "Submitted")
+		self.assertEqual(asset.get_value_after_depreciation(), 100000)
+
+		jv = make_journal_entry(
+			"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
+		)
+		for d in jv.accounts:
+			d.reference_type = "Asset"
+			d.reference_name = asset.name
+		jv.voucher_type = "Depreciation Entry"
+		jv.insert()
+		jv.submit()
+
+		asset.reload()
+		self.assertEqual(asset.get_value_after_depreciation(), 99900)
+
+		jv.cancel()
+
+		asset.reload()
+		self.assertEqual(asset.get_value_after_depreciation(), 100000)
+
+	def test_manual_depreciation_with_incorrect_jv_voucher_type(self):
+		asset = create_asset(
+			item_code="Macbook Pro",
+			calculate_depreciation=1,
+			purchase_date="2020-01-30",
+			available_for_use_date="2020-01-30",
+			expected_value_after_useful_life=10000,
+			total_number_of_depreciations=10,
+			frequency_of_depreciation=1,
+			submit=1,
+		)
+
+		jv = make_journal_entry(
+			"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
+		)
+		for d in jv.accounts:
+			d.reference_type = "Asset"
+			d.reference_name = asset.name
+			d.account_type = "Depreciation"
+		jv.voucher_type = "Journal Entry"
+
+		self.assertRaises(frappe.ValidationError, jv.insert)
 
 
 def create_asset_data():
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
index 0213328..8426ed4 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -150,7 +150,9 @@
 			if d.depreciation_method in ("Straight Line", "Manual"):
 				end_date = max(s.schedule_date for s in depr_schedule)
 				total_days = date_diff(end_date, self.date)
-				rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
+				rate_per_day = flt(d.value_after_depreciation - d.expected_value_after_useful_life) / flt(
+					total_days
+				)
 				from_date = self.date
 			else:
 				no_of_depreciations = len([s.name for s in depr_schedule if not s.journal_entry])
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
index 65a4226..4f7b836 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
@@ -94,11 +94,11 @@
 			label: __("Finance Book"),
 			fieldtype: "Link",
 			options: "Finance Book",
-			depends_on: "eval: doc.only_depreciable_assets == 1",
+			depends_on: "eval: doc.filter_by_finance_book == 1",
 		},
 		{
-			fieldname:"only_depreciable_assets",
-			label: __("Only depreciable assets"),
+			fieldname:"filter_by_finance_book",
+			label: __("Filter by Finance Book"),
 			fieldtype: "Check"
 		},
 		{
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index 5fbcbe2..984b3fd 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -45,8 +45,6 @@
 		filters.year_end_date = getdate(fiscal_year.year_end_date)
 
 		conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
-	if filters.get("only_depreciable_assets"):
-		conditions["calculate_depreciation"] = filters.get("only_depreciable_assets")
 	if filters.get("only_existing_assets"):
 		conditions["is_existing_asset"] = filters.get("only_existing_assets")
 	if filters.get("asset_category"):
@@ -106,7 +104,7 @@
 
 	assets_linked_to_fb = None
 
-	if filters.only_depreciable_assets:
+	if filters.filter_by_finance_book:
 		assets_linked_to_fb = frappe.db.get_all(
 			doctype="Asset Finance Book",
 			filters={"finance_book": filters.finance_book or ("is", "not set")},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
index d7907e4..6594746 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
@@ -43,7 +43,7 @@
 		});
 
 		listview.page.add_action_item(__("Advance Payment"), ()=>{
-			erpnext.bulk_transaction_processing.create(listview, "Purchase Order", "Advance Payment");
+			erpnext.bulk_transaction_processing.create(listview, "Purchase Order", "Payment Entry");
 		});
 
 	}
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 642d51c..d0ec654 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1662,7 +1662,10 @@
 				)
 				self.append("payment_schedule", data)
 
-		if not automatically_fetch_payment_terms:
+		if not (
+			automatically_fetch_payment_terms
+			and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype)
+		):
 			for d in self.get("payment_schedule"):
 				if d.invoice_portion:
 					d.payment_amount = flt(
@@ -1901,12 +1904,14 @@
 		reconcilation_entry.party = secondary_party
 		reconcilation_entry.reference_type = self.doctype
 		reconcilation_entry.reference_name = self.name
-		reconcilation_entry.cost_center = self.cost_center
+		reconcilation_entry.cost_center = self.cost_center or erpnext.get_default_cost_center(
+			self.company
+		)
 
 		advance_entry.account = primary_account
 		advance_entry.party_type = primary_party_type
 		advance_entry.party = primary_party
-		advance_entry.cost_center = self.cost_center
+		advance_entry.cost_center = self.cost_center or erpnext.get_default_cost_center(self.company)
 		advance_entry.is_advance = "Yes"
 
 		if self.doctype == "Sales Invoice":
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index b0cf724..799fed9 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -576,7 +576,9 @@
 
 @frappe.whitelist()
 @frappe.validate_and_sanitize_search_inputs
-def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters):
+def get_filtered_dimensions(
+	doctype, txt, searchfield, start, page_len, filters, reference_doctype=None
+):
 	from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
 		get_dimension_filter_map,
 	)
@@ -617,7 +619,12 @@
 		query_filters.append(["name", query_selector, dimensions])
 
 	output = frappe.get_list(
-		doctype, fields=fields, filters=query_filters, or_filters=or_filters, as_list=1
+		doctype,
+		fields=fields,
+		filters=query_filters,
+		or_filters=or_filters,
+		as_list=1,
+		reference_doctype=reference_doctype,
 	)
 
 	return [tuple(d) for d in set(output)]
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 479fef7..a27e348 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -329,9 +329,10 @@
 		"""Create batches if required. Called before submit"""
 		for d in self.items:
 			if d.get(warehouse_field) and not d.batch_no:
-				has_batch_no, create_new_batch = frappe.db.get_value(
+				has_batch_no, create_new_batch = frappe.get_cached_value(
 					"Item", d.item_code, ["has_batch_no", "create_new_batch"]
 				)
+
 				if has_batch_no and create_new_batch:
 					d.batch_no = (
 						frappe.get_doc(
@@ -414,7 +415,7 @@
 				"voucher_no": self.name,
 				"voucher_detail_no": d.name,
 				"actual_qty": (self.docstatus == 1 and 1 or -1) * flt(d.get("stock_qty")),
-				"stock_uom": frappe.db.get_value(
+				"stock_uom": frappe.get_cached_value(
 					"Item", args.get("item_code") or d.get("item_code"), "stock_uom"
 				),
 				"incoming_rate": 0,
@@ -609,7 +610,7 @@
 	def validate_customer_provided_item(self):
 		for d in self.get("items"):
 			# Customer Provided parts will have zero valuation rate
-			if frappe.db.get_value("Item", d.item_code, "is_customer_provided_item"):
+			if frappe.get_cached_value("Item", d.item_code, "is_customer_provided_item"):
 				d.allow_zero_valuation_rate = 1
 
 	def set_rate_of_stock_uom(self):
@@ -722,7 +723,7 @@
 		message += _("Please adjust the qty or edit {0} to proceed.").format(rule_link)
 		return message
 
-	def repost_future_sle_and_gle(self):
+	def repost_future_sle_and_gle(self, force=False):
 		args = frappe._dict(
 			{
 				"posting_date": self.posting_date,
@@ -733,7 +734,7 @@
 			}
 		)
 
-		if future_sle_exists(args) or repost_required_for_queue(self):
+		if force or future_sle_exists(args) or repost_required_for_queue(self):
 			item_based_reposting = cint(
 				frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting")
 			)
@@ -894,9 +895,6 @@
 	)
 
 	for d in data:
-		if key not in frappe.local.future_sle:
-			frappe.local.future_sle[key] = frappe._dict({})
-
 		frappe.local.future_sle[key][(d.item_code, d.warehouse)] = d.total_row
 
 	return len(data)
@@ -919,7 +917,7 @@
 
 def get_cached_data(args, key):
 	if key not in frappe.local.future_sle:
-		return False
+		frappe.local.future_sle[key] = frappe._dict({})
 
 	if args.get("item_code"):
 		item_key = (args.get("item_code"), args.get("warehouse"))
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 6a5fead..2a8d65f 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -59,7 +59,7 @@
 			if not self.get(field) and frappe.db.field_exists(self.opportunity_from, field):
 				try:
 					value = frappe.db.get_value(self.opportunity_from, self.party_name, field)
-					self.db_set(field, value)
+					self.set(field, value)
 				except Exception:
 					continue
 
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 7cdcef9..ad9aafe 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -652,7 +652,7 @@
 
 frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) {
 	var d = locals[cdt][cdn];
-
+	if(!d.workstation) return;
 	frappe.call({
 		"method": "frappe.client.get",
 		args: {
diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js
index b480c70..784e83a 100644
--- a/erpnext/manufacturing/doctype/routing/routing.js
+++ b/erpnext/manufacturing/doctype/routing/routing.js
@@ -50,7 +50,7 @@
 
 	workstation: function(frm, cdt, cdn) {
 		const d = locals[cdt][cdn];
-
+		if(!d.workstation) return;
 		frappe.call({
 			"method": "frappe.client.get",
 			args: {
diff --git a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
index de96a6c..38e0585 100644
--- a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
+++ b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py
@@ -69,7 +69,7 @@
 			"label": _("Id"),
 			"fieldname": "name",
 			"fieldtype": "Link",
-			"options": "Work Order",
+			"options": "Quality Inspection",
 			"width": 100,
 		},
 		{"label": _("Report Date"), "fieldname": "report_date", "fieldtype": "Date", "width": 150},
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 74c8af1..03c7b01 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -332,3 +332,4 @@
 erpnext.patches.v14_0.migrate_gl_to_payment_ledger
 execute:frappe.delete_doc_if_exists("Report", "Tax Detail")
 erpnext.patches.v15_0.enable_all_leads
+erpnext.patches.v14_0.update_company_in_ldc
diff --git a/erpnext/patches/v14_0/update_closing_balances.py b/erpnext/patches/v14_0/update_closing_balances.py
index 40a1851..f47e730 100644
--- a/erpnext/patches/v14_0/update_closing_balances.py
+++ b/erpnext/patches/v14_0/update_closing_balances.py
@@ -26,7 +26,15 @@
 			pcv_doc.year_start_date = get_fiscal_year(
 				pcv.posting_date, pcv.fiscal_year, company=pcv.company
 			)[1]
-			gl_entries = pcv_doc.get_gl_entries()
+
+			gl_entries = frappe.db.get_all(
+				"GL Entry", filters={"voucher_no": pcv.name, "is_cancelled": 0}, fields=["*"]
+			)
+			for entry in gl_entries:
+				entry["is_period_closing_voucher_entry"] = 1
+				entry["closing_date"] = pcv_doc.posting_date
+				entry["period_closing_voucher"] = pcv_doc.name
+
 			closing_entries = pcv_doc.get_grouped_gl_entries(get_opening_entries=get_opening_entries)
 			make_closing_entries(gl_entries + closing_entries, voucher_name=pcv.name)
 			company_wise_order[pcv.company].append(pcv.posting_date)
diff --git a/erpnext/patches/v14_0/update_company_in_ldc.py b/erpnext/patches/v14_0/update_company_in_ldc.py
new file mode 100644
index 0000000..ca95cf2
--- /dev/null
+++ b/erpnext/patches/v14_0/update_company_in_ldc.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# License: MIT. See LICENSE
+
+
+import frappe
+
+from erpnext import get_default_company
+
+
+def execute():
+	company = get_default_company()
+	if company:
+		for d in frappe.get_all("Lower Deduction Certificate", pluck="name"):
+			frappe.db.set_value("Lower Deduction Certificate", d, "company", company, update_modified=False)
diff --git a/erpnext/public/js/projects/timer.js b/erpnext/public/js/projects/timer.js
index 9dae711..0209f4c 100644
--- a/erpnext/public/js/projects/timer.js
+++ b/erpnext/public/js/projects/timer.js
@@ -68,7 +68,7 @@
 			// New activity if no activities found
 			var args = dialog.get_values();
 			if(!args) return;
-			if (frm.doc.time_logs.length <= 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) {
+			if (frm.doc.time_logs.length == 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) {
 				frm.doc.time_logs = [];
 			}
 			row = frappe.model.add_child(frm.doc, "Timesheet Detail", "time_logs");
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
index c32ab6b..d332b4e 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
@@ -10,6 +10,7 @@
   "tax_withholding_category",
   "fiscal_year",
   "column_break_3",
+  "company",
   "certificate_no",
   "section_break_3",
   "supplier",
@@ -123,11 +124,18 @@
    "label": "Tax Withholding Category",
    "options": "Tax Withholding Category",
    "reqd": 1
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-10-23 18:33:38.962622",
+ "modified": "2023-04-18 08:25:35.302081",
  "modified_by": "Administrator",
  "module": "Regional",
  "name": "Lower Deduction Certificate",
@@ -136,5 +144,6 @@
  "permissions": [],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index ee9161b..de63f6d 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -547,7 +547,7 @@
 		# qty is for packed items, because packed items don't have stock_qty field
 		qty = source.get("qty")
 		target.project = source_parent.project
-		target.qty = qty - requested_item_qty.get(source.name, 0)
+		target.qty = qty - requested_item_qty.get(source.name, 0) - source.delivered_qty
 		target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
 
 		args = target.as_dict().copy()
@@ -581,7 +581,7 @@
 				"doctype": "Material Request Item",
 				"field_map": {"name": "sales_order_item", "parent": "sales_order"},
 				"condition": lambda doc: not frappe.db.exists("Product Bundle", doc.item_code)
-				and doc.stock_qty > requested_item_qty.get(doc.name, 0),
+				and (doc.stock_qty - doc.delivered_qty) > requested_item_qty.get(doc.name, 0),
 				"postprocess": update_item,
 			},
 		},
@@ -1340,8 +1340,9 @@
 						.select(Sum(wo.qty))
 						.where(
 							(wo.production_item == i.item_code)
-							& (wo.sales_order == so.name) * (wo.sales_order_item == i.name)
-							& (wo.docstatus.lte(2))
+							& (wo.sales_order == so.name)
+							& (wo.sales_order_item == i.name)
+							& (wo.docstatus.lt(2))
 						)
 						.run()[0][0]
 					)
diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js
index 4691190..64c58ef 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_list.js
+++ b/erpnext/selling/doctype/sales_order/sales_order_list.js
@@ -57,7 +57,7 @@
 		});
 
 		listview.page.add_action_item(__("Advance Payment"), ()=>{
-			erpnext.bulk_transaction_processing.create(listview, "Sales Order", "Advance Payment");
+			erpnext.bulk_transaction_processing.create(listview, "Sales Order", "Payment Entry");
 		});
 
 	}
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 627914f..ba8bbc2 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1878,6 +1878,37 @@
 		self.assertEqual(pe.references[1].reference_name, so.name)
 		self.assertEqual(pe.references[1].allocated_amount, 300)
 
+	def test_delivered_item_material_request(self):
+		"SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."
+		from erpnext.manufacturing.doctype.work_order.work_order import (
+			make_stock_entry as make_se_from_wo,
+		)
+		from erpnext.stock.doctype.material_request.material_request import raise_work_orders
+
+		so = make_sales_order(
+			item_list=[
+				{"item_code": "_Test FG Item", "qty": 10, "rate": 100, "warehouse": "Work In Progress - _TC"}
+			]
+		)
+
+		make_stock_entry(
+			item_code="_Test FG Item", target="Work In Progress - _TC", qty=4, basic_rate=100
+		)
+
+		dn = make_delivery_note(so.name)
+		dn.items[0].qty = 4
+		dn.submit()
+
+		so.load_from_db()
+		self.assertEqual(so.items[0].delivered_qty, 4)
+
+		mr = make_material_request(so.name)
+		mr.material_request_type = "Purchase"
+		mr.schedule_date = today()
+		mr.save()
+
+		self.assertEqual(mr.items[0].qty, 6)
+
 
 def automatically_fetch_payment_terms(enable=1):
 	accounts_settings = frappe.get_doc("Accounts Settings")
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 9f9f5cb..c18e851 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -118,7 +118,7 @@
 
 	def so_required(self):
 		"""check in manage account if sales order required or not"""
-		if frappe.db.get_value("Selling Settings", None, "so_required") == "Yes":
+		if frappe.db.get_single_value("Selling Settings", "so_required") == "Yes":
 			for d in self.get("items"):
 				if not d.against_sales_order:
 					frappe.throw(_("Sales Order required for Item {0}").format(d.item_code))
@@ -205,7 +205,7 @@
 		super(DeliveryNote, self).validate_warehouse()
 
 		for d in self.get_item_list():
-			if not d["warehouse"] and frappe.db.get_value("Item", d["item_code"], "is_stock_item") == 1:
+			if not d["warehouse"] and frappe.get_cached_value("Item", d["item_code"], "is_stock_item") == 1:
 				frappe.throw(_("Warehouse required for stock Item {0}").format(d["item_code"]))
 
 	def update_current_stock(self):
@@ -271,6 +271,9 @@
 	def check_credit_limit(self):
 		from erpnext.selling.doctype.customer.customer import check_credit_limit
 
+		if self.per_billed == 100:
+			return
+
 		extra_amount = 0
 		validate_against_credit_limit = False
 		bypass_credit_limit_check_at_sales_order = cint(
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 180adee..e46cab0 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -629,7 +629,8 @@
    "no_copy": 1,
    "options": "Sales Order",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "against_sales_invoice",
@@ -662,7 +663,8 @@
    "label": "Against Sales Invoice Item",
    "no_copy": 1,
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "installed_qty",
@@ -854,7 +856,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-04-06 09:28:29.182053",
+ "modified": "2023-05-01 21:05:14.175640",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index bbed099..aabc6fc 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -6,7 +6,7 @@
 from frappe.exceptions import QueryDeadlockError, QueryTimeoutError
 from frappe.model.document import Document
 from frappe.query_builder import DocType, Interval
-from frappe.query_builder.functions import Now
+from frappe.query_builder.functions import Max, Now
 from frappe.utils import cint, get_link_to_form, get_weekday, getdate, now, nowtime
 from frappe.utils.user import get_users_with_role
 from rq.timeouts import JobTimeoutException
@@ -36,11 +36,38 @@
 		)
 
 	def validate(self):
+		self.validate_period_closing_voucher()
 		self.set_status(write=False)
 		self.reset_field_values()
 		self.set_company()
 		self.validate_accounts_freeze()
 
+	def validate_period_closing_voucher(self):
+		year_end_date = self.get_max_year_end_date(self.company)
+		if year_end_date and getdate(self.posting_date) <= getdate(year_end_date):
+			msg = f"Due to period closing, you cannot repost item valuation before {year_end_date}"
+			frappe.throw(_(msg))
+
+	@staticmethod
+	def get_max_year_end_date(company):
+		data = frappe.get_all(
+			"Period Closing Voucher", fields=["fiscal_year"], filters={"docstatus": 1, "company": company}
+		)
+
+		if not data:
+			return
+
+		fiscal_years = [d.fiscal_year for d in data]
+		table = frappe.qb.DocType("Fiscal Year")
+
+		query = (
+			frappe.qb.from_(table)
+			.select(Max(table.year_end_date))
+			.where((table.name.isin(fiscal_years)) & (table.disabled == 0))
+		).run()
+
+		return query[0][0] if query else None
+
 	def validate_accounts_freeze(self):
 		acc_settings = frappe.db.get_value(
 			"Accounts Settings",
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index ce85702..f3adefb 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -1508,11 +1508,15 @@
 	elif args.get("against_sales_invoice"):
 		sales_order = frappe.db.get_all(
 			"Sales Invoice Item",
-			filters={"parent": args.get("against_sales_invoice"), "item_code": args.get("item_code")},
+			filters={
+				"parent": args.get("against_sales_invoice"),
+				"item_code": args.get("item_code"),
+				"docstatus": 1,
+			},
 			fields="sales_order",
 		)
 		if sales_order and sales_order[0]:
-			if get_reserved_qty_for_so(sales_order[0][0], args.get("item_code")):
+			if get_reserved_qty_for_so(sales_order[0].sales_order, args.get("item_code")):
 				reserved_so = sales_order[0]
 	elif args.get("sales_order"):
 		if get_reserved_qty_for_so(args.get("sales_order"), args.get("item_code")):
diff --git a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
index e9c9608..e4f657c 100644
--- a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
+++ b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py
@@ -84,7 +84,7 @@
 	closing_date = add_days(from_date, -1)
 	for key, stock_data in voucher_wise_dict.items():
 		prev_stock_value = get_stock_value_on(
-			posting_date=closing_date, item_code=key[0], warehouse=key[1]
+			posting_date=closing_date, item_code=key[0], warehouses=key[1]
 		)
 		for data in stock_data:
 			expected_stock_value = prev_stock_value + data.stock_value_difference
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 82fc0df..8b517bf 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -1392,7 +1392,7 @@
 	if not frappe.db.exists(
 		"Repost Item Valuation", {"voucher_no": doc.name, "status": "Queued", "docstatus": "1"}
 	):
-		doc.repost_future_sle_and_gle()
+		doc.repost_future_sle_and_gle(force=True)
 
 
 def get_stock_reco_qty_shift(args):
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index b8c5187..fb52697 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -7,10 +7,11 @@
 
 import frappe
 from frappe import _
-from frappe.query_builder.functions import CombineDatetime
+from frappe.query_builder.functions import CombineDatetime, IfNull, Sum
 from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime
 
 import erpnext
+from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
 from erpnext.stock.valuation import FIFOValuation, LIFOValuation
 
 BarcodeScanResult = Dict[str, Optional[str]]
@@ -53,50 +54,36 @@
 	return stock_value
 
 
-def get_stock_value_on(warehouse=None, posting_date=None, item_code=None):
+def get_stock_value_on(
+	warehouses: list | str = None, posting_date: str = None, item_code: str = None
+) -> float:
 	if not posting_date:
 		posting_date = nowdate()
 
-	values, condition = [posting_date], ""
-
-	if warehouse:
-
-		lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"])
-
-		if is_group:
-			values.extend([lft, rgt])
-			condition += "and exists (\
-				select name from `tabWarehouse` wh where wh.name = sle.warehouse\
-				and wh.lft >= %s and wh.rgt <= %s)"
-
-		else:
-			values.append(warehouse)
-			condition += " AND warehouse = %s"
-
-	if item_code:
-		values.append(item_code)
-		condition += " AND item_code = %s"
-
-	stock_ledger_entries = frappe.db.sql(
-		"""
-		SELECT item_code, stock_value, name, warehouse
-		FROM `tabStock Ledger Entry` sle
-		WHERE posting_date <= %s {0}
-			and is_cancelled = 0
-		ORDER BY timestamp(posting_date, posting_time) DESC, creation DESC
-	""".format(
-			condition
-		),
-		values,
-		as_dict=1,
+	sle = frappe.qb.DocType("Stock Ledger Entry")
+	query = (
+		frappe.qb.from_(sle)
+		.select(IfNull(Sum(sle.stock_value_difference), 0))
+		.where((sle.posting_date <= posting_date) & (sle.is_cancelled == 0))
+		.orderby(CombineDatetime(sle.posting_date, sle.posting_time), order=frappe.qb.desc)
+		.orderby(sle.creation, order=frappe.qb.desc)
 	)
 
-	sle_map = {}
-	for sle in stock_ledger_entries:
-		if not (sle.item_code, sle.warehouse) in sle_map:
-			sle_map[(sle.item_code, sle.warehouse)] = flt(sle.stock_value)
+	if warehouses:
+		if isinstance(warehouses, str):
+			warehouses = [warehouses]
 
-	return sum(sle_map.values())
+		warehouses = set(warehouses)
+		for wh in list(warehouses):
+			if frappe.db.get_value("Warehouse", wh, "is_group"):
+				warehouses.update(get_child_warehouses(wh))
+
+		query = query.where(sle.warehouse.isin(warehouses))
+
+	if item_code:
+		query = query.where(sle.item_code == item_code)
+
+	return query.run(as_list=True)[0][0]
 
 
 @frappe.whitelist()
diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py
index c1579b3..5e57b31 100644
--- a/erpnext/utilities/bulk_transaction.py
+++ b/erpnext/utilities/bulk_transaction.py
@@ -69,7 +69,7 @@
 		"Sales Order": {
 			"Sales Invoice": sales_order.make_sales_invoice,
 			"Delivery Note": sales_order.make_delivery_note,
-			"Advance Payment": payment_entry.get_payment_entry,
+			"Payment Entry": payment_entry.get_payment_entry,
 		},
 		"Sales Invoice": {
 			"Delivery Note": sales_invoice.make_delivery_note,
@@ -86,11 +86,11 @@
 		"Supplier Quotation": {
 			"Purchase Order": supplier_quotation.make_purchase_order,
 			"Purchase Invoice": supplier_quotation.make_purchase_invoice,
-			"Advance Payment": payment_entry.get_payment_entry,
 		},
 		"Purchase Order": {
 			"Purchase Invoice": purchase_order.make_purchase_invoice,
 			"Purchase Receipt": purchase_order.make_purchase_receipt,
+			"Payment Entry": payment_entry.get_payment_entry,
 		},
 		"Purchase Invoice": {
 			"Purchase Receipt": purchase_invoice.make_purchase_receipt,
@@ -98,12 +98,13 @@
 		},
 		"Purchase Receipt": {"Purchase Invoice": purchase_receipt.make_purchase_invoice},
 	}
-	if to_doctype in ["Advance Payment", "Payment Entry"]:
+	if to_doctype in ["Payment Entry"]:
 		obj = mapper[from_doctype][to_doctype](from_doctype, doc_name)
 	else:
 		obj = mapper[from_doctype][to_doctype](doc_name)
 
 	obj.flags.ignore_validate = True
+	obj.set_title_field()
 	obj.insert(ignore_mandatory=True)