fix: serial and batch for internal transfer (#40467)

* fix: serial and batch for internal transfer

* chore: fix test cases
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 85e9d16..7e3eec5 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -3951,7 +3951,6 @@
 		)
 
 		supplier.append("companies", {"company": allowed_to_interact_with})
-
 		supplier.insert()
 		supplier_name = supplier.name
 	else:
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 8211857..c530727 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -513,6 +513,14 @@
 						(not cint(self.is_return) and self.docstatus == 1)
 						or (cint(self.is_return) and self.docstatus == 2)
 					):
+						serial_and_batch_bundle = d.get("serial_and_batch_bundle")
+						if self.is_internal_transfer() and self.is_return and self.docstatus == 2:
+							serial_and_batch_bundle = frappe.db.get_value(
+								"Stock Ledger Entry",
+								{"voucher_detail_no": d.name, "warehouse": d.from_warehouse},
+								"serial_and_batch_bundle",
+							)
+
 						from_warehouse_sle = self.get_sl_entries(
 							d,
 							{
@@ -521,19 +529,24 @@
 								"outgoing_rate": d.rate,
 								"recalculate_rate": 1,
 								"dependant_sle_voucher_detail_no": d.name,
+								"serial_and_batch_bundle": serial_and_batch_bundle,
 							},
 						)
 
 						sl_entries.append(from_warehouse_sle)
 
+					type_of_transaction = "Inward"
+					if self.docstatus == 2:
+						type_of_transaction = "Outward"
+
 					sle = self.get_sl_entries(
 						d,
 						{
 							"actual_qty": flt(pr_qty),
 							"serial_and_batch_bundle": (
 								d.serial_and_batch_bundle
-								if not self.is_internal_transfer()
-								else self.get_package_for_target_warehouse(d)
+								if not self.is_internal_transfer() or self.is_return
+								else self.get_package_for_target_warehouse(d, type_of_transaction=type_of_transaction)
 							),
 						},
 					)
@@ -570,7 +583,17 @@
 						or (cint(self.is_return) and self.docstatus == 1)
 					):
 						from_warehouse_sle = self.get_sl_entries(
-							d, {"actual_qty": -1 * pr_qty, "warehouse": d.from_warehouse, "recalculate_rate": 1}
+							d,
+							{
+								"actual_qty": -1 * pr_qty,
+								"warehouse": d.from_warehouse,
+								"recalculate_rate": 1,
+								"serial_and_batch_bundle": (
+									self.get_package_for_target_warehouse(d, d.from_warehouse, "Inward")
+									if self.is_internal_transfer() and self.is_return
+									else None
+								),
+							},
 						)
 
 						sl_entries.append(from_warehouse_sle)
@@ -597,13 +620,15 @@
 			via_landed_cost_voucher=via_landed_cost_voucher,
 		)
 
-	def get_package_for_target_warehouse(self, item) -> str:
+	def get_package_for_target_warehouse(self, item, warehouse=None, type_of_transaction=None) -> str:
 		if not item.serial_and_batch_bundle:
 			return ""
 
+		if not warehouse:
+			warehouse = item.warehouse
+
 		return self.make_package_for_transfer(
-			item.serial_and_batch_bundle,
-			item.warehouse,
+			item.serial_and_batch_bundle, warehouse, type_of_transaction=type_of_transaction
 		)
 
 	def update_ordered_and_reserved_qty(self):
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 1ddcaa7..5594816 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -423,6 +423,15 @@
 			]:
 				type_of_transaction = "Outward"
 
