Merge pull request #36720 from git-avc/lost_reason_opportunity

fix: lost opportunity reason dialog don't appears
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 2adc123..7b7ce7a 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -163,6 +163,15 @@
 		this.frm.refresh();
 	}
 
+	invoice_name() {
+		this.frm.trigger("get_unreconciled_entries");
+	}
+
+	payment_name() {
+		this.frm.trigger("get_unreconciled_entries");
+	}
+
+
 	clear_child_tables() {
 		this.frm.clear_table("invoices");
 		this.frm.clear_table("payments");
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
index 5f6c703..b88791d 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
@@ -27,8 +27,10 @@
   "bank_cash_account",
   "cost_center",
   "sec_break1",
+  "invoice_name",
   "invoices",
   "column_break_15",
+  "payment_name",
   "payments",
   "sec_break2",
   "allocation"
@@ -137,6 +139,7 @@
    "label": "Minimum Invoice Amount"
   },
   {
+   "default": "50",
    "description": "System will fetch all the entries if limit value is zero.",
    "fieldname": "invoice_limit",
    "fieldtype": "Int",
@@ -167,6 +170,7 @@
    "label": "Maximum Payment Amount"
   },
   {
+   "default": "50",
    "description": "System will fetch all the entries if limit value is zero.",
    "fieldname": "payment_limit",
    "fieldtype": "Int",
@@ -194,13 +198,23 @@
    "label": "Default Advance Account",
    "mandatory_depends_on": "doc.party_type",
    "options": "Account"
+  },
+  {
+   "fieldname": "invoice_name",
+   "fieldtype": "Data",
+   "label": "Filter on Invoice"
+  },
+  {
+   "fieldname": "payment_name",
+   "fieldtype": "Data",
+   "label": "Filter on Payment"
   }
  ],
  "hide_toolbar": 1,
  "icon": "icon-resize-horizontal",
  "issingle": 1,
  "links": [],
- "modified": "2023-06-09 13:02:48.718362",
+ "modified": "2023-08-15 05:35:50.109290",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 3a9e80a..07b46a4 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -5,6 +5,7 @@
 import frappe
 from frappe import _, msgprint, qb
 from frappe.model.document import Document
+from frappe.query_builder import Criterion
 from frappe.query_builder.custom import ConstantColumn
 from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
 
@@ -74,6 +75,9 @@
 			}
 		)
 
+		if self.payment_name:
+			condition.update({"name": self.payment_name})
+
 		payment_entries = get_advance_payment_entries(
 			self.party_type,
 			self.party,
@@ -89,6 +93,9 @@
 	def get_jv_entries(self):
 		condition = self.get_conditions()
 
+		if self.payment_name:
+			condition += f" and t1.name like '%%{self.payment_name}%%'"
+
 		if self.get("cost_center"):
 			condition += f" and t2.cost_center = '{self.cost_center}' "
 
@@ -146,6 +153,15 @@
 	def get_return_invoices(self):
 		voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
 		doc = qb.DocType(voucher_type)
+
+		conditions = []
+		conditions.append(doc.docstatus == 1)
+		conditions.append(doc[frappe.scrub(self.party_type)] == self.party)
+		conditions.append(doc.is_return == 1)
+
+		if self.payment_name:
+			conditions.append(doc.name.like(f"%{self.payment_name}%"))
+
 		self.return_invoices = (
 			qb.from_(doc)
 			.select(
@@ -153,11 +169,7 @@
 				doc.name.as_("voucher_no"),
 				doc.return_against,
 			)
-			.where(
-				(doc.docstatus == 1)
-				& (doc[frappe.scrub(self.party_type)] == self.party)
-				& (doc.is_return == 1)
-			)
+			.where(Criterion.all(conditions))
 			.run(as_dict=True)
 		)
 
@@ -226,6 +238,8 @@
 			min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None,
 			max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None,
 			accounting_dimensions=self.accounting_dimension_filter_conditions,
+			limit=self.invoice_limit,
+			voucher_no=self.invoice_name,
 		)
 
 		cr_dr_notes = (
@@ -401,59 +415,6 @@
 
 		self.get_unreconciled_entries()
 
-	def make_difference_entry(self, row):
-		journal_entry = frappe.new_doc("Journal Entry")
-		journal_entry.voucher_type = "Exchange Gain Or Loss"
-		journal_entry.company = self.company
-		journal_entry.posting_date = nowdate()
-		journal_entry.multi_currency = 1
-
-		party_account_currency = frappe.get_cached_value(
-			"Account", self.receivable_payable_account, "account_currency"
-		)
-		difference_account_currency = frappe.get_cached_value(
-			"Account", row.difference_account, "account_currency"
-		)
-
-		# Account Currency has balance
-		dr_or_cr = "debit" if self.party_type == "Customer" else "credit"
-		reverse_dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
-
-		journal_account = frappe._dict(
-			{
-				"account": self.receivable_payable_account,
-				"party_type": self.party_type,
-				"party": self.party,
-				"account_currency": party_account_currency,
-				"exchange_rate": 0,
-				"cost_center": erpnext.get_default_cost_center(self.company),
-				"reference_type": row.against_voucher_type,
-				"reference_name": row.against_voucher,
-				dr_or_cr: flt(row.difference_amount),
-				dr_or_cr + "_in_account_currency": 0,
-			}
-		)
-
-		journal_entry.append("accounts", journal_account)
-
-		journal_account = frappe._dict(
-			{
-				"account": row.difference_account,
-				"account_currency": difference_account_currency,
-				"exchange_rate": 1,
-				"cost_center": erpnext.get_default_cost_center(self.company),
-				reverse_dr_or_cr + "_in_account_currency": flt(row.difference_amount),
-				reverse_dr_or_cr: flt(row.difference_amount),
-			}
-		)
-
-		journal_entry.append("accounts", journal_account)
-
-		journal_entry.save()
-		journal_entry.submit()
-
-		return journal_entry
-
 	def get_payment_details(self, row, dr_or_cr):
 		return frappe._dict(
 			{
@@ -619,16 +580,6 @@
 
 
 def reconcile_dr_cr_note(dr_cr_notes, company):
-	def get_difference_row(inv):
-		if inv.difference_amount != 0 and inv.difference_account:
-			difference_row = {
-				"account": inv.difference_account,
-				inv.dr_or_cr: abs(inv.difference_amount) if inv.difference_amount > 0 else 0,
-				reconcile_dr_or_cr: abs(inv.difference_amount) if inv.difference_amount < 0 else 0,
-				"cost_center": erpnext.get_default_cost_center(company),
-			}
-			return difference_row
-
 	for inv in dr_cr_notes:
 		voucher_type = "Credit Note" if inv.voucher_type == "Sales Invoice" else "Debit Note"
 
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 6f0b801..ae132eb 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -131,6 +131,7 @@
 			args: { "pos_profile": frm.pos_profile },
 			callback: ({ message: profile }) => {
 				this.update_customer_groups_settings(profile?.customer_groups);
+				this.frm.set_value("company", profile?.company);
 			},
 		});
 	}
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 89a9611..842f159 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -49,6 +49,7 @@
 		self.validate_pos()
 		self.validate_payment_amount()
 		self.validate_loyalty_transaction()
+		self.validate_company_with_pos_company()
 		if self.coupon_code:
 			from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
 
@@ -281,6 +282,14 @@
 			if total_amount_in_payments and total_amount_in_payments < invoice_total:
 				frappe.throw(_("Total payments amount can't be greater than {}").format(-invoice_total))
 
