fix: valuation rate for the subcontracting receipt supplied items with Serial and Batch Bundle (#38094)

fix: valuation rate for the subcontracting receipt supplied items with batch
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 5fa66b1..3d55a08 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -626,6 +626,18 @@
 						(row.item_code, row.get(self.subcontract_data.order_field))
 					] -= row.qty
 
+	def __set_rate_for_serial_and_batch_bundle(self):
+		if self.doctype != "Subcontracting Receipt":
+			return
+
+		for row in self.get(self.raw_material_table):
+			if not row.get("serial_and_batch_bundle"):
+				continue
+
+			row.rate = frappe.get_cached_value(
+				"Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"
+			)
+
 	def __modify_serial_and_batch_bundle(self):
 		if self.is_new():
 			return
@@ -681,6 +693,7 @@
 		self.__remove_changed_rows()
 		self.__set_supplied_items()
 		self.__modify_serial_and_batch_bundle()
+		self.__set_rate_for_serial_and_batch_bundle()
 
 	def __validate_batch_no(self, row, key):
 		if row.get("batch_no") and row.get("batch_no") not in self.__transferred_items.get(key).get(
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index dcbd9b2..be37994 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -12,6 +12,7 @@
   "posting_date",
   "posting_time",
   "is_adjustment_entry",
+  "auto_created_serial_and_batch_bundle",
   "column_break_6",
   "voucher_type",
   "voucher_no",
@@ -340,6 +341,13 @@
    "fieldname": "is_adjustment_entry",
    "fieldtype": "Check",
    "label": "Is Adjustment Entry"
+  },
+  {
+   "default": "0",
+   "depends_on": "serial_and_batch_bundle",
+   "fieldname": "auto_created_serial_and_batch_bundle",
+   "fieldtype": "Check",
+   "label": "Auto Created Serial and Batch Bundle"
   }
  ],
  "hide_toolbar": 1,
@@ -348,7 +356,7 @@
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2023-10-23 18:07:42.063615",
+ "modified": "2023-11-14 16:47:39.791967",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Ledger Entry",
diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py
index 5998274..da98455 100644
--- a/erpnext/stock/serial_batch_bundle.py
+++ b/erpnext/stock/serial_batch_bundle.py
@@ -129,7 +129,9 @@
 			frappe.throw(_(error_msg))
 
 	def set_serial_and_batch_bundle(self, sn_doc):
-		self.sle.db_set("serial_and_batch_bundle", sn_doc.name)
+		self.sle.db_set(
+			{"serial_and_batch_bundle": sn_doc.name, "auto_created_serial_and_batch_bundle": 1}
+		)
 
 		if sn_doc.is_rejected:
 			frappe.db.set_value(
@@ -143,6 +145,12 @@
 	@property
 	def child_doctype(self):
 		child_doctype = self.sle.voucher_type + " Item"
+
+		if (
+			self.sle.voucher_type == "Subcontracting Receipt" and self.sle.dependant_sle_voucher_detail_no
+		):
+			child_doctype = "Subcontracting Receipt Supplied Item"
+
 		if self.sle.voucher_type == "Stock Entry":
 			child_doctype = "Stock Entry Detail"
 
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 6390894..9142a27 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -766,7 +766,9 @@
 		sle.doctype = "Stock Ledger Entry"
 		frappe.get_doc(sle).db_update()
 
-		if not self.args.get("sle_id"):
+		if not self.args.get("sle_id") or (
+			sle.serial_and_batch_bundle and sle.auto_created_serial_and_batch_bundle
+		):
 			self.update_outgoing_rate_on_transaction(sle)
 
 	def reset_actual_qty_for_stock_reco(self, sle):
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index 19a1c93..36001eb 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -13,6 +13,16 @@
 		frm.trigger('set_queries');
 	},
 
+	on_submit(frm) {
+		frm.events.refresh_serial_batch_bundle_field(frm);
+	},
+
+	refresh_serial_batch_bundle_field(frm) {
+		frappe.route_hooks.after_submit = (frm_obj) => {
+			frm_obj.reload_doc();
+		}
+	},
+
 	refresh: (frm) => {
 		if (frm.doc.docstatus > 0) {
 			frm.add_custom_button(__('Stock Ledger'), () => {
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index 96babf2..6191a8c 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -576,6 +576,97 @@
 		self.assertEqual(scr.items[0].rm_cost_per_qty, 300)
 		self.assertEqual(scr.items[0].service_cost_per_qty, 100)
 
+	def test_subcontracting_receipt_valuation_with_auto_created_serial_batch_bundle(self):
+		set_backflush_based_on("BOM")
+
+		fg_item = make_item(properties={"is_stock_item": 1, "is_sub_contracted_item": 1}).name
+		rm_item1 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+			}
+		).name
+
+		rm_item2 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_batch_no": 1,
+				"has_serial_no": 1,
+				"create_new_batch": 1,
+				"batch_number_series": "BNGS-.####",
+				"serial_no_series": "BNSS-.####",
+			}
+		).name
+
+		rm_item3 = make_item(
+			properties={
+				"is_stock_item": 1,
+				"has_serial_no": 1,
+				"serial_no_series": "BSSSS-.####",
+			}
+		).name
+
+		bom = make_bom(item=fg_item, raw_materials=[rm_item1, rm_item2, rm_item3])
+
+		rm_batch_no = None
+		for row in bom.items:
+			make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=300,
+			)
+
+			make_stock_entry(
+				item_code=row.item_code,
+				qty=1,
+				target="_Test Warehouse 1 - _TC",
+				rate=400,
+			)
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 1",
+				"qty": 1,
+				"rate": 100,
+				"fg_item": fg_item,
+				"fg_item_qty": 1,
+			},
+		]
+		sco = get_subcontracting_order(service_items=service_items)
+
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1
+		)
+		scr = make_subcontracting_receipt(sco.name)
+		scr.save()
+		for row in scr.supplied_items:
+			self.assertNotEqual(row.rate, 300.00)
+			self.assertFalse(row.serial_and_batch_bundle)
+
+		scr.submit()
+		scr.reload()
+
+		for row in scr.supplied_items:
+			self.assertEqual(row.rate, 300.00)
+			self.assertTrue(row.serial_and_batch_bundle)
+			auto_created_serial_batch = frappe.db.get_value(
+				"Stock Ledger Entry",
+				{"voucher_no": scr.name, "voucher_detail_no": row.name},
+				"auto_created_serial_and_batch_bundle",
+			)
+
+			self.assertTrue(auto_created_serial_batch)
+
+		self.assertEqual(scr.items[0].rm_cost_per_qty, 900)
+		self.assertEqual(scr.items[0].service_cost_per_qty, 100)
+		frappe.db.set_single_value(
+			"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 0
+		)
+
 	def test_subcontracting_receipt_raw_material_rate(self):
 		# Step - 1: Set Backflush Based On as "BOM"
 		set_backflush_based_on("BOM")