fix: purchase return are allowed even when assets are not cancelled (#20797)

* fix: purchase return are allowed even when assets are not cancelled

* chore: test case

* fix: error message

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index fcc9098..0e72ec2 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -45,6 +45,7 @@
 		self.validate_warehouse()
 		self.validate_from_warehouse()
 		self.set_supplier_address()
+		self.validate_asset_return()
 
 		if self.doctype=="Purchase Invoice":
 			self.validate_purchase_receipt_if_update_stock()
@@ -100,6 +101,19 @@
 				for d in tax_for_valuation:
 					d.category = 'Total'
 				msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
+	
+	def validate_asset_return(self):
+		if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return:
+			return
+
+		purchase_doc_field = 'purchase_receipt' if self.doctype == 'Purchase Receipt' else 'purchase_invoice'
+		not_cancelled_asset = [d.name for d in frappe.db.get_all("Asset", {
+			purchase_doc_field: self.return_against,
+			"docstatus": 1
+		})]
+		if self.is_return and len(not_cancelled_asset):
+			frappe.throw(_("{} has submitted assets linked to it. You need to cancel the assets to create purchase return.".format(self.return_against)),
+				title=_("Not Allowed"))
 
 	def get_asset_items(self):
 		if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index cba7f20..113da9f 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -375,6 +375,33 @@
 
 		location = frappe.db.get_value('Asset', assets[0].name, 'location')
 		self.assertEquals(location, "Test Location")
+	
+	def test_purchase_return_with_submitted_asset(self):
+		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return
+
+		pr = make_purchase_receipt(item_code="Test Asset Item", qty=1)
+
+		asset = frappe.get_doc("Asset", {
+			'purchase_receipt': pr.name
+		})
+		asset.available_for_use_date = frappe.utils.nowdate()
+		asset.gross_purchase_amount = 50.0
+		asset.append("finance_books", {
+			"expected_value_after_useful_life": 10,
+			"depreciation_method": "Straight Line",
+			"total_number_of_depreciations": 3,
+			"frequency_of_depreciation": 1,
+			"depreciation_start_date": frappe.utils.nowdate()
+		})
+		asset.submit()
+
+		pr_return = make_purchase_return(pr.name)
+		self.assertRaises(frappe.exceptions.ValidationError, pr_return.submit)
+		
+		asset.load_from_db()
+		asset.cancel()
+		
+		pr_return.submit()
 
 	def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self):
 		from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center