+	def validate_company_with_pos_company(self):
+		if self.company != frappe.db.get_value("POS Profile", self.pos_profile, "company"):
+			frappe.throw(
+				_("Company {} does not match with POS Profile Company {}").format(
+					self.company, frappe.db.get_value("POS Profile", self.pos_profile, "company")
+				)
+			)
+
 	def validate_loyalty_transaction(self):
 		if self.redeem_loyalty_points and (
 			not self.loyalty_redemption_account or not self.loyalty_redemption_cost_center
@@ -359,6 +368,7 @@
 		profile = {}
 		if self.pos_profile:
 			profile = frappe.get_doc("POS Profile", self.pos_profile)
+			self.company = profile.get("company")
 
 		if not self.get("payments") and not for_validate:
 			update_multi_mode_option(self, profile)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 7581366..e5adeae 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -716,6 +716,7 @@
    "fieldtype": "Table",
    "hide_days": 1,
    "hide_seconds": 1,
+   "label": "Items",
    "oldfieldname": "entries",
    "oldfieldtype": "Table",
    "options": "Sales Invoice Item",
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 0d67752..8bd7b5a 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -14,7 +14,7 @@
 from frappe.contacts.doctype.contact.contact import get_contact_details
 from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
 from frappe.model.utils import get_fetch_values
-from frappe.query_builder.functions import Date, Sum
+from frappe.query_builder.functions import Abs, Date, Sum
 from frappe.utils import (
 	add_days,
 	add_months,
@@ -922,35 +922,34 @@
 
 
 def get_partywise_advanced_payment_amount(
-	party_type, posting_date=None, future_payment=0, company=None, party=None, account_type=None
+	party_type, posting_date=None, future_payment=0, company=None, party=None
 ):
-	gle = frappe.qb.DocType("GL Entry")
+	ple = frappe.qb.DocType("Payment Ledger Entry")
 	query = (
-		frappe.qb.from_(gle)
-		.select(gle.party)
+		frappe.qb.from_(ple)
+		.select(ple.party, Abs(Sum(ple.amount).as_("amount")))
 		.where(
-			(gle.party_type.isin(party_type)) & (gle.against_voucher.isnull()) & (gle.is_cancelled == 0)
+			(ple.party_type.isin(party_type))
+			& (ple.amount < 0)
+			& (ple.against_voucher_no == ple.voucher_no)
+			& (ple.delinked == 0)
 		)
-		.groupby(gle.party)
+		.groupby(ple.party)
 	)
-	if account_type == "Receivable":
-		query = query.select(Sum(gle.credit).as_("amount"))
-	else:
-		query = query.select(Sum(gle.debit).as_("amount"))
 
 	if posting_date:
 		if future_payment:
-			query = query.where((gle.posting_date <= posting_date) | (Date(gle.creation) <= posting_date))
+			query = query.where((ple.posting_date <= posting_date) | (Date(ple.creation) <= posting_date))
 		else:
-			query = query.where(gle.posting_date <= posting_date)
+			query = query.where(ple.posting_date <= posting_date)
 
 	if company:
-		query = query.where(gle.company == company)
+		query = query.where(ple.company == company)
 
 	if party:
-		query = query.where(gle.party == party)
+		query = query.where(ple.party == party)
 
-	data = query.run(as_dict=True)
+	data = query.run()
 	if data:
 		return frappe._dict(data)
 
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index f78a840..751063a 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -214,8 +214,8 @@
 		for party_type in self.party_type:
 			if self.filters.get(scrub(party_type)):
 				amount = ple.amount_in_account_currency
-		else:
-			amount = ple.amount
+			else:
+				amount = ple.amount
 		amount_in_account_currency = ple.amount_in_account_currency
 
 		# update voucher
@@ -1090,7 +1090,10 @@
 			.where(
 				(je.company == self.filters.company)
 				& (je.posting_date.lte(self.filters.report_date))
-				& (je.voucher_type == "Exchange Rate Revaluation")
+				& (
+					(je.voucher_type == "Exchange Rate Revaluation")
+					| (je.voucher_type == "Exchange Gain Or Loss")
+				)
 			)
 			.run()
 		)
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 da4c9da..cffc878 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -50,13 +50,12 @@
 				self.filters.show_future_payments,
 				self.filters.company,
 				party=party,
-				account_type=self.account_type,
 			)
 			or {}
 		)
 
 		if self.filters.show_gl_balance:
-			gl_balance_map = get_gl_balance(self.filters.report_date)
+			gl_balance_map = get_gl_balance(self.filters.report_date, self.filters.company)
 
 		for party, party_dict in self.party_total.items():
 			if party_dict.outstanding == 0:
@@ -233,12 +232,12 @@
 		self.add_column(label="Total Amount Due", fieldname="total_due")
 
 
