refactor: rename doctype serial and batch ledger to serial and batch entry
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index f46cec6..230a8b3 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -510,10 +510,6 @@
 			if self.is_old_subcontracting_flow:
 				self.set_consumed_qty_in_subcontract_order()
 
-			from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
-
-			update_serial_nos_after_submit(self, "items")
-
 		# this sequence because outstanding may get -negative
 		self.make_gl_entries()
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 714f24a..69e0cf2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -38,11 +38,7 @@
 from erpnext.setup.doctype.company.company import update_company_current_month_sales
 from erpnext.stock.doctype.batch.batch import set_batch_nos
 from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so
-from erpnext.stock.doctype.serial_no.serial_no import (
-	get_delivery_note_serial_no,
-	get_serial_nos,
-	update_serial_nos_after_submit,
-)
+from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no, get_serial_nos
 
 form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
 
@@ -262,8 +258,6 @@
 		# because updating reserved qty in bin depends upon updated delivered qty in SO
 		if self.update_stock == 1:
 			self.update_stock_ledger()
-		if self.is_return and self.update_stock:
-			update_serial_nos_after_submit(self, "items")
 
 		# this sequence because outstanding may get -ve
 		self.make_gl_entries()
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 8c3bd4d..8b9e0aa 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -387,7 +387,7 @@
 		bundle_doc.voucher_no = self.name
 		bundle_doc.is_cancelled = 0
 
-		for row in bundle_doc.ledgers:
+		for row in bundle_doc.entries:
 			row.is_outward = 0
 			row.qty = abs(row.qty)
 			row.stock_value_difference = abs(row.stock_value_difference)
@@ -398,8 +398,7 @@
 
 			row.warehouse = warehouse
 
-		bundle_doc.set_total_qty()
-		bundle_doc.set_avg_rate()
+		bundle_doc.calculate_qty_and_amount()
 		bundle_doc.flags.ignore_permissions = True
 
 		if not do_not_submit:
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 1418e5f..b929883 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -509,7 +509,7 @@
 
 				qty -= qty_to_consumed
 				if qty_to_consumed > 0:
-					bundle.append("ledgers", {"batch_no": batch_no, "qty": qty_to_consumed * -1})
+					bundle.append("entries", {"batch_no": batch_no, "qty": qty_to_consumed * -1})
 
 	def __set_serial_nos_for_bundle(self, bundle, qty, key):
 		bundle.has_serial_no = 1
@@ -525,7 +525,7 @@
 				if batch_no:
 					self.available_materials[key]["batch_no"][batch_no] -= 1
 
