Merge branch 'develop' into pick-list-enhance
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 462d967..14fdffc 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -193,7 +193,7 @@
 
 	all_dimensions = []
 	lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
-	children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
+	children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
 	all_dimensions += [c.name for c in children]
 
 	return all_dimensions
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 81effd0..7fb598b 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -434,7 +434,9 @@
 				if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
 					filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
 						filters.get(dimension.fieldname))
-				additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
+					additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
+				else:
+					additional_conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
 
 	return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
 
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 898ac13..649b363 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -202,7 +202,9 @@
 				if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
 					filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
 						filters.get(dimension.fieldname))
-				conditions.append("{0} in %({0})s".format(dimension.fieldname))
+					conditions.append("{0} in %({0})s".format(dimension.fieldname))
+				else:
+					conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
 
 	return "and {}".format(" and ".join(conditions)) if conditions else ""
 
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index 9864e40..b6e61b1 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -344,16 +344,19 @@
 	accounting_dimensions = get_accounting_dimensions(as_list=False)
 
 	if accounting_dimensions:
+		common_condition = """
+			and exists(select name from `tabSales Invoice Item`
+				where parent=`tabSales Invoice`.name
+			"""
 		for dimension in accounting_dimensions:
 			if filters.get(dimension.fieldname):
 				if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
 					filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
 						filters.get(dimension.fieldname))
 
