solved conflicts
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 6fe1811..3715d77 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_import": 1,
  "autoname": "naming_series:",
  "creation": "2013-05-21 16:16:39",
@@ -417,6 +418,7 @@
    "fieldname": "contact_email",
    "fieldtype": "Small Text",
    "label": "Contact Email",
+   "options": "Email",
    "print_hide": 1,
    "read_only": 1
   },
@@ -1287,7 +1289,8 @@
  "icon": "fa fa-file-text",
  "idx": 204,
  "is_submittable": 1,
- "modified": "2019-09-17 22:31:42.666601",
+ "links": [],
+ "modified": "2019-12-24 12:51:58.613538",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 0f4d445..9ea5a51 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -90,6 +90,7 @@
 		self.validate_account_for_change_amount()
 		self.validate_fixed_asset()
 		self.set_income_account_for_fixed_assets()
+		self.validate_item_cost_centers()
 		validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_invoice_reference)
 
 		if cint(self.is_pos):
@@ -147,6 +148,12 @@
 					elif asset.status in ("Scrapped", "Cancelled", "Sold"):
 						frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}").format(d.idx, d.asset, asset.status))
 
+	def validate_item_cost_centers(self):
+		for item in self.items:
+			cost_center_company = frappe.get_cached_value("Cost Center", item.cost_center, "company")
+			if cost_center_company != self.company:
+				frappe.throw(_("Row #{0}: Cost Center {1} does not belong to company {2}").format(frappe.bold(item.idx), frappe.bold(item.cost_center), frappe.bold(self.company)))
+
 	def before_save(self):
 		set_account_for_mode_of_payment(self)
 
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
index bd4b4d7..69f9907 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
@@ -18,6 +18,10 @@
 	account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
 	gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
 
+	if payment_doctype == "Payment Entry" and payment_entry.unallocated_amount > transaction.unallocated_amount:
+		frappe.throw(_("The unallocated amount of Payment Entry {0} \
+			is greater than the Bank Transaction's unallocated amount").format(payment_name))
+		
 	if transaction.unallocated_amount == 0:
 		frappe.throw(_("This bank transaction is already fully reconciled"))
 
@@ -373,4 +377,4 @@
 			'start': start,
 			'page_len': page_len
 		}
-	)
\ No newline at end of file
+	)
diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
index 0c99f14..7854660 100644
--- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
+++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
@@ -4,126 +4,141 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import formatdate, getdate, flt, add_days
+from frappe.utils import formatdate, flt, add_days
+
 
 def execute(filters=None):
 	filters.day_before_from_date = add_days(filters.from_date, -1)
 	columns, data = get_columns(filters), get_data(filters)
 	return columns, data
-	
+
+
 def get_data(filters):
 	data = []
-	
+
 	asset_categories = get_asset_categories(filters)
 	assets = get_assets(filters)
-	asset_costs = get_asset_costs(assets, filters)
-	asset_depreciations = get_accumulated_depreciations(assets, filters)
-	
+
 	for asset_category in asset_categories:
 		row = frappe._dict()
-		row.asset_category = asset_category
-		row.update(asset_costs.get(asset_category))
+		# row.asset_category = asset_category
+		row.update(asset_category)
 
-		row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase)
-			- flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
-			
-		row.update(asset_depreciations.get(asset_category))
-		row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) + 
-			flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
-		
-		row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) - 
-			flt(row.accumulated_depreciation_as_on_from_date))
-		
-		row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) - 
-			flt(row.accumulated_depreciation_as_on_to_date))
-	
+		row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) -
+				flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
+
+		row.update(next(asset for asset in assets if asset["asset_category"] == asset_category.get("asset_category", "")))
+		row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
+				flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
+
+		row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
+				flt(row.accumulated_depreciation_as_on_from_date))
+
+		row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
+				flt(row.accumulated_depreciation_as_on_to_date))
+
 		data.append(row)
-		
+
 	return data
-	
+
+
 def get_asset_categories(filters):
-	return frappe.db.sql_list("""
-		select distinct asset_category from `tabAsset` 
-		where docstatus=1 and company=%s and purchase_date <= %s
-	""", (filters.company, filters.to_date))
-	
+	return frappe.db.sql("""
+		SELECT asset_category,
+			   ifnull(sum(case when purchase_date < %(from_date)s then
+							   case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
+									gross_purchase_amount
+							   else
+									0
+							   end
+						   else
+								0
+						   end), 0) as cost_as_on_from_date,
+			   ifnull(sum(case when purchase_date >= %(from_date)s then
+			   						gross_purchase_amount
+			   				   else
+			   				   		0
+			   				   end), 0) as cost_of_new_purchase,
+			   ifnull(sum(case when ifnull(disposal_date, 0) != 0
+			   						and disposal_date >= %(from_date)s
+			   						and disposal_date <= %(to_date)s then
+							   case when status = "Sold" then
+							   		gross_purchase_amount
+							   else
+							   		0
+							   end
+						   else
+								0
+						   end), 0) as cost_of_sold_asset,
+			   ifnull(sum(case when ifnull(disposal_date, 0) != 0
+			   						and disposal_date >= %(from_date)s
+			   						and disposal_date <= %(to_date)s then
+							   case when status = "Scrapped" then
+							   		gross_purchase_amount
+							   else
+							   		0
+							   end
+						   else
+								0
+						   end), 0) as cost_of_scrapped_asset
+		from `tabAsset`
+		where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s
+		group by asset_category
+	""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
+
+
 def get_assets(filters):
 	return frappe.db.sql("""
-		select name, asset_category, purchase_date, gross_purchase_amount, disposal_date, status
-		from `tabAsset` 
-		where docstatus=1 and company=%s and purchase_date <= %s""", 
-		(filters.company, filters.to_date), as_dict=1)
-		
-def get_asset_costs(assets, filters):
-	asset_costs = frappe._dict()
-	for d in assets:
-		asset_costs.setdefault(d.asset_category, frappe._dict({
-			"cost_as_on_from_date": 0,
-			"cost_of_new_purchase": 0,
-			"cost_of_sold_asset": 0,
-			"cost_of_scrapped_asset": 0
-		}))
-		
-		costs = asset_costs[d.asset_category]
-		
-		if getdate(d.purchase_date) < getdate(filters.from_date):
-			if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date):
-				costs.cost_as_on_from_date += flt(d.gross_purchase_amount)
-		else:
-			costs.cost_of_new_purchase += flt(d.gross_purchase_amount)
-			
-			if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \
-					and getdate(d.disposal_date) <= getdate(filters.to_date):
-				if d.status == "Sold":
-					costs.cost_of_sold_asset += flt(d.gross_purchase_amount)
-				elif d.status == "Scrapped":
-					costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount)
-			
-	return asset_costs
-	
-def get_accumulated_depreciations(assets, filters):
-	asset_depreciations = frappe._dict()
-	for d in assets:
-		asset = frappe.get_doc("Asset", d.name)
-		
-		if d.asset_category in asset_depreciations:
-			asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation
-		else:
-			asset_depreciations.setdefault(d.asset_category, frappe._dict({
-				"accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
-				"depreciation_amount_during_the_period": 0,
-				"depreciation_eliminated_during_the_period": 0
-			}))
+		SELECT results.asset_category,
+			   sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
+			   sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
+			   sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
+		from (SELECT a.asset_category,
+				   ifnull(sum(a.opening_accumulated_depreciation +
+							  case when ds.schedule_date < %(from_date)s and
+										(ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
+								   ds.depreciation_amount
+							  else
+								   0
+							  end), 0) as accumulated_depreciation_as_on_from_date,
+				   ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
+										and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
+								   ds.depreciation_amount
+							  else
+								   0
+							  end), 0) as depreciation_eliminated_during_the_period,
 
-		depr = asset_depreciations[d.asset_category]
+				   ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
+										and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
+								   ds.depreciation_amount
+							  else
+								   0
+							  end), 0) as depreciation_amount_during_the_period
+			from `tabAsset` a, `tabDepreciation Schedule` ds
+			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent
+			group by a.asset_category
+			union
+			SELECT a.asset_category,
+				   ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
+										and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
+									0
+							   else
+									a.opening_accumulated_depreciation
+							   end), 0) as accumulated_depreciation_as_on_from_date,
+				   ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
+								   a.opening_accumulated_depreciation
+							  else
+								   0
+							  end), 0) as depreciation_eliminated_during_the_period,
+				   0 as depreciation_amount_during_the_period
+			from `tabAsset` a
+			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s
+			and not exists(select * from `tabDepreciation Schedule` ds where a.name = ds.parent)
+			group by a.asset_category) as results
+		group by results.asset_category
+		""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
 
-		if not asset.schedules: # if no schedule,
-			if asset.disposal_date:
-				# and disposal is NOT within the period, then opening accumulated depreciation not included
-				if getdate(asset.disposal_date) < getdate(filters.from_date) or getdate(asset.disposal_date) > getdate(filters.to_date):
-					asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] = 0
 
-				# if no schedule, and disposal is within period, accumulated dep is the amount eliminated
-				if getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
-					depr.depreciation_eliminated_during_the_period += asset.opening_accumulated_depreciation
-		
-		for schedule in asset.get("schedules"):
-			if getdate(schedule.schedule_date) < getdate(filters.from_date):
-				if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date):
-					depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount)
-			elif getdate(schedule.schedule_date) <= getdate(filters.to_date):
-				if not asset.disposal_date:
-					depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
-				else:
-					if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
-						depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
-
-			if asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
-				if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
-					depr.depreciation_eliminated_during_the_period += flt(schedule.depreciation_amount)
-		
-	return asset_depreciations
-	
 def get_columns(filters):
 	return [
 		{
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 2451187..3ec4d30 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -46,13 +46,24 @@
 			fieldtype: "Select",
 			options: ["Cost Center", "Project"],
 			default: "Cost Center",
-			reqd: 1
+			reqd: 1,
+			on_change: function() {
+				frappe.query_report.set_filter_value("budget_against_filter", []);
+				frappe.query_report.refresh();
+			}
 		},
 		{
-			fieldname: "cost_center",
-			label: __("Cost Center"),
-			fieldtype: "Link",
-			options: "Cost Center"
+			fieldname:"budget_against_filter",
+			label: __('Dimension Filter'),
+			fieldtype: "MultiSelectList",
+			get_data: function(txt) {
+				if (!frappe.query_report.filters) return;
+
+				let budget_against = frappe.query_report.get_filter_value('budget_against');
+				if (!budget_against) return;
+
+				return frappe.db.get_link_options(budget_against, txt);
+			}
 		},
 		{
 			fieldname:"show_cumulative",
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 8d65ac8..39e218b 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -12,22 +12,22 @@
 from pprint import pprint
 def execute(filters=None):
 	if not filters: filters = {}
-	validate_filters(filters)
+
 	columns = get_columns(filters)
-	if filters.get("cost_center"):
-		cost_centers = [filters.get("cost_center")]
+	if filters.get("budget_against_filter"):
+		dimensions = filters.get("budget_against_filter")
 	else:
-		cost_centers = get_cost_centers(filters)
+		dimensions = get_cost_centers(filters)
 
 	period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
-	cam_map = get_cost_center_account_month_map(filters)
+	cam_map = get_dimension_account_month_map(filters)
 
 	data = []
-	for cost_center in cost_centers:
-		cost_center_items = cam_map.get(cost_center)
-		if cost_center_items:
-			for account, monthwise_data in iteritems(cost_center_items):
-				row = [cost_center, account]
+	for dimension in dimensions:
+		dimension_items = cam_map.get(dimension)
+		if dimension_items:
+			for account, monthwise_data in iteritems(dimension_items):
+				row = [dimension, account]
 				totals = [0, 0, 0]
 				for year in get_fiscal_years(filters):
 					last_total = 0
@@ -55,10 +55,6 @@
 
 	return columns, data
 
-def validate_filters(filters):
-	if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
-		frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
-
 def get_columns(filters):
 	columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
 
@@ -98,11 +94,12 @@
 	else:
 		return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
 
-#Get cost center & target details
-def get_cost_center_target_details(filters):
+#Get dimension & target details
+def get_dimension_target_details(filters):
 	cond = ""
-	if filters.get("cost_center"):
-		cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
+	if filters.get("budget_against_filter"):
+		cond += " and b.{budget_against} in (%s)".format(budget_against = \
+			frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
 
 	return frappe.db.sql("""
 			select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
@@ -110,8 +107,8 @@
 			where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
 			and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
 		""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
-		(filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
-
+		tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')), 
+		as_dict=True)
 
 
 #Get target distribution details of accounts of cost center
@@ -153,14 +150,14 @@
 
 	return cc_actual_details
 
-def get_cost_center_account_month_map(filters):
+def get_dimension_account_month_map(filters):
 	import datetime
-	cost_center_target_details = get_cost_center_target_details(filters)
+	dimension_target_details = get_dimension_target_details(filters)
 	tdd = get_target_distribution_details(filters)
 
 	cam_map = {}
 
-	for ccd in cost_center_target_details:
+	for ccd in dimension_target_details:
 		actual_details = get_actual_details(ccd.budget_against, filters)
 
 		for month_id in range(1, 13):
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 8cd44c7..d4c5ace 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -342,6 +342,7 @@
    "fieldname": "contact_email",
    "fieldtype": "Small Text",
    "label": "Contact Email",
+   "options": "Email",
    "print_hide": 1,
    "read_only": 1
   },