-def get_gl_balance(report_date):
+def get_gl_balance(report_date, company):
 	return frappe._dict(
 		frappe.db.get_all(
 			"GL Entry",
 			fields=["party", "sum(debit -  credit)"],
-			filters={"posting_date": ("<=", report_date), "is_cancelled": 0},
+			filters={"posting_date": ("<=", report_date), "is_cancelled": 0, "company": company},
 			group_by="party",
 			as_list=1,
 		)
diff --git a/erpnext/accounts/report/accounts_receivable_summary/test_accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/test_accounts_receivable_summary.py
new file mode 100644
index 0000000..3ee35a1
--- /dev/null
+++ b/erpnext/accounts/report/accounts_receivable_summary/test_accounts_receivable_summary.py
@@ -0,0 +1,203 @@
+import unittest
+
+import frappe
+from frappe.tests.utils import FrappeTestCase, change_settings
+from frappe.utils import today
+
+from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.report.accounts_receivable_summary.accounts_receivable_summary import execute
+from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
+
+
+class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
+	def setUp(self):
+		self.maxDiff = None
+		self.create_company()
+		self.create_customer()
+		self.create_item()
+		self.clear_old_entries()
+
+	def tearDown(self):
+		frappe.db.rollback()
+
+	def test_01_receivable_summary_output(self):
+		"""
+		Test for Invoices, Paid, Advance and Outstanding
+		"""
+		filters = {
+			"company": self.company,
+			"customer": self.customer,
+			"posting_date": today(),
+			"range1": 30,
+			"range2": 60,
+			"range3": 90,
+			"range4": 120,
+		}
+
+		si = create_sales_invoice(
+			item=self.item,
+			company=self.company,
+			customer=self.customer,
+			debit_to=self.debit_to,
+			posting_date=today(),
+			parent_cost_center=self.cost_center,
+			cost_center=self.cost_center,
+			rate=200,
+			price_list_rate=200,
+		)
+
+		customer_group, customer_territory = frappe.db.get_all(
+			"Customer",
+			filters={"name": self.customer},
+			fields=["customer_group", "territory"],
+			as_list=True,
+		)[0]
+
+		report = execute(filters)
+		rpt_output = report[1]
+		expected_data = {
+			"party_type": "Customer",
+			"advance": 0,
+			"party": self.customer,
+			"invoiced": 200.0,
+			"paid": 0.0,
+			"credit_note": 0.0,
+			"outstanding": 200.0,
+			"range1": 200.0,
+			"range2": 0.0,
+			"range3": 0.0,
+			"range4": 0.0,
+			"range5": 0.0,
+			"total_due": 200.0,
+			"future_amount": 0.0,
+			"sales_person": [],
+			"currency": si.currency,
+			"territory": customer_territory,
+			"customer_group": customer_group,
+		}
+
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+		# simulate advance payment
+		pe = get_payment_entry(si.doctype, si.name)
+		pe.paid_amount = 50
+		pe.references[0].allocated_amount = 0  # this essitially removes the reference
+		pe.save().submit()
+
+		# update expected data with advance
+		expected_data.update(
+			{
+				"advance": 50.0,
+				"outstanding": 150.0,
+				"range1": 150.0,
+				"total_due": 150.0,
+			}
+		)
+
+		report = execute(filters)
+		rpt_output = report[1]
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+		# make partial payment
+		pe = get_payment_entry(si.doctype, si.name)
+		pe.paid_amount = 125
+		pe.references[0].allocated_amount = 125
+		pe.save().submit()
+
+		# update expected data after advance and partial payment
+		expected_data.update(
+			{"advance": 50.0, "paid": 125.0, "outstanding": 25.0, "range1": 25.0, "total_due": 25.0}
+		)
+
+		report = execute(filters)
+		rpt_output = report[1]
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+	@change_settings("Selling Settings", {"cust_master_name": "Naming Series"})
+	def test_02_various_filters_and_output(self):
+		filters = {
+			"company": self.company,
+			"customer": self.customer,
+			"posting_date": today(),
+			"range1": 30,
+			"range2": 60,
+			"range3": 90,
+			"range4": 120,
+		}
+
+		si = create_sales_invoice(
+			item=self.item,
+			company=self.company,
+			customer=self.customer,
+			debit_to=self.debit_to,
+			posting_date=today(),
+			parent_cost_center=self.cost_center,
+			cost_center=self.cost_center,
+			rate=200,
+			price_list_rate=200,
+		)
+		# make partial payment
+		pe = get_payment_entry(si.doctype, si.name)
+		pe.paid_amount = 150
+		pe.references[0].allocated_amount = 150
+		pe.save().submit()
+
+		customer_group, customer_territory = frappe.db.get_all(
+			"Customer",
+			filters={"name": self.customer},
+			fields=["customer_group", "territory"],
+			as_list=True,
+		)[0]
+
+		report = execute(filters)
+		rpt_output = report[1]
+		expected_data = {
+			"party_type": "Customer",
+			"advance": 0,
+			"party": self.customer,
+			"party_name": self.customer,
+			"invoiced": 200.0,
+			"paid": 150.0,
+			"credit_note": 0.0,
+			"outstanding": 50.0,
+			"range1": 50.0,
+			"range2": 0.0,
+			"range3": 0.0,
+			"range4": 0.0,
+			"range5": 0.0,
+			"total_due": 50.0,
+			"future_amount": 0.0,
+			"sales_person": [],
+			"currency": si.currency,
+			"territory": customer_territory,
+			"customer_group": customer_group,
+		}
+
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+		# with gl balance filter
+		filters.update({"show_gl_balance": True})
+		expected_data.update({"gl_balance": 50.0, "diff": 0.0})
+		report = execute(filters)
+		rpt_output = report[1]
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+		# with gl balance and future payments filter
+		filters.update({"show_future_payments": True})
+		expected_data.update({"remaining_balance": 50.0})
+		report = execute(filters)
+		rpt_output = report[1]
+		self.assertEqual(len(rpt_output), 1)
+		self.assertDictEqual(rpt_output[0], expected_data)
+
+		# invoice fully paid
+		pe = get_payment_entry(si.doctype, si.name).save().submit()
+		report = execute(filters)
+		rpt_output = report[1]
+		self.assertEqual(len(rpt_output), 0)
diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py
index 70bbf7e..debfffd 100644
--- a/erpnext/accounts/test/accounts_mixin.py
+++ b/erpnext/accounts/test/accounts_mixin.py
@@ -1,4 +1,5 @@
 import frappe
+from frappe import qb
 
 from erpnext.stock.doctype.item.test_item import create_item
 
@@ -103,3 +104,15 @@
 				)
 				new_acc.save()
 				setattr(self, acc.attribute_name, new_acc.name)
+
+	def clear_old_entries(self):
+		doctype_list = [
+			"GL Entry",
+			"Payment Ledger Entry",
+			"Sales Invoice",
+			"Purchase Invoice",
+			"Payment Entry",
+			"Journal Entry",
+		]
+		for doctype in doctype_list:
+			qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run()
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index bccf6f1..9d6d0f9 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -908,7 +908,9 @@
 	min_outstanding=None,
 	max_outstanding=None,
 	accounting_dimensions=None,
-	vouchers=None,
+	vouchers=None, # list of dicts [{'voucher_type': '', 'voucher_no': ''}] for filtering
+	limit=None, # passed by reconciliation tool
+	voucher_no=None, # filter passed by reconciliation tool
 ):
 
 	ple = qb.DocType("Payment Ledger Entry")
@@ -941,6 +943,8 @@
 		max_outstanding=max_outstanding,
 		get_invoices=True,
 		accounting_dimensions=accounting_dimensions or [],
+		limit=limit,
+		voucher_no=voucher_no,
 	)
 
 	for d in invoice_list:
@@ -1678,12 +1682,13 @@
 		self.voucher_posting_date = []
 		self.min_outstanding = None
 		self.max_outstanding = None
+		self.limit = self.voucher_no = None
 
 	def reset(self):
 		# clear filters
 		self.vouchers.clear()
 		self.common_filter.clear()
-		self.min_outstanding = self.max_outstanding = None
+		self.min_outstanding = self.max_outstanding = self.limit = None
 
 		# clear result
 		self.voucher_outstandings.clear()
@@ -1697,6 +1702,7 @@
 
 		filter_on_voucher_no = []
 		filter_on_against_voucher_no = []
+
 		if self.vouchers:
 			voucher_types = set([x.voucher_type for x in self.vouchers])
 			voucher_nos = set([x.voucher_no for x in self.vouchers])
@@ -1707,6 +1713,10 @@
 			filter_on_against_voucher_no.append(ple.against_voucher_type.isin(voucher_types))
 			filter_on_against_voucher_no.append(ple.against_voucher_no.isin(voucher_nos))
 
+		if self.voucher_no:
+			filter_on_voucher_no.append(ple.voucher_no.like(f"%{self.voucher_no}%"))
+			filter_on_against_voucher_no.append(ple.against_voucher_no.like(f"%{self.voucher_no}%"))
+
 		# build outstanding amount filter
 		filter_on_outstanding_amount = []
 		if self.min_outstanding:
@@ -1822,6 +1832,11 @@
 				)
 			)
 
+		if self.limit:
+			self.cte_query_voucher_amount_and_outstanding = (
+				self.cte_query_voucher_amount_and_outstanding.limit(self.limit)
+			)
+
 		# execute SQL
 		self.voucher_outstandings = self.cte_query_voucher_amount_and_outstanding.run(as_dict=True)
 
@@ -1835,6 +1850,8 @@
 		get_payments=False,
 		get_invoices=False,
 		accounting_dimensions=None,