-				conditions += """ and exists(select name from `tabSales Invoice Item`
-					where parent=`tabSales Invoice`.name
-						and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname)
-
+					conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname)
+				else:
+					conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in (%({0})s))".format(dimension.fieldname)
 
 	return conditions
 
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 5fe6b41..d783241 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -126,7 +126,9 @@
 				if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
 					filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
 						filters.get(dimension.fieldname))
-				additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
+					additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
+				else:
+					additional_conditions += "and {0} in (%({0})s)".format(dimension.fieldname)
 
 				query_filters.update({
 					dimension.fieldname: filters.get(dimension.fieldname)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index fd009ec..031d41c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -662,4 +662,6 @@
 erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
 erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
 erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
+erpnext.patches.v12_0.recalculate_requested_qty_in_bin
+erpnext.patches.v12_0.set_total_batch_quantity
 erpnext.patches.v12_0.set_updated_purpose_in_pick_list
diff --git a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
new file mode 100644
index 0000000..8267df9
--- /dev/null
+++ b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
+
+def execute():
+	bin_details = frappe.db.sql("""
+		SELECT item_code, warehouse
+		FROM `tabBin`""",as_dict=1)
+
+	for entry in bin_details:
+		update_bin_qty(entry.get("item_code"), entry.get("warehouse"), {
+			"indented_qty": get_indented_qty(entry.get("item_code"), entry.get("warehouse"))
+		})
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_total_batch_quantity.py b/erpnext/patches/v12_0/set_total_batch_quantity.py
new file mode 100644
index 0000000..d373275
--- /dev/null
+++ b/erpnext/patches/v12_0/set_total_batch_quantity.py
@@ -0,0 +1,11 @@
+import frappe
+
+
+def execute():
+	frappe.reload_doc("stock", "doctype", "batch")
+
+	for batch in frappe.get_all("Batch", fields=["name", "batch_id"]):
+		batch_qty = frappe.db.get_value("Stock Ledger Entry",
+			{"docstatus": 1, "batch_no": batch.batch_id, "is_cancelled": "No"},
+			"sum(actual_qty)") or 0.0
+		frappe.db.set_value("Batch", batch.name, "batch_qty", batch_qty, update_modified=False)
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 4397fe4..2c436b2 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -473,6 +473,7 @@
 							item_code: item.item_code,
 							barcode: item.barcode,
 							serial_no: item.serial_no,
+							batch_no: item.batch_no,
 							set_warehouse: me.frm.doc.set_warehouse,
 							warehouse: item.warehouse,
 							customer: me.frm.doc.customer || me.frm.doc.party_name,
@@ -637,6 +638,7 @@
 
 				// Add the new list to the serial no. field in grid with each in new line
 				item.serial_no = valid_serial_nos.join('\n');
+				item.conversion_factor = item.conversion_factor || 1;
 
 				refresh_field("serial_no", item.name, item.parentfield);
 				if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
diff --git a/erpnext/stock/doctype/batch/batch.json b/erpnext/stock/doctype/batch/batch.json
index e6d4e9d..1eb4577 100644
--- a/erpnext/stock/doctype/batch/batch.json
+++ b/erpnext/stock/doctype/batch/batch.json
@@ -1,554 +1,194 @@
 {
- "allow_copy": 0,
- "allow_guest_to_view": 0,
  "allow_import": 1,
- "allow_rename": 0,
  "autoname": "field:batch_id",
- "beta": 0,
  "creation": "2013-03-05 14:50:38",
- "custom": 0,
- "docstatus": 0,
  "doctype": "DocType",
  "document_type": "Setup",
- "editable_grid": 0,
  "engine": "InnoDB",
+ "field_order": [
+  "sb_disabled",
+  "disabled",
+  "sb_batch",
+  "batch_id",
+  "item",
+  "item_name",
+  "image",
+  "parent_batch",
+  "manufacturing_date",
+  "column_break_3",
+  "batch_qty",
+  "stock_uom",
+  "expiry_date",
+  "source",
+  "supplier",
+  "column_break_9",
+  "reference_doctype",
+  "reference_name",
+  "section_break_7",
+  "description"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
+   "default": "0",
+   "fieldname": "disabled",
+   "fieldtype": "Check",
+   "label": "Disabled"
+  },
+  {
    "depends_on": "eval:doc.__islocal",
    "fieldname": "batch_id",
    "fieldtype": "Data",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
    "in_list_view": 1,
-   "in_standard_filter": 0,
    "label": "Batch ID",
-   "length": 0,
    "no_copy": 1,
    "oldfieldname": "batch_id",
    "oldfieldtype": "Data",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
    "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
    "unique": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "item",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 1,
    "in_standard_filter": 1,
    "label": "Item",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "item",
    "oldfieldtype": "Link",
    "options": "Item",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "image",
    "fieldtype": "Attach Image",
    "hidden": 1,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "image",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "label": "image"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "depends_on": "eval:doc.parent_batch",
    "fieldname": "parent_batch",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Parent Batch",
-   "length": 0,
-   "no_copy": 0,
    "options": "Batch",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fieldname": "column_break_3",
-   "fieldtype": "Column Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fieldname": "disabled",
-   "fieldtype": "Check",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Disabled",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "default": "Today",
    "fieldname": "manufacturing_date",
    "fieldtype": "Date",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Manufacturing Date",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "label": "Manufacturing Date"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
    "fieldname": "expiry_date",
    "fieldtype": "Date",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Expiry Date",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "expiry_date",
-   "oldfieldtype": "Date",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "oldfieldtype": "Date"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "source",
    "fieldtype": "Section Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Source",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "label": "Source"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "supplier",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Supplier",
-   "length": 0,
-   "no_copy": 0,
    "options": "Supplier",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break_9",
-   "fieldtype": "Column Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "reference_doctype",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Source Document Type",
-   "length": 0,
-   "no_copy": 0,
    "options": "DocType",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "reference_name",
    "fieldtype": "Dynamic Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Source Document Name",
-   "length": 0,
-   "no_copy": 0,
    "options": "reference_doctype",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "section_break_7",
-   "fieldtype": "Section Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Section Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "description",
    "fieldtype": "Small Text",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Batch Description",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "description",
    "oldfieldtype": "Small Text",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0,
    "width": "300px"
+  },
+  {
+   "fieldname": "sb_disabled",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "sb_batch",
+   "fieldtype": "Section Break",
+   "label": "Batch Details"
+  },
+  {
+   "fetch_from": "item.item_name",
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Item Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "batch_qty",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Batch Quantity",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "item.stock_uom",
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "Batch UOM",
+   "options": "UOM",
+   "read_only": 1
   }
  ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
  "icon": "fa fa-archive",
  "idx": 1,
  "image_field": "image",
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
  "max_attachments": 5,
- "modified": "2018-08-29 06:28:57.985997",
+ "modified": "2019-10-03 22:38:45.104056",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Batch",
  "owner": "harshada@webnotestech.com",
  "permissions": [
   {
-   "amend": 0,
-   "cancel": 0,
    "create": 1,
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
    "import": 1,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "Item Manager",
    "set_user_permissions": 1,
    "share": 1,
-   "submit": 0,
    "write": 1
   }
  ],
  "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
+ "sort_field": "modified",
  "sort_order": "DESC",
- "title_field": "item",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "title_field": "batch_id"
 }
\ No newline at end of file
diff --git a/erpnext/stock/doctype/batch/batch_dashboard.py b/erpnext/stock/doctype/batch/batch_dashboard.py
new file mode 100644
index 0000000..eb6a97e
--- /dev/null
+++ b/erpnext/stock/doctype/batch/batch_dashboard.py
@@ -0,0 +1,27 @@
+from __future__ import unicode_literals
+
+from frappe import _
+
+
+def get_data():
+	return {
+		'fieldname': 'batch_no',
+		'transactions': [
+			{
+				'label': _('Buy'),
+				'items': ['Purchase Invoice', 'Purchase Receipt']
+			},
+			{
+				'label': _('Sell'),
+				'items': ['Sales Invoice', 'Delivery Note']
+			},
+			{
+				'label': _('Move'),
+				'items': ['Stock Entry']
+			},
+			{
+				'label': _('Quality'),
+				'items': ['Quality Inspection']
+			}
+		]
+	}
diff --git a/erpnext/stock/doctype/batch/batch_list.js b/erpnext/stock/doctype/batch/batch_list.js
index 7ee81aa..d4f74c3 100644
--- a/erpnext/stock/doctype/batch/batch_list.js
+++ b/erpnext/stock/doctype/batch/batch_list.js
@@ -1,12 +1,14 @@
 frappe.listview_settings['Batch'] = {
-	add_fields: ["item", "expiry_date"],
-	get_indicator: function(doc) {
-		if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
-			return [__("Expired"), "red", "expiry_date,>=,Today"]
-		} else if(doc.expiry_date) {
-			return [__("Not Expired"), "green", "expiry_date,<,Today"]
+	add_fields: ["item", "expiry_date", "batch_qty", "disabled"],
+	get_indicator: (doc) => {
+		if (doc.disabled) {
+			return [__("Disabled"), "darkgrey", "disabled,=,1"];
+		} else if (!doc.batch_qty) {
+			return [__("Empty"), "darkgrey", "batch_qty,=,0|disabled,=,0"];
+		} else if (doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
+			return [__("Expired"), "red", "expiry_date,not in,|expiry_date,<=,Today|batch_qty,>,0|disabled,=,0"]
 		} else {
-			return ["Not Set", "darkgrey", ""];
-		}
+			return [__("Active"), "green", "batch_qty,>,0|disabled,=,0"];
+		};
 	}
 };
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 32445a6..1fce504 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -7,7 +7,7 @@
 import unittest
 
 from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
-from frappe.utils import cint
+from frappe.utils import cint, flt
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
 
 class TestBatch(unittest.TestCase):
@@ -35,12 +35,13 @@
 		receipt = frappe.get_doc(dict(
 			doctype='Purchase Receipt',
 			supplier='_Test Supplier',
+			company='_Test Company',
 			items=[
 				dict(
 					item_code='ITEM-BATCH-1',
 					qty=batch_qty,
 					rate=10,
-					warehouse= 'Stores - WP'
+					warehouse= 'Stores - _TC'
 				)
 			]
 		)).insert()
@@ -175,6 +176,18 @@
 
 		self.assertEqual(get_batch_qty('batch a', '_Test Warehouse - _TC'), 90)
 
+	def test_total_batch_qty(self):
+		self.make_batch_item('ITEM-BATCH-3')
+		existing_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
+		stock_entry = self.make_new_batch_and_entry('ITEM-BATCH-3', 'B100', '_Test Warehouse - _TC')
+
+		current_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
+		self.assertEqual(current_batch_qty, existing_batch_qty + 90)
+
+		stock_entry.cancel()
+		current_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
+		self.assertEqual(current_batch_qty, existing_batch_qty)
+		
 	@classmethod
 	def make_new_batch_and_entry(cls, item_name, batch_name, warehouse):
 		'''Make a new stock entry for given target warehouse and batch name of item'''
@@ -208,6 +221,8 @@
 		stock_entry.insert()
 		stock_entry.submit()
 
+		return stock_entry
+
 	def test_batch_name_with_naming_series(self):
 		stock_settings = frappe.get_single('Stock Settings')
 		use_naming_series = cint(stock_settings.use_naming_series)
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index e2e84c4..7d31942 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -101,6 +101,7 @@
 		self.add_default_uom_in_conversion_factor_table()
 		self.validate_conversion_factor()
 		self.validate_item_type()
+		self.validate_naming_series()
 		self.check_for_active_boms()
 		self.fill_customer_code()
 		self.check_item_tax()
@@ -186,7 +187,7 @@
 					or frappe.db.get_single_value('Stock Settings', 'default_warehouse'))
 			if default_warehouse:
 				warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
-			
+
 			if not default_warehouse or warehouse_company != default.company:
 				default_warehouse = frappe.db.get_value('Warehouse',
 					{'warehouse_name': _('Stores'), 'company': default.company})
@@ -522,6 +523,13 @@
 		if self.has_serial_no == 0 and self.serial_no_series:
 			self.serial_no_series = None
 
+	def validate_naming_series(self):
+		for field in ["serial_no_series", "batch_number_series"]:
+			series = self.get(field)
+			if series and "#" in series and "." not in series:
+				frappe.throw(_("Invalid naming series (. missing) for {0}")
+					.format(frappe.bold(self.meta.get_field(field).label)))
+
 	def check_for_active_boms(self):
 		if self.default_bom:
 			bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
@@ -1007,8 +1015,6 @@
 		order by pr.posting_date desc, pr.posting_time desc, pr.name desc
 		limit 1""", (item_code, cstr(doc_name)), as_dict=1)
 