@@ -1054,7 +1055,7 @@
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2019-12-18 13:13:22.852412",
+ "modified": "2019-12-24 12:44:13.137194",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 08f5d8b..1712369 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -118,6 +118,73 @@
 		self.assertEqual(po.get("items")[0].amount, 1400)
 		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
 
+	
+	def test_add_new_item_in_update_child_qty_rate(self):
+		po = create_purchase_order(do_not_save=1)
+		po.items[0].qty = 4
+		po.save()
+		po.submit()
+		pr = make_pr_against_po(po.name, 2)
+
+		po.load_from_db()
+		first_item_of_po = po.get("items")[0]
+
+		trans_item = json.dumps([
+			{
+				'item_code': first_item_of_po.item_code,
+				'rate': first_item_of_po.rate,
+				'qty': first_item_of_po.qty,
+				'docname': first_item_of_po.name
+			},
+			{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}
+		])
+		update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+		po.reload()
+		self.assertEquals(len(po.get('items')), 2)
+		self.assertEqual(po.status, 'To Receive and Bill')
+
+	
+	def test_remove_item_in_update_child_qty_rate(self):
+		po = create_purchase_order(do_not_save=1)
+		po.items[0].qty = 4
+		po.save()
+		po.submit()
+		pr = make_pr_against_po(po.name, 2)
+
+		po.reload()
+		first_item_of_po = po.get("items")[0]
+		# add an item
+		trans_item = json.dumps([
+			{
+				'item_code': first_item_of_po.item_code,
+				'rate': first_item_of_po.rate,
+				'qty': first_item_of_po.qty,
+				'docname': first_item_of_po.name
+			},
+			{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}])
+		update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+		po.reload()
+		# check if can remove received item
+		trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.get("items")[1].name}])
+		self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Purchase Order', trans_item, po.name)
+
+		first_item_of_po = po.get("items")[0]
+		trans_item = json.dumps([
+			{
+				'item_code': first_item_of_po.item_code,
+				'rate': first_item_of_po.rate,
+				'qty': first_item_of_po.qty,
+				'docname': first_item_of_po.name
+			}
+		])
+		update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+		po.reload()
+		self.assertEquals(len(po.get('items')), 1)
+		self.assertEqual(po.status, 'To Receive and Bill')
+
 	def test_update_qty(self):
 		po = create_purchase_order()
 
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 6150516..86f5d53 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1155,6 +1155,25 @@
 	child_item.base_amount = 1 # Initiallize value will update in parent validation
 	return child_item
 
+def check_and_delete_children(parent, data):
+	deleted_children = []
+	updated_item_names = [d.get("docname") for d in data]
+	for item in parent.items:
+		if item.name not in updated_item_names:
+			deleted_children.append(item)
+
+	for d in deleted_children:
+		if parent.doctype == "Sales Order" and flt(d.delivered_qty):
+			frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been delivered").format(d.idx, d.item_code))
+
+		if parent.doctype == "Purchase Order" and flt(d.received_qty):
+			frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been received").format(d.idx, d.item_code))
+		
+		if flt(d.billed_amt):
+			frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been billed.").format(d.idx, d.item_code))
+
+		d.cancel()
+		d.delete()
 
 @frappe.whitelist()
 def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
@@ -1163,6 +1182,8 @@
 	sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
 	parent = frappe.get_doc(parent_doctype, parent_doctype_name)
 
+	check_and_delete_children(parent, data)
+
 	for d in data:
 		new_child_flag = False
 		if not d.get("docname"):
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 7b4a4c9..5c31900 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -311,6 +311,7 @@
 				and sle.item_code = %(item_code)s
 				and sle.warehouse = %(warehouse)s
 				and (sle.batch_no like %(txt)s
+				or batch.expiry_date like %(txt)s
 				or batch.manufacturing_date like %(txt)s)
 				and batch.docstatus < 2
 				{cond}
@@ -329,6 +330,7 @@
 			where batch.disabled = 0
 			and item = %(item_code)s
 			and (name like %(txt)s
+			or expiry_date like %(txt)s
 			or manufacturing_date like %(txt)s)
 			and docstatus < 2
 			{0}
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 9dbd5be..9a9f3d1 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -148,13 +148,6 @@
 		if sales_team and total != 100.0:
 			throw(_("Total allocated percentage for sales team should be 100"))
 
-	def validate_order_type(self):
-		valid_types = ["Sales", "Maintenance", "Shopping Cart"]
-		if not self.order_type:
-			self.order_type = "Sales"
-		elif self.order_type not in valid_types:
-			throw(_("Order Type must be one of {0}").format(comma_or(valid_types)))
-
 	def validate_max_discount(self):
 		for d in self.get("items"):
 			if d.item_code:
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 122e2b4..0c88d28 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
 frappe.provide("erpnext");
@@ -7,57 +7,54 @@
 erpnext.LeadController = frappe.ui.form.Controller.extend({
 	setup: function () {
 		this.frm.make_methods = {
+			'Customer': this.make_customer,
 			'Quotation': this.make_quotation,
-			'Opportunity': this.create_opportunity
-		}
-
-		this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) {
-			return { query: "erpnext.controllers.queries.customer_query" }
-		}
+			'Opportunity': this.make_opportunity
+		};
 
 		this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
 	},
 
 	onload: function () {
-		if (cur_frm.fields_dict.lead_owner.df.options.match(/^User/)) {
-			cur_frm.fields_dict.lead_owner.get_query = function (doc, cdt, cdn) {
-				return { query: "frappe.core.doctype.user.user.user_query" }
-			}
-		}
+		this.frm.set_query("customer", function (doc, cdt, cdn) {
+			return { query: "erpnext.controllers.queries.customer_query" }
+		});
 
-		if (cur_frm.fields_dict.contact_by.df.options.match(/^User/)) {
-			cur_frm.fields_dict.contact_by.get_query = function (doc, cdt, cdn) {
-				return { query: "frappe.core.doctype.user.user.user_query" }
-			}
-		}
+		this.frm.set_query("lead_owner", function (doc, cdt, cdn) {
+			return { query: "frappe.core.doctype.user.user.user_query" }
+		});
+
+		this.frm.set_query("contact_by", function (doc, cdt, cdn) {
+			return { query: "frappe.core.doctype.user.user.user_query" }
+		});
 	},
 
 	refresh: function () {
-		var doc = this.frm.doc;
+		let doc = this.frm.doc;
 		erpnext.toggle_naming_series();
 		frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' }
 
-		if(!doc.__islocal && doc.__onload && !doc.__onload.is_customer) {
-			this.frm.add_custom_button(__("Customer"), this.create_customer, __('Create'));
-			this.frm.add_custom_button(__("Opportunity"), this.create_opportunity, __('Create'));
-			this.frm.add_custom_button(__("Quotation"), this.make_quotation, __('Create'));
+		if (!this.frm.is_new() && doc.__onload && !doc.__onload.is_customer) {
+			this.frm.add_custom_button(__("Customer"), this.make_customer, __("Create"));
+			this.frm.add_custom_button(__("Opportunity"), this.make_opportunity, __("Create"));
+			this.frm.add_custom_button(__("Quotation"), this.make_quotation, __("Create"));
 		}
 
-		if (!this.frm.doc.__islocal) {
-			frappe.contacts.render_address_and_contact(cur_frm);
+		if (!this.frm.is_new()) {
+			frappe.contacts.render_address_and_contact(this.frm);
 		} else {
-			frappe.contacts.clear_address_and_contact(cur_frm);
+			frappe.contacts.clear_address_and_contact(this.frm);
 		}
 	},
 
-	create_customer: function () {
+	make_customer: function () {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.lead.lead.make_customer",
 			frm: cur_frm
 		})
 	},
 
-	create_opportunity: function () {
+	make_opportunity: function () {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.crm.doctype.lead.lead.make_opportunity",
 			frm: cur_frm
@@ -77,7 +74,7 @@
 	},
 
 	company_name: function () {
-		if (this.frm.doc.organization_lead == 1) {
+		if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) {
 			this.frm.set_value("lead_name", this.frm.doc.company_name);
 		}
 	},
@@ -85,7 +82,7 @@
 	contact_date: function () {
 		if (this.frm.doc.contact_date) {
 			let d = moment(this.frm.doc.contact_date);
-			d.add(1, "hours");
+			d.add(1, "day");
 			this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat));
 		}
 	}
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index eb68c67..bc007b1 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_events_in_timeline": 1,
  "allow_import": 1,
  "autoname": "naming_series:",
