fix: Calcellation logic for reconciliation of serialized items
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index bd24257..f609a0b 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -122,8 +122,8 @@
 			self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days)
 
 		if has_expiry_date and not self.expiry_date:
-			frappe.throw(_('Expiry date is mandatory for selected item'))
-			frappe.msgprint(_('Set items shelf life in days, to set expiry based on manufacturing_date plus self life'))
+			frappe.msgprint(_('Expiry date is mandatory for selected item.'))
+			frappe.throw(_("Set item's shelf life in days, to set expiry based on manufacturing date plus shelf-life."))
 
 	def get_name_from_naming_series(self):
 		"""
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index d1bc31e..c203f8b 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -415,6 +415,9 @@
 	if not stock_ledger_entries: return
 
 	for d in controller.get(parentfield):
+		if d.serial_no:
+			continue
+
 		update_rejected_serial_nos = True if (controller.doctype in ("Purchase Receipt", "Purchase Invoice")
 			and d.rejected_qty) else False
 		accepted_serial_nos_updated = False
@@ -426,7 +429,6 @@
 			warehouse = d.warehouse
 			qty = (d.qty if controller.doctype == "Stock Reconciliation"
 				else d.stock_qty)
-
 		for sle in stock_ledger_entries:
 			if sle.voucher_detail_no==d.name:
 				if not accepted_serial_nos_updated and qty and abs(sle.actual_qty)==qty \
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 0abcbb3..f40560a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -359,7 +359,7 @@
 				d.basic_rate = 0.0
 			elif d.t_warehouse and not d.basic_rate:
 				d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
-					self.doctype, d.name, d.allow_zero_valuation_rate,
+					self.doctype, self.name, d.allow_zero_valuation_rate,
 					currency=erpnext.get_company_currency(self.company))
 
 	def set_actual_qty(self):
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 2be667c..d9e62c7 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -52,7 +52,6 @@
 		def _changed(item):
 			item_dict = get_stock_balance_for(item.item_code, item.warehouse,
 				self.posting_date, self.posting_time, batch_no=item.batch_no)
-
 			if (((item.qty is None or item.qty==item_dict.get("qty")) and
 				(item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and not item.serial_no)
 				or (item.serial_no and item.serial_no == item_dict.get("serial_nos"))):
@@ -261,16 +260,7 @@
 
 				sl_entries.append(new_args)
 
-			if self.docstatus == 2:
-				args.update({
-					'actual_qty': 1,
-					'incoming_rate': row.valuation_rate,
-					'valuation_rate': row.valuation_rate
-				})
-
-				sl_entries.append(args)
-
-		if self.docstatus == 1 and row.qty:
+		if row.qty:
 			args = self.get_sle_for_items(row)
 
 			args.update({
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index e7cb9ad..7f7835f 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -55,10 +55,12 @@
 #get all details
 def get_stock_ledger_entries(filters):
 	conditions = get_conditions(filters)
-	return frappe.db.sql("""select item_code, batch_no, warehouse,
-		posting_date, actual_qty
+	return frappe.db.sql("""
+		select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
 		from `tabStock Ledger Entry`
-		where docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse""" %
+		where docstatus < 2 and ifnull(batch_no, '') != '' %s
+		group by voucher_no, batch_no, item_code, warehouse
+		order by item_code, warehouse""" %
 		conditions, as_dict=1)
 
 def get_item_warehouse_batch_map(filters, float_precision):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index e46823e..ff5b026 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -486,6 +486,7 @@
 	if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
 			and cint(erpnext.is_perpetual_inventory_enabled(company)):
 		frappe.local.message_log = []
-		frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no))
+		frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting / cancelling this entry.")
+			.format(item_code, voucher_type, voucher_no))
 
 	return valuation_rate