+			warehouse = source_doc.warehouse if qty_field == "stock_qty" else source_doc.rejected_warehouse
+			if source_parent.doctype in [
+				"Sales Invoice",
+				"POS Invoice",
+				"Delivery Note",
+			] and source_parent.get("is_internal_customer"):
+				type_of_transaction = "Outward"
+				warehouse = source_doc.target_warehouse
+
 			cls_obj = SerialBatchCreation(
 				{
 					"type_of_transaction": type_of_transaction,
@@ -432,7 +441,7 @@
 					"returned_serial_nos": returned_serial_nos,
 					"voucher_type": source_parent.doctype,
 					"do_not_submit": True,
-					"warehouse": source_doc.warehouse,
+					"warehouse": warehouse,
 					"has_serial_no": item_details.has_serial_no,
 					"has_batch_no": item_details.has_batch_no,
 				}
@@ -575,11 +584,14 @@
 			if not item_details.has_batch_no and not item_details.has_serial_no:
 				return
 
-			for qty_field in ["stock_qty", "rejected_qty"]:
-				if target_doc.get(qty_field) and not target_doc.get("use_serial_batch_fields"):
+			if not target_doc.get("use_serial_batch_fields"):
+				for qty_field in ["stock_qty", "rejected_qty"]:
+					if not target_doc.get(qty_field):
+						continue
+
 					update_serial_batch_no(source_doc, target_doc, source_parent, item_details, qty_field)
-				elif target_doc.get(qty_field) and target_doc.get("use_serial_batch_fields"):
-					update_non_bundled_serial_nos(source_doc, target_doc, source_parent)
+			elif target_doc.get("use_serial_batch_fields"):
+				update_non_bundled_serial_nos(source_doc, target_doc, source_parent)
 
 	def update_non_bundled_serial_nos(source_doc, target_doc, source_parent):
 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 359d721..9d86cb2 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -439,8 +439,10 @@
 				# Get incoming rate based on original item cost based on valuation method
 				qty = flt(d.get("stock_qty") or d.get("actual_qty"))
 
-				if not d.incoming_rate or (
-					get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return")
+				if (
+					not d.incoming_rate
+					or self.is_internal_transfer()
+					or (get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return"))
 				):
 					d.incoming_rate = get_incoming_rate(
 						{
@@ -455,6 +457,8 @@
 							"voucher_no": self.name,
 							"voucher_detail_no": d.name,
 							"allow_zero_valuation": d.get("allow_zero_valuation"),
+							"batch_no": d.batch_no,
+							"serial_no": d.serial_no,
 						},
 						raise_error_if_no_rate=False,
 					)
@@ -527,13 +531,26 @@
 		self.make_sl_entries(sl_entries)
 
 	def get_sle_for_source_warehouse(self, item_row):
+		serial_and_batch_bundle = item_row.serial_and_batch_bundle
+		if serial_and_batch_bundle and self.is_internal_transfer() and self.is_return:
+			if self.docstatus == 1:
+				serial_and_batch_bundle = self.make_package_for_transfer(
+					serial_and_batch_bundle, item_row.warehouse, type_of_transaction="Inward"
+				)
+			else:
+				serial_and_batch_bundle = frappe.db.get_value(
+					"Stock Ledger Entry",
+					{"voucher_detail_no": item_row.name, "warehouse": item_row.warehouse},
+					"serial_and_batch_bundle",
+				)
+
 		sle = self.get_sl_entries(
 			item_row,
 			{
 				"actual_qty": -1 * flt(item_row.qty),
 				"incoming_rate": item_row.incoming_rate,
 				"recalculate_rate": cint(self.is_return),
-				"serial_and_batch_bundle": item_row.serial_and_batch_bundle,
+				"serial_and_batch_bundle": serial_and_batch_bundle,
 			},
 		)
 		if item_row.target_warehouse and not cint(self.is_return):
@@ -554,9 +571,15 @@
 				if item_row.warehouse:
 					sle.dependant_sle_voucher_detail_no = item_row.name
 
-			if item_row.serial_and_batch_bundle:
+			if item_row.serial_and_batch_bundle and not cint(self.is_return):
+				type_of_transaction = "Inward"
+				if cint(self.is_return):
+					type_of_transaction = "Outward"
+
 				sle["serial_and_batch_bundle"] = self.make_package_for_transfer(
-					item_row.serial_and_batch_bundle, item_row.target_warehouse
+					item_row.serial_and_batch_bundle,
+					item_row.target_warehouse,
+					type_of_transaction=type_of_transaction,
 				)
 
 		return sle
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index a3fbdda..15eeff5 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -236,6 +236,14 @@
 			qty = row.get("rejected_qty")
 			warehouse = row.get("rejected_warehouse")
 
+		if (
+			self.is_internal_transfer()
+			and self.doctype in ["Sales Invoice", "Delivery Note"]
+			and self.is_return
+		):
+			warehouse = row.get("target_warehouse") or row.get("warehouse")
+			type_of_transaction = "Outward"
+
 		bundle_details.update(
 			{
 				"qty": qty,
@@ -579,7 +587,7 @@
 		bundle_doc.warehouse = warehouse
 		bundle_doc.type_of_transaction = type_of_transaction
 		bundle_doc.voucher_type = self.doctype
-		bundle_doc.voucher_no = self.name
+		bundle_doc.voucher_no = "" if self.is_new() or self.docstatus == 2 else self.name
 		bundle_doc.is_cancelled = 0
 
 		for row in bundle_doc.entries:
@@ -595,6 +603,7 @@
 
 		bundle_doc.calculate_qty_and_amount()
 		bundle_doc.flags.ignore_permissions = True
+		bundle_doc.flags.ignore_validate = True
 		bundle_doc.save(ignore_permissions=True)
 
 		return bundle_doc.name
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 24133b8..42d37bf4 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -542,6 +542,10 @@
 			frappe.throw(__("Please add atleast one Serial No / Batch No"));
 		}
 
+		if (!warehouse) {
+			frappe.throw(__("Please select a Warehouse"));
+		}
+
 		frappe
 			.call({
 				method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index a3903a3..0d2d207 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -333,6 +333,7 @@
 							"type_of_transaction": "Outward",
 							"serial_and_batch_bundle": bundle_id,
 							"item_code": item.get("item_code"),
+							"warehouse": item.get("warehouse"),
 						}
 					)
 
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index fa2c21f..5cf2080 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -2559,6 +2559,280 @@
 				self.assertEqual(row.serial_no, "\n".join(serial_nos[:2]))
 				self.assertEqual(row.rejected_serial_no, serial_nos[2])
 
+	def test_internal_transfer_with_serial_batch_items_and_their_valuation(self):
+		from erpnext.controllers.sales_and_purchase_return import make_return_doc
+		from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
+		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+		prepare_data_for_internal_transfer()
+
+		customer = "_Test Internal Customer 2"
+		company = "_Test Company with perpetual inventory"
+
+		batch_item_doc = make_item(
+			"_Test Batch Item For Stock Transfer",
+			{"has_batch_no": 1, "create_new_batch": 1, "batch_number_series": "BT-BIFST-.####"},
+		)
+
+		serial_item_doc = make_item(
+			"_Test Serial No Item For Stock Transfer",
+			{"has_serial_no": 1, "serial_no_series": "BT-BIFST-.####"},
+		)
+
+		inward_entry = make_purchase_receipt(
+			item_code=batch_item_doc.name,
+			qty=10,
+			rate=150,
+			warehouse="Stores - TCP1",
+			company="_Test Company with perpetual inventory",
+			use_serial_batch_fields=1,
+			do_not_submit=1,
+		)
+
+		inward_entry.append(
+			"items",
+			{
+				"item_code": serial_item_doc.name,
+				"qty": 15,
+				"rate": 250,
+				"item_name": serial_item_doc.item_name,
+				"conversion_factor": 1.0,
+				"uom": serial_item_doc.stock_uom,
+				"stock_uom": serial_item_doc.stock_uom,
+				"warehouse": "Stores - TCP1",
+				"use_serial_batch_fields": 1,
+			},
+		)
+
+		inward_entry.submit()
+		inward_entry.reload()
+
+		for row in inward_entry.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_dn = create_delivery_note(
+			item_code=inward_entry.items[0].item_code,
+			company=company,
+			customer=customer,
+			cost_center="Main - TCP1",
+			expense_account="Cost of Goods Sold - TCP1",
+			qty=10,
+			rate=500,
+			warehouse="Stores - TCP1",
+			target_warehouse="Work In Progress - TCP1",
+			batch_no=get_batch_from_bundle(inward_entry.items[0].serial_and_batch_bundle),
+			use_serial_batch_fields=1,
+			do_not_submit=1,
+		)
+
+		inter_transfer_dn.append(
+			"items",
+			{
+				"item_code": serial_item_doc.name,
+				"qty": 15,
+				"rate": 350,
+				"item_name": serial_item_doc.item_name,
+				"conversion_factor": 1.0,
+				"uom": serial_item_doc.stock_uom,
+				"stock_uom": serial_item_doc.stock_uom,
+				"warehouse": "Stores - TCP1",
+				"target_warehouse": "Work In Progress - TCP1",
+				"serial_no": "\n".join(
+					get_serial_nos_from_bundle(inward_entry.items[1].serial_and_batch_bundle)
+				),
+				"use_serial_batch_fields": 1,
+			},
+		)
+
+		inter_transfer_dn.submit()
+		inter_transfer_dn.reload()
+		for row in inter_transfer_dn.items:
+			if row.item_code == batch_item_doc.name:
+				self.assertEqual(row.rate, 150.0)
+			else:
+				self.assertEqual(row.rate, 250.0)
+
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_pr = make_inter_company_purchase_receipt(inter_transfer_dn.name)
+		for row in inter_transfer_pr.items:
+			row.from_warehouse = "Work In Progress - TCP1"
+			row.warehouse = "Stores - TCP1"
+		inter_transfer_pr.submit()
+
+		for row in inter_transfer_pr.items:
+			if row.item_code == batch_item_doc.name:
+				self.assertEqual(row.rate, 150.0)
+			else:
+				self.assertEqual(row.rate, 250.0)
+
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_pr_return = make_return_doc("Purchase Receipt", inter_transfer_pr.name)
+
+		inter_transfer_pr_return.submit()
+		inter_transfer_pr_return.reload()
+		for row in inter_transfer_pr_return.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+			if row.item_code == serial_item_doc.name:
+				self.assertEqual(row.rate, 250.0)
+				serial_nos = get_serial_nos_from_bundle(row.serial_and_batch_bundle)
+				for sn in serial_nos:
+					serial_no_details = frappe.db.get_value("Serial No", sn, ["status", "warehouse"], as_dict=1)
+					self.assertTrue(serial_no_details.status == "Active")
+					self.assertEqual(serial_no_details.warehouse, "Work In Progress - TCP1")
+
+		inter_transfer_dn_return = make_return_doc("Delivery Note", inter_transfer_dn.name)
+		inter_transfer_dn_return.posting_date = today()
+		inter_transfer_dn_return.posting_time = nowtime()
+		for row in inter_transfer_dn_return.items:
+			row.target_warehouse = "Work In Progress - TCP1"
+
+		inter_transfer_dn_return.submit()
+		inter_transfer_dn_return.reload()
+
+		for row in inter_transfer_dn_return.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+
+	def test_internal_transfer_with_serial_batch_items_without_user_serial_batch_fields(self):
+		from erpnext.controllers.sales_and_purchase_return import make_return_doc
+		from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
+		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+		frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
+
+		prepare_data_for_internal_transfer()
+
+		customer = "_Test Internal Customer 2"
+		company = "_Test Company with perpetual inventory"
+
+		batch_item_doc = make_item(
+			"_Test Batch Item For Stock Transfer USE SERIAL BATCH FIELDS",
+			{"has_batch_no": 1, "create_new_batch": 1, "batch_number_series": "USBF-BT-BIFST-.####"},
+		)
+
+		serial_item_doc = make_item(
+			"_Test Serial No Item For Stock Transfer USE SERIAL BATCH FIELDS",
+			{"has_serial_no": 1, "serial_no_series": "USBF-BT-BIFST-.####"},
+		)
+
+		inward_entry = make_purchase_receipt(
+			item_code=batch_item_doc.name,
+			qty=10,
+			rate=150,
+			warehouse="Stores - TCP1",
+			company="_Test Company with perpetual inventory",
+			use_serial_batch_fields=0,
+			do_not_submit=1,
+		)
+
+		inward_entry.append(
+			"items",
+			{
+				"item_code": serial_item_doc.name,
+				"qty": 15,
+				"rate": 250,
+				"item_name": serial_item_doc.item_name,
+				"conversion_factor": 1.0,
+				"uom": serial_item_doc.stock_uom,
+				"stock_uom": serial_item_doc.stock_uom,
+				"warehouse": "Stores - TCP1",
+				"use_serial_batch_fields": 0,
+			},
+		)
+
+		inward_entry.submit()
+		inward_entry.reload()
+
+		for row in inward_entry.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_dn = create_delivery_note(
+			item_code=inward_entry.items[0].item_code,
+			company=company,
+			customer=customer,
+			cost_center="Main - TCP1",
+			expense_account="Cost of Goods Sold - TCP1",
+			qty=10,
+			rate=500,
+			warehouse="Stores - TCP1",
+			target_warehouse="Work In Progress - TCP1",
+			batch_no=get_batch_from_bundle(inward_entry.items[0].serial_and_batch_bundle),
+			use_serial_batch_fields=0,
+			do_not_submit=1,
+		)
+
+		inter_transfer_dn.append(
+			"items",
+			{
+				"item_code": serial_item_doc.name,
+				"qty": 15,
+				"rate": 350,
+				"item_name": serial_item_doc.item_name,
+				"conversion_factor": 1.0,
+				"uom": serial_item_doc.stock_uom,
+				"stock_uom": serial_item_doc.stock_uom,
+				"warehouse": "Stores - TCP1",
+				"target_warehouse": "Work In Progress - TCP1",
+				"serial_no": "\n".join(
+					get_serial_nos_from_bundle(inward_entry.items[1].serial_and_batch_bundle)
+				),
+				"use_serial_batch_fields": 0,
+			},
+		)
+
+		inter_transfer_dn.submit()
+		inter_transfer_dn.reload()
+		for row in inter_transfer_dn.items:
+			if row.item_code == batch_item_doc.name:
+				self.assertEqual(row.rate, 150.0)
+			else:
+				self.assertEqual(row.rate, 250.0)
+
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_pr = make_inter_company_purchase_receipt(inter_transfer_dn.name)
+		for row in inter_transfer_pr.items:
+			row.from_warehouse = "Work In Progress - TCP1"
+			row.warehouse = "Stores - TCP1"
+		inter_transfer_pr.submit()
+
+		for row in inter_transfer_pr.items:
+			if row.item_code == batch_item_doc.name:
+				self.assertEqual(row.rate, 150.0)
+			else:
+				self.assertEqual(row.rate, 250.0)
+
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		inter_transfer_pr_return = make_return_doc("Purchase Receipt", inter_transfer_pr.name)
+
+		inter_transfer_pr_return.submit()
+		inter_transfer_pr_return.reload()
+		for row in inter_transfer_pr_return.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+			if row.item_code == serial_item_doc.name:
+				self.assertEqual(row.rate, 250.0)
+				serial_nos = get_serial_nos_from_bundle(row.serial_and_batch_bundle)
+				for sn in serial_nos:
+					serial_no_details = frappe.db.get_value("Serial No", sn, ["status", "warehouse"], as_dict=1)
+					self.assertTrue(serial_no_details.status == "Active")
+					self.assertEqual(serial_no_details.warehouse, "Work In Progress - TCP1")
+
+		inter_transfer_dn_return = make_return_doc("Delivery Note", inter_transfer_dn.name)
+		inter_transfer_dn_return.posting_date = today()
+		inter_transfer_dn_return.posting_time = nowtime()
+		for row in inter_transfer_dn_return.items:
+			row.target_warehouse = "Work In Progress - TCP1"
+
+		inter_transfer_dn_return.submit()
+		inter_transfer_dn_return.reload()
+
+		for row in inter_transfer_dn_return.items:
+			self.assertTrue(row.serial_and_batch_bundle)
+
+		frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
+
 
 def prepare_data_for_internal_transfer():
 	from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
index 7a58462..59ef43e 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
@@ -113,6 +113,7 @@
   {
    "fieldname": "voucher_no",
    "fieldtype": "Dynamic Link",
+   "in_standard_filter": 1,
    "label": "Voucher No",
    "no_copy": 1,
    "options": "voucher_type",
@@ -250,7 +251,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-12-07 17:56:55.528563",
+ "modified": "2024-03-15 15:22:24.003486",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Serial and Batch Bundle",
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 08cb3ca..9a7395f 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
@@ -801,6 +801,7 @@
 		self.set_purchase_document_no()
 
 	def on_submit(self):
+		self.validate_batch_inventory()
 		self.validate_serial_nos_inventory()
 
 	def set_purchase_document_no(self):
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index b206406..5b321de 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -2611,6 +2611,7 @@
 						"type_of_transaction": "Outward",
 						"serial_and_batch_bundle": item.get("serial_and_batch_bundle"),
 						"item_code": item.get("item_code"),
+						"warehouse": item.get("t_warehouse"),
 					}
 				)
 
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 39166e2..01a43b3 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -1008,6 +1008,7 @@
 				"type_of_transaction": "Inward",
 				"serial_and_batch_bundle": s2.items[0].serial_and_batch_bundle,
 				"item_code": "_Test Serialized Item",
+				"warehouse": "_Test Warehouse - _TC",
 			}
 		)
 
diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py
index 4e87fa0..7b42103 100644
--- a/erpnext/stock/serial_batch_bundle.py
+++ b/erpnext/stock/serial_batch_bundle.py
@@ -820,6 +820,10 @@
 			self.remove_returned_serial_nos(new_package)
 
 		new_package.docstatus = 0
+		new_package.warehouse = self.warehouse
+		new_package.voucher_no = ""
+		new_package.posting_date = today()
+		new_package.posting_time = nowtime()
 		new_package.type_of_transaction = self.type_of_transaction
 		new_package.returned_against = self.get("returned_against")
 		new_package.save()