@@ -16,6 +17,8 @@
   "col_break123",
   "lead_owner",
   "status",
+  "salutation",
+  "designation",
   "gender",
   "source",
   "customer",
@@ -28,17 +31,22 @@
   "ends_on",
   "notes_section",
   "notes",
-  "contact_info",
-  "address_desc",
+  "address_info",
   "address_html",
+  "address_title",
+  "address_line1",
+  "address_line2",
+  "city",
+  "county",
   "column_break2",
   "contact_html",
+  "state",
+  "country",
+  "pincode",
+  "contact_section",
   "phone",
-  "salutation",
   "mobile_no",
   "fax",
-  "website",
-  "territory",
   "more_info",
   "type",
   "market_segment",
@@ -46,8 +54,11 @@
   "request_type",
   "column_break3",
   "company",
+  "website",
+  "territory",
   "unsubscribed",
-  "blog_subscriber"
+  "blog_subscriber",
+  "title"
  ],
  "fields": [
   {
@@ -73,7 +84,6 @@
    "set_only_once": 1
   },
   {
-   "depends_on": "eval:!doc.organization_lead",
    "fieldname": "lead_name",
    "fieldtype": "Data",
    "in_global_search": 1,
@@ -130,7 +140,13 @@
    "search_index": 1
   },
   {
-   "depends_on": "eval:!doc.organization_lead",
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "salutation",
+   "fieldtype": "Link",
+   "label": "Salutation",
+   "options": "Salutation"
+  },
+  {
    "fieldname": "gender",
    "fieldtype": "Link",
    "label": "Gender",
@@ -217,39 +233,73 @@
    "label": "Notes"
   },
   {
-   "collapsible": 1,
-   "fieldname": "contact_info",
-   "fieldtype": "Section Break",
-   "label": "Address & Contact",
-   "oldfieldtype": "Column Break",
-   "options": "fa fa-map-marker"
-  },
-  {
-   "depends_on": "eval:doc.__islocal",
-   "fieldname": "address_desc",
-   "fieldtype": "HTML",
-   "label": "Address Desc",
-   "print_hide": 1
-  },
-  {
    "fieldname": "address_html",
    "fieldtype": "HTML",
    "label": "Address HTML",
    "read_only": 1
   },
   {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "address_title",
+   "fieldtype": "Data",
+   "label": "Address Title"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "address_line1",
+   "fieldtype": "Data",
+   "label": "Address Line 1"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "address_line2",
+   "fieldtype": "Data",
+   "label": "Address Line 2"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "city",
+   "fieldtype": "Data",
+   "label": "City/Town"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "county",
+   "fieldtype": "Data",
+   "label": "County"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "state",
+   "fieldtype": "Data",
+   "label": "State"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "country",
+   "fieldtype": "Link",
+   "label": "Country",
+   "options": "Country"
+  },
+  {
+   "depends_on": "eval: doc.__islocal",
+   "fieldname": "pincode",
+   "fieldtype": "Data",
+   "label": "Postal Code",
+   "options": "Country"
+  },
+  {
    "fieldname": "column_break2",
    "fieldtype": "Column Break"
   },
   {
-   "depends_on": "eval:doc.organization_lead",
    "fieldname": "contact_html",
    "fieldtype": "HTML",
    "label": "Contact HTML",
    "read_only": 1
   },
   {
-   "depends_on": "eval:!doc.organization_lead",
+   "depends_on": "eval: doc.__islocal",
    "fieldname": "phone",
    "fieldtype": "Data",
    "label": "Phone",
@@ -257,14 +307,7 @@
    "oldfieldtype": "Data"
   },
   {
-   "depends_on": "eval:!doc.organization_lead",
-   "fieldname": "salutation",
-   "fieldtype": "Link",
-   "label": "Salutation",
-   "options": "Salutation"
-  },
-  {
-   "depends_on": "eval:!doc.organization_lead",
+   "depends_on": "eval: doc.__islocal",
    "fieldname": "mobile_no",
    "fieldtype": "Data",
    "label": "Mobile No.",
@@ -272,7 +315,7 @@
    "oldfieldtype": "Data"
   },
   {
-   "depends_on": "eval:!doc.organization_lead",
+   "depends_on": "eval: doc.__islocal",
    "fieldname": "fax",
    "fieldtype": "Data",
    "label": "Fax",
@@ -280,22 +323,6 @@
    "oldfieldtype": "Data"
   },
   {
-   "fieldname": "website",
-   "fieldtype": "Data",
-   "label": "Website",
-   "oldfieldname": "website",
-   "oldfieldtype": "Data"
-  },
-  {
-   "fieldname": "territory",
-   "fieldtype": "Link",
-   "label": "Territory",
-   "oldfieldname": "territory",
-   "oldfieldtype": "Link",
-   "options": "Territory",
-   "print_hide": 1
-  },
-  {
    "collapsible": 1,
    "fieldname": "more_info",
    "fieldtype": "Section Break",
@@ -351,6 +378,22 @@
    "remember_last_selected_value": 1
   },
   {
+   "fieldname": "website",
+   "fieldtype": "Data",
+   "label": "Website",
+   "oldfieldname": "website",
+   "oldfieldtype": "Data"
+  },
+  {
+   "fieldname": "territory",
+   "fieldtype": "Link",
+   "label": "Territory",
+   "oldfieldname": "territory",
+   "oldfieldtype": "Link",
+   "options": "Territory",
+   "print_hide": 1
+  },
+  {
    "default": "0",
    "fieldname": "unsubscribed",
    "fieldtype": "Check",
@@ -361,12 +404,42 @@
    "fieldname": "blog_subscriber",
    "fieldtype": "Check",
    "label": "Blog Subscriber"
+  },
+  {
+   "fieldname": "title",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Title",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "designation",
+   "fieldtype": "Link",
+   "label": "Designation",
+   "options": "Designation"
+  },
+  {
+   "collapsible": 1,
+   "collapsible_depends_on": "eval: doc.__islocal",
+   "fieldname": "address_info",
+   "fieldtype": "Section Break",
+   "label": "Address & Contact",
+   "oldfieldtype": "Column Break",
+   "options": "fa fa-map-marker"
+  },
+  {
+   "collapsible": 1,
+   "collapsible_depends_on": "eval: doc.__islocal",
+   "fieldname": "contact_section",
+   "fieldtype": "Section Break",
+   "label": "Contact"
   }
  ],
  "icon": "fa fa-user",
  "idx": 5,
  "image_field": "image",
- "modified": "2019-09-19 12:49:02.536647",
+ "links": [],
+ "modified": "2019-12-24 16:00:44.239168",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Lead",
@@ -438,5 +511,5 @@
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
- "title_field": "lead_name"
+ "title_field": "title"
 }
\ No newline at end of file
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 1dae4b9..6cab18dc 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -2,18 +2,19 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
-import frappe
-from frappe import _
-from frappe.utils import (cstr, validate_email_address, cint, comma_and, has_gravatar, now, getdate, nowdate)
-from frappe.model.mapper import get_mapped_doc
 
-from erpnext.controllers.selling_controller import SellingController
-from frappe.contacts.address_and_contact import load_address_and_contact
+import frappe
 from erpnext.accounts.party import set_taxes
+from erpnext.controllers.selling_controller import SellingController
+from frappe import _
+from frappe.contacts.address_and_contact import load_address_and_contact
 from frappe.email.inbox import link_communication_to_document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, comma_and, cstr, getdate, has_gravatar, nowdate, validate_email_address
 
 sender_field = "email_id"
 
+
 class Lead(SellingController):
 	def get_feed(self):
 		return '{0}: {1}'.format(_(self.status), self.lead_name)
@@ -23,15 +24,23 @@
 		self.get("__onload").is_customer = customer
 		load_address_and_contact(self)
 
+	def before_insert(self):
+		self.address_doc = self.create_address()
+		self.contact_doc = self.create_contact()
+
+	def after_insert(self):
+		self.update_links()
+		# after the address and contact are created, flush the field values
+		# to avoid inconsistent reporting in case the documents are changed
+		self.flush_address_and_contact_fields()
+
 	def validate(self):
 		self.set_lead_name()
+		self.set_title()
 		self._prev = frappe._dict({
-			"contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if \
-				(not cint(self.get("__islocal"))) else None,
-			"ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if \
-				(not cint(self.get("__islocal"))) else None,
-			"contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if \
-				(not cint(self.get("__islocal"))) else None,
+			"contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None,
+			"ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None,
+			"contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None,
 		})
 
 		self.set_status()
@@ -39,7 +48,7 @@
 
 		if self.email_id:
 			if not self.flags.ignore_email_validation:
-				validate_email_address(self.email_id, True)
+				validate_email_address(self.email_id, throw=True)
 
 			if self.email_id == self.lead_owner:
 				frappe.throw(_("Lead Owner cannot be same as the Lead"))
@@ -53,8 +62,7 @@
 		if self.contact_date and getdate(self.contact_date) < getdate(nowdate()):
 			frappe.throw(_("Next Contact Date cannot be in the past"))
 
-		if self.ends_on and self.contact_date and\
-			(self.ends_on < self.contact_date):
+		if self.ends_on and self.contact_date and (self.ends_on < self.contact_date):
 			frappe.throw(_("Ends On date cannot be before Next Contact Date."))
 
 	def on_update(self):
@@ -66,23 +74,21 @@
 			"starts_on": self.contact_date,
 			"ends_on": self.ends_on or "",
 			"subject": ('Contact ' + cstr(self.lead_name)),