+		limit=None,
+		voucher_no=None,
 	):
 		"""
 		Fetch voucher amount and outstanding amount from Payment Ledger using Database CTE
@@ -1856,6 +1873,8 @@
 		self.max_outstanding = max_outstanding
 		self.get_payments = get_payments
 		self.get_invoices = get_invoices
+		self.limit = limit
+		self.voucher_no = voucher_no
 		self.query_for_outstanding()
 
 		return self.voucher_outstandings
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 0a2f61d..962292b 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -228,15 +228,19 @@
 				{name: __("Schedule Date"), editable: false, resizable: false, width: 270},
 				{name: __("Depreciation Amount"), editable: false, resizable: false, width: 164},
 				{name: __("Accumulated Depreciation Amount"), editable: false, resizable: false, width: 164},
-				{name: __("Journal Entry"), editable: false, resizable: false, format: value => `<a href="/app/journal-entry/${value}">${value}</a>`, width: 312}
+				{name: __("Journal Entry"), editable: false, resizable: false, format: value => `<a href="/app/journal-entry/${value}">${value}</a>`, width: 304}
 			],
 			data: data,
+			layout: "fluid",
 			serialNoColumn: false,
 			checkboxColumn: true,
 			cellHeight: 35
 		});
 
-		datatable.style.setStyle(`.dt-scrollable`, {'font-size': '0.75rem', 'margin-bottom': '1rem'});
+		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`, {'color': 'var(--text-color)'});
 		datatable.style.setStyle(`.dt-cell--col-1`, {'text-align': 'center'});
 		datatable.style.setStyle(`.dt-cell--col-2`, {'font-weight': 600});
 		datatable.style.setStyle(`.dt-cell--col-3`, {'font-weight': 600});
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 2060c6c..ddb09c1 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -56,7 +56,6 @@
 
 	def on_submit(self):
 		self.validate_in_use_date()
-		self.set_status()
 		self.make_asset_movement()
 		if not self.booked_fixed_asset and self.validate_make_gl_entry():
 			self.make_gl_entries()
@@ -72,6 +71,7 @@
 						"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
 					).format(asset_depr_schedules_links)
 				)
+		self.set_status()
 		add_asset_activity(self.name, _("Asset submitted"))
 
 	def on_cancel(self):
@@ -96,11 +96,14 @@
 					"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
 				).format(asset_depr_schedules_links)
 			)
-		if not frappe.db.exists(
-			{
-				"doctype": "Asset Activity",
-				"asset": self.name,
-			}
+		if (
+			not frappe.db.exists(
+				{
+					"doctype": "Asset Activity",
+					"asset": self.name,
+				}
+			)
+			and not self.flags.asset_created_via_asset_capitalization
 		):
 			add_asset_activity(self.name, _("Asset created"))
 
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index cd66f1d..90eae2d 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -19,6 +19,7 @@
 from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
 from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
 from erpnext.assets.doctype.asset.asset import (
+	get_asset_value_after_depreciation,
 	make_sales_invoice,
 	split_asset,
 	update_maintenance_status,
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 324b739..0bf2fbb 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -509,6 +509,7 @@
 		asset_doc.gross_purchase_amount = total_target_asset_value
 		asset_doc.purchase_receipt_amount = total_target_asset_value
 		asset_doc.flags.ignore_validate = True
+		asset_doc.flags.asset_created_via_asset_capitalization = True
 		asset_doc.insert()
 
 		self.target_asset = asset_doc.name
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 39ebd4e..83350aa 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -107,7 +107,7 @@
 			have_asset_details_been_modified, not_manual_depr_or_have_manual_depr_details_been_modified
 		):
 			self.make_depr_schedule(asset_doc, row, date_of_disposal, update_asset_finance_book_row)
-			self.set_accumulated_depreciation(row, date_of_disposal, date_of_return)
+			self.set_accumulated_depreciation(asset_doc, row, date_of_disposal, date_of_return)
 
 	def have_asset_details_been_modified(self, asset_doc):
 		return (
@@ -157,7 +157,12 @@
 		self.status = "Draft"
 
 	def make_depr_schedule(
-		self, asset_doc, row, date_of_disposal, update_asset_finance_book_row=True
+		self,
+		asset_doc,
+		row,
+		date_of_disposal,
+		update_asset_finance_book_row=True,
+		value_after_depreciation=None,
 	):
 		if not self.get("depreciation_schedule"):
 			self.depreciation_schedule = []
@@ -167,7 +172,9 @@
 
 		start = self.clear_depr_schedule()
 
-		self._make_depr_schedule(asset_doc, row, start, date_of_disposal, update_asset_finance_book_row)
+		self._make_depr_schedule(
+			asset_doc, row, start, date_of_disposal, update_asset_finance_book_row, value_after_depreciation
+		)
 
 	def clear_depr_schedule(self):
 		start = 0
@@ -187,23 +194,30 @@
 		return start
 
 	def _make_depr_schedule(
-		self, asset_doc, row, start, date_of_disposal, update_asset_finance_book_row
+		self,
+		asset_doc,
+		row,
+		start,
+		date_of_disposal,
+		update_asset_finance_book_row,
+		value_after_depreciation,
 	):
 		asset_doc.validate_asset_finance_books(row)
 
-		value_after_depreciation = _get_value_after_depreciation_for_making_schedule(asset_doc, row)
+		if not value_after_depreciation:
+			value_after_depreciation = _get_value_after_depreciation_for_making_schedule(asset_doc, row)
 		row.value_after_depreciation = value_after_depreciation
 
 		if update_asset_finance_book_row:
 			row.db_update()
 
-		number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint(
+		final_number_of_depreciations = cint(row.total_number_of_depreciations) - cint(
 			self.number_of_depreciations_booked
 		)
 
 		has_pro_rata = _check_is_pro_rata(asset_doc, row)
 		if has_pro_rata:
-			number_of_pending_depreciations += 1
+			final_number_of_depreciations += 1
 
 		has_wdv_or_dd_non_yearly_pro_rata = False
 		if (
@@ -219,7 +233,9 @@
 
 		depreciation_amount = 0
 
-		for n in range(start, number_of_pending_depreciations):
+		number_of_pending_depreciations = final_number_of_depreciations - start
+
+		for n in range(start, final_number_of_depreciations):
 			# If depreciation is already completed (for double declining balance)
 			if skip_row:
 				continue
@@ -236,10 +252,11 @@
 				n,
 				prev_depreciation_amount,
 				has_wdv_or_dd_non_yearly_pro_rata,
+				number_of_pending_depreciations,
 			)
 
 			if not has_pro_rata or (
-				n < (cint(number_of_pending_depreciations) - 1) or number_of_pending_depreciations == 2
+				n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2
 			):
 				schedule_date = add_months(
 					row.depreciation_start_date, n * cint(row.frequency_of_depreciation)
@@ -310,7 +327,7 @@
 				)
 
 			# For last row
-			elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
+			elif has_pro_rata and n == cint(final_number_of_depreciations) - 1:
 				if not asset_doc.flags.increase_in_asset_life:
 					# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
 					asset_doc.to_date = add_months(
@@ -343,7 +360,7 @@
 			# Adjust depreciation amount in the last period based on the expected value after useful life
 			if row.expected_value_after_useful_life and (
 				(
-					n == cint(number_of_pending_depreciations) - 1
+					n == cint(final_number_of_depreciations) - 1
 					and value_after_depreciation != row.expected_value_after_useful_life
 				)
 				or value_after_depreciation < row.expected_value_after_useful_life
@@ -392,6 +409,7 @@
 
 	def set_accumulated_depreciation(
 		self,
+		asset_doc,
 		row,
 		date_of_disposal=None,
 		date_of_return=None,
@@ -403,13 +421,21 @@
 			if self.depreciation_method == "Straight Line" or self.depreciation_method == "Manual"
 		]
 
-		accumulated_depreciation = flt(self.opening_accumulated_depreciation)
+		accumulated_depreciation = None
 		value_after_depreciation = flt(row.value_after_depreciation)
 
 		for i, d in enumerate(self.get("depreciation_schedule")):
 			if ignore_booked_entry and d.journal_entry:
 				continue
 
+			if not accumulated_depreciation:
+				if i > 0 and asset_doc.flags.decrease_in_asset_value_due_to_value_adjustment:
+					accumulated_depreciation = self.get("depreciation_schedule")[
+						i - 1
+					].accumulated_depreciation_amount
+				else:
+					accumulated_depreciation = flt(self.opening_accumulated_depreciation)
+
 			depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
 			value_after_depreciation -= flt(depreciation_amount)
 
@@ -507,9 +533,12 @@
 	schedule_idx=0,
 	prev_depreciation_amount=0,
 	has_wdv_or_dd_non_yearly_pro_rata=False,
+	number_of_pending_depreciations=0,
 ):
 	if fb_row.depreciation_method in ("Straight Line", "Manual"):
-		return get_straight_line_or_manual_depr_amount(asset, fb_row, schedule_idx)
+		return get_straight_line_or_manual_depr_amount(
+			asset, fb_row, schedule_idx, number_of_pending_depreciations
+		)
 	else:
 		rate_of_depreciation = get_updated_rate_of_depreciation_for_wdv_and_dd(
 			asset, depreciable_value, fb_row
@@ -529,7 +558,9 @@
 	return fb_row.rate_of_depreciation
 
 
-def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx):
+def get_straight_line_or_manual_depr_amount(
+	asset, row, schedule_idx, number_of_pending_depreciations
+):
 	# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
 	if asset.flags.increase_in_asset_life:
 		return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
@@ -540,6 +571,36 @@
 		return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt(
 			row.total_number_of_depreciations
 		)
+	# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
+	elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
+		if row.daily_depreciation:
+			daily_depr_amount = (
+				flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+			) / date_diff(
+				add_months(
+					row.depreciation_start_date,
+					flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
+					* row.frequency_of_depreciation,
+				),
+				add_months(
+					row.depreciation_start_date,
+					flt(
+						row.total_number_of_depreciations
+						- asset.number_of_depreciations_booked
+						- number_of_pending_depreciations
+					)
+					* row.frequency_of_depreciation,
+				),
+			)
+			to_date = add_months(row.depreciation_start_date, schedule_idx * row.frequency_of_depreciation)
+			from_date = add_months(
+				row.depreciation_start_date, (schedule_idx - 1) * row.frequency_of_depreciation
+			)
+			return daily_depr_amount * date_diff(to_date, from_date)
+		else:
+			return (
+				flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+			) / number_of_pending_depreciations
 	# if the Depreciation Schedule is being prepared for the first time
 	else:
 		if row.daily_depreciation:
@@ -669,7 +730,12 @@
 
 
 def make_new_active_asset_depr_schedules_and_cancel_current_ones(
-	asset_doc, notes, date_of_disposal=None, date_of_return=None
+	asset_doc,
+	notes,
+	date_of_disposal=None,
+	date_of_return=None,
+	value_after_depreciation=None,
+	ignore_booked_entry=False,
 ):
 	for row in asset_doc.get("finance_books"):
 		current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
@@ -695,8 +761,12 @@
 			row.rate_of_depreciation = new_rate_of_depreciation
 			new_asset_depr_schedule_doc.rate_of_depreciation = new_rate_of_depreciation
 
-		new_asset_depr_schedule_doc.make_depr_schedule(asset_doc, row, date_of_disposal)
-		new_asset_depr_schedule_doc.set_accumulated_depreciation(row, date_of_disposal, date_of_return)
+		new_asset_depr_schedule_doc.make_depr_schedule(
+			asset_doc, row, date_of_disposal, value_after_depreciation=value_after_depreciation
+		)
+		new_asset_depr_schedule_doc.set_accumulated_depreciation(
+			asset_doc, row, date_of_disposal, date_of_return, ignore_booked_entry
+		)
 
 		new_asset_depr_schedule_doc.notes = notes
 
@@ -709,9 +779,20 @@
 def get_temp_asset_depr_schedule_doc(
 	asset_doc, row, date_of_disposal=None, date_of_return=None, update_asset_finance_book_row=False
 ):
-	asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
+	current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+		asset_doc.name, "Active", row.finance_book
+	)
 
-	asset_depr_schedule_doc.prepare_draft_asset_depr_schedule_data(
+	if not current_asset_depr_schedule_doc:
+		frappe.throw(
+			_("Asset Depreciation Schedule not found for Asset {0} and Finance Book {1}").format(
+				asset_doc.name, row.finance_book
+			)
+		)
+
+	temp_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+
+	temp_asset_depr_schedule_doc.prepare_draft_asset_depr_schedule_data(
 		asset_doc,
 		row,
 		date_of_disposal,
@@ -719,7 +800,7 @@
 		update_asset_finance_book_row,
 	)
 
-	return asset_depr_schedule_doc
+	return temp_asset_depr_schedule_doc
 
 
 @frappe.whitelist()
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 823b6e9..9be7243 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import date_diff, flt, formatdate, get_link_to_form, getdate
+from frappe.utils import flt, formatdate, get_link_to_form, getdate
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_checks_for_pl_and_bs_accounts,
@@ -14,8 +14,7 @@
 from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
 from erpnext.assets.doctype.asset_activity.asset_activity import add_asset_activity
 from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
-	get_asset_depr_schedule_doc,
-	get_depreciation_amount,
+	make_new_active_asset_depr_schedules_and_cancel_current_ones,
 )
 
 
@@ -27,7 +26,7 @@
 
 	def on_submit(self):
 		self.make_depreciation_entry()
-		self.reschedule_depreciations(self.new_asset_value)
+		self.update_asset(self.new_asset_value)
 		add_asset_activity(
 			self.asset,
 			_("Asset's value adjusted after submission of Asset Value Adjustment {0}").format(
@@ -36,7 +35,7 @@
 		)
 
 	def on_cancel(self):
-		self.reschedule_depreciations(self.current_asset_value)
+		self.update_asset(self.current_asset_value)
 		add_asset_activity(
 			self.asset,
 			_("Asset's value adjusted after cancellation of Asset Value Adjustment {0}").format(
@@ -124,73 +123,33 @@
 
 		self.db_set("journal_entry", je.name)
 
-	def reschedule_depreciations(self, asset_value):
+	def update_asset(self, asset_value):
 		asset = frappe.get_doc("Asset", self.asset)
-		country = frappe.get_value("Company", self.company, "country")
 
-		for d in asset.finance_books:
-			d.value_after_depreciation = asset_value
+		if not asset.calculate_depreciation:
+			asset.value_after_depreciation = asset_value
+			asset.save()
+			return
 
-			current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
-				asset.name, "Active", d.finance_book
+		asset.flags.decrease_in_asset_value_due_to_value_adjustment = True
+
+		if self.docstatus == 1:
+			notes = _(
+				"This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}."
+			).format(
+				get_link_to_form("Asset", asset.name),
+				get_link_to_form(self.get("doctype"), self.get("name")),
+			)
+		elif self.docstatus == 2:
+			notes = _(
+				"This schedule was created when Asset {0}'s Asset Value Adjustment {1} was cancelled."
+			).format(
+				get_link_to_form("Asset", asset.name),
+				get_link_to_form(self.get("doctype"), self.get("name")),
 			)
 
-			new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
-			new_asset_depr_schedule_doc.status = "Draft"
-			new_asset_depr_schedule_doc.docstatus = 0
-
-			current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
-			current_asset_depr_schedule_doc.cancel()
-
-			if self.docstatus == 1:
-				notes = _(
-					"This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}."
-				).format(
-					get_link_to_form(asset.doctype, asset.name),
-					get_link_to_form(self.get("doctype"), self.get("name")),
-				)
-			elif self.docstatus == 2:
-				notes = _(
-					"This schedule was created when Asset {0}'s Asset Value Adjustment {1} was cancelled."
-				).format(
-					get_link_to_form(asset.doctype, asset.name),
-					get_link_to_form(self.get("doctype"), self.get("name")),
-				)
-			new_asset_depr_schedule_doc.notes = notes
-
-			new_asset_depr_schedule_doc.insert()
-
-			depr_schedule = new_asset_depr_schedule_doc.get("depreciation_schedule")
-
-			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 - 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])
-
-			value_after_depreciation = d.value_after_depreciation
-			for data in depr_schedule:
-				if not data.journal_entry:
-					if d.depreciation_method in ("Straight Line", "Manual"):
-						days = date_diff(data.schedule_date, from_date)
-						depreciation_amount = days * rate_per_day
-						from_date = data.schedule_date
-					else:
-						depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, d)
-
-					if depreciation_amount:
-						value_after_depreciation -= flt(depreciation_amount)
-						data.depreciation_amount = depreciation_amount
-
-			d.db_update()
-
-			new_asset_depr_schedule_doc.set_accumulated_depreciation(d, ignore_booked_entry=True)
-			for asset_data in depr_schedule:
-				if not asset_data.journal_entry:
-					asset_data.db_update()
-
-			new_asset_depr_schedule_doc.submit()
+		make_new_active_asset_depr_schedules_and_cancel_current_ones(
+			asset, notes, value_after_depreciation=asset_value, ignore_booked_entry=True
+		)
+		asset.flags.ignore_validate_update_after_submit = True
+		asset.save()
diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
index 0b3dcba..5d49759 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
@@ -4,9 +4,10 @@
 import unittest
 
 import frappe
-from frappe.utils import add_days, get_last_day, nowdate
+from frappe.utils import add_days, cstr, get_last_day, getdate, nowdate
 
 from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation
+from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries
 from erpnext.assets.doctype.asset.test_asset import create_asset_data
 from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
 	get_asset_depr_schedule_doc,
@@ -49,27 +50,23 @@
 
 	def test_asset_depreciation_value_adjustment(self):
 		pr = make_purchase_receipt(
-			item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location"
+			item_code="Macbook Pro", qty=1, rate=120000.0, location="Test Location"
 		)
 
 		asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
 		asset_doc = frappe.get_doc("Asset", asset_name)
 		asset_doc.calculate_depreciation = 1
+		asset_doc.available_for_use_date = "2023-01-15"
+		asset_doc.purchase_date = "2023-01-15"
 
-		month_end_date = get_last_day(nowdate())
-		purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
-
-		asset_doc.available_for_use_date = purchase_date
-		asset_doc.purchase_date = purchase_date
-		asset_doc.calculate_depreciation = 1
 		asset_doc.append(
 			"finance_books",
 			{
 				"expected_value_after_useful_life": 200,
 				"depreciation_method": "Straight Line",
-				"total_number_of_depreciations": 3,
-				"frequency_of_depreciation": 10,
-				"depreciation_start_date": month_end_date,
+				"total_number_of_depreciations": 12,
+				"frequency_of_depreciation": 1,
+				"depreciation_start_date": "2023-01-31",
 			},
 		)
 		asset_doc.submit()
@@ -77,9 +74,15 @@
 		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
 		self.assertEquals(first_asset_depr_schedule.status, "Active")
 
+		post_depreciation_entries(getdate("2023-08-21"))
+
 		current_value = get_asset_value_after_depreciation(asset_doc.name)
+
 		adj_doc = make_asset_value_adjustment(
-			asset=asset_doc.name, current_asset_value=current_value, new_asset_value=50000.0
+			asset=asset_doc.name,
+			current_asset_value=current_value,
+			new_asset_value=50000.0,
+			date="2023-08-21",
 		)
 		adj_doc.submit()
 
@@ -90,8 +93,8 @@
 		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
 
 		expected_gle = (
-			("_Test Accumulated Depreciations - _TC", 0.0, 50000.0),
-			("_Test Depreciations - _TC", 50000.0, 0.0),
+			("_Test Accumulated Depreciations - _TC", 0.0, 4625.29),
+			("_Test Depreciations - _TC", 4625.29, 0.0),
 		)
 
 		gle = frappe.db.sql(
@@ -103,6 +106,29 @@
 
 		self.assertSequenceEqual(gle, expected_gle)
 
+		expected_schedules = [
+			["2023-01-31", 5474.73, 5474.73],
+			["2023-02-28", 9983.33, 15458.06],
+			["2023-03-31", 9983.33, 25441.39],
+			["2023-04-30", 9983.33, 35424.72],
+			["2023-05-31", 9983.33, 45408.05],
+			["2023-06-30", 9983.33, 55391.38],
+			["2023-07-31", 9983.33, 65374.71],
+			["2023-08-31", 8300.0, 73674.71],
+			["2023-09-30", 8300.0, 81974.71],
+			["2023-10-31", 8300.0, 90274.71],
+			["2023-11-30", 8300.0, 98574.71],
+			["2023-12-31", 8300.0, 106874.71],
+			["2024-01-15", 8300.0, 115174.71],
+		]
+
+		schedules = [
+			[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+			for d in second_asset_depr_schedule.get("depreciation_schedule")
+		]
+
+		self.assertEqual(schedules, expected_schedules)
+
 
 def make_asset_value_adjustment(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 7c33056..f6a1951 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -185,8 +185,7 @@
 
 			if(!in_list(["Closed", "Delivered"], doc.status)) {
 				if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received, 2) < 100 && flt(this.frm.doc.per_billed, 2) < 100) {
-					// Don't add Update Items button if the PO is following the new subcontracting flow.
-					if (!(this.frm.doc.is_subcontracted && !this.frm.doc.is_old_subcontracting_flow)) {
+					if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) {
 						this.frm.add_custom_button(__('Update Items'), () => {
 							erpnext.utils.update_child_items({
 								frm: this.frm,
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 06b9d29..3576cd4 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -52,6 +52,7 @@
 	def onload(self):
 		supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
 		self.set_onload("supplier_tds", supplier_tds)
+		self.set_onload("can_update_items", self.can_update_items())
 
 	def validate(self):
 		super(PurchaseOrder, self).validate()
@@ -450,6 +451,17 @@
 		else:
 			self.db_set("per_received", 0, update_modified=False)
 
+	def can_update_items(self) -> bool:
+		result = True
+
+		if self.is_subcontracted and not self.is_old_subcontracting_flow:
+			if frappe.db.exists(
+				"Subcontracting Order", {"purchase_order": self.name, "docstatus": ["!=", 2]}
+			):
+				result = False
+
+		return result
+
 
 def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor=1.0):
 	"""get last purchase rate for an item"""
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 3edaffa..55c01e8 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -901,6 +901,71 @@
 
 		self.assertRaises(frappe.ValidationError, po.save)
 
+	def test_update_items_for_subcontracting_purchase_order(self):
+		from erpnext.controllers.tests.test_subcontracting_controller import (
+			get_subcontracting_order,
+			make_bom_for_subcontracted_items,
+			make_raw_materials,
+			make_service_items,
+			make_subcontracted_items,
+		)
+
+		def update_items(po, qty):
+			trans_items = [po.items[0].as_dict()]
+			trans_items[0]["qty"] = qty
+			trans_items[0]["fg_item_qty"] = qty
+			trans_items = json.dumps(trans_items, default=str)
+
+			return update_child_qty_rate(
+				po.doctype,
+				trans_items,
+				po.name,
+			)
+
+		make_subcontracted_items()
+		make_raw_materials()
+		make_service_items()
+		make_bom_for_subcontracted_items()
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 7",
+				"qty": 10,
+				"rate": 100,
+				"fg_item": "Subcontracted Item SA7",
+				"fg_item_qty": 10,
+			},
+		]
+		po = create_purchase_order(
+			rm_items=service_items,
+			is_subcontracted=1,
+			supplier_warehouse="_Test Warehouse 1 - _TC",
+		)
+
+		update_items(po, qty=20)
+		po.reload()
+
+		# Test - 1: Items should be updated as there is no Subcontracting Order against PO
+		self.assertEqual(po.items[0].qty, 20)
+		self.assertEqual(po.items[0].fg_item_qty, 20)
+
+		sco = get_subcontracting_order(po_name=po.name, warehouse="_Test Warehouse - _TC")
+
+		# Test - 2: ValidationError should be raised as there is Subcontracting Order against PO
+		self.assertRaises(frappe.ValidationError, update_items, po=po, qty=30)
+
+		sco.reload()
+		sco.cancel()
+		po.reload()
+
+		update_items(po, qty=30)
+		po.reload()
+
+		# Test - 3: Items should be updated as the Subcontracting Order is cancelled
+		self.assertEqual(po.items[0].qty, 30)
+		self.assertEqual(po.items[0].fg_item_qty, 30)
+
 
 def prepare_data_for_internal_transfer():
 	from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index fbfc1ac..06dbd86 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -25,6 +25,7 @@
   "col_break_email_1",
   "html_llwp",
   "send_attached_files",
+  "send_document_print",
   "sec_break_email_2",
   "message_for_supplier",
   "terms_section_break",
@@ -283,13 +284,21 @@
    "fieldname": "send_attached_files",
    "fieldtype": "Check",
    "label": "Send Attached Files"
+  },
+  {
+   "default": "0",
+   "description": "If enabled, a print of this document will be attached to each email",
+   "fieldname": "send_document_print",
+   "fieldtype": "Check",
+   "label": "Send Document Print",
+   "print_hide": 1
   }
  ],
  "icon": "fa fa-shopping-cart",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-08-08 16:30:10.870429",
+ "modified": "2023-08-09 12:20:26.850623",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Request for Quotation",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index 56840c1..6b39982 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -205,10 +205,24 @@
 		if preview:
 			return {"message": message, "subject": subject}
 
-		attachments = None
+		attachments = []
 		if self.send_attached_files:
 			attachments = self.get_attachments()
 
+		if self.send_document_print:
+			supplier_language = frappe.db.get_value("Supplier", data.supplier, "language")
+			system_language = frappe.db.get_single_value("System Settings", "language")
+			attachments.append(
+				frappe.attach_print(
+					self.doctype,
+					self.name,
+					doc=self,
+					print_format=self.meta.default_print_format or "Standard",
+					lang=supplier_language or system_language,
+					letterhead=self.letter_head,
+				)
+			)
+
 		self.send_email(data, sender, subject, message, attachments)
 
 	def send_email(self, data, sender, subject, message, attachments):
@@ -218,7 +232,6 @@
 			recipients=data.email_id,
 			sender=sender,
 			attachments=attachments,
-			print_format=self.meta.default_print_format or "Standard",
 			send_email=True,
 			doctype=self.doctype,
 			name=self.name,
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index 71019e8..a7e03c0 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -154,31 +154,35 @@
 	procurement_record = []
 	if procurement_record_against_mr:
 		procurement_record += procurement_record_against_mr
+
 	for po in purchase_order_entry:
 		# fetch material records linked to the purchase order item
-		mr_record = mr_records.get(po.material_request_item, [{}])[0]
-		procurement_detail = {
-			"material_request_date": mr_record.get("transaction_date"),
-			"cost_center": po.cost_center,
-			"project": po.project,
-			"requesting_site": po.warehouse,
-			"requestor": po.owner,
-			"material_request_no": po.material_request,
-			"item_code": po.item_code,
-			"quantity": flt(po.qty),
-			"unit_of_measurement": po.stock_uom,
-			"status": po.status,
-			"purchase_order_date": po.transaction_date,
-			"purchase_order": po.parent,
-			"supplier": po.supplier,
-			"estimated_cost": flt(mr_record.get("amount")),
-			"actual_cost": flt(pi_records.get(po.name)),
-			"purchase_order_amt": flt(po.amount),
-			"purchase_order_amt_in_company_currency": flt(po.base_amount),
-			"expected_delivery_date": po.schedule_date,
-			"actual_delivery_date": pr_records.get(po.name),
-		}
-		procurement_record.append(procurement_detail)
+		material_requests = mr_records.get(po.material_request_item, [{}])
+
+		for mr_record in material_requests:
+			procurement_detail = {
+				"material_request_date": mr_record.get("transaction_date"),
+				"cost_center": po.cost_center,
+				"project": po.project,
+				"requesting_site": po.warehouse,
+				"requestor": po.owner,
+				"material_request_no": po.material_request,
+				"item_code": po.item_code,
+				"quantity": flt(po.qty),
+				"unit_of_measurement": po.stock_uom,
+				"status": po.status,
+				"purchase_order_date": po.transaction_date,
+				"purchase_order": po.parent,
+				"supplier": po.supplier,
+				"estimated_cost": flt(mr_record.get("amount")),
+				"actual_cost": flt(pi_records.get(po.name)),
+				"purchase_order_amt": flt(po.amount),
+				"purchase_order_amt_in_company_currency": flt(po.base_amount),
+				"expected_delivery_date": po.schedule_date,
+				"actual_delivery_date": pr_records.get(po.name),
+			}
+			procurement_record.append(procurement_detail)
+
 	return procurement_record
 
 
@@ -301,7 +305,7 @@
 			& (parent.name == child.parent)
 			& (parent.status.notin(("Closed", "Completed", "Cancelled")))
 		)
-		.groupby(parent.name, child.item_code)
+		.groupby(parent.name, child.material_request_item)
 	)
 	query = apply_filters_on_query(filters, parent, child, query)
 
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 340ec01..955ebef 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -2418,6 +2418,9 @@
 		q = q.select((payment_entry.target_exchange_rate).as_("exchange_rate"))
 
 	if condition:
+		if condition.get("name", None):
+			q = q.where(payment_entry.name.like(f"%{condition.get('name')}%"))
+
 		q = q.where(payment_entry.company == condition["company"])
 		q = (
 			q.where(payment_entry.posting_date >= condition["from_payment_date"])
@@ -2855,6 +2858,27 @@
 
 		return update_supplied_items
 
+	def validate_fg_item_for_subcontracting(new_data, is_new):
+		if is_new:
+			if not new_data.get("fg_item"):
+				frappe.throw(
+					_("Finished Good Item is not specified for service item {0}").format(new_data["item_code"])
+				)
+			else:
+				is_sub_contracted_item, default_bom = frappe.db.get_value(
+					"Item", new_data["fg_item"], ["is_sub_contracted_item", "default_bom"]
+				)
+
+				if not is_sub_contracted_item:
+					frappe.throw(
+						_("Finished Good Item {0} must be a sub-contracted item").format(new_data["fg_item"])
+					)
+				elif not default_bom:
+					frappe.throw(_("Default BOM not found for FG Item {0}").format(new_data["fg_item"]))
+
+		if not new_data.get("fg_item_qty"):
+			frappe.throw(_("Finished Good Item {0} Qty can not be zero").format(new_data["fg_item"]))
+
 	data = json.loads(trans_items)
 
 	any_qty_changed = False  # updated to true if any item's qty changes
@@ -2886,6 +2910,7 @@
 
 			prev_rate, new_rate = flt(child_item.get("rate")), flt(d.get("rate"))
 			prev_qty, new_qty = flt(child_item.get("qty")), flt(d.get("qty"))
+			prev_fg_qty, new_fg_qty = flt(child_item.get("fg_item_qty")), flt(d.get("fg_item_qty"))
 			prev_con_fac, new_con_fac = flt(child_item.get("conversion_factor")), flt(
 				d.get("conversion_factor")
 			)
@@ -2898,6 +2923,7 @@
 
 			rate_unchanged = prev_rate == new_rate
 			qty_unchanged = prev_qty == new_qty
+			fg_qty_unchanged = prev_fg_qty == new_fg_qty
 			uom_unchanged = prev_uom == new_uom
 			conversion_factor_unchanged = prev_con_fac == new_con_fac
 			any_conversion_factor_changed |= not conversion_factor_unchanged
@@ -2907,6 +2933,7 @@
 			if (
 				rate_unchanged
 				and qty_unchanged
+				and fg_qty_unchanged
 				and conversion_factor_unchanged
 				and uom_unchanged
 				and date_unchanged
@@ -2917,6 +2944,17 @@
 		if flt(child_item.get("qty")) != flt(d.get("qty")):
 			any_qty_changed = True
 
+		if (
+			parent.doctype == "Purchase Order"
+			and parent.is_subcontracted
+			and not parent.is_old_subcontracting_flow
+		):
+			validate_fg_item_for_subcontracting(d, new_child_flag)
+			child_item.fg_item_qty = flt(d["fg_item_qty"])
+
+			if new_child_flag:
+				child_item.fg_item = d["fg_item"]
+
 		child_item.qty = flt(d.get("qty"))
 		rate_precision = child_item.precision("rate") or 2
 		conv_fac_precision = child_item.precision("conversion_factor") or 2
@@ -3020,11 +3058,20 @@
 		parent.update_ordered_qty()
 		parent.update_ordered_and_reserved_qty()
 		parent.update_receiving_percentage()
-		if parent.is_old_subcontracting_flow:
-			if should_update_supplied_items(parent):
-				parent.update_reserved_qty_for_subcontract()
-				parent.create_raw_materials_supplied()
-			parent.save()
+
+		if parent.is_subcontracted:
+			if parent.is_old_subcontracting_flow:
+				if should_update_supplied_items(parent):
+					parent.update_reserved_qty_for_subcontract()
+					parent.create_raw_materials_supplied()
+				parent.save()
+			else:
+				if not parent.can_update_items():
+					frappe.throw(
+						_(
+							"Items cannot be updated as Subcontracting Order is created against the Purchase Order {0}."
+						).format(frappe.bold(parent.name))
+					)
 	else:  # Sales Order
 		parent.validate_warehouse()
 		parent.update_reserved_qty()
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 7b7c53e..b396b27 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -759,7 +759,7 @@
 				"company": self.company,
 				"supplier": self.supplier,
 				"purchase_date": self.posting_date,
-				"calculate_depreciation": 1,
+				"calculate_depreciation": 0,
 				"purchase_receipt_amount": purchase_amount,
 				"gross_purchase_amount": purchase_amount,
 				"asset_quantity": row.qty if is_grouped_asset else 0,
diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py
index eeb35c4..6b61ae9 100644
--- a/erpnext/controllers/tests/test_subcontracting_controller.py
+++ b/erpnext/controllers/tests/test_subcontracting_controller.py
@@ -1090,7 +1090,7 @@
 		po = frappe.get_doc("Purchase Order", args.get("po_name"))
 
 		if po.is_subcontracted:
-			return create_subcontracting_order(po_name=po.name, **args)
+			return create_subcontracting_order(**args)
 
 	if not args.service_items:
 		service_items = [
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 61d2ace..11d5f6a 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -237,14 +237,15 @@
 		deposit = abs(amount)
 		withdrawal = 0.0
 
-	status = "Pending" if transaction["pending"] == "True" else "Settled"
+	status = "Pending" if transaction["pending"] == True else "Settled"
 
 	tags = []
-	try:
-		tags += transaction["category"]
-		tags += [f'Plaid Cat. {transaction["category_id"]}']
-	except KeyError:
-		pass
+	if transaction["category"]:
+		try:
+			tags += transaction["category"]
+			tags += [f'Plaid Cat. {transaction["category_id"]}']
+		except KeyError:
+			pass
 
 	if not frappe.db.exists("Bank Transaction", dict(transaction_id=transaction["transaction_id"])):
 		try:
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 261aa76..131f438 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -347,7 +347,7 @@
 			if not data.pending_qty:
 				continue
 
-			item_details = get_item_details(data.item_code)
+			item_details = get_item_details(data.item_code, throw=False)
 			if self.combine_items:
 				if item_details.bom_no in refs:
 					refs[item_details.bom_no]["so_details"].append(
@@ -795,6 +795,9 @@
 			if not row.item_code:
 				frappe.throw(_("Row #{0}: Please select Item Code in Assembly Items").format(row.idx))
 
+			if not row.bom_no:
+				frappe.throw(_("Row #{0}: Please select the BOM No in Assembly Items").format(row.idx))
+
 			bom_data = []
 
 			warehouse = row.warehouse if self.skip_available_sub_assembly_item else None
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 7c15bf9..5ad79f9 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -1082,7 +1082,7 @@
 
 
 @frappe.whitelist()
-def get_item_details(item, project=None, skip_bom_info=False):
+def get_item_details(item, project=None, skip_bom_info=False, throw=True):
 	res = frappe.db.sql(
 		"""
 		select stock_uom, description, item_name, allow_alternative_item,
