Merge pull request #35158 from rohitwaghchaure/fixed-internal-trasfer-condition

fix: internal transfer condition
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 082128a..3df48e2 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(
 					{
@@ -1715,6 +1733,13 @@
 	# bank or cash
 	bank = get_bank_cash_account(doc, bank_account)
 
+	# if default bank or cash account is not set in company master and party has default company bank account, fetch it
+	if party_type in ["Customer", "Supplier"] and not bank:
+		party_bank_account = get_party_bank_account(party_type, doc.get(scrub(party_type)))
+		if party_bank_account:
+			account = frappe.db.get_value("Bank Account", party_bank_account, "account")
+			bank = get_bank_cash_account(doc, account)
+
 	paid_amount, received_amount = set_paid_amount_and_received_amount(
 		dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc
 	)
@@ -1931,19 +1956,27 @@
 	paid_amount = received_amount = 0
 	if party_account_currency == bank.account_currency:
 		paid_amount = received_amount = abs(outstanding_amount)
-	elif payment_type == "Receive":
-		paid_amount = abs(outstanding_amount)
-		if bank_amount:
-			received_amount = bank_amount
-		else:
-			received_amount = paid_amount * doc.get("conversion_rate", 1)
 	else:
-		received_amount = abs(outstanding_amount)
-		if bank_amount:
-			paid_amount = bank_amount
+		company_currency = frappe.get_cached_value("Company", doc.get("company"), "default_currency")
+		if payment_type == "Receive":
+			paid_amount = abs(outstanding_amount)
+			if bank_amount:
+				received_amount = bank_amount
+			else:
+				if company_currency != bank.account_currency:
+					received_amount = paid_amount / doc.get("conversion_rate", 1)
+				else:
+					received_amount = paid_amount * doc.get("conversion_rate", 1)
 		else:
-			# if party account currency and bank currency is different then populate paid amount as well
-			paid_amount = received_amount * doc.get("conversion_rate", 1)
+			received_amount = abs(outstanding_amount)
+			if bank_amount:
+				paid_amount = bank_amount
+			else:
+				if company_currency != bank.account_currency:
+					paid_amount = received_amount / doc.get("conversion_rate", 1)
+				else:
+					# if party account currency and bank currency is different then populate paid amount as well
+					paid_amount = received_amount * doc.get("conversion_rate", 1)
 
 	return paid_amount, received_amount
 
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/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index b4d369e..f76dfff 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -89,6 +89,7 @@
   "column_break8",
   "grand_total",
   "rounding_adjustment",
+  "use_company_roundoff_cost_center",
   "rounded_total",
   "in_words",
   "total_advance",
@@ -1559,13 +1560,19 @@
    "fieldname": "only_include_allocated_payments",
    "fieldtype": "Check",
    "label": "Only Include Allocated Payments"
+  },
+  {
+   "default": "0",
+   "fieldname": "use_company_roundoff_cost_center",
+   "fieldtype": "Check",
+   "label": "Use Company Default Round Off Cost Center"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-04-03 22:57:14.074982",
+ "modified": "2023-04-28 12:57:50.832598",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index a617447..868a150 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -978,7 +978,7 @@
 
 	def make_precision_loss_gl_entry(self, gl_entries):
 		round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
-			self.company, "Purchase Invoice", self.name
+			self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
 		)
 
 		precision_loss = self.get("base_net_total") - flt(
@@ -992,7 +992,9 @@
 						"account": round_off_account,
 						"against": self.supplier,
 						"credit": precision_loss,
-						"cost_center": self.cost_center or round_off_cost_center,
+						"cost_center": round_off_cost_center
+						if self.use_company_roundoff_cost_center
+						else self.cost_center or round_off_cost_center,
 						"remarks": _("Net total calculation precision loss"),
 					}
 				)
@@ -1386,7 +1388,7 @@
 			not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment
 		):
 			round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
-				self.company, "Purchase Invoice", self.name
+				self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
 			)
 
 			gl_entries.append(
@@ -1396,7 +1398,9 @@
 						"against": self.supplier,
 						"debit_in_account_currency": self.rounding_adjustment,
 						"debit": self.base_rounding_adjustment,
-						"cost_center": self.cost_center or round_off_cost_center,
+						"cost_center": round_off_cost_center
+						if self.use_company_roundoff_cost_center
+						else (self.cost_center or round_off_cost_center),
 					},
 					item=self,
 				)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index a41e13c..6a65b30 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -79,6 +79,7 @@
   "column_break5",
   "grand_total",
   "rounding_adjustment",