-			"description": ('Contact ' + cstr(self.lead_name)) + \
-				(self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
+			"description": ('Contact ' + cstr(self.lead_name)) + (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
 		}, force)
 
 	def check_email_id_is_unique(self):
 		if self.email_id:
 			# validate email is unique
-			duplicate_leads = frappe.db.sql_list("""select name from tabLead
-				where email_id=%s and name!=%s""", (self.email_id, self.name))
+			duplicate_leads = frappe.get_all("Lead", filters={"email_id": self.email_id, "name": ["!=", self.name]})
+			duplicate_leads = [lead.name for lead in duplicate_leads]
 
 			if duplicate_leads:
 				frappe.throw(_("Email Address must be unique, already exists for {0}")
 					.format(comma_and(duplicate_leads)), frappe.DuplicateEntryError)
 
 	def on_trash(self):
-		frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""",
-			self.name)
+		frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name)
 
 		self.delete_events()
 
@@ -115,10 +121,101 @@
 
 			self.lead_name = self.company_name
 
+	def set_title(self):
+		if self.organization_lead:
+			self.title = self.company_name
+		else:
+			self.title = self.lead_name
+
+	def create_address(self):
+		address_fields = ["address_title", "address_line1", "address_line2",
+			"city", "county", "state", "country", "pincode"]
+		info_fields = ["email_id", "phone", "fax"]
+
+		# do not create an address if no fields are available,
+		# skipping country since the system auto-sets it from system defaults
+		if not any([self.get(field) for field in address_fields if field != "country"]):
+			return
+
+		address = frappe.new_doc("Address")
+		address.update({addr_field: self.get(addr_field) for addr_field in address_fields})
+		address.update({info_field: self.get(info_field) for info_field in info_fields})
+		address.insert()
+
+		return address
+
+	def create_contact(self):
+		if not self.lead_name:
+			self.set_lead_name()
+
+		names = self.lead_name.split(" ")
+		if len(names) > 1:
+			first_name, last_name = names[0], " ".join(names[1:])
+		else:
+			first_name, last_name = self.lead_name, None
+
+		contact = frappe.new_doc("Contact")
+		contact.update({
+			"first_name": first_name,
+			"last_name": last_name,
+			"salutation": self.salutation,
+			"gender": self.gender,
+			"designation": self.designation,
+		})
+
+		if self.email_id:
+			contact.append("email_ids", {
+				"email_id": self.email_id,
+				"is_primary": 1
+			})
+
+		if self.phone:
+			contact.append("phone_nos", {
+				"phone": self.phone,
+				"is_primary": 1
+			})
+
+		if self.mobile_no:
+			contact.append("phone_nos", {
+				"phone": self.mobile_no
+			})
+
+		contact.insert()
+
+		return contact
+
+	def update_links(self):
+		# update address links
+		if self.address_doc:
+			self.address_doc.append("links", {
+				"link_doctype": "Lead",
+				"link_name": self.name,
+				"link_title": self.lead_name
+			})
+			self.address_doc.save()
+
+		# update contact links
+		if self.contact_doc:
+			self.contact_doc.append("links", {
+				"link_doctype": "Lead",
+				"link_name": self.name,
+				"link_title": self.lead_name
+			})
+			self.contact_doc.save()
+
+	def flush_address_and_contact_fields(self):
+		fields = ['address_line1', 'address_line2', 'address_title',
+			'city', 'county', 'country', 'fax', 'pincode', 'state']
+
+		for field in fields:
+			self.set(field, None)
+
+
 @frappe.whitelist()
 def make_customer(source_name, target_doc=None):
 	return _make_customer(source_name, target_doc)
 
+
 def _make_customer(source_name, target_doc=None, ignore_permissions=False):
 	def set_missing_values(source, target):
 		if source.company_name:
@@ -143,6 +240,7 @@
 
 	return doclist
 
+
 @frappe.whitelist()
 def make_opportunity(source_name, target_doc=None):
 	def set_missing_values(source, target):
@@ -164,6 +262,7 @@
 
 	return target_doc
 
+
 @frappe.whitelist()
 def make_quotation(source_name, target_doc=None):
 	def set_missing_values(source, target):
@@ -205,7 +304,8 @@
 
 @frappe.whitelist()
 def get_lead_details(lead, posting_date=None, company=None):
-	if not lead: return {}
+	if not lead:
+		return {}
 
 	from erpnext.accounts.party import set_address_details
 	out = frappe._dict()
@@ -231,6 +331,7 @@
 
 	return out
 
+
 @frappe.whitelist()
 def make_lead_from_communication(communication, ignore_communication_links=False):
 	""" raise a issue from email """
@@ -267,4 +368,4 @@
 
 	lead = leads[0].name if leads else None
 
-	return lead
\ No newline at end of file
+	return lead
diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py
index 058d476..28df2fc 100644
--- a/erpnext/education/doctype/instructor/instructor.py
+++ b/erpnext/education/doctype/instructor/instructor.py
@@ -27,7 +27,7 @@
 		self.validate_duplicate_employee()
 
 	def validate_duplicate_employee(self):
-		if self.employee and frappe.db.get_value("Instructor", {'employee': self.employee}, 'name'):
+		if self.employee and frappe.db.get_value("Instructor", {'employee': self.employee, 'name': ['!=', self.name]}, 'name'):
 			frappe.throw(_("Employee ID is linked with another instructor"))
 
 
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 242531b..4d49503 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -164,6 +164,12 @@
 		if self.personal_email:
 			validate_email_address(self.personal_email, True)
 
+	def set_preferred_email(self):
+		preferred_email_field = frappe.scrub(self.prefered_contact_email)
+		if preferred_email_field:
+			preferred_email = self.get(preferred_email_field)
+			self.prefered_email = preferred_email
+
 	def validate_status(self):
 		if self.status == 'Left':
 			reports_to = frappe.db.get_all('Employee',
diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py
index 0d01c67..f362539 100644
--- a/erpnext/hub_node/api.py
+++ b/erpnext/hub_node/api.py
@@ -115,6 +115,16 @@
 
 	return valid_items
 
+@frappe.whitelist()
+def update_item(ref_doc, data):
+	data = json.loads(data)
+
+	data.update(dict(doctype='Hub Item', name=ref_doc))
+	try:
+		connection = get_hub_connection()
+		connection.update(data)
+	except Exception as e:
+		frappe.log_error(message=e, title='Hub Sync Error')
 
 @frappe.whitelist()
 def publish_selected_items(items_to_publish):
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index c4238ac..ff4ebfe 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -856,4 +856,4 @@
 
 	doc.set_item_locations()
 
-	return doc
\ No newline at end of file
+	return doc
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e26b1c8..89be499 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -649,5 +649,7 @@
 erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger
 erpnext.patches.v12_0.update_price_or_product_discount
 erpnext.patches.v12_0.set_production_capacity_in_workstation
+erpnext.patches.v12_0.set_employee_preferred_emails
 erpnext.patches.v12_0.set_against_blanket_order_in_sales_and_purchase_order
 erpnext.patches.v12_0.set_cost_center_in_child_table_of_expense_claim
+erpnext.patches.v12_0.set_lead_title_field
diff --git a/erpnext/patches/v12_0/set_employee_preferred_emails.py b/erpnext/patches/v12_0/set_employee_preferred_emails.py
new file mode 100644
index 0000000..2763561
--- /dev/null
+++ b/erpnext/patches/v12_0/set_employee_preferred_emails.py
@@ -0,0 +1,16 @@
+import frappe

+

+

+def execute():

+	employees = frappe.get_all("Employee",

+		filters={"prefered_email": ""},

+		fields=["name", "prefered_contact_email", "company_email", "personal_email", "user_id"])

+

+	for employee in employees:

+		preferred_email_field = frappe.scrub(employee.prefered_contact_email)

+

+		if not preferred_email_field:

+			continue

+

+		preferred_email = employee.get(preferred_email_field)

+		frappe.db.set_value("Employee", employee.name, "prefered_email", preferred_email, update_modified=False)

diff --git a/erpnext/patches/v12_0/set_lead_title_field.py b/erpnext/patches/v12_0/set_lead_title_field.py
new file mode 100644
index 0000000..86e0003
--- /dev/null
+++ b/erpnext/patches/v12_0/set_lead_title_field.py
@@ -0,0 +1,11 @@
+import frappe
+
+
+def execute():
+	frappe.reload_doc("crm", "doctype", "lead")
+	frappe.db.sql("""
+		UPDATE
+			`tabLead`
+		SET
+			title = IF(organization_lead = 1, company_name, lead_name)
+	""")
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 6ca0958..3b907da 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1808,14 +1808,44 @@
 	}
 });
 
-erpnext.show_serial_batch_selector = function(frm, d, callback, on_close, show_dialog) {
+erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_dialog) {
+	let warehouse, receiving_stock, existing_stock;
+	if (frm.doc.is_return) {
+		if (["Purchase Receipt", "Purchase Invoice"].includes(frm.doc.doctype)) {
+			existing_stock = true;
+			warehouse = d.warehouse;
+		} else if (["Delivery Note", "Sales Invoice"].includes(frm.doc.doctype)) {
+			receiving_stock = true;
+		}
+	} else {
+		if (frm.doc.doctype == "Stock Entry") {
+			if (frm.doc.purpose == "Material Receipt") {
+				receiving_stock = true;
+			} else {
+				existing_stock = true;
+				warehouse = d.s_warehouse;
+			}
+		} else {
+			existing_stock = true;
+			warehouse = d.warehouse;
+		}
+	}
+
+	if (!warehouse) {
+		if (receiving_stock) {
+			warehouse = ["like", ""];
+		} else if (existing_stock) {
+			warehouse = ["!=", ""];
+		}
+	}
+
 	frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {
 		new erpnext.SerialNoBatchSelector({
 			frm: frm,
 			item: d,
 			warehouse_details: {
 				type: "Warehouse",
-				name: d.warehouse
+				name: warehouse
 			},
 			callback: callback,
 			on_close: on_close
diff --git a/erpnext/public/js/hub/components/edit_details_dialog.js b/erpnext/public/js/hub/components/edit_details_dialog.js
new file mode 100644
index 0000000..97c5f83
--- /dev/null
+++ b/erpnext/public/js/hub/components/edit_details_dialog.js
@@ -0,0 +1,41 @@
+function edit_details_dialog(params) {
+	let dialog = new frappe.ui.Dialog({
+		title: __('Update Details'),
+		fields: [
+			{
+				label: 'Item Name',
+				fieldname: 'item_name',
+				fieldtype: 'Data',
+				default: params.defaults.item_name,
+				reqd: 1
+			},
+			{
+				label: 'Hub Category',
+				fieldname: 'hub_category',
+				fieldtype: 'Autocomplete',
+				default: params.defaults.hub_category,
+				options: [],
+				reqd: 1
+			},
+			{
+				label: 'Description',
+				fieldname: 'description',
+				fieldtype: 'Text',
+				default: params.defaults.description,
+				options: [],
+				reqd: 1
+			}
+		],
+		primary_action_label: params.primary_action.label || __('Update Details'),
+		primary_action: params.primary_action.fn
+	});
+
+	hub.call('get_categories').then(categories => {
+		categories = categories.map(d => d.name);
+		dialog.fields_dict.hub_category.set_data(categories);
+	});
+
+	return dialog;
+}
+
+export { edit_details_dialog };
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
index 841d004..1174478 100644
--- a/erpnext/public/js/hub/pages/Item.vue
+++ b/erpnext/public/js/hub/pages/Item.vue
@@ -1,10 +1,5 @@
 <template>
-	<div
-		class="marketplace-page"
-		:data-page-name="page_name"
-		v-if="init || item"
-	>
-
+	<div class="marketplace-page" :data-page-name="page_name" v-if="init || item">
 		<detail-view
 			:title="title"
 			:image="image"
@@ -12,20 +7,15 @@
 			:menu_items="menu_items"
 			:show_skeleton="init"
 		>
-			<detail-header-item slot="detail-header-item"
-				:value="item_subtitle"
-			></detail-header-item>
-			<detail-header-item slot="detail-header-item"
-				:value="item_views_and_ratings"
-			></detail-header-item>
+			<detail-header-item slot="detail-header-item" :value="item_subtitle"></detail-header-item>
+			<detail-header-item slot="detail-header-item" :value="item_views_and_ratings"></detail-header-item>
 
-			<button v-if="primary_action" slot="detail-header-item"
+			<button
+				v-if="primary_action"
+				slot="detail-header-item"
 				class="btn btn-primary btn-sm margin-top"
 				@click="primary_action.action"
-			>
-				{{ primary_action.label }}
-			</button>
-
+			>{{ primary_action.label }}</button>
 		</detail-view>
 
 		<review-area v-if="!init" :hub_item_name="hub_item_name"></review-area>
@@ -35,6 +25,7 @@
 <script>
 import ReviewArea from '../components/ReviewArea.vue';
 import { get_rating_html } from '../components/reviews';
+import { edit_details_dialog } from '../components/edit_details_dialog';
 
 export default {
 	name: 'item-page',
@@ -51,21 +42,20 @@
 			item: null,
 			title: null,
 			image: null,
-			sections: [],
-
+			sections: []
 		};
 	},
 	computed: {
 		is_own_item() {
 			let is_own_item = false;
-			if(this.item) {
-				if(this.item.hub_seller === hub.settings.hub_seller_name) {
+			if (this.item) {
+				if (this.item.hub_seller === hub.settings.hub_seller_name) {
 					is_own_item = true;
 				}
 			}
 			return is_own_item;
 		},
-		menu_items(){
+		menu_items() {
 			return [
 				{
 					label: __('Save Item'),
@@ -92,11 +82,11 @@
 					condition: hub.is_user_registered() && this.is_own_item,
 					action: this.unpublish_item
 				}
-			]
+			];
 		},
 
 		item_subtitle() {
-			if(!this.item) {
+			if (!this.item) {
 				return '';
 			}
 
@@ -105,25 +95,31 @@
 			const rating = this.item.average_rating;
 
 			if (rating > 0) {
-				subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
+				subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`);
 			}
 
-			subtitle_items.push({value:this.item.company,on_click:this.go_to_seller_profile_page});
+			subtitle_items.push({
+				value: this.item.company,
+				on_click: this.go_to_seller_profile_page
+			});
 
 			return subtitle_items;
 		},
 
 		item_views_and_ratings() {
-			if(!this.item) {
+			if (!this.item) {
 				return '';
 			}
 
 			let stats = __('No views yet');
-			if(this.item.view_count) {
+			if (this.item.view_count) {
 				const views_message = __(`${this.item.view_count} Views`);
 
 				const rating_html = get_rating_html(this.item.average_rating);
-				const rating_count = this.item.no_of_ratings > 0 ? `${this.item.no_of_ratings} reviews` : __('No reviews yet');
+				const rating_count =
+					this.item.no_of_ratings > 0
+						? `${this.item.no_of_ratings} reviews`
+						: __('No reviews yet');
 
 				stats = [views_message, rating_html, rating_count];
 			}
@@ -136,7 +132,7 @@
 				return {
 					label: __('Contact Seller'),
 					action: this.contact_seller.bind(this)
-				}
+				};
 			} else {
 				return undefined;
 			}
@@ -156,7 +152,7 @@
 			setTimeout(() => {
 				hub.call('add_item_view', {
 					hub_item_name: this.hub_item_name
-				})
+				});
 				// .then(() => {
 				// 	erpnext.hub.item_view_cache.push(this.hub_item_name);
 				// });
@@ -167,12 +163,12 @@
 		get_item_details() {
 			this.item_received = hub.call('get_item_details', { hub_item_name: this.hub_item_name })
 				.then(item => {
-				this.init = false;
-				this.item = item;
+					this.init = false;
+					this.item = item;
 
-				this.build_data();
-				this.make_dialogs();
-			});
+					this.build_data();
+					this.make_dialogs();
+				});
 		},
 		go_to_seller_profile_page(seller_name) {
 			frappe.set_route(`marketplace/seller/${seller_name}`);
@@ -200,36 +196,41 @@
 		make_dialogs() {
 			this.make_contact_seller_dialog();
 			this.make_report_item_dialog();
+			this.make_editing_dialog();
 		},
 
 		add_to_saved_items() {
 			hub.call('add_item_to_user_saved_items', {
-				hub_item_name: this.hub_item_name,
-				hub_user: frappe.session.user
-			})
-			.then(() => {
-				const saved_items_link = `<b><a href="#marketplace/saved-items">${__('Saved')}</a></b>`
-				frappe.show_alert(saved_items_link);
-				erpnext.hub.trigger('action:item_save');
-			})
-			.catch(e => {
-				console.error(e);
-			});
+					hub_item_name: this.hub_item_name,
+					hub_user: frappe.session.user
+				})
+				.then(() => {
+					const saved_items_link = `<b><a href="#marketplace/saved-items">${__(
+						'Saved'
+					)}</a></b>`;
+					frappe.show_alert(saved_items_link);
+					erpnext.hub.trigger('action:item_save');
+				})
+				.catch(e => {
+					console.error(e);
+				});
 		},
 
 		add_to_featured_items() {
 			hub.call('add_item_to_seller_featured_items', {
-				hub_item_name: this.hub_item_name,
-				hub_user: frappe.session.user
-			},)
-			.then(() => {
-				const featured_items_link = `<b><a href="#marketplace/featured-items">${__('Added to Featured Items')}</a></b>`
-				frappe.show_alert(featured_items_link);
-				erpnext.hub.trigger('action:item_feature');
-			})
-			.catch(e => {
-				console.error(e);
-			});
+					hub_item_name: this.hub_item_name,
+					hub_user: frappe.session.user
+				})
+				.then(() => {
+					const featured_items_link = `<b><a href="#marketplace/featured-items">${__(
+						'Added to Featured Items'
+					)}</a></b>`;
+					frappe.show_alert(featured_items_link);
+					erpnext.hub.trigger('action:item_feature');
+				})
+				.catch(e => {
+					console.error(e);
+				});
 		},
 
 		make_contact_seller_dialog() {
@@ -252,13 +253,13 @@
 					if (!message) return;
 
 					hub.call('send_message', {
-						hub_item: this.item.name,
-						message
-					})
+							hub_item: this.item.name,
+							message
+						})
 						.then(() => {
 							this.contact_seller_dialog.hide();
 							frappe.set_route('marketplace', 'buying', this.item.name);
-							erpnext.hub.trigger('action:send_message')
+							erpnext.hub.trigger('action:send_message');
 						});
 				}
 			});
@@ -275,7 +276,10 @@
 					}
 				],
 				primary_action: ({ message }) => {
-					hub.call('add_reported_item', { hub_item_name: this.item.name, message })
+					hub.call('add_reported_item', {
+							hub_item_name: this.item.name,
+							message
+						})
 						.then(() => {
 							d.hide();
 							frappe.show_alert(__('Item Reported'));
@@ -284,26 +288,62 @@
 			});
 		},
 
+		make_editing_dialog() {
+			this.edit_dialog = edit_details_dialog({
+				primary_action: {
+					fn: values => {
+						this.update_details(values);
+						this.edit_dialog.hide();
+					}
+				},
+				defaults: {
+					item_name: this.item.item_name,
+					hub_category: this.item.hub_category,
+					description: this.item.description
+				}
+			});
+		},
+
+		update_details(values) {
+			frappe.call('erpnext.hub_node.api.update_item', {
+					ref_doc: this.item.name,
+					data: values
+				})
+				.then(r => {
+					return this.get_item_details();
+				})
+				.then(() => {
+					frappe.show_alert(__(`${this.item.item_name} Updated`));
+				});
+		},
+
 		contact_seller() {
 			this.contact_seller_dialog.show();
 		},
 
 		report_item() {
 			if (!hub.is_seller_registered()) {
-				frappe.throw(__('Please login as a Marketplace User to report this item.'));
+				frappe.throw(
+					__('Please login as a Marketplace User to report this item.')
+				);
 			}
 			this.report_item_dialog.show();
 		},
 
 		edit_details() {
-			frappe.msgprint(__('This feature is under development...'));
+			if (!hub.is_seller_registered()) {
+				frappe.throw(
+					__('Please login as a Marketplace User to edit this item.')
+				);
+			}
+			this.edit_dialog.show();
 		},
 
 		unpublish_item() {
 			frappe.msgprint(__('This feature is under development...'));
 		}
 	}
-}
+};
 </script>
 
 <style scoped></style>
diff --git a/erpnext/public/js/templates/address_list.html b/erpnext/public/js/templates/address_list.html
index 2379ef6..0f967b6 100644
--- a/erpnext/public/js/templates/address_list.html
+++ b/erpnext/public/js/templates/address_list.html
@@ -1,23 +1,22 @@
 <div class="clearfix"></div>
 {% for(var i=0, l=addr_list.length; i<l; i++) { %}
-    <div class="address-box">
-    <p class="h6">
-        {%= i+1 %}. {%= addr_list[i].address_type!="Other" ? __(addr_list[i].address_type) : addr_list[i].address_title %}
-        {% if(addr_list[i].is_primary_address) { %}
-            <span class="text-muted">({%= __("Primary") %})</span>{% } %}
-        {% if(addr_list[i].is_shipping_address) { %}
-            <span class="text-muted">({%= __("Shipping") %})</span>{% } %}
+<div class="address-box">
+	<p class="h6">
+		{%= i+1 %}. {%= addr_list[i].address_title %}{% if(addr_list[i].address_type!="Other") { %}
+		<span class="text-muted">({%= __(addr_list[i].address_type) %})</span>{% } %}
+		{% if(addr_list[i].is_primary_address) { %}
+		<span class="text-muted">({%= __("Primary") %})</span>{% } %}
+		{% if(addr_list[i].is_shipping_address) { %}
+		<span class="text-muted">({%= __("Shipping") %})</span>{% } %}
 
-        <a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}"
-            class="btn btn-default btn-xs pull-right"
-				style="margin-top:-3px; margin-right: -5px;">
-            {%= __("Edit") %}</a>
-    </p>
-        <p>{%= addr_list[i].display %}</p>
-    </div>
+		<a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}" class="btn btn-default btn-xs pull-right"
+			style="margin-top:-3px; margin-right: -5px;">
+			{%= __("Edit") %}</a>
+	</p>
+	<p>{%= addr_list[i].display %}</p>
+</div>
 {% } %}
 {% if(!addr_list.length) { %}
 <p class="text-muted small">{%= __("No address added yet.") %}</p>
 {% } %}
-<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
-
+<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
\ No newline at end of file
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f363999..3f444f8 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -458,7 +458,8 @@
 					fieldname:"item_code",
 					options: 'Item',
 					in_list_view: 1,
-					read_only: 1,
+					read_only: 0,
+					disabled: 0,
 					label: __('Item Code')
 				}, {
 					fieldtype:'Float',
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 41a59d0..61a6939 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -389,12 +389,14 @@
 
 		let serial_no_filters = {
 			item_code: me.item_code,
+			batch_no: this.doc.batch_no || null,
 			delivery_document_no: ""
 		}
 
 		if (me.warehouse_details.name) {
 			serial_no_filters['warehouse'] = me.warehouse_details.name;
 		}
+
 		return [
 			{fieldtype: 'Section Break', label: __('Serial Numbers')},
 			{
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 790b2f0..9ebef0d 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -26,7 +26,6 @@
 		super(Quotation, self).validate()
 		self.set_status()
 		self.update_opportunity()
-		self.validate_order_type()
 		self.validate_uom_is_integer("stock_uom", "qty")
 		self.validate_valid_till()
 		self.set_customer_name()
@@ -40,9 +39,6 @@
 	def has_sales_order(self):
 		return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.name, "docstatus": 1})
 
-	def validate_order_type(self):
-		super(Quotation, self).validate_order_type()
-
 	def update_lead(self):
 		if self.quotation_to == "Lead" and self.party_name:
 			frappe.get_doc("Lead", self.party_name).set_status(update=True)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 2112a41..94bbb79 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -34,7 +34,6 @@
 
 	def validate(self):
 		super(SalesOrder, self).validate()
-		self.validate_order_type()
 		self.validate_delivery_date()
 		self.validate_proj_cust()
 		self.validate_po()
@@ -100,9 +99,6 @@
 					frappe.msgprint(_("Quotation {0} not of type {1}")
 						.format(d.prevdoc_docname, self.order_type))
 
-	def validate_order_type(self):
-		super(SalesOrder, self).validate_order_type()
-
 	def validate_delivery_date(self):
 		if self.order_type == 'Sales' and not self.skip_delivery_note:
 			delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date]
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index feb6b76..d8e9a63 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -321,7 +321,12 @@
 		create_dn_against_so(so.name, 4)
 		make_sales_invoice(so.name)
 
-		trans_item = json.dumps([{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}])
+		first_item_of_so = so.get("items")[0]
+		trans_item = json.dumps([
+			{'item_code' : first_item_of_so.item_code, 'rate' : first_item_of_so.rate, \
+				'qty' : first_item_of_so.qty, 'docname': first_item_of_so.name},
+			{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}
+		])
 		update_child_qty_rate('Sales Order', trans_item, so.name)
 
 		so.reload()
@@ -330,6 +335,48 @@
 		self.assertEqual(so.get("items")[-1].qty, 7)
 		self.assertEqual(so.get("items")[-1].amount, 1400)
 		self.assertEqual(so.status, 'To Deliver and Bill')
+	
+	def test_remove_item_in_update_child_qty_rate(self):
+		so = make_sales_order(**{
+			"item_list": [{
+				"item_code": '_Test Item',
+				"qty": 5,
+				"rate":1000
+			}]
+		})
+		create_dn_against_so(so.name, 2)
+		make_sales_invoice(so.name)
+
+		# add an item so as to try removing items
+		trans_item = json.dumps([
+			{"item_code": '_Test Item', "qty": 5, "rate":1000, "docname": so.get("items")[0].name},
+			{"item_code": '_Test Item 2', "qty": 2, "rate":500}
+		])
+		update_child_qty_rate('Sales Order', trans_item, so.name)
+		so.reload()
+		self.assertEqual(len(so.get("items")), 2)
+
+		# check if delivered items can be removed
+		trans_item = json.dumps([{
+			"item_code": '_Test Item 2',
+			"qty": 2,
+			"rate":500,
+			"docname": so.get("items")[1].name
+		}])
+		self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Sales Order', trans_item, so.name)
+
+		#remove last added item
+		trans_item = json.dumps([{
+			"item_code": '_Test Item',
+			"qty": 5,
+			"rate":1000,
+			"docname": so.get("items")[0].name
+		}])
+		update_child_qty_rate('Sales Order', trans_item, so.name)
+		
+		so.reload()
+		self.assertEqual(len(so.get("items")), 1)
+		self.assertEqual(so.status, 'To Deliver and Bill')
 
 
 	def test_update_child_qty_rate(self):
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 86b09c2..aad37d3 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -77,10 +77,12 @@
   "ordered_qty",
   "planned_qty",
   "column_break_69",
-  "delivered_qty",
   "work_order_qty",
+  "delivered_qty",
   "produced_qty",
   "returned_qty",
+  "shopping_cart_section",
+  "additional_notes",
   "section_break_63",
   "page_break",
   "item_tax_rate",
@@ -746,15 +748,20 @@
    "label": "Image"
   },
   {
-   "default": "0",
-   "fieldname": "against_blanket_order",
-   "fieldtype": "Check",
-   "label": "Against Blanket Order"
+   "collapsible": 1,
+   "fieldname": "shopping_cart_section",
+   "fieldtype": "Section Break",
+   "label": "Shopping Cart"
+  },
+  {
+   "fieldname": "additional_notes",
+   "fieldtype": "Text",
+   "label": "Additional Notes"
   }
  ],
  "idx": 1,
  "istable": 1,
- "modified": "2019-11-19 14:19:29.491945",
+ "modified": "2019-12-11 18:06:26.238169",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order Item",
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 3e890b4..0524eee 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -261,15 +261,14 @@
 
 
 def get_batches(item_code, warehouse, qty=1, throw=False):
-	batches = frappe.db.sql(
-		'select batch_id, sum(actual_qty) as qty from `tabBatch` join `tabStock Ledger Entry` ignore index (item_code, warehouse) '
-		'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
-		'where `tabStock Ledger Entry`.item_code = %s and  `tabStock Ledger Entry`.warehouse = %s '
-		'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
-		'group by batch_id '
-		'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
-		(item_code, warehouse),
-		as_dict=True
-	)
 
-	return batches
+	return frappe.db.sql("""
+		select batch_id, sum(`tabStock Ledger Entry`.actual_qty) as qty
+		from `tabBatch`
+			join `tabStock Ledger Entry` ignore index (item_code, warehouse)
+				on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )
+		where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s
+			and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)
+		group by batch_id
+		order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
+	""", (item_code, warehouse), as_dict=True)
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index 6a7eecf..a025f06 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -79,6 +79,21 @@
 		}, () => {
 			frm.reload_doc();
 		});
+	},
+
+	driver: function (frm) {
+		if (frm.doc.driver) {
+			frappe.call({
+				method: "erpnext.stock.doctype.delivery_trip.delivery_trip.get_driver_email",
+				args: {
+					driver: frm.doc.driver
+				},
+				callback: (data) => {
+					frm.set_value("driver_email", data.message.email);
+				}
+			});
+		};
+	},
 
 	},
 
@@ -196,4 +211,4 @@
 			frappe.model.set_value(cdt, cdn, "customer_contact", "");
 		}
 	}
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
index 0a52624..1bacf46 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "naming_series:",
  "creation": "2017-10-16 16:45:48.293335",
  "doctype": "DocType",
@@ -13,6 +14,7 @@
   "section_break_3",
   "driver",
   "driver_name",
+  "driver_email",
   "driver_address",
   "total_distance",
   "uom",
@@ -167,10 +169,17 @@
    "fieldtype": "Link",
    "label": "Driver Address",
    "options": "Address"
+  },
+  {
+   "fieldname": "driver_email",
+   "fieldtype": "Data",
+   "label": "Driver Email",
+   "read_only": 1
   }
  ],
  "is_submittable": 1,
- "modified": "2019-09-27 15:43:01.975139",
+ "links": [],
+ "modified": "2019-12-06 17:06:59.681952",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Trip",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index 77d322e..e2c5b91 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -387,3 +387,9 @@
 		file_name="Delivery Note", print_format=dispatch_attachment)
 
 	return [attachments]
+
+@frappe.whitelist()
+def get_driver_email(driver):
+	employee = frappe.db.get_value("Driver", driver, "employee")
+	email = frappe.db.get_value("Employee", employee, "prefered_email")
+	return {"email": email}
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index d6bc1a9..27cd997 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_import": 1,
  "autoname": "naming_series:",
  "creation": "2013-05-21 16:16:39",
@@ -305,6 +306,7 @@
    "fieldname": "contact_email",
    "fieldtype": "Small Text",
    "label": "Contact Email",
+   "options": "Email",
    "print_hide": 1,
    "read_only": 1
   },
@@ -1056,7 +1058,8 @@
  "icon": "fa fa-truck",
  "idx": 261,
  "is_submittable": 1,
- "modified": "2019-09-27 14:24:49.044505",
+ "links": [],
+ "modified": "2019-12-24 12:52:17.216304",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 060175f..691f92f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -88,7 +88,7 @@
 
 		if getdate(self.posting_date) > getdate(nowdate()):
 			throw(_("Posting Date cannot be future date"))
-	
+
 	def validate_cwip_accounts(self):
 		for item in self.get('items'):
 			if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
@@ -362,7 +362,7 @@
 					# valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
 					self.update_assets(item, item.valuation_rate)
 		return gl_entries
-	
+
 	def add_asset_gl_entries(self, item, gl_entries):
 		arbnb_account = self.get_company_default("asset_received_but_not_billed")
 		# This returns category's cwip account if not then fallback to company's default cwip account
@@ -395,7 +395,7 @@
 			"credit_in_account_currency": (base_asset_amount
 				if asset_rbnb_currency == self.company_currency else asset_amount)
 		}, item=item))
-	
+
 	def add_lcv_gl_entries(self, item, gl_entries):
 		expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
 		if not is_cwip_accounting_enabled(item.asset_category):
@@ -404,7 +404,7 @@
 		else:
 			# This returns company's default cwip account
 			asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
-		
+
 		gl_entries.append(self.get_gl_dict({
 			"account": expenses_included_in_asset_valuation,
 			"against": asset_account,
@@ -424,7 +424,7 @@
 		}, item=item))
 
 	def update_assets(self, item, valuation_rate):
-		assets = frappe.db.get_all('Asset', 
+		assets = frappe.db.get_all('Asset',
 			filters={ 'purchase_receipt': self.name, 'item_code': item.item_code }
 		)
 
@@ -610,27 +610,36 @@
 	return doclist
 
 def get_item_account_wise_additional_cost(purchase_document):
-	landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt",
-		{"receipt_document": purchase_document, "docstatus": 1}, "parent")
+	landed_cost_vouchers = frappe.get_all("Landed Cost Purchase Receipt", fields=["parent"],
+		filters = {"receipt_document": purchase_document, "docstatus": 1})
 
-	if not landed_cost_voucher:
+	if not landed_cost_vouchers:
 		return
 
 	total_item_cost = 0
 	item_account_wise_cost = {}
-	landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", landed_cost_voucher)
-	based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+	item_cost_allocated = []
 
-	for item in landed_cost_voucher_doc.items:
-		total_item_cost += item.get(based_on_field)
+	for lcv in landed_cost_vouchers:
+		landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+		based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
 
-	for item in landed_cost_voucher_doc.items:
-		if item.receipt_document == purchase_document:
-			for account in landed_cost_voucher_doc.taxes:
-				item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
-				item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
-				item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
-					account.amount * item.get(based_on_field) / total_item_cost
+		for item in landed_cost_voucher_doc.items:
+			if item.purchase_receipt_item not in item_cost_allocated:
+				total_item_cost += item.get(based_on_field)
+				item_cost_allocated.append(item.purchase_receipt_item)
+
+	for lcv in landed_cost_vouchers:
+		landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+		based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+		for item in landed_cost_voucher_doc.items:
+			if item.receipt_document == purchase_document:
+				for account in landed_cost_voucher_doc.taxes:
+					item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
+					item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
+					item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
+						account.amount * item.get(based_on_field) / total_item_cost
 
 	return item_account_wise_cost
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 1b9660e..47f6cf6 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -808,24 +808,26 @@
 
 		if self.bom_no:
 
+			backflush_based_on = frappe.db.get_single_value("Manufacturing Settings",
+				"backflush_raw_materials_based_on")
+
 			if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
 					"Send to Subcontractor", "Material Transfer for Manufacture", "Material Consumption for Manufacture"]:
 
 				if self.work_order and self.purpose == "Material Transfer for Manufacture":
-					item_dict = self.get_pending_raw_materials()
+					item_dict = self.get_pending_raw_materials(backflush_based_on)
 					if self.to_warehouse and self.pro_doc:
 						for item in itervalues(item_dict):
 							item["to_warehouse"] = self.pro_doc.wip_warehouse
 					self.add_to_stock_entry_detail(item_dict)
 
 				elif (self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
-					and not self.pro_doc.skip_transfer and frappe.db.get_single_value("Manufacturing Settings",
-					"backflush_raw_materials_based_on")== "Material Transferred for Manufacture"):
+					and not self.pro_doc.skip_transfer and backflush_based_on == "Material Transferred for Manufacture"):
 					self.get_transfered_raw_materials()
 
-				elif self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture") and \
-					frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "BOM" and \
-					frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1:
+				elif (self.work_order and backflush_based_on== "BOM" and
+					(self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
+					and frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1):
 					self.get_unconsumed_raw_materials()
 
 				else:
@@ -1034,10 +1036,6 @@
 				filters={'parent': self.work_order, 'item_code': item_code},
 				fields=["required_qty", "consumed_qty"]
 				)
-			if not req_items:
-				frappe.msgprint(_("Did not found transfered item {0} in Work Order {1}, the item not added in Stock Entry")
-					.format(item_code, self.work_order))
-				continue
 
 			req_qty = flt(req_items[0].required_qty)
 			req_qty_each = flt(req_qty / manufacturing_qty)
@@ -1085,18 +1083,20 @@
 					}
 				})
 
-	def get_pending_raw_materials(self):
+	def get_pending_raw_materials(self, backflush_based_on=None):
 		"""
 			issue (item quantity) that is pending to issue or desire to transfer,
 			whichever is less
 		"""
-		item_dict = self.get_pro_order_required_items()
+		item_dict = self.get_pro_order_required_items(backflush_based_on)
+
 		max_qty = flt(self.pro_doc.qty)
 		for item, item_details in iteritems(item_dict):
 			pending_to_issue = flt(item_details.required_qty) - flt(item_details.transferred_qty)
 			desire_to_transfer = flt(self.fg_completed_qty) * flt(item_details.required_qty) / max_qty
 
-			if desire_to_transfer <= pending_to_issue:
+			if (desire_to_transfer <= pending_to_issue or
+				(desire_to_transfer > 0 and backflush_based_on == "Material Transferred for Manufacture")):
 				item_dict[item]["qty"] = desire_to_transfer
 			elif pending_to_issue > 0:
 				item_dict[item]["qty"] = pending_to_issue
@@ -1114,7 +1114,7 @@
 
 		return item_dict
 
-	def get_pro_order_required_items(self):
+	def get_pro_order_required_items(self, backflush_based_on=None):
 		item_dict = frappe._dict()
 		pro_order = frappe.get_doc("Work Order", self.work_order)
 		if not frappe.db.get_value("Warehouse", pro_order.wip_warehouse, "is_group"):
@@ -1123,7 +1123,8 @@
 			wip_warehouse = None
 
 		for d in pro_order.get("required_items"):
-			if (flt(d.required_qty) > flt(d.transferred_qty) and
+			if ( ((flt(d.required_qty) > flt(d.transferred_qty)) or
+				(backflush_based_on == "Material Transferred for Manufacture")) and
 				(d.include_item_in_manufacturing or self.purpose != "Material Transfer for Manufacture")):
 				item_row = d.as_dict()
 				if d.source_warehouse and not frappe.db.get_value("Warehouse", d.source_warehouse, "is_group"):
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
index b23c908..23700c9 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
@@ -16,6 +16,29 @@
 			"fieldtype": "Date",
 			"width": "80",
 			"default": frappe.datetime.get_today()
+		},
+		{
+			"fieldname": "item",
+			"label": __("Item"),
+			"fieldtype": "Link",
+			"options": "Item",
+			"width": "80"
 		}
-	]
+	],
+	"formatter": function (value, row, column, data, default_formatter) {
+		if (column.fieldname == "Batch" && data && !!data["Batch"]) {
+			value = data["Batch"];
+			column.link_onclick = "frappe.query_reports['Batch-Wise Balance History'].set_batch_route_to_stock_ledger(" + JSON.stringify(data) + ")";
+		}
+
+		value = default_formatter(value, row, column, data);
+		return value;
+	},
+	"set_batch_route_to_stock_ledger": function (data) {
+		frappe.route_options = {
+			"batch_no": data["Batch"]
+		};
+
+		frappe.set_route("query-report", "Stock Ledger");
+	}
 }
\ No newline at end of file
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 7f7835f..2c95084 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
@@ -2,9 +2,11 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+
 import frappe
 from frappe import _
-from frappe.utils import flt, cint, getdate
+from frappe.utils import cint, flt, getdate
+
 
 def execute(filters=None):
 	if not filters: filters = {}
@@ -17,29 +19,31 @@
 
 	data = []
 	for item in sorted(iwb_map):
-		for wh in sorted(iwb_map[item]):
-			for batch in sorted(iwb_map[item][wh]):
-				qty_dict = iwb_map[item][wh][batch]
-				if qty_dict.opening_qty or qty_dict.in_qty or qty_dict.out_qty or qty_dict.bal_qty:
-					data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
-						flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
-						flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision),
-						 item_map[item]["stock_uom"]
-					])
+		if not filters.get("item") or filters.get("item") == item:
+			for wh in sorted(iwb_map[item]):
+				for batch in sorted(iwb_map[item][wh]):
+					qty_dict = iwb_map[item][wh][batch]
+					if qty_dict.opening_qty or qty_dict.in_qty or qty_dict.out_qty or qty_dict.bal_qty:
+						data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
+							flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
+							flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision),
+							item_map[item]["stock_uom"]
+						])
 
 	return columns, data
 
+
 def get_columns(filters):
 	"""return columns based on filters"""
 
 	columns = [_("Item") + ":Link/Item:100"] + [_("Item Name") + "::150"] + [_("Description") + "::150"] + \
-	[_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + ":Float:90"] + \
-	[_("In Qty") + ":Float:80"] + [_("Out Qty") + ":Float:80"] + [_("Balance Qty") + ":Float:90"] + \
-	[_("UOM") + "::90"]
-
+		[_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + ":Float:90"] + \
+		[_("In Qty") + ":Float:80"] + [_("Out Qty") + ":Float:80"] + [_("Balance Qty") + ":Float:90"] + \
+		[_("UOM") + "::90"]
 
 	return columns
 
+
 def get_conditions(filters):
 	conditions = ""
 	if not filters.get("from_date"):
@@ -52,7 +56,8 @@
 
 	return conditions
 
-#get all details
+
+# get all details
 def get_stock_ledger_entries(filters):
 	conditions = get_conditions(filters)
 	return frappe.db.sql("""