@@ -1118,12 +1118,15 @@
 
 	if not res["bom_no"]:
 		if project:
-			res = get_item_details(item)
+			res = get_item_details(item, throw=throw)
 			frappe.msgprint(
 				_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1
 			)
 		else:
-			frappe.throw(_("Default BOM for {0} not found").format(item))
+			msg = _("Default BOM for {0} not found").format(item)
+			frappe.msgprint(msg, raise_exception=throw, indicator="yellow", alert=(not throw))
+
+			return res
 
 	bom_data = frappe.db.get_value(
 		"BOM",
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f456e5e..c11d123 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -579,7 +579,9 @@
 			"conversion_factor": d.conversion_factor,
 			"qty": d.qty,
 			"rate": d.rate,
-			"uom": d.uom
+			"uom": d.uom,
+			"fg_item": d.fg_item,
+			"fg_item_qty": d.fg_item_qty,
 		}
 	});
 
@@ -678,6 +680,37 @@
 		})
 	}
 
+	if (frm.doc.doctype == 'Purchase Order' && frm.doc.is_subcontracted && !frm.doc.is_old_subcontracting_flow) {
+		fields.push({
+			fieldtype:'Link',
+			fieldname:'fg_item',
+			options: 'Item',
+			reqd: 1,
+			in_list_view: 0,
+			read_only: 0,
+			disabled: 0,
+			label: __('Finished Good Item'),
+			get_query: () => {
+				return {
+					filters: {
+						'is_stock_item': 1,
+						'is_sub_contracted_item': 1,
+						'default_bom': ['!=', '']
+					}
+				}
+			},
+		}, {
+			fieldtype:'Float',
+			fieldname:'fg_item_qty',
+			reqd: 1,
+			default: 0,
+			read_only: 0,
+			in_list_view: 0,
+			label: __('Finished Good Item Qty'),
+			precision: get_precision('fg_item_qty')
+		})
+	}
+
 	let dialog = new frappe.ui.Dialog({
 		title: __("Update Items"),
 		size: "extra-large",
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 1139c4b..9efae6a 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -656,7 +656,10 @@
 					"job_card_item": "job_card_item",
 				},
 				"postprocess": update_item,
-				"condition": lambda doc: doc.ordered_qty < doc.stock_qty,
+				"condition": lambda doc: (
+					flt(doc.ordered_qty, doc.precision("ordered_qty"))
+					< flt(doc.stock_qty, doc.precision("ordered_qty"))
+				),
 			},
 		},
 		target_doc,
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 248b705..258a503 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -647,7 +647,7 @@
 
 	def update_distinct_item_warehouses(self, dependant_sle):
 		key = (dependant_sle.item_code, dependant_sle.warehouse)
-		val = frappe._dict({"sle": dependant_sle, "dependent_voucher_detail_nos": []})
+		val = frappe._dict({"sle": dependant_sle})
 
 		if key not in self.distinct_item_warehouses:
 			self.distinct_item_warehouses[key] = val
@@ -661,6 +661,8 @@
 
 			if getdate(dependant_sle.posting_date) < getdate(existing_sle_posting_date):
 				val.sle_changed = True
+				dependent_voucher_detail_nos.append(dependant_sle.voucher_detail_no)
+				val.dependent_voucher_detail_nos = dependent_voucher_detail_nos
 				self.distinct_item_warehouses[key] = val
 				self.new_items_found = True
 			elif dependant_sle.voucher_detail_no not in set(dependent_voucher_detail_nos):