-	
-	
 	purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
 							   or "1900-01-01")
 	purchase_receipt_date = getdate(last_purchase_receipt and
@@ -1016,7 +1022,7 @@
 
 	if last_purchase_order and (purchase_order_date >= purchase_receipt_date or not last_purchase_receipt):
 		# use purchase order
-		
+
 		last_purchase = last_purchase_order[0]
 		purchase_date = purchase_order_date
 
@@ -1036,7 +1042,7 @@
 		"discount_percentage": flt(last_purchase.discount_percentage),
 		"purchase_date": purchase_date
 	})
-	
+
 
 	conversion_rate = flt(conversion_rate) or 1.0
 	out.update({
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 79cdc1a..b925aed 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -276,8 +276,8 @@
 		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
 		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
-		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
-		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
+		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
+		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
 
 		from erpnext.stock.doctype.material_request.material_request import make_stock_entry
 
@@ -331,8 +331,8 @@
 		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
 		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
-		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
-		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
+		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 27.0)
+		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 1.5)
 
 		# check if per complete is as expected for Stock Entry cancelled
 		se.cancel()
@@ -344,8 +344,8 @@
 		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
 		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
-		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
-		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
+		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
+		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
 
 	def test_completed_qty_for_over_transfer(self):
 		existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
@@ -425,8 +425,8 @@
 		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
 		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