+  "use_company_roundoff_cost_center",
   "rounded_total",
   "in_words",
   "total_advance",
@@ -2135,6 +2136,12 @@
    "fieldname": "only_include_allocated_payments",
    "fieldtype": "Check",
    "label": "Only Include Allocated Payments"
+  },
+  {
+   "default": "0",
+   "fieldname": "use_company_roundoff_cost_center",
+   "fieldtype": "Check",
+   "label": "Use Company default Cost Center for Round off"
   }
  ],
  "icon": "fa fa-file-text",
@@ -2147,7 +2154,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2023-04-03 22:55:14.206473",
+ "modified": "2023-04-28 14:15:59.901154",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index db61995..e16b1b1 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1464,7 +1464,7 @@
 			and not self.is_internal_transfer()
 		):
 			round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
-				self.company, "Sales Invoice", self.name
+				self.company, "Sales Invoice", self.name, self.use_company_roundoff_cost_center
 			)
 
 			gl_entries.append(
@@ -1476,7 +1476,9 @@
 							self.rounding_adjustment, self.precision("rounding_adjustment")
 						),
 						"credit": flt(self.base_rounding_adjustment, self.precision("base_rounding_adjustment")),
-						"cost_center": self.cost_center or round_off_cost_center,
+						"cost_center": round_off_cost_center
+						if self.use_company_roundoff_cost_center
+						else (self.cost_center or round_off_cost_center),
 					},
 					item=self,
 				)
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 6b2546e..a929ff1 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -475,7 +475,9 @@
 			round_off_gle[dimension] = dimension_values.get(dimension)
 
 
-def get_round_off_account_and_cost_center(company, voucher_type, voucher_no):
+def get_round_off_account_and_cost_center(
+	company, voucher_type, voucher_no, use_company_default=False
+):
 	round_off_account, round_off_cost_center = frappe.get_cached_value(
 		"Company", company, ["round_off_account", "round_off_cost_center"]
 	) or [None, None]
@@ -483,7 +485,7 @@
 	meta = frappe.get_meta(voucher_type)
 
 	# Give first preference to parent cost center for round off GLE
-	if meta.has_field("cost_center"):
+	if not use_company_default and meta.has_field("cost_center"):
 		parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center")
 		if parent_cost_center:
 			round_off_cost_center = parent_cost_center
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index debe655..76a01db 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -538,13 +538,20 @@
 			query = query.where(gl_entry.cost_center.isin(filters.cost_center))
 
 		if filters.get("include_default_book_entries"):
+			company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
+
+			if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
+				frappe.throw(
+					_("To use a different finance book, please uncheck 'Include Default Book Entries'")
+				)
+
 			query = query.where(
-				(gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(filters.company_fb), ""]))
+				(gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)]))
 				| (gl_entry.finance_book.isnull())
 			)
 		else:
 			query = query.where(
-				(gl_entry.finance_book.isin([cstr(filters.company_fb), ""])) | (gl_entry.finance_book.isnull())
+				(gl_entry.finance_book.isin([cstr(filters.finance_book)])) | (gl_entry.finance_book.isnull())
 			)
 
 	if accounting_dimensions:
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 2100f26..57a9091 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -176,7 +176,8 @@
 		{
 			"fieldname": "include_default_book_entries",
 			"label": __("Include Default Book Entries"),
-			"fieldtype": "Check"
+			"fieldtype": "Check",
+			"default": 1
 		},
 		{
 			"fieldname": "show_cancelled_entries",
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 27b84c4..0b05c11 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -244,13 +244,23 @@
 	if filters.get("project"):
 		conditions.append("project in %(project)s")
 
-	if filters.get("finance_book"):
-		if filters.get("include_default_book_entries"):
-			conditions.append(
-				"(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
-			)
+	if filters.get("include_default_book_entries"):
+		if filters.get("finance_book"):
+			if filters.get("company_fb") and cstr(filters.get("finance_book")) != cstr(
+				filters.get("company_fb")
+			):
+				frappe.throw(
+					_("To use a different finance book, please uncheck 'Include Default Book Entries'")
+				)
+			else:
+				conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)")
 		else:
-			conditions.append("finance_book in (%(finance_book)s)")
+			conditions.append("(finance_book in (%(company_fb)s) OR finance_book IS NULL)")
+	else:
+		if filters.get("finance_book"):
+			conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)")
+		else:
+			conditions.append("(finance_book IS NULL)")
 
 	if not filters.get("show_cancelled_entries"):
 		conditions.append("is_cancelled = 0")
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 53611ab..57dac2a 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -248,13 +248,20 @@
 		opening_balance = opening_balance.where(closing_balance.project == filters.project)
 
 	if filters.get("include_default_book_entries"):
