Merge pull request #40975 from rohitwaghchaure/fixed-donot-validate-for-lcv

fix: do not validate batch qty for LCV
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 4df3726..84bf6aa 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -1119,7 +1119,7 @@
 		message += _("Please adjust the qty or edit {0} to proceed.").format(rule_link)
 		return message
 
-	def repost_future_sle_and_gle(self, force=False):
+	def repost_future_sle_and_gle(self, force=False, via_landed_cost_voucher=False):
 		args = frappe._dict(
 			{
 				"posting_date": self.posting_date,
@@ -1127,6 +1127,7 @@
 				"voucher_type": self.doctype,
 				"voucher_no": self.name,
 				"company": self.company,
+				"via_landed_cost_voucher": via_landed_cost_voucher,
 			}
 		)
 
@@ -1138,7 +1139,11 @@
 				frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting")
 			)
 			if item_based_reposting:
-				create_item_wise_repost_entries(voucher_type=self.doctype, voucher_no=self.name)
+				create_item_wise_repost_entries(
+					voucher_type=self.doctype,
+					voucher_no=self.name,
+					via_landed_cost_voucher=via_landed_cost_voucher,
+				)
 			else:
 				create_repost_item_valuation_entry(args)
 
@@ -1510,11 +1515,14 @@
 	repost_entry.allow_zero_rate = args.allow_zero_rate
 	repost_entry.flags.ignore_links = True
 	repost_entry.flags.ignore_permissions = True
+	repost_entry.via_landed_cost_voucher = args.via_landed_cost_voucher
 	repost_entry.save()
 	repost_entry.submit()
 
 
-def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=False):
+def create_item_wise_repost_entries(
+	voucher_type, voucher_no, allow_zero_rate=False, via_landed_cost_voucher=False
+):
 	"""Using a voucher create repost item valuation records for all item-warehouse pairs."""
 
 	stock_ledger_entries = get_items_to_be_repost(voucher_type, voucher_no)
@@ -1538,6 +1546,7 @@
 		repost_entry.allow_zero_rate = allow_zero_rate
 		repost_entry.flags.ignore_links = True
 		repost_entry.flags.ignore_permissions = True
+		repost_entry.via_landed_cost_voucher = via_landed_cost_voucher
 		repost_entry.submit()
 		repost_entries.append(repost_entry)
 
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index 222ffb4..4325f26 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -253,7 +253,7 @@
 			doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True)
 			doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
 			doc.make_gl_entries()
-			doc.repost_future_sle_and_gle()
+			doc.repost_future_sle_and_gle(via_landed_cost_voucher=True)
 
 	def validate_asset_qty_and_status(self, receipt_document_type, receipt_document):
 		for item in self.get("items"):
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 32b384d..13b7f97 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -745,6 +745,207 @@
 				frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"),
 			)
 