-		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
-		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
+		self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
+		self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
 
 	def test_incorrect_mapping_of_stock_entry(self):
 		# submit material request of type Transfer
@@ -512,7 +512,7 @@
 		mr.submit()
 
 		#testing bin value after material request is submitted
-		self.assertEqual(_get_requested_qty(), existing_requested_qty + 54.0)
+		self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0)
 
 		# receive items to allow issue
 		self._insert_stock_entry(60, 6, "_Test Warehouse - _TC")
@@ -609,6 +609,8 @@
 	def test_customer_provided_parts_mr(self):
 		from erpnext.stock.doctype.material_request.material_request import make_stock_entry
 		create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
+		existing_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
+
 		mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
 		se = make_stock_entry(mr.name)
 		se.insert()
@@ -617,7 +619,10 @@
 		self.assertEqual(se.get("items")[0].material_request, mr.name)
 		mr = frappe.get_doc("Material Request", mr.name)
 		mr.submit()
+		current_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
+
 		self.assertEqual(mr.per_ordered, 100)
+		self.assertEqual(existing_requested_qty, current_requested_qty)
 
 def make_material_request(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 35446ec..e38bb38 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -47,6 +47,7 @@
   "is_subcontracted",
   "supplier_warehouse",
   "items_section",
+  "scan_barcode",
   "items",
   "pricing_rule_details",
   "pricing_rules",
@@ -1070,13 +1071,18 @@
    "label": "Inter Company Reference",
    "options": "Delivery Note",
    "read_only": 1
+  },
+  {
+   "fieldname": "scan_barcode",
+   "fieldtype": "Data",
+   "label": "Scan Barcode"
   }
  ],
  "icon": "fa fa-truck",
  "idx": 261,
  "is_submittable": 1,
  "links": [],