+		company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
+
+		if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
+			frappe.throw(
+				_("To use a different finance book, please uncheck 'Include Default Book Entries'")
+			)
+
 		opening_balance = opening_balance.where(
-			(closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(filters.company_fb), ""]))
+			(closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)]))
 			| (closing_balance.finance_book.isnull())
 		)
 	else:
 		opening_balance = opening_balance.where(
-			(closing_balance.finance_book.isin([cstr(filters.finance_book), ""]))
+			(closing_balance.finance_book.isin([cstr(filters.finance_book)]))
 			| (closing_balance.finance_book.isnull())
 		)
 
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index f899516..877362d 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -87,6 +87,12 @@
 			frappe.db.get_value("Work Order Operation", self.operation_id, "completed_qty")
 		)
 
+		over_production_percentage = flt(
+			frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order")
+		)
+
+		wo_qty = wo_qty + (wo_qty * over_production_percentage / 100)
+
 		job_card_qty = frappe.get_all(
 			"Job Card",
 			fields=["sum(for_quantity)"],
@@ -101,8 +107,17 @@
 		job_card_qty = flt(job_card_qty[0][0]) if job_card_qty else 0
 
 		if job_card_qty and ((job_card_qty - completed_qty) > wo_qty):
-			msg = f"""Job Card quantity cannot be greater than
-				Work Order quantity for the operation {self.operation}"""
+			form_link = get_link_to_form("Manufacturing Settings", "Manufacturing Settings")
+
+			msg = f"""
+				Qty To Manufacture in the job card
+				cannot be greater than Qty To Manufacture in the
+				work order for the operation {bold(self.operation)}.
+				<br><br><b>Solution: </b> Either you can reduce the
+				Qty To Manufacture in the job card or set the
+				'Overproduction Percentage For Work Order'
+				in the {form_link}."""
+
 			frappe.throw(_(msg), title=_("Extra Job Card Quantity"))
 
 	def set_sub_operations(self):
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
index 8c61d54..09bf1d8 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
@@ -16,6 +16,7 @@
   "column_break_4",
   "quantity",
   "uom",
+  "conversion_factor",
   "projected_qty",
   "reserved_qty_for_production",
   "safety_stock",
@@ -169,11 +170,17 @@
    "label": "Qty As Per BOM",
    "no_copy": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "conversion_factor",
+   "fieldtype": "Float",
+   "label": "Conversion Factor",
+   "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2022-11-26 14:59:25.879631",
+ "modified": "2023-05-03 12:43:29.895754",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Material Request Plan Item",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 62715e6..ab7aa52 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -336,10 +336,6 @@
 	},
 
 	get_items_for_material_requests(frm, warehouses) {
-		let set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
-			'min_order_qty', 'required_bom_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'ordered_qty',
-			'reserved_qty_for_production', 'material_request_type'];
-
 		frappe.call({
 			method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
 			freeze: true,
@@ -352,11 +348,11 @@
 					frm.set_value('mr_items', []);
 					r.message.forEach(row => {
 						let d = frm.add_child('mr_items');
-						set_fields.forEach(field => {
-							if (row[field]) {
+						for (let field in row) {
+							if (field !== 'name') {
 								d[field] = row[field];
 							}
-						});
+						}
 					});
 				}
 				refresh_field('mr_items');
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 0cc0f80..df50cbf 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -28,6 +28,7 @@
 from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
 from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
 from erpnext.stock.get_item_details import get_conversion_factor
+from erpnext.stock.utils import get_or_make_bin
 from erpnext.utilities.transaction_base import validate_uom_is_integer
 
 
@@ -398,9 +399,20 @@
 		self.set_status()
 		self.db_set("status", self.status)
 
+	def on_submit(self):
+		self.update_bin_qty()
+
 	def on_cancel(self):
 		self.db_set("status", "Cancelled")
 		self.delete_draft_work_order()
+		self.update_bin_qty()
+
+	def update_bin_qty(self):
+		for d in self.mr_items:
+			if d.warehouse:
+				bin_name = get_or_make_bin(d.item_code, d.warehouse)
+				bin = frappe.get_doc("Bin", bin_name, for_update=True)
+				bin.update_reserved_qty_for_production_plan()
 
 	def delete_draft_work_order(self):
 		for d in frappe.get_all(
@@ -1068,6 +1080,7 @@
 			"item_code": row.item_code,
 			"item_name": row.item_name,
 			"quantity": required_qty / conversion_factor,
+			"conversion_factor": conversion_factor,
 			"required_bom_qty": total_qty,
 			"stock_uom": row.get("stock_uom"),
 			"warehouse": warehouse
@@ -1474,3 +1487,34 @@
 	for field in ["wip_warehouse", "fg_warehouse"]:
 		if not row.get(field):
 			row[field] = default_warehouses.get(field)
+
+
+def get_reserved_qty_for_production_plan(item_code, warehouse):
+	from erpnext.manufacturing.doctype.work_order.work_order import get_reserved_qty_for_production
+
+	table = frappe.qb.DocType("Production Plan")
+	child = frappe.qb.DocType("Material Request Plan Item")
+
+	query = (
+		frappe.qb.from_(table)
+		.inner_join(child)
+		.on(table.name == child.parent)
+		.select(Sum(child.quantity * IfNull(child.conversion_factor, 1.0)))
+		.where(
+			(table.docstatus == 1)
+			& (child.item_code == item_code)
+			& (child.warehouse == warehouse)
+			& (table.status.notin(["Completed", "Closed"]))
+		)
+	).run()
+
+	if not query:
+		return 0.0
+
+	reserved_qty_for_production_plan = flt(query[0][0])
+
+	reserved_qty_for_production = flt(
+		get_reserved_qty_for_production(item_code, warehouse, check_production_plan=True)
+	)
+
+	return reserved_qty_for_production_plan - reserved_qty_for_production
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 2bf14c2..91864d0 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -868,6 +868,27 @@
 		for item_code in mr_items:
 			self.assertTrue(item_code in validate_mr_items)
 
+	def test_resered_qty_for_production_plan_for_material_requests(self):
+		from erpnext.stock.utils import get_or_make_bin
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		before_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		pln = create_production_plan(item_code="Test Production Item 1")
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		self.assertEqual(after_qty - before_qty, 1)
+
+		pln = frappe.get_doc("Production Plan", pln.name)
+		pln.cancel()
+
+		bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
+		after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
+
+		self.assertEqual(after_qty, before_qty)
+
 
 def create_production_plan(**args):
 	"""
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 540b7dc..bb53c8c 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -1649,6 +1649,14 @@
 		job_card2 = frappe.copy_doc(job_card_doc)
 		self.assertRaises(frappe.ValidationError, job_card2.save)
 
+		frappe.db.set_single_value(
+			"Manufacturing Settings", "overproduction_percentage_for_work_order", 100
+		)
+
+		job_card2 = frappe.copy_doc(job_card_doc)
+		job_card2.time_logs = []
+		job_card2.save()
+
 
 def prepare_data_for_workstation_type_check():
 	from erpnext.manufacturing.doctype.operation.test_operation import make_operation
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 66b871c..7584522 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -558,12 +558,19 @@
 			and self.production_plan_item
 			and not self.production_plan_sub_assembly_item
 		):
-			qty = frappe.get_value("Production Plan Item", self.production_plan_item, "ordered_qty") or 0.0
+			table = frappe.qb.DocType("Work Order")
 
-			if self.docstatus == 1:
-				qty += self.qty
-			elif self.docstatus == 2:
-				qty -= self.qty
+			query = (
+				frappe.qb.from_(table)
+				.select(Sum(table.qty))
+				.where(
+					(table.production_plan == self.production_plan)
+					& (table.production_plan_item == self.production_plan_item)
+					& (table.docstatus == 1)
+				)
+			).run()
+
+			qty = flt(query[0][0]) if query else 0
 
 			frappe.db.set_value("Production Plan Item", self.production_plan_item, "ordered_qty", qty)
 
@@ -1476,12 +1483,14 @@
 	return doc
 
 
-def get_reserved_qty_for_production(item_code: str, warehouse: str) -> float:
+def get_reserved_qty_for_production(
+	item_code: str, warehouse: str, check_production_plan: bool = False
+) -> float:
 	"""Get total reserved quantity for any item in specified warehouse"""
 	wo = frappe.qb.DocType("Work Order")
 	wo_item = frappe.qb.DocType("Work Order Item")
 
-	return (
+	query = (
 		frappe.qb.from_(wo)
 		.from_(wo_item)
 		.select(
@@ -1502,7 +1511,12 @@
 				| (wo_item.required_qty > wo_item.consumed_qty)
 			)
 		)
-	).run()[0][0] or 0.0
+	)
+
+	if check_production_plan:
+		query = query.where(wo.production_plan.isnotnull())
+
+	return query.run()[0][0] or 0.0
 
 
 @frappe.whitelist()
diff --git a/erpnext/stock/doctype/bin/bin.json b/erpnext/stock/doctype/bin/bin.json
index d822f4a..a115727 100644
--- a/erpnext/stock/doctype/bin/bin.json
+++ b/erpnext/stock/doctype/bin/bin.json
@@ -15,6 +15,7 @@
   "projected_qty",
   "reserved_qty_for_production",
   "reserved_qty_for_sub_contract",
+  "reserved_qty_for_production_plan",
   "ma_rate",
   "stock_uom",
   "fcfs_rate",
@@ -165,13 +166,19 @@
    "oldfieldname": "stock_value",
    "oldfieldtype": "Currency",
    "read_only": 1
+  },
+  {
+   "fieldname": "reserved_qty_for_production_plan",
+   "fieldtype": "Float",
+   "label": "Reserved Qty for Production Plan",
+   "read_only": 1
   }
  ],
  "hide_toolbar": 1,
  "idx": 1,
  "in_create": 1,
  "links": [],
- "modified": "2022-03-30 07:22:23.868602",
+ "modified": "2023-05-02 23:26:21.806965",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Bin",
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 72654e6..5abea9e 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -24,8 +24,30 @@
 			- flt(self.reserved_qty)
 			- flt(self.reserved_qty_for_production)
 			- flt(self.reserved_qty_for_sub_contract)
+			- flt(self.reserved_qty_for_production_plan)
 		)
 
+	def update_reserved_qty_for_production_plan(self, skip_project_qty_update=False):
+		"""Update qty reserved for production from Production Plan tables
+		in open production plan"""
+		from erpnext.manufacturing.doctype.production_plan.production_plan import (
+			get_reserved_qty_for_production_plan,
+		)
+
+		self.reserved_qty_for_production_plan = get_reserved_qty_for_production_plan(
+			self.item_code, self.warehouse
+		)
+
+		self.db_set(
+			"reserved_qty_for_production_plan",
+			flt(self.reserved_qty_for_production_plan),
+			update_modified=True,
+		)
+
+		if not skip_project_qty_update:
+			self.set_projected_qty()
+			self.db_set("projected_qty", self.projected_qty, update_modified=True)
+
 	def update_reserved_qty_for_production(self):
 		"""Update qty reserved for production from Production Item tables
 		in open work orders"""
@@ -35,11 +57,13 @@
 			self.item_code, self.warehouse
 		)
 
-		self.set_projected_qty()
-
 		self.db_set(
 			"reserved_qty_for_production", flt(self.reserved_qty_for_production), update_modified=True
 		)
+
+		self.update_reserved_qty_for_production_plan(skip_project_qty_update=True)
+
+		self.set_projected_qty()
 		self.db_set("projected_qty", self.projected_qty, update_modified=True)
 
 	def update_reserved_qty_for_sub_contracting(self, subcontract_doctype="Subcontracting Order"):
@@ -141,6 +165,7 @@
 			"planned_qty",
 			"reserved_qty_for_production",
 			"reserved_qty_for_sub_contract",
+			"reserved_qty_for_production_plan",
 		],
 		as_dict=1,
 	)
@@ -188,6 +213,7 @@
 		- flt(reserved_qty)
 		- flt(bin_details.reserved_qty_for_production)
 		- flt(bin_details.reserved_qty_for_sub_contract)
+		- flt(bin_details.reserved_qty_for_production_plan)
 	)
 
 	frappe.db.set_value(
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index f477d8f..31c756d 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -76,6 +76,7 @@
 				bin.ordered_qty,
 				bin.reserved_qty,
 				bin.reserved_qty_for_production,
+				bin.reserved_qty_for_production_plan,
 				bin.reserved_qty_for_sub_contract,
 				reserved_qty_for_pos,
 				bin.projected_qty,
@@ -174,6 +175,13 @@
 			"convertible": "qty",
 		},
 		{
+			"label": _("Reserved for Production Plan"),
+			"fieldname": "reserved_qty_for_production_plan",
+			"fieldtype": "Float",
+			"width": 100,
+			"convertible": "qty",
+		},
+		{
 			"label": _("Reserved for Sub Contracting"),
 			"fieldname": "reserved_qty_for_sub_contract",
 			"fieldtype": "Float",
@@ -232,6 +240,7 @@
 			bin.reserved_qty,
 			bin.reserved_qty_for_production,
 			bin.reserved_qty_for_sub_contract,
+			bin.reserved_qty_for_production_plan,
 			bin.projected_qty,
 		)
 		.orderby(bin.item_code, bin.warehouse)