@@ -63,6 +68,7 @@
 		order by item_code, warehouse""" %
 		conditions, as_dict=1)
 
+
 def get_item_warehouse_batch_map(filters, float_precision):
 	sle = get_stock_ledger_entries(filters)
 	iwb_map = {}
@@ -90,6 +96,7 @@
 
 	return iwb_map
 
+
 def get_item_details(filters):
 	item_map = {}
 	for d in frappe.db.sql("select name, item_name, description, stock_uom from tabItem", as_dict=1):
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js
index 3fab327..df3bba5 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.js
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.js
@@ -77,7 +77,15 @@
 			"fieldtype": "Link",
 			"options": "UOM"
 		}
-	]
+	],
+	"formatter": function (value, row, column, data, default_formatter) {
+		value = default_formatter(value, row, column, data);
+		if (column.fieldname == "out_qty" && data.out_qty < 0) {
+			value = "<span style='color:red'>" + value + "</span>";
+		}
+
+		return value;
+	},
 }
 
 // $(function() {
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index d757ecb..36fdcfd 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -2,9 +2,11 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+
 import frappe
-from frappe import _
 from erpnext.stock.utils import update_included_uom_in_report
+from frappe import _
+
 
 def execute(filters=None):
 	include_uom = filters.get("include_uom")
@@ -36,7 +38,22 @@
 
 			sle.update({
 				"qty_after_transaction": actual_qty,
-				"stock_value": stock_value
+				"stock_value": stock_value,
+				"in_qty": max(sle.actual_qty, 0),
+				"out_qty": min(sle.actual_qty, 0)
+			})
+
+		# get the name of the item that was produced using this item
+		if sle.voucher_type == "Stock Entry":
+			purpose, work_order, fg_completed_qty = frappe.db.get_value(sle.voucher_type, sle.voucher_no, ["purpose", "work_order", "fg_completed_qty"])
+
+			if purpose == "Manufacture" and work_order:
+				finished_product = frappe.db.get_value("Work Order", work_order, "item_name")
+				finished_qty = fg_completed_qty
+
+			sle.update({
+				"finished_product": finished_product,
+				"finished_qty": finished_qty,
 			})
 
 		data.append(sle)
@@ -47,53 +64,74 @@
 	update_included_uom_in_report(columns, data, include_uom, conversion_factors)
 	return columns, data
 
+
 def get_columns():
 	columns = [
-		{"label": _("Date"), "fieldname": "date", "fieldtype": "Datetime", "width": 95},
-		{"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 130},
+		{"label": _("Date"), "fieldname": "date", "fieldtype": "Datetime", "width": 150},
+		{"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 100},
 		{"label": _("Item Name"), "fieldname": "item_name", "width": 100},
+		{"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 90},
+		{"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
+		{"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
+		{"label": _("Balance Qty"), "fieldname": "qty_after_transaction", "fieldtype": "Float", "width": 100, "convertible": "qty"},
+		{"label": _("Finished Product"), "fieldname": "finished_product", "width": 100},
+		{"label": _("Finished Qty"), "fieldname": "finished_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
+		{"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 150},
+		{"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 150},
 		{"label": _("Item Group"), "fieldname": "item_group", "fieldtype": "Link", "options": "Item Group", "width": 100},
 		{"label": _("Brand"), "fieldname": "brand", "fieldtype": "Link", "options": "Brand", "width": 100},
 		{"label": _("Description"), "fieldname": "description", "width": 200},
-		{"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 100},
-		{"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 100},
-		{"label": _("Qty"), "fieldname": "actual_qty", "fieldtype": "Float", "width": 50, "convertible": "qty"},
-		{"label": _("Balance Qty"), "fieldname": "qty_after_transaction", "fieldtype": "Float", "width": 100, "convertible": "qty"},
-		{"label": _("Incoming Rate"), "fieldname": "incoming_rate", "fieldtype": "Currency", "width": 110,
-			"options": "Company:company:default_currency", "convertible": "rate"},
-		{"label": _("Valuation Rate"), "fieldname": "valuation_rate", "fieldtype": "Currency", "width": 110,
-			"options": "Company:company:default_currency", "convertible": "rate"},
-		{"label": _("Balance Value"), "fieldname": "stock_value", "fieldtype": "Currency", "width": 110,
-			"options": "Company:company:default_currency"},
+		{"label": _("Incoming Rate"), "fieldname": "incoming_rate", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency", "convertible": "rate"},
+		{"label": _("Valuation Rate"), "fieldname": "valuation_rate", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency", "convertible": "rate"},
+		{"label": _("Balance Value"), "fieldname": "stock_value", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency"},
 		{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 110},
 		{"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 100},
 		{"label": _("Batch"), "fieldname": "batch_no", "fieldtype": "Link", "options": "Batch", "width": 100},
-		{"label": _("Serial #"), "fieldname": "serial_no", "width": 100},
+		{"label": _("Serial #"), "fieldname": "serial_no", "fieldtype": "Link", "options": "Serial No", "width": 100},
 		{"label": _("Project"), "fieldname": "project", "fieldtype": "Link", "options": "Project", "width": 100},
 		{"label": _("Company"), "fieldname": "company", "fieldtype": "Link", "options": "Company", "width": 110}
 	]
 
 	return columns
 
+
 def get_stock_ledger_entries(filters, items):
 	item_conditions_sql = ''
 	if items:
 		item_conditions_sql = 'and sle.item_code in ({})'\
 			.format(', '.join([frappe.db.escape(i) for i in items]))
 
-	return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
-			item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
-			stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project, stock_value_difference
-		from `tabStock Ledger Entry` sle
-		where company = %(company)s and
-			posting_date between %(from_date)s and %(to_date)s
-			{sle_conditions}
-			{item_conditions_sql}
-			order by posting_date asc, posting_time asc, creation asc"""\
-		.format(
-			sle_conditions=get_sle_conditions(filters),
-			item_conditions_sql = item_conditions_sql
-		), filters, as_dict=1)
+	sl_entries = frappe.db.sql("""
+		SELECT
+			concat_ws(" ", posting_date, posting_time) AS date,
+			item_code,
+			warehouse,
+			actual_qty,
+			qty_after_transaction,
+			incoming_rate,
+			valuation_rate,
+			stock_value,
+			voucher_type,
+			voucher_no,
+			batch_no,
+			serial_no,
+			company,
+			project,
+			stock_value_difference
+		FROM
+			`tabStock Ledger Entry` sle
+		WHERE
+			company = %(company)s
+				AND posting_date BETWEEN %(from_date)s AND %(to_date)s
+				{sle_conditions}
+				{item_conditions_sql}
+		ORDER BY
+			posting_date asc, posting_time asc, creation asc
+		""".format(sle_conditions=get_sle_conditions(filters), item_conditions_sql=item_conditions_sql),
+		filters, as_dict=1)
+
+	return sl_entries
+
 
 def get_items(filters):
 	conditions = []