- "modified": "2019-12-30 19:12:49.709711",
+ "modified": "2020-04-06 16:31:37.444891",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 5fe89d6..45ed498 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -37,11 +37,19 @@
 	def on_submit(self):
 		self.check_stock_frozen_date()
 		self.actual_amt_check()
+		self.calculate_batch_qty()
 
 		if not self.get("via_landed_cost_voucher"):
 			from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
 			process_serial_no(self)
 
+	def calculate_batch_qty(self):
+		if self.batch_no:
+			batch_qty = frappe.db.get_value("Stock Ledger Entry", 
+				{"docstatus": 1, "batch_no": self.batch_no, "is_cancelled": "No"},
+				"sum(actual_qty)") or 0
+			frappe.db.set_value("Batch", self.batch_no, "batch_qty", batch_qty)
+
 	#check for item quantity available in stock
 	def actual_amt_check(self):
 		if self.batch_no and not self.get("allow_negative_stock"):
@@ -139,4 +147,3 @@
 
 	frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
 	frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
-
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index afa2394..0a49c26 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -488,12 +488,14 @@
 		["has_serial_no", "has_batch_no"], as_dict=1)
 
 	serial_nos = ""
-	if item_dict.get("has_serial_no"):
-		qty, rate, serial_nos = get_qty_rate_for_serial_nos(item_code,
-			warehouse, posting_date, posting_time, item_dict)
+	with_serial_no = True if item_dict.get("has_serial_no") else False
+	data = get_stock_balance(item_code, warehouse, posting_date, posting_time,
+		with_valuation_rate=with_valuation_rate, with_serial_no=with_serial_no)
+
+	if with_serial_no:
+		qty, rate, serial_nos = data
 	else:
-		qty, rate = get_stock_balance(item_code, warehouse,
-			posting_date, posting_time, with_valuation_rate=with_valuation_rate)
+		qty, rate = data
 
 	if item_dict.get("has_batch_no"):
 		qty = get_batch_qty(batch_no, warehouse) or 0
@@ -504,28 +506,6 @@
 		'serial_nos': serial_nos
 	}
 
-def get_qty_rate_for_serial_nos(item_code, warehouse, posting_date, posting_time, item_dict):
-	args = {
-		"item_code": item_code,
-		"warehouse": warehouse,
-		"posting_date": posting_date,
-		"posting_time": posting_time,
-	}
-
-	serial_nos_list = [serial_no.get("name")
-			for serial_no in get_available_serial_nos(args)]
-
-	qty = len(serial_nos_list)
-	serial_nos = '\n'.join(serial_nos_list)
-	args.update({
-		'qty': qty,
-		"serial_nos": serial_nos
-	})
-
-	rate = get_incoming_rate(args, raise_error_if_no_rate=False) or 0
-
-	return qty, rate, serial_nos
-
 @frappe.whitelist()
 def get_difference_account(purpose, company):
 	if purpose == 'Stock Reconciliation':
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 9c5a8e1..b1bfc90 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -245,7 +245,7 @@
 		'item_group_defaults': item_group_defaults,
 		'brand_defaults': brand_defaults
 	})
-	
+
 	warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)
 
 	if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
@@ -279,7 +279,7 @@
 		"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
 		'has_serial_no': item.has_serial_no,
 		'has_batch_no': item.has_batch_no,
-		"batch_no": None,
+		"batch_no": args.get("batch_no"),
 		"uom": args.uom,
 		"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
 		"qty": flt(args.qty) or 1.0,
@@ -377,7 +377,7 @@
 
 	else:
 		warehouse = args.get('warehouse')
-	
+
 	return warehouse
 
 def update_barcode_value(out):
diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
index 94ec314..1af68dd 100644
--- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
+++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
@@ -35,7 +35,7 @@
 		gl_data = voucher_wise_gl_data.get(key) or {}
 		d.account_value = gl_data.get("account_value", 0)
 		d.difference_value = (d.stock_value - d.account_value)
-		if abs(d.difference_value) > 1.0/10 ** currency_precision:
+		if abs(d.difference_value) > 0.1:
 			data.append(d)
 
 	return data
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index e5dc6b1..2bdb04e 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -113,13 +113,24 @@
 	return flt(reserved_qty[0][0]) if reserved_qty else 0
 
 def get_indented_qty(item_code, warehouse):
-	indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
+	inward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
+			from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
+			where mr_item.item_code=%s and mr_item.warehouse=%s
+			and mr.material_request_type in ('Purchase', 'Manufacture')
+			and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
+			and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
+
+	outward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
 		from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
 		where mr_item.item_code=%s and mr_item.warehouse=%s
+		and mr.material_request_type in ('Material Issue', 'Material Transfer')
 		and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
 		and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
 
-	return flt(indented_qty[0][0]) if indented_qty else 0
+	inward_qty, outward_qty = flt(inward_qty[0][0]) if inward_qty else 0, flt(outward_qty[0][0]) if outward_qty else 0
+	indented_qty = inward_qty - outward_qty
+
+	return indented_qty
 
 def get_ordered_qty(item_code, warehouse):
 	ordered_qty = frappe.db.sql("""
@@ -145,9 +156,9 @@
 	from erpnext.stock.utils import get_bin
 	bin = get_bin(item_code, warehouse)
 	mismatch = False
-	for fld, val in qty_dict.items():
-		if flt(bin.get(fld)) != flt(val):
-			bin.set(fld, flt(val))
+	for field, value in qty_dict.items():
+		if flt(bin.get(field)) != flt(value):
+			bin.set(field, flt(value))
 			mismatch = True
 
 	if mismatch:
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index f3381c7..7f32b8d 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -74,7 +74,8 @@
 	return sum(sle_map.values())
 
 @frappe.whitelist()
-def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False):
+def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None,
+	with_valuation_rate=False, with_serial_no=False):
 	"""Returns stock balance quantity at given warehouse on given posting date or current date.
 
 	If `with_valuation_rate` is True, will return tuple (qty, rate)"""
@@ -84,17 +85,51 @@
 	if not posting_date: posting_date = nowdate()
 	if not posting_time: posting_time = nowtime()
 
-	last_entry = get_previous_sle({
+	args = {
 		"item_code": item_code,
 		"warehouse":warehouse,
 		"posting_date": posting_date,
-		"posting_time": posting_time })
+		"posting_time": posting_time
+	}
+
+	last_entry = get_previous_sle(args)
 
 	if with_valuation_rate:
-		return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
+		if with_serial_no:
+			serial_nos = last_entry.get("serial_no")
+
+			if (serial_nos and
+				len(get_serial_nos_data(serial_nos)) < last_entry.qty_after_transaction):
+				serial_nos = get_serial_nos_data_after_transactions(args)
+
+			return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
+				if last_entry else (0.0, 0.0, 0.0))
+		else:
+			return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
 	else:
 		return last_entry.qty_after_transaction if last_entry else 0.0
 
+def get_serial_nos_data_after_transactions(args):
+	serial_nos = []
+	data = frappe.db.sql(""" SELECT serial_no, actual_qty
+		FROM `tabStock Ledger Entry`
+		WHERE
+			item_code = %(item_code)s and warehouse = %(warehouse)s
+			and timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)
+			order by posting_date, posting_time asc """, args, as_dict=1)
+
+	for d in data:
+		if d.actual_qty > 0:
+			serial_nos.extend(get_serial_nos_data(d.serial_no))
+		else:
+			serial_nos = list(set(serial_nos) - set(get_serial_nos_data(d.serial_no)))
+
+	return '\n'.join(serial_nos)
+
+def get_serial_nos_data(serial_nos):
+	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+	return get_serial_nos(serial_nos)
+
 @frappe.whitelist()
 def get_latest_stock_qty(item_code, warehouse=None):
 	values, condition = [item_code], ""