+	def test_do_not_validate_landed_cost_voucher_with_serial_batch_for_legacy_pr(self):
+		from erpnext.stock.doctype.item.test_item import make_item
+		from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import get_auto_batch_nos
+
+		frappe.flags.ignore_serial_batch_bundle_validation = True
+		frappe.flags.use_serial_and_batch_fields = True
+		sn_item = "Test Don't Validate Landed Cost Voucher Serial NO for Legacy PR"
+		batch_item = "Test Don't Validate Landed Cost Voucher Batch NO for Legacy PR"
+		sn_item_doc = make_item(
+			sn_item,
+			{
+				"has_serial_no": 1,
+				"serial_no_series": "SN-TDVLCVSNO-.####",
+				"is_stock_item": 1,
+			},
+		)
+
+		batch_item_doc = make_item(
+			batch_item,
+			{
+				"has_batch_no": 1,
+				"batch_number_series": "BATCH-TDVLCVSNO-.####",
+				"create_new_batch": 1,
+				"is_stock_item": 1,
+			},
+		)
+
+		serial_nos = [
+			"SN-TDVLCVSNO-0001",
+			"SN-TDVLCVSNO-0002",
+			"SN-TDVLCVSNO-0003",
+			"SN-TDVLCVSNO-0004",
+			"SN-TDVLCVSNO-0005",
+		]
+
+		for sn in serial_nos:
+			if not frappe.db.exists("Serial No", sn):
+				sn_doc = frappe.get_doc(
+					{
+						"doctype": "Serial No",
+						"item_code": sn_item,
+						"serial_no": sn,
+					}
+				)
+				sn_doc.insert()
+
+		if not frappe.db.exists("Batch", "BATCH-TDVLCVSNO-0001"):
+			batch_doc = frappe.get_doc(
+				{
+					"doctype": "Batch",
+					"item": batch_item,
+					"batch_id": "BATCH-TDVLCVSNO-0001",
+				}
+			)
+			batch_doc.insert()
+
+		warehouse = "_Test Warehouse - _TC"
+		company = frappe.db.get_value("Warehouse", warehouse, "company")
+
+		pr = make_purchase_receipt(
+			company=company,
+			warehouse=warehouse,
+			item_code=sn_item,
+			qty=5,
+			rate=100,
+			uom=sn_item_doc.stock_uom,
+			stock_uom=sn_item_doc.stock_uom,
+			do_not_submit=True,
+		)
+
+		pr.append(
+			"items",
+			{
+				"item_code": batch_item,
+				"item_name": batch_item,
+				"description": "Test Batch Item",
+				"uom": batch_item_doc.stock_uom,
+				"stock_uom": batch_item_doc.stock_uom,
+				"qty": 5,
+				"rate": 100,
+				"warehouse": warehouse,
+			},
+		)
+
+		pr.submit()
+		pr.reload()
+
+		for sn in serial_nos:
+			sn_doc = frappe.get_doc("Serial No", sn)
+			sn_doc.db_set(
+				{
+					"warehouse": warehouse,
+					"status": "Active",
+				}
+			)
+
+		batch_doc.db_set(
+			{
+				"batch_qty": 5,
+			}
+		)
+
+		for row in pr.items:
+			if row.item_code == sn_item:
+				row.db_set("serial_no", ", ".join(serial_nos))
+			else:
+				row.db_set("batch_no", "BATCH-TDVLCVSNO-0001")
+
+		stock_ledger_entries = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": pr.name})
+		for sle in stock_ledger_entries:
+			doc = frappe.get_doc("Stock Ledger Entry", sle.name)
+			if doc.item_code == sn_item:
+				doc.db_set("serial_no", ", ".join(serial_nos))
+			else:
+				doc.db_set("batch_no", "BATCH-TDVLCVSNO-0001")
+
+		dn = create_delivery_note(
+			company=company,
+			warehouse=warehouse,
+			item_code=sn_item,
+			qty=5,
+			rate=100,
+			uom=sn_item_doc.stock_uom,
+			stock_uom=sn_item_doc.stock_uom,
+			do_not_submit=True,
+		)
+
+		dn.append(
+			"items",
+			{
+				"item_code": batch_item,
+				"item_name": batch_item,
+				"description": "Test Batch Item",
+				"uom": batch_item_doc.stock_uom,
+				"stock_uom": batch_item_doc.stock_uom,
+				"qty": 5,
+				"rate": 100,
+				"warehouse": warehouse,
+			},
+		)
+
+		dn.submit()
+
+		stock_ledger_entries = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": dn.name})
+		for sle in stock_ledger_entries:
+			doc = frappe.get_doc("Stock Ledger Entry", sle.name)
+			if doc.item_code == sn_item:
+				doc.db_set("serial_no", ", ".join(serial_nos))
+			else:
+				doc.db_set("batch_no", "BATCH-TDVLCVSNO-0001")
+
+		available_batches = get_auto_batch_nos(
+			frappe._dict(
+				{
+					"item_code": batch_item,
+					"warehouse": warehouse,
+					"batch_no": ["BATCH-TDVLCVSNO-0001"],
+					"consider_negative_batches": True,
+				}
+			)
+		)[0]
+
+		self.assertFalse(available_batches.get("qty"))
+
+		frappe.flags.ignore_serial_batch_bundle_validation = False
+		frappe.flags.use_serial_and_batch_fields = False
+
+		lcv = make_landed_cost_voucher(
+			company=pr.company,
+			receipt_document_type="Purchase Receipt",
+			receipt_document=pr.name,
+			charges=20,
+			distribute_charges_based_on="Qty",
+			do_not_save=True,
+		)
+
+		lcv.get_items_from_purchase_receipts()
+		lcv.save()
+		lcv.submit()
+
+		pr.reload()
+
+		for row in pr.items:
+			self.assertEqual(row.valuation_rate, 102)
+			self.assertTrue(row.serial_and_batch_bundle)
+			self.assertEqual(
+				row.valuation_rate,
+				frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"),
+			)
+
+		lcv.cancel()
+		pr.reload()
+
+		for row in pr.items:
+			self.assertEqual(row.valuation_rate, 100)
+			self.assertTrue(row.serial_and_batch_bundle)
+			self.assertEqual(
+				row.valuation_rate,
+				frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"),
+			)
+
 
 def make_landed_cost_voucher(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index 19aad3f..286a220 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -860,6 +860,12 @@
 		self.validate_batch_inventory()
 
 	def validate_batch_inventory(self):
+		if (
+			self.voucher_type in ["Purchase Invoice", "Purchase Receipt"]
+			and frappe.db.get_value(self.voucher_type, self.voucher_no, "docstatus") == 1
+		):
+			return
+
 		if not self.has_batch_no:
 			return