@@ -111,6 +149,7 @@
 			.format(" and ".join(conditions)), filters)
 	return items
 
+
 def get_item_details(items, sl_entries, include_uom):
 	item_details = {}
 	if not items:
@@ -140,6 +179,7 @@
 
 	return item_details
 
+
 def get_sle_conditions(filters):
 	conditions = []
 	if filters.get("warehouse"):
@@ -155,6 +195,7 @@
 
 	return "and {}".format(" and ".join(conditions)) if conditions else ""
 
+
 def get_opening_balance(filters, columns):
 	if not (filters.item_code and filters.warehouse and filters.from_date):
 		return
@@ -166,13 +207,17 @@
 		"posting_date": filters.from_date,
 		"posting_time": "00:00:00"
 	})
-	row = {}
-	row["item_code"] = _("'Opening'")
-	for dummy, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')):
-			row[v] = last_entry.get(v, 0)
+
+	row = {
+		"item_code": _("'Opening'"),
+		"qty_after_transaction": last_entry.get("qty_after_transaction", 0),
+		"valuation_rate": last_entry.get("valuation_rate", 0),
+		"stock_value": last_entry.get("stock_value", 0)
+	}
 
 	return row
 
+
 def get_warehouse_condition(warehouse):
 	warehouse_details = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"], as_dict=1)
 	if warehouse_details:
@@ -182,6 +227,7 @@
 
 	return ''
 
+
 def get_item_group_condition(item_group):
 	item_group_details = frappe.db.get_value("Item Group", item_group, ["lft", "rgt"], as_dict=1)
 	if item_group_details:
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index fe53f34..f7f3548 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -65,16 +65,6 @@
 					reqd: 1
 				},
 				{
-					label: __('Address Type'),
-					fieldname: 'address_type',
-					fieldtype: 'Select',
-					options: [
-						'Billing',
-						'Shipping'
-					],
-					reqd: 1
-				},
-				{
 					label: __('Address Line 1'),
 					fieldname: 'address_line1',
 					fieldtype: 'Data',
@@ -97,15 +87,36 @@
 					fieldtype: 'Data'
 				},
 				{
+					label: __('Country'),
+					fieldname: 'country',
+					fieldtype: 'Link',
+					options: 'Country',
+					reqd: 1
+				},
+				{
+					fieldname: "column_break0",
+					fieldtype: "Column Break",
+					width: "50%"
+				},
+				{
+					label: __('Address Type'),
+					fieldname: 'address_type',
+					fieldtype: 'Select',
+					options: [
+						'Billing',
+						'Shipping'
+					],
+					reqd: 1
+				},
+				{
 					label: __('Pin Code'),
 					fieldname: 'pincode',
 					fieldtype: 'Data'
 				},
 				{
-					label: __('Country'),
-					fieldname: 'country',
-					fieldtype: 'Link',
-					reqd: 1
+					fieldname: "phone",
+					fieldtype: "Data",
+					label: "Phone"
 				},
 			],
 			primary_action_label: __('Save'),
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index b301fc0..912702e 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -83,12 +83,10 @@
 		</div>
 	{% endif %}
 
-	{% if cart_settings.enable_checkout %}
 	<div class="cart-addresses mt-5">
 	{% include "templates/includes/cart/cart_address.html" %}
 	</div>
 	{% endif %}
-	{% endif %}
 </div>
 
 <div class="row mt-5">