-			bundle.append("ledgers", {"serial_no": sn, "batch_no": batch_no, "qty": -1})
+			bundle.append("entries", {"serial_no": sn, "batch_no": batch_no, "qty": -1})
 
 			self.available_materials[key]["serial_no"].remove(sn)
 
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 2a81651..14ea2f8 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -360,7 +360,7 @@
 					item.is_rejected = false;
 
 					frappe.require(path, function() {
-						new erpnext.SerialNoBatchBundleUpdate(
+						new erpnext.SerialBatchPackageSelector(
 							me.frm, item, (r) => {
 								if (r) {
 									me.frm.refresh_fields();
@@ -388,7 +388,7 @@
 					item.is_rejected = true;
 
 					frappe.require(path, function() {
-						new erpnext.SerialNoBatchBundleUpdate(
+						new erpnext.SerialBatchPackageSelector(
 							me.frm, item, (r) => {
 								if (r) {
 									me.frm.refresh_fields();
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index e706ab9..70c403b 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -2318,7 +2318,16 @@
 	}
 
 	frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {
-		new erpnext.SerialNoBatchBundleUpdate(frm, item_row, (r) => {
+		if (in_list(["Sales Invoice", "Delivery Note"], frm.doc.doctype)) {
+			item_row.outward = frm.doc.is_return ? 0 : 1;
+		} else {
+			item_row.outward = frm.doc.is_return ? 1 : 0;
+		}
+
+		item_row.type_of_transaction = (item_row.outward === 1
+			? "Outward":"Inward");
+
+		new erpnext.SerialBatchPackageSelector(frm, item_row, (r) => {
 			if (r) {
 				frm.refresh_fields();
 				frappe.model.set_value(item_row.doctype, item_row.name,
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index c35e4a5..b893231 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -1,4 +1,4 @@
-erpnext.SerialNoBatchBundleUpdate = class SerialNoBatchBundleUpdate {
+erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
 	constructor(frm, item, callback) {
 		this.frm = frm;
 		this.item = item;
@@ -105,7 +105,7 @@
 		});
 
 		fields.push({
-			fieldname: 'ledgers',
+			fieldname: 'entries',
 			fieldtype: 'Table',
 			allow_bulk_edit: true,
 			data: [],
@@ -228,8 +228,8 @@
 			callback: (r) => {
 				debugger
 				if (r.message) {
-					this.dialog.fields_dict.ledgers.df.data = r.message;
-					this.dialog.fields_dict.ledgers.grid.refresh();
+					this.dialog.fields_dict.entries.df.data = r.message;
+					this.dialog.fields_dict.entries.grid.refresh();
 				}
 			}
 		});
@@ -239,44 +239,40 @@
 		const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
 
 		if (scan_serial_no) {
-			this.dialog.fields_dict.ledgers.df.data.push({
+			this.dialog.fields_dict.entries.df.data.push({
 				serial_no: scan_serial_no
 			});
 
 			this.dialog.fields_dict.scan_serial_no.set_value('');
 		} else if (scan_batch_no) {
-			this.dialog.fields_dict.ledgers.df.data.push({
+			this.dialog.fields_dict.entries.df.data.push({
 				batch_no: scan_batch_no
 			});
 
 			this.dialog.fields_dict.scan_batch_no.set_value('');
 		}
 
-		this.dialog.fields_dict.ledgers.grid.refresh();
+		this.dialog.fields_dict.entries.grid.refresh();
 	}
 
 	update_ledgers() {
-		if (!this.frm.is_new()) {
-			let ledgers = this.dialog.get_values().ledgers;
+		let entries = this.dialog.get_values().entries;
 
-			if (ledgers && !ledgers.length || !ledgers) {
-				frappe.throw(__('Please add atleast one Serial No / Batch No'));
-			}
-
-			frappe.call({
-				method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers',
-				args: {
-					ledgers: ledgers,
-					child_row: this.item,
-					doc: this.frm.doc,
-				}
-			}).then(r => {
-				this.callback && this.callback(r.message);
-				this.dialog.hide();
-			})
-		} else {
-			frappe.msgprint(__('Please save the document first'));
+		if (entries && !entries.length || !entries) {
+			frappe.throw(__('Please add atleast one Serial No / Batch No'));
 		}
+
+		frappe.call({
+			method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers',
+			args: {
+				entries: entries,
+				child_row: this.item,
+				doc: this.frm.doc,
+			}
+		}).then(r => {
+			this.callback && this.callback(r.message);
+			this.dialog.hide();
+		})
 	}
 
 	render_data() {
@@ -298,9 +294,9 @@
 
 	set_data(data) {
 		data.forEach(d => {
-			this.dialog.fields_dict.ledgers.df.data.push(d);
+			this.dialog.fields_dict.entries.df.data.push(d);
 		});
 
-		this.dialog.fields_dict.ledgers.grid.refresh();
+		this.dialog.fields_dict.entries.grid.refresh();
 	}
 }
\ No newline at end of file
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 6c18b74..f8e000a 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -441,7 +441,7 @@
 					}
 
 					frappe.require(path, function() {
-						new erpnext.SerialNoBatchBundleUpdate(
+						new erpnext.SerialBatchPackageSelector(
 							me.frm, item, (r) => {
 								if (r) {
 									me.frm.refresh_fields();
diff --git a/erpnext/stock/deprecated_serial_batch.py b/erpnext/stock/deprecated_serial_batch.py
index f2d266a..14717c6 100644
--- a/erpnext/stock/deprecated_serial_batch.py
+++ b/erpnext/stock/deprecated_serial_batch.py
@@ -67,8 +67,8 @@
 
 class DeprecatedBatchNoValuation:
 	def calculate_avg_rate_from_deprecarated_ledgers(self):
-		ledgers = self.get_sle_for_batches()
-		for ledger in ledgers:
+		entries = self.get_sle_for_batches()
+		for ledger in entries:
 			self.batch_avg_rate[ledger.batch_no] += flt(ledger.batch_value) / flt(ledger.batch_qty)
 			self.available_qty[ledger.batch_no] += flt(ledger.batch_qty)
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 284d003..1ac2f35 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -240,11 +240,6 @@
 		# because updating ordered qty, reserved_qty_for_subcontract in bin
 		# depends upon updated ordered qty in PO
 		self.update_stock_ledger()
-
-		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
-
-		update_serial_nos_after_submit(self, "items")
-
 		self.make_gl_entries()
 		self.repost_future_sle_and_gle()
 		self.set_consumed_qty_in_subcontract_order()
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
index f16a72b..858b333 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
@@ -16,7 +16,7 @@
 				method: "set_warehouse",
 				doc: frm.doc,
 				callback(r) {
-					refresh_field("ledgers");
+					refresh_field("entries");
 				}
 			})
 		}
@@ -31,11 +31,11 @@
 	},
 
 	toggle_fields(frm) {
-		frm.fields_dict.ledgers.grid.update_docfield_property(
+		frm.fields_dict.entries.grid.update_docfield_property(
 			'serial_no', 'read_only', !frm.doc.has_serial_no
 		);
 
-		frm.fields_dict.ledgers.grid.update_docfield_property(
+		frm.fields_dict.entries.grid.update_docfield_property(
 			'batch_no', 'read_only', !frm.doc.has_batch_no
 		);
 	},
@@ -74,7 +74,7 @@
 			};
 		});
 
-		frm.set_query('serial_no', 'ledgers', () => {
+		frm.set_query('serial_no', 'entries', () => {
 			return {
 				filters: {
 					item_code: frm.doc.item_code,
@@ -82,7 +82,7 @@
 			};
 		});
 
-		frm.set_query('batch_no', 'ledgers', () => {
+		frm.set_query('batch_no', 'entries', () => {
 			return {
 				filters: {
 					item: frm.doc.item_code,
@@ -90,7 +90,7 @@
 			};
 		});
 
-		frm.set_query('warehouse', 'ledgers', () => {
+		frm.set_query('warehouse', 'entries', () => {
 			return {
 				filters: {
 					company: frm.doc.company,
@@ -101,7 +101,7 @@
 });
 
 
-frappe.ui.form.on("Serial and Batch Ledger", {
+frappe.ui.form.on("Serial and Batch Entry", {
 	ledgers_add(frm, cdt, cdn) {
 		if (frm.doc.warehouse) {
 			locals[cdt][cdn].warehouse = frm.doc.warehouse;
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 7493c79..00d6b3f 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
@@ -17,7 +17,7 @@
   "has_serial_no",
   "has_batch_no",
   "serial_no_and_batch_no_tab",
-  "ledgers",
+  "entries",
   "quantity_and_rate_section",
   "total_qty",
   "item_group",
@@ -95,15 +95,8 @@
   },
   {
    "fieldname": "serial_no_and_batch_no_tab",
-   "fieldtype": "Section Break"
-  },
-  {
-   "allow_bulk_edit": 1,
-   "fieldname": "ledgers",
-   "fieldtype": "Table",
-   "label": "Ledgers",
-   "options": "Serial and Batch Ledger",
-   "reqd": 1
+   "fieldtype": "Section Break",
+   "label": "Serial / Batch No"
   },
   {
    "fieldname": "voucher_type",
@@ -232,12 +225,19 @@
    "label": "Voucher Detail No",
    "no_copy": 1,
    "read_only": 1
+  },
+  {
+   "allow_bulk_edit": 1,
+   "fieldname": "entries",
+   "fieldtype": "Table",
+   "options": "Serial and Batch Entry",
+   "reqd": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-03-12 16:05:18.141958",
+ "modified": "2023-03-21 10:52:25.105421",
  "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 4969713..9013ef0 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
@@ -28,19 +28,16 @@
 
 	def before_save(self):
 		self.set_is_outward()
-		self.set_total_qty()
+		self.calculate_qty_and_amount()
 		self.set_warehouse()
 		self.set_incoming_rate()
 		self.validate_qty_and_stock_value_difference()
 
-		if self.ledgers:
-			self.set_avg_rate()
-
 	def validate_serial_nos_inventory(self):
 		if not (self.has_serial_no and self.type_of_transaction == "Outward"):
 			return
 
-		serial_nos = [d.serial_no for d in self.ledgers if d.serial_no]
+		serial_nos = [d.serial_no for d in self.entries if d.serial_no]
 		serial_no_warehouse = frappe._dict(
 			frappe.get_all(
 				"Serial No",
@@ -68,7 +65,7 @@
 		if self.type_of_transaction != "Outward":
 			return
 
-		for d in self.ledgers:
+		for d in self.entries:
 			if d.qty and d.qty > 0:
 				d.qty *= -1
 
@@ -76,7 +73,7 @@
 				d.stock_value_difference *= -1
 
 	def get_serial_nos(self):
-		return [d.serial_no for d in self.ledgers if d.serial_no]
+		return [d.serial_no for d in self.entries if d.serial_no]
 
 	def set_incoming_rate_for_outward_transaction(self, row=None, save=False):
 		sle = self.get_sle_for_outward_transaction(row)
@@ -94,7 +91,7 @@
 				item_code=self.warehouse,
 			)
 
-		for d in self.ledgers:
+		for d in self.entries:
 			available_qty = 0
 			if self.has_serial_no:
 				d.incoming_rate = abs(sn_obj.serial_no_incoming_rate.get(d.serial_no, 0.0))
@@ -130,19 +127,23 @@
 				"serial_and_batch_bundle": self.name,
 				"actual_qty": self.total_qty,
 				"company": self.company,
-				"serial_nos": [row.serial_no for row in self.ledgers if row.serial_no],
-				"batch_nos": {row.batch_no: row for row in self.ledgers if row.batch_no},
+				"serial_nos": [row.serial_no for row in self.entries if row.serial_no],
+				"batch_nos": {row.batch_no: row for row in self.entries if row.batch_no},
 			}
 		)
 
 	def set_incoming_rate_for_inward_transaction(self, row=None, save=False):
-		rate = row.valuation_rate if row else 0.0
-		precision = frappe.get_precision(self.child_table, "valuation_rate") or 2
+		valuation_field = "valuation_rate"
+		if self.voucher_type in ["Sales Invoice", "Delivery Note"]:
+			valuation_field = "incoming_rate"
+
+		rate = row.get(valuation_field) if row else 0.0
+		precision = frappe.get_precision(self.child_table, valuation_field) or 2
 
 		if not rate and self.voucher_detail_no and self.voucher_no:
-			rate = frappe.db.get_value(self.child_table, self.voucher_detail_no, "valuation_rate")
+			rate = frappe.db.get_value(self.child_table, self.voucher_detail_no, valuation_field)
 
-		for d in self.ledgers:
+		for d in self.entries:
 			if self.voucher_type in ["Stock Reconciliation", "Stock Entry"] and d.incoming_rate:
 				continue
 
@@ -180,8 +181,9 @@
 			self.db_set(values_to_set)
 
 		# self.validate_voucher_no()
-		self.validate_quantity(row)
 		self.set_incoming_rate(save=True, row=row)
+		self.calculate_qty_and_amount(save=True)
+		self.validate_quantity(row)
 
 	def validate_voucher_no(self):
 		if self.is_new():
@@ -215,10 +217,13 @@
 		if not self.has_serial_no:
 			return
 
-		serial_nos = [d.serial_no for d in self.ledgers if d.serial_no]
+		serial_nos = [d.serial_no for d in self.entries if d.serial_no]
+
+		if not serial_nos:
+			return
 
 		parent = frappe.qb.DocType("Serial and Batch Bundle")
-		child = frappe.qb.DocType("Serial and Batch Ledger")
+		child = frappe.qb.DocType("Serial and Batch Entry")
 
 		timestamp_condition = CombineDatetime(
 			parent.posting_date, parent.posting_time
@@ -260,8 +265,6 @@
 			frappe.throw(_(msg), title=_(title), exc=SerialNoExistsInFutureTransactionError)
 
 	def validate_quantity(self, row):
-		self.set_total_qty(save=True)
-
 		precision = row.precision
 		qty_field = "qty"
 		if self.voucher_type in ["Subcontracting Receipt"]:
@@ -275,7 +278,7 @@
 			)
 
 	def set_is_outward(self):
-		for row in self.ledgers:
+		for row in self.entries:
 			if self.type_of_transaction == "Outward" and row.qty > 0:
 				row.qty *= -1
 			elif self.type_of_transaction == "Inward" and row.qty < 0:
@@ -285,30 +288,34 @@
 
 	@frappe.whitelist()
 	def set_warehouse(self):
-		for row in self.ledgers:
+		for row in self.entries:
 			if row.warehouse != self.warehouse:
 				row.warehouse = self.warehouse
 
-	def set_total_qty(self, save=False):
-		if not self.ledgers:
-			return
-
-		self.total_qty = sum([row.qty for row in self.ledgers])
-		if save:
-			self.db_set("total_qty", self.total_qty)
-
-	def set_avg_rate(self):
+	def calculate_qty_and_amount(self, save=False):
 		self.total_amount = 0.0
+		self.total_qty = 0.0
+		self.avg_rate = 0.0
 
-		for row in self.ledgers:
+		for row in self.entries:
 			rate = flt(row.incoming_rate) or flt(row.outgoing_rate)
 			self.total_amount += flt(row.qty) * rate
+			self.total_qty += flt(row.qty)
 
 		if self.total_qty:
 			self.avg_rate = flt(self.total_amount) / flt(self.total_qty)
 
+		if save:
+			self.db_set(
+				{
+					"total_qty": self.total_qty,
+					"avg_rate": self.avg_rate,
+					"total_amount": self.total_amount,
+				}
+			)
+
 	def calculate_outgoing_rate(self):
-		if not (self.has_serial_no and self.ledgers):
+		if not (self.has_serial_no and self.entries):
 			return
 
 		if not (self.voucher_type and self.voucher_no):
@@ -332,7 +339,7 @@
 		serial_nos = []
 		batch_nos = []
 
-		for row in self.ledgers:
+		for row in self.entries:
 			if row.serial_no:
 				serial_nos.append(row.serial_no)
 
@@ -362,7 +369,7 @@
 			frappe.db.set_value("Stock Ledger Entry", sle.name, "serial_and_batch_bundle", None)
 
 	def clear_table(self):
-		self.set("ledgers", [])
+		self.set("entries", [])
 
 	@property
 	def child_table(self):
@@ -434,15 +441,15 @@
 	return frappe.get_all(
 		"Serial and Batch Bundle",
 		fields=[
-			"`tabSerial and Batch Ledger`.`name`",
-			"`tabSerial and Batch Ledger`.`qty`",
-			"`tabSerial and Batch Ledger`.`warehouse`",
-			"`tabSerial and Batch Ledger`.`batch_no`",
-			"`tabSerial and Batch Ledger`.`serial_no`",
+			"`tabSerial and Batch Entry`.`name`",
+			"`tabSerial and Batch Entry`.`qty`",
+			"`tabSerial and Batch Entry`.`warehouse`",
+			"`tabSerial and Batch Entry`.`batch_no`",
+			"`tabSerial and Batch Entry`.`serial_no`",
 		],
 		filters=[
 			["Serial and Batch Bundle", "item_code", "=", item_code],
-			["Serial and Batch Ledger", "parent", "=", name],
+			["Serial and Batch Entry", "parent", "=", name],
 			["Serial and Batch Bundle", "voucher_no", "=", voucher_no],
 			["Serial and Batch Bundle", "docstatus", "!=", 2],
 		],
@@ -450,31 +457,30 @@
 
 
 @frappe.whitelist()
-def add_serial_batch_ledgers(ledgers, child_row, doc) -> object:
+def add_serial_batch_ledgers(entries, child_row, doc) -> object:
 	if isinstance(child_row, str):
 		child_row = frappe._dict(frappe.parse_json(child_row))
 
-	if isinstance(ledgers, str):
-		ledgers = frappe.parse_json(ledgers)
+	if isinstance(entries, str):
+		entries = frappe.parse_json(entries)
 
 	if doc and isinstance(doc, str):
-		d = frappe.parse_json(doc)
-		parent_doc = frappe.get_doc(d.doctype, d.name)
+		parent_doc = frappe.parse_json(doc)
 
 	if frappe.db.exists("Serial and Batch Bundle", child_row.serial_and_batch_bundle):
-		doc = update_serial_batch_no_ledgers(ledgers, child_row, parent_doc)
+		doc = update_serial_batch_no_ledgers(entries, child_row, parent_doc)
 	else:
-		doc = create_serial_batch_no_ledgers(ledgers, child_row, parent_doc)
+		doc = create_serial_batch_no_ledgers(entries, child_row, parent_doc)
 
 	return doc
 
 
-def create_serial_batch_no_ledgers(ledgers, child_row, parent_doc) -> object:
+def create_serial_batch_no_ledgers(entries, child_row, parent_doc) -> object:
 
 	warehouse = child_row.rejected_warhouse if child_row.is_rejected else child_row.warehouse
 
 	type_of_transaction = child_row.type_of_transaction
-	if parent_doc.doctype == "Stock Entry":
+	if parent_doc.get("doctype") == "Stock Entry":
 		type_of_transaction = "Outward" if child_row.s_warehouse else "Inward"
 		warehouse = child_row.s_warehouse or child_row.t_warehouse
 
@@ -482,21 +488,19 @@
 		{
 			"doctype": "Serial and Batch Bundle",
 			"voucher_type": child_row.parenttype,
-			"voucher_no": child_row.parent,
 			"item_code": child_row.item_code,
 			"warehouse": warehouse,
-			"voucher_detail_no": child_row.name,
 			"is_rejected": child_row.is_rejected,
 			"type_of_transaction": type_of_transaction,
-			"posting_date": parent_doc.posting_date,
-			"posting_time": parent_doc.posting_time,
+			"posting_date": parent_doc.get("posting_date"),
+			"posting_time": parent_doc.get("posting_time"),
 		}
 	)
 
-	for row in ledgers:
+	for row in entries:
 		row = frappe._dict(row)
 		doc.append(
-			"ledgers",
+			"entries",
 			{
 				"qty": (row.qty or 1.0) * (1 if type_of_transaction == "Inward" else -1),
 				"warehouse": warehouse,
@@ -514,16 +518,16 @@
 	return doc
 
 
-def update_serial_batch_no_ledgers(ledgers, child_row, parent_doc) -> object:
+def update_serial_batch_no_ledgers(entries, child_row, parent_doc) -> object:
 	doc = frappe.get_doc("Serial and Batch Bundle", child_row.serial_and_batch_bundle)
 	doc.voucher_detail_no = child_row.name
 	doc.posting_date = parent_doc.posting_date
 	doc.posting_time = parent_doc.posting_time
-	doc.set("ledgers", [])
+	doc.set("entries", [])
 
-	for d in ledgers:
+	for d in entries:
 		doc.append(
-			"ledgers",
+			"entries",
 			{
 				"qty": 1 if doc.type_of_transaction == "Inward" else -1,
 				"warehouse": d.get("warehouse"),
@@ -543,7 +547,7 @@
 	kwargs = frappe._dict(kwargs)
 
 	sle_table = frappe.qb.DocType("Stock Ledger Entry")
-	serial_batch_table = frappe.qb.DocType("Serial and Batch Ledger")
+	serial_batch_table = frappe.qb.DocType("Serial and Batch Entry")
 
 	query = (
 		frappe.qb.from_(sle_table)
@@ -638,7 +642,7 @@
 
 def get_available_batches(kwargs):
 	stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
-	batch_ledger = frappe.qb.DocType("Serial and Batch Ledger")
+	batch_ledger = frappe.qb.DocType("Serial and Batch Entry")
 	batch_table = frappe.qb.DocType("Batch")
 
 	query = (
@@ -708,7 +712,7 @@
 
 def get_ledgers_from_serial_batch_bundle(**kwargs) -> List[frappe._dict]:
 	bundle_table = frappe.qb.DocType("Serial and Batch Bundle")
-	serial_batch_table = frappe.qb.DocType("Serial and Batch Ledger")
+	serial_batch_table = frappe.qb.DocType("Serial and Batch Entry")
 
 	query = (
 		frappe.qb.from_(bundle_table)
@@ -776,7 +780,7 @@
 
 def get_stock_ledger_entries(item_code, warehouse):
 	stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
-	batch_ledger = frappe.qb.DocType("Serial and Batch Ledger")
+	batch_ledger = frappe.qb.DocType("Serial and Batch Entry")
 
 	return (
 		frappe.qb.from_(stock_ledger_entry)
diff --git a/erpnext/stock/doctype/serial_and_batch_ledger/__init__.py b/erpnext/stock/doctype/serial_and_batch_entry/__init__.py
similarity index 100%
rename from erpnext/stock/doctype/serial_and_batch_ledger/__init__.py
rename to erpnext/stock/doctype/serial_and_batch_entry/__init__.py
diff --git a/erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.json b/erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.json
similarity index 97%
rename from erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.json
rename to erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.json
index f2d4d55..44f3c08 100644
--- a/erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.json
+++ b/erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.json
@@ -110,7 +110,7 @@
  "modified": "2023-03-17 09:11:31.548862",
  "modified_by": "Administrator",
  "module": "Stock",
- "name": "Serial and Batch Ledger",
+ "name": "Serial and Batch Entry",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
diff --git a/erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.py b/erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.py
similarity index 82%
rename from erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.py
rename to erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.py
index 945fdc1..337403e 100644
--- a/erpnext/stock/doctype/serial_and_batch_ledger/serial_and_batch_ledger.py
+++ b/erpnext/stock/doctype/serial_and_batch_entry/serial_and_batch_entry.py
@@ -5,5 +5,5 @@
 from frappe.model.document import Document
 
 
-class SerialandBatchLedger(Document):
+class SerialandBatchEntry(Document):
 	pass
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index e4e8e17..e0c32e4 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1114,7 +1114,7 @@
 				item.outward = item.s_warehouse ? 1 : 0;
 
 				frappe.require(path, function() {
-					new erpnext.SerialNoBatchBundleUpdate(
+					new erpnext.SerialBatchPackageSelector(
 						frm, item, (r) => {
 							if (r) {
 								frm.refresh_fields();
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d71814b..0bfecae 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -242,6 +242,9 @@
 		if self.purpose == "Material Transfer" and self.outgoing_stock_entry:
 			self.set_material_request_transfer_status("In Transit")
 
+	def on_update(self):
+		self.set_serial_and_batch_bundle()
+
 	def set_job_card_data(self):
 		if self.job_card and not self.work_order:
 			data = frappe.db.get_value(
@@ -696,6 +699,9 @@
 		self.set_total_incoming_outgoing_value()
 		self.set_total_amount()
 
+		if not reset_outgoing_rate:
+			self.set_serial_and_batch_bundle()
+
 	def set_basic_rate(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
 		"""
 		Set rate for outgoing, scrapped and finished items
@@ -2830,7 +2836,7 @@
 			while qty > 0:
 				qty -= 1
 				doc.append(
-					"ledgers",
+					"entries",
 					{
 						"batch_no": batch_no,
 						"serial_no": batchwise_serial_nos.get(batch_no).pop(0),
@@ -2842,12 +2848,12 @@
 	elif row.serial_nos:
 		doc.has_serial_no = 1
 		for serial_no in row.serial_nos:
-			doc.append("ledgers", {"serial_no": serial_no, "warehouse": row.warehouse, "qty": -1})
+			doc.append("entries", {"serial_no": serial_no, "warehouse": row.warehouse, "qty": -1})
 
 	elif row.batches_to_be_consume:
 		doc.has_batch_no = 1
 		for batch_no, qty in row.batches_to_be_consume.items():
-			doc.append("ledgers", {"batch_no": batch_no, "warehouse": row.warehouse, "qty": qty * -1})
+			doc.append("entries", {"batch_no": batch_no, "warehouse": row.warehouse, "qty": qty * -1})
 
 	return doc.insert(ignore_permissions=True).name
 
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index eda4d2d..19f48e7 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -63,10 +63,6 @@
 		self.make_gl_entries()
 		self.repost_future_sle_and_gle()
 
-		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
-
-		update_serial_nos_after_submit(self, "items")
-
 	def on_cancel(self):
 		self.validate_reserved_stock()
 		self.ignore_linked_doctypes = (
@@ -108,7 +104,7 @@
 
 					for serial_no_row in serial_nos_details:
 						serial_and_batch_bundle.append(
-							"ledgers",
+							"entries",
 							{
 								"serial_no": serial_no_row.serial_no,
 								"qty": -1,
@@ -122,7 +118,7 @@
 
 					for batch_no, qty in batch_nos_details.items():
 						serial_and_batch_bundle.append(
-							"ledgers",
+							"entries",
 							{
 								"batch_no": batch_no,
 								"qty": qty * -1,
@@ -144,7 +140,7 @@
 				bundle_doc.warehouse = item.warehouse
 				bundle_doc.type_of_transaction = "Inward"
 
-				for row in bundle_doc.ledgers:
+				for row in bundle_doc.entries:
 					if row.qty < 0:
 						row.qty = abs(row.qty)
 
@@ -153,8 +149,7 @@
 
 					row.is_outward = 0
 
-				bundle_doc.set_total_qty()
-				bundle_doc.set_avg_rate()
+				bundle_doc.calculate_qty_and_amount()
 				bundle_doc.flags.ignore_permissions = True
 				bundle_doc.save()
 				item.serial_and_batch_bundle = bundle_doc.name
diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py
index e375223..f82c309 100644
--- a/erpnext/stock/serial_batch_bundle.py
+++ b/erpnext/stock/serial_batch_bundle.py
@@ -141,12 +141,8 @@
 			self.add_serial_no_to_bundle(sn_doc, sr_nos, incoming_rate, batch_no)
 		elif self.item_details.has_batch_no:
 			self.add_batch_no_to_bundle(sn_doc, batch_no, incoming_rate)
-			sn_doc.save()
 
-		sn_doc.load_from_db()
-		sn_doc.flags.ignore_validate = True
-		sn_doc.flags.ignore_mandatory = True
-
+		sn_doc.save()
 		sn_doc.submit()
 		self.set_serial_and_batch_bundle(sn_doc)
 
@@ -174,39 +170,19 @@
 		return is_rejected(self.sle.voucher_type, self.sle.voucher_detail_no, self.sle.warehouse)
 
 	def add_serial_no_to_bundle(self, sn_doc, serial_nos, incoming_rate, batch_no=None):
-		ledgers = []
-
-		fields = [
-			"name",
-			"serial_no",
-			"batch_no",
-			"warehouse",
-			"item_code",
-			"qty",
-			"incoming_rate",
-			"parent",
-			"parenttype",
-			"parentfield",
-		]
-
 		for serial_no in serial_nos:
-			ledgers.append(
-				(
-					frappe.generate_hash("Serial and Batch Ledger", 10),
-					serial_no,
-					batch_no,
-					self.warehouse,
-					self.item_details.item_code,
-					1,
-					incoming_rate,
-					sn_doc.name,
-					sn_doc.doctype,
-					"ledgers",
-				)
+			sn_doc.append(
+				"entries",
+				{
+					"serial_no": serial_no,
+					"qty": 1,
+					"incoming_rate": incoming_rate,
+					"batch_no": batch_no,
+					"warehouse": self.warehouse,
+					"is_outward": 0,
+				},
 			)
 
-		frappe.db.bulk_insert("Serial and Batch Ledger", fields=fields, values=set(ledgers))
-
 	def add_batch_no_to_bundle(self, sn_doc, batch_no, incoming_rate):
 		stock_value_difference = flt(self.sle.actual_qty) * flt(incoming_rate)
 
@@ -214,7 +190,7 @@
 			stock_value_difference *= -1
 
 		sn_doc.append(
-			"ledgers",
+			"entries",
 			{
 				"batch_no": batch_no,
 				"qty": self.sle.actual_qty,
@@ -336,14 +312,14 @@
 		).run()
 
 	def set_batch_no_in_serial_nos(self):
-		ledgers = frappe.get_all(
-			"Serial and Batch Ledger",
+		entries = frappe.get_all(
+			"Serial and Batch Entry",
 			fields=["serial_no", "batch_no"],
 			filters={"parent": self.sle.serial_and_batch_bundle},
 		)
 
 		batch_serial_nos = {}
-		for ledger in ledgers:
+		for ledger in entries:
 			batch_serial_nos.setdefault(ledger.batch_no, []).append(ledger.serial_no)
 
 		for batch_no, serial_nos in batch_serial_nos.items():
@@ -360,9 +336,9 @@
 	if check_outward:
 		filters["is_outward"] = 1
 
-	ledgers = frappe.get_all("Serial and Batch Ledger", fields=["serial_no"], filters=filters)
+	entries = frappe.get_all("Serial and Batch Entry", fields=["serial_no"], filters=filters)
 
-	return [d.serial_no for d in ledgers]
+	return [d.serial_no for d in entries]
 
 
 class SerialNoBundleValuation(DeprecatedSerialNoValuation):
@@ -380,12 +356,12 @@
 			)
 
 		else:
-			ledgers = self.get_serial_no_ledgers()
+			entries = self.get_serial_no_ledgers()
 
 			self.serial_no_incoming_rate = defaultdict(float)
 			self.stock_value_change = 0.0
 
-			for ledger in ledgers:
+			for ledger in entries:
 				self.stock_value_change += ledger.incoming_rate * -1
 				self.serial_no_incoming_rate[ledger.serial_no] = ledger.incoming_rate
 
@@ -403,7 +379,7 @@
 				), child.name, child.serial_no, child.warehouse
 			FROM
 				`tabSerial and Batch Bundle` as parent,
-				`tabSerial and Batch Ledger` as child
+				`tabSerial and Batch Entry` as child
 			WHERE
 				parent.name = child.parent
 				AND child.serial_no IN ({', '.join([frappe.db.escape(s) for s in serial_nos])})
@@ -428,7 +404,7 @@
 			SELECT
 				ledger.serial_no, ledger.incoming_rate, ledger.warehouse
 			FROM
-				`tabSerial and Batch Ledger` AS ledger,
+				`tabSerial and Batch Entry` AS ledger,
 				({subquery}) AS SubQuery
 			WHERE
 				ledger.name = SubQuery.name
@@ -508,11 +484,11 @@
 				"Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "total_amount"
 			)
 		else:
-			ledgers = self.get_batch_no_ledgers()
+			entries = self.get_batch_no_ledgers()
 
 			self.batch_avg_rate = defaultdict(float)
 			self.available_qty = defaultdict(float)
-			for ledger in ledgers:
+			for ledger in entries:
 				self.batch_avg_rate[ledger.batch_no] += flt(ledger.incoming_rate) / flt(ledger.qty)
 				self.available_qty[ledger.batch_no] += flt(ledger.qty)
 
@@ -521,7 +497,7 @@
 
 	def get_batch_no_ledgers(self) -> List[dict]:
 		parent = frappe.qb.DocType("Serial and Batch Bundle")
-		child = frappe.qb.DocType("Serial and Batch Ledger")
+		child = frappe.qb.DocType("Serial and Batch Entry")
 
 		batch_nos = list(self.batch_nos.keys())
 
@@ -554,13 +530,13 @@
 		if self.sle.get("batch_nos"):
 			return self.sle.batch_nos
 
-		ledgers = frappe.get_all(
-			"Serial and Batch Ledger",
+		entries = frappe.get_all(
+			"Serial and Batch Entry",
 			fields=["batch_no", "qty", "name"],
 			filters={"parent": self.sle.serial_and_batch_bundle, "is_outward": 1},
 		)
 
-		return {d.batch_no: d for d in ledgers}
+		return {d.batch_no: d for d in entries}
 
 	def set_stock_value_difference(self):
 		self.stock_value_change = 0
@@ -568,7 +544,7 @@
 			stock_value_change = self.batch_avg_rate[batch_no] * ledger.qty
 			self.stock_value_change += stock_value_change
 			frappe.db.set_value(
-				"Serial and Batch Ledger", ledger.name, "stock_value_difference", stock_value_change
+				"Serial and Batch Entry", ledger.name, "stock_value_difference", stock_value_change
 			)
 
 	def calculate_valuation_rate(self):
@@ -638,7 +614,7 @@
 
 def set_batch_details_from_package(ids, batches):
 	entries = frappe.get_all(
-		"Serial and Batch Ledger",
+		"Serial and Batch Entry",
 		filters={"parent": ("in", ids), "is_outward": 0},
 		fields=["batch_no", "qty"],
 	)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 416355a..dfb7786 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -1370,7 +1370,7 @@
 ):
 
 	sle = frappe.qb.DocType("Stock Ledger Entry")
-	batch_ledger = frappe.qb.DocType("Serial and Batch Ledger")
+	batch_ledger = frappe.qb.DocType("Serial and Batch Entry")
 
 	timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime(
 		posting_date, posting_time
@@ -1382,7 +1382,7 @@
 		) & (sle.creation < creation)
 
 	batches = frappe.get_all(
-		"Serial and Batch Ledger", fields=["batch_no"], filters={"parent": serial_and_batch_bundle}
+		"Serial and Batch Entry", fields=["batch_no"], filters={"parent": serial_and_batch_bundle}
 	)
 
 	batch_details = (
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 40dfd0d..212bf7f 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -95,11 +95,6 @@
 		self.set_subcontracting_order_status()
 		self.set_consumed_qty_in_subcontract_order()
 		self.update_stock_ledger()
-
-		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
-
-		update_serial_nos_after_submit(self, "items")
-
 		self.make_gl_entries()
 		self.repost_future_sle_and_gle()
 		self.update_status()