Merge pull request #16694 from rmehta/refactor-comments

fix: refactored comments API. Depends on https://github.com/frappe/frappe/pull/6891
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 3802fea..abd3be6 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '11.1.4'
+__version__ = '11.1.6'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index 906dfbe..e305652 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -60,7 +60,7 @@
 	deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
 	last_gl_entry, skip = False, False
 
-	booking_end_date = getdate(add_days(today(), -1)) if not end_date else end_date
+	booking_end_date = getdate(add_days(today(), -1) if not end_date else end_date)
 	if booking_end_date < item.service_start_date or \
 		(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
 		return None, None, None, True
@@ -71,7 +71,7 @@
 		last_gl_entry = True
 		booking_end_date = item.service_stop_date
 
-	booking_start_date = getdate(add_months(today(), -1)) if not start_date else start_date
+	booking_start_date = getdate(add_months(today(), -1) if not start_date else start_date)
 	booking_start_date = booking_start_date \
 		if booking_start_date > item.service_start_date else item.service_start_date
 
@@ -113,7 +113,6 @@
 			group by voucher_detail_no
 		'''.format(total_credit_debit, total_credit_debit_currency),
 			(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
-
 		already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
 		base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
 		if account_currency==doc.company_currency:
@@ -128,15 +127,19 @@
 	# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
 	# start_date: 1st of the last month or the start date
 	# end_date: end_date or today-1
+	enable_check = "enable_deferred_revenue" \
+		if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
 
 	gl_entries = []
 	for item in doc.get('items'):
+		if not item.get(enable_check): continue
+
 		skip = False
 		last_gl_entry, booking_start_date, booking_end_date, skip = \
 			get_booking_dates(doc, item, start_date, end_date)
 
 		if skip: continue
-		total_days = date_diff(item.service_end_date, item.service_start_date)
+		total_days = date_diff(item.service_end_date, item.service_start_date) + 1
 		total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
 
 		account_currency = get_account_currency(item.expense_account)
@@ -175,6 +178,10 @@
 				'project': project
 			}, account_currency)
 		)
-
 	if gl_entries:
-		make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
+		try:
+			make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
+			frappe.db.commit()
+		except:
+			frappe.db.rollback()
+			frappe.log_error(message = frappe.get_traceback(), title = _("Error while processing deferred accounting for {0}").format(doc.name))
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 655926b..696736d 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -171,7 +171,7 @@
 			if not frappe.db.exists(self.party_type, self.party):
 				frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
 
-			if self.party_account:
+			if self.party_account and self.party_type in ("Customer", "Supplier"):
 				self.validate_account_type(self.party_account,
 					[erpnext.get_party_account_type(self.party_type)])
 
@@ -689,7 +689,7 @@
 
 	account_currency = get_account_currency(party_account)
 	account_balance = get_balance_on(party_account, date, cost_center=cost_center)
-	_party_name = "title" if party_type == "Student" else party_type.lower() + "_name"
+	_party_name = "title" if party_type in ("Student", "Shareholder") else party_type.lower() + "_name"
 	party_name = frappe.db.get_value(party_type, party, _party_name)
 	party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
 	if party_type in ["Customer", "Supplier"]:
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 8f3289c..a91eaa6 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -346,7 +346,7 @@
 	if len(pricing_rules) > 1:
 		rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
 		if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
-			pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
+			pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
 				or pricing_rules
 
 	if len(pricing_rules) > 1 and not args.for_shopping_cart:
@@ -369,7 +369,7 @@
 	filtered_rules = []
 	for field in field_set:
 		if args.get(field):
-			filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules)
+			filtered_rules = list(filter(lambda x: x[field]==args[field], pricing_rules))
 			if filtered_rules: break
 
 	return filtered_rules or pricing_rules
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 2530196..638e57e 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -22,7 +22,7 @@
 		invoices = []
 
 		# create invoices for lower than single threshold tax rate
-		for _ in xrange(2):
+		for _ in range(2):
 			pi = create_purchase_invoice(supplier = "Test TDS Supplier")
 			pi.submit()
 			invoices.append(pi)
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 8c3deaf..be66332 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -101,7 +101,7 @@
 					frappe.db.get_value(filters.party_type, filters.party[0], "default_currency"))
 
 		filters["account_currency"] = account_currency or filters.company_currency
-		if filters.account_currency != filters.company_currency:
+		if filters.account_currency != filters.company_currency and not filters.presentation_currency:
 			filters.presentation_currency = filters.account_currency
 
 	return filters
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py
index 5d24096..e33b90d 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.py
+++ b/erpnext/accounts/report/purchase_register/purchase_register.py
@@ -193,7 +193,7 @@
 	pi_items = frappe.db.sql("""
 		select parent, purchase_order, purchase_receipt, po_detail, project
 		from `tabPurchase Invoice Item`
-		where parent in (%s) and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')
+		where parent in (%s)
 	""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
 
 	invoice_po_pr_map = {}
diff --git a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
index 62843e7..a51c427 100644
--- a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
+++ b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py
@@ -47,8 +47,8 @@
 			pe.submit()
 
 		mop = get_mode_of_payments(filters)
-		self.assertTrue('Credit Card' in mop.values()[0])
-		self.assertTrue('Cash' in mop.values()[0])
+		self.assertTrue('Credit Card' in list(mop.values())[0])
+		self.assertTrue('Cash' in list(mop.values())[0])
 
 		# Cancel all Cash payment entry and check if this mode of payment is still fetched.
 		payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Cash", "docstatus": 1}, fields=["name", "docstatus"])
@@ -57,8 +57,8 @@
 			pe.cancel()
 
 		mop = get_mode_of_payments(filters)
-		self.assertTrue('Credit Card' in mop.values()[0])
-		self.assertTrue('Cash' not in mop.values()[0])
+		self.assertTrue('Credit Card' in list(mop.values())[0])
+		self.assertTrue('Cash' not in list(mop.values())[0])
 
 	def test_get_mode_of_payments_details(self):
 		filters = get_filters()
@@ -84,7 +84,7 @@
 
 		mopd = get_mode_of_payment_details(filters)
 
-		mopd_values = mopd.values()[0]
+		mopd_values = list(mopd.values())[0]
 		for mopd_value in mopd_values:
 			if mopd_value[0] == "Credit Card":
 				cc_init_amount = mopd_value[1]
@@ -96,7 +96,7 @@
 			pe.cancel()
 
 		mopd = get_mode_of_payment_details(filters)
-		mopd_values = mopd.values()[0]
+		mopd_values = list(mopd.values())[0]
 		for mopd_value in mopd_values:
 			if mopd_value[0] == "Credit Card":
 				cc_final_amount = mopd_value[1]
diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py
index a8ae94f..8a39744 100644
--- a/erpnext/accounts/report/utils.py
+++ b/erpnext/accounts/report/utils.py
@@ -104,7 +104,7 @@
 		credit_in_account_currency = flt(entry['credit_in_account_currency'])
 		account_currency = entry['account_currency']
 
-		if account_currency != presentation_currency or (account_currency == presentation_currency and not is_p_or_l_account(account)):
+		if account_currency != presentation_currency:
 			value = debit or credit
 
 			date = currency_info['report_date'] if not is_p_or_l_account(account) else entry['posting_date']
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index a9fcff8..1c9d977 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -615,7 +615,7 @@
 	return held_invoices
 
 
-def get_outstanding_invoices(party_type, party, account, condition=None, limit=1000):
+def get_outstanding_invoices(party_type, party, account, condition=None, limit=None):
 	outstanding_invoices = []
 	precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
 
@@ -628,7 +628,7 @@
 
 	invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
 	held_invoices = get_held_invoices(party_type, party)
-	limit_cond = "limit %s" % (limit or 1000)
+	limit_cond = "limit %s" % limit if limit else ""
 
 	invoice_list = frappe.db.sql("""
 		select
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 6b3c3cc73..bbe92f6 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -1812,8 +1812,9 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fetch_from": "company.default_finance_book",
    "fieldname": "default_finance_book", 
-   "fieldtype": "Read Only", 
+   "fieldtype": "Link",
    "hidden": 1, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -1824,12 +1825,12 @@
    "label": "Default Finance Book", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "company.default_finance_book", 
+   "options": "Finance Book",
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
-   "read_only": 0, 
+   "read_only": 1,
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
@@ -1882,7 +1883,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2019-01-15 16:12:48.314196",
+ "modified": "2019-02-12 11:29:01.747819",
  "modified_by": "Administrator", 
  "module": "Assets", 
  "name": "Asset", 
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index e72f59a..e79a2ac 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -459,7 +459,7 @@
 					items_dict = {
 						rm_item_code: {
 							"item_name": rm_item_data["item_name"],
-							"description": item_wh[rm_item_code].get('description'),
+							"description": item_wh.get(rm_item_code, {}).get('description', ""),
 							'qty': rm_item_data["qty"],
 							'from_warehouse': rm_item_data["warehouse"],
 							'stock_uom': rm_item_data["stock_uom"],
diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.json b/erpnext/buying/report/purchase_analytics/purchase_analytics.json
index 996e3ee..7ce779d 100644
--- a/erpnext/buying/report/purchase_analytics/purchase_analytics.json
+++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.json
@@ -1,12 +1,13 @@
 {
- "add_total_row": 0, 
+ "add_total_row": 1, 
  "creation": "2018-10-05 16:08:24.156448", 
+ "disable_prepared_report": 0, 
  "disabled": 0, 
  "docstatus": 0, 
  "doctype": "Report", 
  "idx": 0, 
  "is_standard": "Yes", 
- "modified": "2018-10-05 16:08:33.272201", 
+ "modified": "2019-02-12 14:32:29.107109", 
  "modified_by": "Administrator", 
  "module": "Buying", 
  "name": "Purchase Analytics", 
diff --git a/erpnext/config/accounting.py b/erpnext/config/accounting.py
index a8b9447..9de5b36 100644
--- a/erpnext/config/accounting.py
+++ b/erpnext/config/accounting.py
@@ -108,7 +108,7 @@
 
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
@@ -174,7 +174,6 @@
 					"name": "General Ledger",
 					"doctype": "GL Entry",
 					"is_query_report": True,
-					"onboard": 1,
 				},
 				{
 					"type": "report",
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index c52b9a2..9d1eda5 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -78,7 +78,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py
index 3119824..e49fc60 100644
--- a/erpnext/config/crm.py
+++ b/erpnext/config/crm.py
@@ -106,7 +106,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
@@ -159,52 +159,6 @@
 			]
 		},
 		{
-			"label": _("Support"),
-			"items": [
-				{
-					"type": "doctype",
-					"name": "Issue",
-					"description": _("Support queries from customers."),
-					"onboard": 1,
-				},
-				{
-					"type": "doctype",
-					"name": "Communication",
-					"description": _("Communication log."),
-				},
-				{
-					"type": "doctype",
-					"name": "Warranty Claim",
-					"description": _("Warranty Claim against Serial No."),
-				},
-				{
-					"type": "doctype",
-					"name": "Serial No",
-					"description": _("Single unit of an Item."),
-				},
-				{
-					"type": "page",
-					"name": "support-analytics",
-					"label": _("Support Analytics"),
-					"icon": "fa fa-bar-chart"
-				},
-				{
-					"type": "report",
-					"name": "Minutes to First Response for Issues",
-					"doctype": "Issue",
-					"is_query_report": True,
-					"dependencies": ["Issue"],
-				},
-				{
-					"type": "report",
-					"name": "Support Hours",
-					"doctype": "Issue",
-					"is_query_report": True,
-					"dependencies": ["Issue"]
-				},
-			]
-		},
-		{
 			"label": _("Maintenance"),
 			"icon": "fa fa-star",
 			"items": [
diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py
index 8484c64..5d4dfa1 100644
--- a/erpnext/config/desktop.py
+++ b/erpnext/config/desktop.py
@@ -7,6 +7,16 @@
 	return [
 		# Modules
 		{
+			"module_name": "Getting Started",
+			"category": "Modules",
+			"label": _("Getting Started"),
+			"color": "#1abc9c",
+			"icon": "fa fa-check-square-o",
+			"type": "module",
+			"hidden": 1,
+			"description": "Dive into the basics for your organisation's needs."
+		},
+		{
 			"module_name": "Accounting",
 			"category": "Modules",
 			"label": _("Accounting"),
@@ -14,7 +24,7 @@
 			"icon": "octicon octicon-repo",
 			"type": "module",
 			"hidden": 1,
-			"description": "Accounts, Billing, Payments, Cost Center and Budgeting."
+			"description": "Accounts, billing, payments, cost center and budgeting."
 		},
 		{
 			"module_name": "Selling",
@@ -24,7 +34,7 @@
 			"icon": "octicon octicon-tag",
 			"type": "module",
 			"hidden": 1,
-			"description": "All things Sales, Customer and Products."
+			"description": "Sales orders, quotations, customers and items."
 		},
 		{
 			"module_name": "Buying",
@@ -34,7 +44,7 @@
 			"icon": "octicon octicon-briefcase",
 			"type": "module",
 			"hidden": 1,
-			"description": "Purchasing, Suppliers and Products."
+			"description": "Purchasing, suppliers, material requests, and items."
 		},
 		{
 			"module_name": "Stock",
@@ -44,7 +54,7 @@
 			"icon": "octicon octicon-package",
 			"type": "module",
 			"hidden": 1,
-			"description": "Track Stock Transactions, Reports, and Serialized Items and Batches."
+			"description": "Stock transactions, reports, serial numbers and batches."
 		},
 		{
 			"module_name": "Assets",
@@ -54,7 +64,7 @@
 			"icon": "octicon octicon-database",
 			"hidden": 1,
 			"type": "module",
-			"description": "Asset Maintainance and Tools."
+			"description": "Asset movement, maintainance and tools."
 		},
 		{
 			"module_name": "Projects",
@@ -74,7 +84,17 @@
 			"icon": "octicon octicon-broadcast",
 			"type": "module",
 			"hidden": 1,
-			"description": "Everything in your sales pipeline, from Leads to Customers, to Support."
+			"description": "Sales pipeline, leads, opportunities and customers."
+		},
+		{
+			"module_name": "Help Desk",
+			"category": "Modules",
+			"label": _("Help Desk"),
+			"color": "#1abc9c",
+			"icon": "fa fa-check-square-o",
+			"type": "module",
+			"hidden": 1,
+			"description": "User interactions, support issues and knowledge base."
 		},
 		{
 			"module_name": "HR",
@@ -84,7 +104,7 @@
 			"icon": "octicon octicon-organization",
 			"type": "module",
 			"hidden": 1,
-			"description": "Employee Lifecycle, Payroll, Shifts and Leaves."
+			"description": "Employees, attendance, payroll, leaves and shifts."
 		},
 		{
 			"module_name": "Quality Management",
@@ -94,7 +114,7 @@
 			"icon": "fa fa-check-square-o",
 			"type": "module",
 			"hidden": 1,
-			"description": "Volunteers, Memberships, Grants and Chapters."
+			"description": "Quality goals, procedures, reviews and action."
 		},
 
 
@@ -107,7 +127,7 @@
 			"icon": "octicon octicon-tools",
 			"type": "module",
 			"hidden": 1,
-			"description": "Streamline your production with BOMS, Work Orders and Timesheets."
+			"description": "BOMS, work orders, operations, and timesheets."
 		},
 		{
 			"module_name": "Retail",
@@ -117,7 +137,7 @@
 			"icon": "octicon octicon-credit-card",
 			"type": "module",
 			"hidden": 1,
-			"description": "Point of Sale, Cashier Closing and Loyalty Programs."
+			"description": "Point of Sale and cashier closing."
 		},
 		{
 			"module_name": "Education",
@@ -127,7 +147,7 @@
 			"icon": "octicon octicon-mortar-board",
 			"type": "module",
 			"hidden": 1,
-			"description": "Manage Student Admissions, Fees, Subjects and Score Reports."
+			"description": "Student admissions, fees, courses and scores."
 		},
 
 		{
@@ -138,7 +158,7 @@
 			"icon": "fa fa-heartbeat",
 			"type": "module",
 			"hidden": 1,
-			"description": "Patients appointments, procedures and tests, with diagnosis reports and drug prescriptions."
+			"description": "Patient appointments, procedures and tests."
 		},
 		{
 			"module_name": "Agriculture",
@@ -148,7 +168,7 @@
 			"icon": "octicon octicon-globe",
 			"type": "module",
 			"hidden": 1,
-			"description": "Crop Cycles, Land Areas and Soil and Plant Analysis."
+			"description": "Crop cycles, land areas, soil and plant analysis."
 		},
 		{
 			"module_name": "Hotels",
@@ -158,7 +178,7 @@
 			"icon": "fa fa-bed",
 			"type": "module",
 			"hidden": 1,
-			"description": "Manage Hotel Rooms, Pricing, Reservation and Amenities."
+			"description": "Hotel rooms, pricing, reservation and amenities."
 		},
 
 		{
@@ -169,7 +189,7 @@
 			"icon": "octicon octicon-heart",
 			"type": "module",
 			"hidden": 1,
-			"description": "Make benefiting others easier with Volunteers, Memberships, Grants and Chapters."
+			"description": "Volunteers, memberships, grants and chapters."
 		},
 		{
 			"module_name": "Restaurant",
@@ -191,7 +211,6 @@
 			"label": _("Learn"),
 			"color": "#FF888B",
 			"icon": "octicon octicon-device-camera-video",
-			"type": "module",
 			"is_help": True,
 			"description": "Explore Help Articles and Videos."
 		},
@@ -204,6 +223,6 @@
 			"link": '#marketplace/home',
 			"color": '#FF4136',
 			'standard': 1,
-			"description": "Publish items to other ERPNext users and start a conversation."
+			"description": "Publish items to other ERPNext users."
 		},
 	]
diff --git a/erpnext/config/education.py b/erpnext/config/education.py
index 5a05a25..96e7e81 100644
--- a/erpnext/config/education.py
+++ b/erpnext/config/education.py
@@ -198,7 +198,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"items": [
 				{
 					"type": "doctype",
diff --git a/erpnext/config/getting_started.py b/erpnext/config/getting_started.py
new file mode 100644
index 0000000..19b71d2
--- /dev/null
+++ b/erpnext/config/getting_started.py
@@ -0,0 +1,261 @@
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+active_domains = frappe.get_active_domains()
+
+def get_data():
+	return [
+		{
+			"label": _("Accounting"),
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Item",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Customer",
+					"description": _("Customer database."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Supplier",
+					"description": _("Supplier database."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Company",
+					"description": _("Company (not Customer or Supplier) master."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Account",
+					"icon": "fa fa-sitemap",
+					"label": _("Chart of Accounts"),
+					"route": "#Tree/Account",
+					"description": _("Tree of financial accounts."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Opening Invoice Creation Tool",
+					"description": _("Create Opening Sales and Purchase Invoices"),
+					"onboard": 1,
+				},
+			]
+		},
+		{
+			"label": _("Data Import and Settings"),
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Data Import",
+					"label": _("Import Data"),
+					"icon": "octicon octicon-cloud-upload",
+					"description": _("Import Data from CSV / Excel files."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Letter Head",
+					"description": _("Letter Heads for print templates."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Email Account",
+					"description": _("Add / Manage Email Accounts."),
+					"onboard": 1,
+				},
+
+			]
+		},
+		{
+			"label": _("Stock"),
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Warehouse",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Brand",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "UOM",
+					"label": _("Unit of Measure") + " (UOM)",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Stock Reconciliation",
+					"onboard": 1,
+				},
+			]
+		},
+		{
+			"label": _("CRM"),
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Lead",
+					"description": _("Database of potential customers."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"label": _("Customer Group"),
+					"name": "Customer Group",
+					"icon": "fa fa-sitemap",
+					"link": "Tree/Customer Group",
+					"description": _("Manage Customer Group Tree."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"label": _("Territory"),
+					"name": "Territory",
+					"icon": "fa fa-sitemap",
+					"link": "Tree/Territory",
+					"description": _("Manage Territory Tree."),
+					"onboard": 1,
+				},
+			]
+		},
+		{
+			"label": _("Human Resources"),
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Employee",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Employee Attendance Tool",
+					"hide_count": True,
+					"onboard": 1,
+					"dependencies": ["Employee"]
+				},
+				{
+					"type": "doctype",
+					"name": "Salary Structure",
+					"onboard": 1,
+				},
+			]
+		},
+		{
+			"label": _("Education"),
+			"condition": "Education" in active_domains,
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Student",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Course",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Instructor",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Room",
+					"onboard": 1,
+				},
+			]
+		},
+		{
+			"label": _("Healthcare"),
+			"condition": "Healthcare" in active_domains,
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Patient",
+					"label": _("Patient"),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Physician",
+					"label": _("Physician"),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Diagnosis",
+					"label": _("Diagnosis"),
+					"onboard": 1,
+				}
+			]
+		},
+		{
+			"label": _("Agriculture"),
+			"condition": "Agriculture" in active_domains,
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Crop",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Crop Cycle",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Location",
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Fertilizer",
+					"onboard": 1,
+				}
+			]
+		},
+		{
+			"label": _("Non Profit"),
+			"condition": "Non Profit" in active_domains,
+			"items": [
+				{
+					"type": "doctype",
+					"name": "Member",
+					"description": _("Member information."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Volunteer",
+					"description": _("Volunteer information."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Chapter",
+					"description": _("Chapter information."),
+					"onboard": 1,
+				},
+				{
+					"type": "doctype",
+					"name": "Donor",
+					"description": _("Donor information."),
+					"onboard": 1,
+				},
+			]
+		}
+	]
\ No newline at end of file
diff --git a/erpnext/config/healthcare.py b/erpnext/config/healthcare.py
index e55f736..de0167b 100644
--- a/erpnext/config/healthcare.py
+++ b/erpnext/config/healthcare.py
@@ -105,7 +105,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "icon-cog",
 			"items": [
 				{
diff --git a/erpnext/config/help.py b/erpnext/config/help.py
index 1353892..922afb4 100644
--- a/erpnext/config/help.py
+++ b/erpnext/config/help.py
@@ -30,7 +30,7 @@
 
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"items": [
 				{
 					"type": "help",
diff --git a/erpnext/config/help_desk.py b/erpnext/config/help_desk.py
new file mode 100644
index 0000000..adc84f2
--- /dev/null
+++ b/erpnext/config/help_desk.py
@@ -0,0 +1,62 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+    return [
+        {
+            "label": _("Issues"),
+            "items": [
+                {
+                    "type": "doctype",
+                    "name": "Issue",
+                    "description": _("Support queries from customers."),
+					"onboard": 1,
+                },
+                {
+                    "type": "doctype",
+                    "name": "Communication",
+                    "description": _("Communication log."),
+					"onboard": 1,
+                },
+            ]
+        },
+        {
+            "label": _("Warranty"),
+            "items": [
+                {
+                    "type": "doctype",
+                    "name": "Warranty Claim",
+                    "description": _("Warranty Claim against Serial No."),
+                },
+                {
+                    "type": "doctype",
+                    "name": "Serial No",
+                    "description": _("Single unit of an Item."),
+                },
+            ]
+        },
+        {
+            "label": _("Reports"),
+            "icon": "fa fa-list",
+            "items": [
+                {
+                    "type": "page",
+                    "name": "support-analytics",
+                    "label": _("Support Analytics"),
+                    "icon": "fa fa-bar-chart"
+                },
+                {
+                    "type": "report",
+                    "name": "Minutes to First Response for Issues",
+                    "doctype": "Issue",
+                    "is_query_report": True
+                },
+                {
+                    "type": "report",
+                    "name": "Support Hours",
+                    "doctype": "Issue",
+                    "is_query_report": True
+                },
+            ]
+        },
+    ]
\ No newline at end of file
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 93a9f41..f517a5e 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -106,7 +106,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
diff --git a/erpnext/config/hub_node.py b/erpnext/config/hub_node.py
index 9b9fcc4..0afdeb5 100644
--- a/erpnext/config/hub_node.py
+++ b/erpnext/config/hub_node.py
@@ -4,7 +4,7 @@
 def get_data():
 	return [
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"items": [
 				{
 					"type": "doctype",
diff --git a/erpnext/config/manufacturing.py b/erpnext/config/manufacturing.py
index e1b6980..da60550 100644
--- a/erpnext/config/manufacturing.py
+++ b/erpnext/config/manufacturing.py
@@ -97,7 +97,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"items": [
 				{
 					"type": "doctype",
diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py
index 9e190a7..1b9a7a0 100644
--- a/erpnext/config/selling.py
+++ b/erpnext/config/selling.py
@@ -112,7 +112,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
diff --git a/erpnext/config/settings.py b/erpnext/config/settings.py
index 0bbf6ec..179586f1 100644
--- a/erpnext/config/settings.py
+++ b/erpnext/config/settings.py
@@ -11,7 +11,7 @@
 				{
 					"type": "doctype",
 					"name": "Global Defaults",
-					"label": _("Global Settings"),
+					"label": _("ERPNext Settings"),
 					"description": _("Set Default Values like Company, Currency, Current Fiscal Year, etc."),
 					"hide_count": True,
 					"onboard": 1,
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
index 6c06733..117b615 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -86,7 +86,7 @@
 			]
 		},
 		{
-			"label": _("Setup"),
+			"label": _("Settings"),
 			"icon": "fa fa-cog",
 			"items": [
 				{
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 6be282d..2ce6d21 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1124,15 +1124,15 @@
 		else:
 			child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
 
-		if parent_doctype == "Sales Order" and flt(d.get("qty")) < child_item.delivered_qty:
+		if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
 			frappe.throw(_("Cannot set quantity less than delivered quantity"))
 
-		if parent_doctype == "Purchase Order" and flt(d.get("qty")) < child_item.received_qty:
+		if parent_doctype == "Purchase Order" and flt(d.get("qty")) < flt(child_item.received_qty):
 			frappe.throw(_("Cannot set quantity less than received quantity"))
 
 		child_item.qty = flt(d.get("qty"))
 
-		if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))):
+		if flt(child_item.billed_amt) > (flt(d.get("rate")) * flt(d.get("qty"))):
 			frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
 						 .format(child_item.idx, child_item.item_code))
 		else:
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
index 3234e7a..c21f11e 100644
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
@@ -40,7 +40,7 @@
 				products_response = call_mws_method(products.get_matching_product,marketplaceid=marketplace,
 					asins=asin_list)
 
-				matching_products_list = products_response.parsed 
+				matching_products_list = products_response.parsed
 				for product in matching_products_list:
 					skus = [row["sku"] for row in sku_asin if row["asin"]==product.ASIN]
 					for sku in skus:
@@ -116,7 +116,7 @@
 	mws_settings = frappe.get_doc("Amazon MWS Settings")
 	max_retries = mws_settings.max_retry_limit
 
-	for x in xrange(0, max_retries):
+	for x in range(0, max_retries):
 		try:
 			response = mws_method(*args, **kwargs)
 			return response
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index bb4f62a..1edc102 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -28,7 +28,7 @@
 
 				if not frappe.get_value("Custom Field",{"name":i[0]}) or not frappe.get_value("Custom Field",{"name":i[1]}):
 					create_custom_field_id_and_check_status = True
-					break;
+					break
 
 
 			if create_custom_field_id_and_check_status:
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json
index df56918..26564a3 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_events_in_timeline": 0,
  "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
@@ -55,7 +56,7 @@
    "collapsible": 0, 
    "columns": 0, 
    "fieldname": "item_code", 
-   "fieldtype": "Read Only", 
+   "fieldtype": "Link",
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -71,7 +72,7 @@
    "precision": "", 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
-   "read_only": 0, 
+   "read_only": 1,
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
@@ -707,7 +708,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-08-08 13:00:06.260997", 
+ "modified": "2019-02-12 11:37:18.713344",
  "modified_by": "Administrator", 
  "module": "Healthcare", 
  "name": "Clinical Procedure Template", 
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index af7205b..77a2bbc 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -19,7 +19,6 @@
 				filters: {
 					"root_type": "Asset",
 					"is_group": 0,
-					"account_type": "Payable",
 					"company": frm.doc.company
 				}
 			};
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json
index 83afa8c..76e43d6 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.json
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.json
@@ -195,7 +195,7 @@
    "columns": 0, 
    "fetch_from": "employee.branch", 
    "fieldname": "branch", 
-   "fieldtype": "Read Only", 
+   "fieldtype": "Link",
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -208,11 +208,11 @@
    "no_copy": 0, 
    "oldfieldname": "branch", 
    "oldfieldtype": "Link", 
-   "options": "", 
+   "options": "Branch",
    "permlevel": 0, 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
-   "read_only": 0, 
+   "read_only": 1,
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
@@ -1906,7 +1906,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2019-01-30 11:28:11.774739", 
+ "modified": "2019-02-12 11:24:20.848207",
  "modified_by": "Administrator", 
  "module": "HR", 
  "name": "Salary Slip", 
diff --git a/erpnext/hr/report/salary_register/salary_register.py b/erpnext/hr/report/salary_register/salary_register.py
index 237c5e2..0c42150 100644
--- a/erpnext/hr/report/salary_register/salary_register.py
+++ b/erpnext/hr/report/salary_register/salary_register.py
@@ -19,12 +19,12 @@
 	data = []
 	for ss in salary_slips:
 		row = [ss.name, ss.employee, ss.employee_name, ss.branch, ss.department, ss.designation,
-			ss.company, ss.start_date, ss.end_date, ss.leave_withut_pay, ss.payment_days]
+			ss.company, ss.start_date, ss.end_date, ss.leave_without_pay, ss.payment_days]
 
 		if not ss.branch == None:columns[3] = columns[3].replace('-1','120')
 		if not ss.department  == None: columns[4] = columns[4].replace('-1','120')
 		if not ss.designation  == None: columns[5] = columns[5].replace('-1','120')
-		if not ss.leave_withut_pay  == None: columns[9] = columns[9].replace('-1','130')
+		if not ss.leave_without_pay  == None: columns[9] = columns[9].replace('-1','130')
 
 
 		for e in earning_types:
@@ -115,4 +115,4 @@
 		ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, [])
 		ss_ded_map[d.parent][d.salary_component] = flt(d.amount)
 
-	return ss_ded_map
\ No newline at end of file
+	return ss_ded_map
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 2f2c40e..976b24f 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 import json
+from six import text_type
 from frappe import _
 from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
 from frappe.model.document import Document
@@ -591,10 +592,10 @@
 
 @frappe.whitelist()
 def add_timesheet_detail(timesheet, args):
-	if isinstance(timesheet, unicode):
+	if isinstance(timesheet, text_type):
 		timesheet = frappe.get_doc('Timesheet', timesheet)
 
-	if isinstance(args, unicode):
+	if isinstance(args, text_type):
 		args = json.loads(args)
 
 	timesheet.append('time_logs', args)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 50d8ed2..f439588 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -276,8 +276,8 @@
 				item_dict[(d.item_code, d.material_request_item, d.warehouse)] = item_details
 			else:
 				item_details.update({
-					"qty":flt(item_dict.get((d.item_code, d.sales_order, d.warehouse),{})
-						.get("qty")) + flt(d.planned_qty)
+					"qty": flt(item_dict.get((d.item_code, d.sales_order, d.warehouse),{})
+						.get("qty")) + (flt(d.planned_qty) - flt(d.ordered_qty))
 				})
 				item_dict[(d.item_code, d.sales_order, d.warehouse)] = item_details
 
diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
index b6f7d01..be016ad 100644
--- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
+++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
@@ -13,16 +13,16 @@
 	data = get_bom_stock(filters)
 	qty_to_make = filters.get("qty_to_make")
 
-	for rows in data:
-		item_map = get_item_details(rows[0])
-		reqd_qty = qty_to_make * rows[3]
-		last_pur_price = frappe.db.get_value("Item", rows[0], "last_purchase_rate")
-		if rows[4] > 0:
-			diff_qty = rows[4] - reqd_qty
-			summ_data.append([rows[0], rows[1], item_map[rows[0]]["manufacturer"], item_map[rows[0]]["manufacturer_part_no"], rows[3], rows[4], reqd_qty, diff_qty, last_pur_price])
+	for row in data:
+		item_map = get_item_details(row.item_code)
+		reqd_qty = qty_to_make * row.actual_qty
+		last_pur_price = frappe.db.get_value("Item", row.item_code, "last_purchase_rate")
+		if row.to_build > 0:
+			diff_qty = row.to_build - reqd_qty
+			summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, row.to_build, reqd_qty, diff_qty, last_pur_price])
 		else:
 			diff_qty = 0 - reqd_qty
-			summ_data.append([rows[0], rows[1], item_map[rows[0]]["manufacturer"], item_map[rows[0]]["manufacturer_part_no"], rows[3], "0.000", reqd_qty, diff_qty, last_pur_price])
+			summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, "0.000", reqd_qty, diff_qty, last_pur_price])
 
 	return columns, summ_data
 
@@ -72,8 +72,8 @@
 				bom_item.item_code,
 				bom_item.description,
 				bom_item.{qty_field},
-				sum(ledger.actual_qty) as actual_qty,
-				sum(FLOOR(ledger.actual_qty / bom_item.{qty_field}))as to_build
+				ifnull(sum(ledger.actual_qty), 0) as actual_qty,
+				ifnull(sum(FLOOR(ledger.actual_qty / bom_item.{qty_field})), 0) as to_build
 			FROM
 				{table} AS bom_item
 				LEFT JOIN `tabBin` AS ledger
@@ -83,7 +83,7 @@
 			WHERE
 				bom_item.parent = '{bom}' and bom_item.parenttype='BOM'
 
-			GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom))
+			GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1)
 
 def get_item_details(item_code):
 		items = frappe.db.sql("""select it.item_group, it.item_name, it.stock_uom, it.name, it.brand, it.description, it.manufacturer_part_no, it.manufacturer from tabItem it where it.item_code = %s""", item_code, as_dict=1)
diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.json b/erpnext/manufacturing/report/production_analytics/production_analytics.json
index 023e0a8..946cd33 100644
--- a/erpnext/manufacturing/report/production_analytics/production_analytics.json
+++ b/erpnext/manufacturing/report/production_analytics/production_analytics.json
@@ -1,13 +1,14 @@
 {
- "add_total_row": 0, 
+ "add_total_row": 1, 
  "creation": "2018-10-11 19:28:37.085066", 
+ "disable_prepared_report": 0, 
  "disabled": 0, 
  "docstatus": 0, 
  "doctype": "Report", 
  "idx": 0, 
  "is_standard": "Yes", 
  "letter_head": "", 
- "modified": "2018-10-11 19:28:37.085066", 
+ "modified": "2019-02-12 14:32:16.392521", 
  "modified_by": "Administrator", 
  "module": "Manufacturing", 
  "name": "Production Analytics", 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 8ab6153..0826ec6 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -581,4 +581,5 @@
 erpnext.patches.v11_0.renamed_from_to_fields_in_project
 erpnext.patches.v11_0.add_permissions_in_gst_settings
 erpnext.patches.v11_1.setup_guardian_role
+execute:frappe.delete_doc('DocType', 'Notification Control')
 erpnext.patches.v12_0.move_item_tax_to_item_tax_template
diff --git a/erpnext/patches/v11_0/create_department_records_for_each_company.py b/erpnext/patches/v11_0/create_department_records_for_each_company.py
index 1257f19..b5a7bd9 100644
--- a/erpnext/patches/v11_0/create_department_records_for_each_company.py
+++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py
@@ -27,8 +27,10 @@
 		for company in companies:
 			copy_doc = frappe.copy_doc(department_doc)
 			copy_doc.update({"company": company.name})
-			copy_doc.insert()
-
+			try:
+				copy_doc.insert()
+			except frappe.DuplicateEntryError:
+				pass
 			# append list of new department for each company
 			comp_dict[company.name][department.name] = copy_doc.name
 
diff --git a/erpnext/patches/v11_0/update_total_qty_field.py b/erpnext/patches/v11_0/update_total_qty_field.py
index fcb76af..992454a 100644
--- a/erpnext/patches/v11_0/update_total_qty_field.py
+++ b/erpnext/patches/v11_0/update_total_qty_field.py
@@ -19,9 +19,10 @@
 			SELECT
 				parent, SUM(qty) as qty
 			FROM
-				`tab%s Item`
+				`tab{0} Item`
+			where parenttype = '{0}'
 			GROUP BY parent
-		''' % (doctype), as_dict = True)
+		'''.format(doctype), as_dict = True)
 
 		# Query to update total_qty might become too big, Update in batches
 		# batch_size is chosen arbitrarily, Don't try too hard to reason about it
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 3b42f6a6..e3fd1a8 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -66,11 +66,11 @@
 
 	def validate(self):
 		self.validate_project_name()
-		self.validate_dates()
 		self.validate_weights()
 		self.sync_tasks()
 		self.tasks = []
 		self.load_tasks()
+		self.validate_dates()
 		self.send_welcome_email()
 		self.update_percent_complete()
 
@@ -79,6 +79,24 @@
 			frappe.throw(_("Project {0} already exists").format(frappe.safe_decode(self.project_name)))
 
 	def validate_dates(self):
+		if self.tasks:
+			for d in self.tasks:
+				if self.expected_start_date:
+					if d.start_date and getdate(d.start_date) < getdate(self.expected_start_date):
+						frappe.throw(_("Start date of task <b>{0}</b> cannot be less than <b>{1}</b> expected start date <b>{2}</b>")
+							.format(d.title, self.name, self.expected_start_date))
+					if d.end_date and getdate(d.end_date) < getdate(self.expected_start_date):
+						frappe.throw(_("End date of task <b>{0}</b> cannot be less than <b>{1}</b> expected start date <b>{2}</b>")
+							.format(d.title, self.name, self.expected_start_date))
+
+				if self.expected_end_date:
+					if d.start_date and getdate(d.start_date) > getdate(self.expected_end_date):
+						frappe.throw(_("Start date of task <b>{0}</b> cannot be greater than <b>{1}</b> expected end date <b>{2}</b>")
+							.format(d.title, self.name, self.expected_end_date))
+					if d.end_date and getdate(d.end_date) > getdate(self.expected_end_date):
+						frappe.throw(_("End date of task <b>{0}</b> cannot be greater than <b>{1}</b> expected end date <b>{2}</b>")
+							.format(d.title, self.name, self.expected_end_date))
+
 		if self.expected_start_date and self.expected_end_date:
 			if getdate(self.expected_end_date) < getdate(self.expected_start_date):
 				frappe.throw(_("Expected End Date can not be less than Expected Start Date"))
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 1fcb3c6..6613eb1 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -44,12 +44,6 @@
 		if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
 			frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
 
-		if(self.project):
-			if frappe.db.exists("Project", self.project):
-				expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
-				if  self.exp_end_date and expected_end_date and getdate(self.exp_end_date) > getdate(expected_end_date) :
-					frappe.throw(_("Expected end date cannot be after Project: <b>'{0}'</b> Expected end date").format(self.project), EndDateCannotBeGreaterThanProjectEndDateError)
-
 	def validate_status(self):
 		if self.status!=self.get_db_value("status") and self.status == "Closed":
 			for d in self.depends_on:
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index 6fb5412..9971946 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -5,7 +5,7 @@
 import unittest
 from frappe.utils import getdate, nowdate, add_days
 
-from erpnext.projects.doctype.task.task import CircularReferenceError, EndDateCannotBeGreaterThanProjectEndDateError
+from erpnext.projects.doctype.task.task import CircularReferenceError
 
 class TestTask(unittest.TestCase):
 	def test_circular_reference(self):
@@ -97,15 +97,6 @@
 
 		self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
 
-	def test_end_date_validation(self):
-		task_end = create_task("Testing_Enddate_validation", add_days(nowdate(), 35), add_days(nowdate(), 45), save=False)
-		pro = frappe.get_doc("Project", task_end.project)
-		pro.expected_end_date = add_days(nowdate(), 40)
-		pro.save()
-		self.assertRaises(EndDateCannotBeGreaterThanProjectEndDateError, task_end.save)
-
-
-
 def create_task(subject, start=None, end=None, depends_on=None, project=None, save=True):
 	if not frappe.db.exists("Task", subject):
 		task = frappe.new_doc('Task')
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index 8692440..3757315 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -18,7 +18,7 @@
 			return{
 				filters: {
 					'project': child.project,
-					'status': ["!=", "Closed"]
+					'status': ["!=", "Cancelled"]
 				}
 			}
 		}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index ff90d13..5da7e73 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -276,13 +276,11 @@
 	scan_barcode: function() {
 		let scan_barcode_field = this.frm.fields_dict["scan_barcode"];
 
-		let show_description = function(idx, item_code, exist=null) {
-			if(exist) {
-				scan_barcode_field.set_new_description(__('Row : ') + idx + ' ' +
-					item_code + __(' Qty increased by 1'));
+		let show_description = function(idx, exist = null) {
+			if (exist) {
+				scan_barcode_field.set_new_description(__('Row #{0}: Qty increased by 1', [idx]));
 			} else {
-				scan_barcode_field.set_new_description(__('New row : ') + idx + ' ' +
-					item_code + __('  Created'));
+				scan_barcode_field.set_new_description(__('Row #{0}: Item added', [idx]));
 			}
 		}
 
@@ -291,38 +289,39 @@
 				method: "erpnext.selling.page.point_of_sale.point_of_sale.search_serial_or_batch_or_barcode_number",
 				args: { search_value: this.frm.doc.scan_barcode }
 			}).then(r => {
-
-				if(r && r.message && r.message.item_code) {
-					let child = "";
-					let add_row_index = -1;
-					let cur_grid= this.frm.fields_dict["items"].grid;
-
-					this.frm.doc.items.map(d => {
-						if(d.item_code==r.message.item_code){
-							add_row_index = d.idx;
-							return;
-						} else if(!d.item_code && add_row_index==-1) {
-							add_row_index = d.idx;
-						}
-					});
-
-					if(add_row_index == -1) {
-						child = frappe.model.add_child(this.frm.doc, cur_grid.doctype, "items", add_row_index);
-					} else {
-						child = cur_grid.get_grid_row(add_row_index-1).doc;
-					}
-					show_description(child.idx, r.message.item_code, child.item_code);
-
-					frappe.model.set_value(child.doctype, child.name, {
-						"item_code": r.message.item_code,
-						"qty": (child.qty || 0) + 1
-					});
+				const data = r && r.message;
+				if (!data) {
+					scan_barcode_field.set_new_description(__('Cannot find Item with this barcode'));
+					return;
 				}
-				else{
-					scan_barcode_field.set_new_description(this.frm.doc.scan_barcode +__(' does not exist!'));
+
+				let cur_grid = this.frm.fields_dict.items.grid;
+
+				let row_to_modify = null;
+				const existing_item_row = this.frm.doc.items.find(d => d.item_code === data.item_code);
+				const blank_item_row = this.frm.doc.items.find(d => !d.item_code);
+
+				if (existing_item_row) {
+					row_to_modify = existing_item_row;
+				} else if (blank_item_row) {
+					row_to_modify = blank_item_row;
 				}
+
+				if (!row_to_modify) {
+					// add new row
+					row_to_modify = frappe.model.add_child(this.frm.doc, cur_grid.doctype, 'items');
+				}
+
+				show_description(row_to_modify.idx, row_to_modify.item_code);
+
+				frappe.model.set_value(row_to_modify.doctype, row_to_modify.name, {
+					item_code: data.item_code,
+					qty: (row_to_modify.qty || 0) + 1
+				});
+
+				this.frm.refresh_field('items');
 			});
-			scan_barcode_field.set_value("");
+			scan_barcode_field.set_value('');
 		}
 		return false;
 	},
diff --git a/erpnext/regional/germany/__init__.py b/erpnext/regional/germany/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/germany/__init__.py
diff --git a/erpnext/regional/germany/address_template.html b/erpnext/regional/germany/address_template.html
new file mode 100644
index 0000000..0df7867
--- /dev/null
+++ b/erpnext/regional/germany/address_template.html
@@ -0,0 +1,8 @@
+{{ address_line1 }}<br>
+{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
+{{ pincode }} {{ city }}<br>
+{% if country %}{{ country }}<br>{% endif -%}
+<br>
+{% if phone %}Tel: {{ phone }}<br>{% endif -%}
+{% if fax %}Fax: {{ fax }}<br>{% endif -%}
+{% if email_id %}E-Mail: {{ email_id }}<br>{% endif -%}
diff --git a/erpnext/regional/germany/setup.py b/erpnext/regional/germany/setup.py
new file mode 100644
index 0000000..a547136
--- /dev/null
+++ b/erpnext/regional/germany/setup.py
@@ -0,0 +1,31 @@
+import os
+import frappe
+
+
+def setup(company=None, patch=True):
+	if not patch:
+		update_address_template()
+
+
+def update_address_template():
+	"""
+	Read address template from file. Update existing Address Template or create a
+	new one.
+	"""
+	dir_name = os.path.dirname(__file__)
+	template_path = os.path.join(dir_name, 'address_template.html')
+
+	with open(template_path, 'r') as template_file:
+		template_html = template_file.read()
+
+	address_template = frappe.db.get_value('Address Template', 'Germany')
+
+	if address_template:
+		frappe.db.set_value('Address Template', 'Germany', 'template', template_html)
+	else:
+		# make new html template for Germany
+		frappe.get_doc(dict(
+			doctype='Address Template',
+			country='Germany',
+			template=template_html
+		)).insert()
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index a6d723a..c5498c7 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -345,13 +345,14 @@
 	if company and tds_account:
 		accounts = [dict(company=company, account=tds_account)]
 
-	fiscal_year = get_fiscal_year(today(), company=accounts[0].get('company'))[0]
+	fiscal_year = get_fiscal_year(today(), company=company)[0]
 	docs = get_tds_details(accounts, fiscal_year)
 
 	for d in docs:
 		try:
 			doc = frappe.get_doc(d)
 			doc.flags.ignore_permissions = True
+			doc.flags.ignore_mandatory = True
 			doc.insert()
 		except frappe.DuplicateEntryError:
 			doc = frappe.get_doc("Tax Withholding Category", d.get("name"))
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
index a9e4303..eb242d0 100644
--- a/erpnext/selling/report/address_and_contacts/address_and_contacts.py
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
@@ -102,7 +102,8 @@
 	records = frappe.get_list(doctype, filters=filters, fields=fields, as_list=True)
 	for d in records:
 		details = party_details.get(d[0])
-		details.setdefault(frappe.scrub(doctype), []).append(d[1:])
+		if details:
+			details.setdefault(frappe.scrub(doctype), []).append(d[1:])
 
 	return party_details
 
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.json b/erpnext/selling/report/sales_analytics/sales_analytics.json
index 5c95f28..bd82302 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.json
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.json
@@ -1,12 +1,13 @@
 {
- "add_total_row": 0, 
+ "add_total_row": 1, 
  "creation": "2018-09-21 12:46:29.451048", 
+ "disable_prepared_report": 0, 
  "disabled": 0, 
  "docstatus": 0, 
  "doctype": "Report", 
  "idx": 0, 
  "is_standard": "Yes", 
- "modified": "2018-09-21 12:46:29.451048", 
+ "modified": "2019-02-12 14:30:40.043652", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Analytics", 
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 6009bcc..d21de0e 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -252,7 +252,7 @@
 	from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
 	make_default_records()
 
-	make_records(records, True)
+	make_records(records)
 
 	set_more_defaults()
 
@@ -366,7 +366,7 @@
 		}
 	]
 
-	make_records(records, True)
+	make_records(records)
 
 
 def install_post_company_fixtures(args=None):
@@ -474,7 +474,7 @@
 		},
 	]
 
-	make_records(records, True)
+	make_records(records)
 
 
 def get_fy_details(fy_start_date, fy_end_date):
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index ef0a317..71fd821 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -2,6 +2,7 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+from six import text_type
 import frappe
 from frappe import _
 from frappe.model.document import Document
@@ -60,7 +61,7 @@
 	:param prefix: Naming series prefix gotten from Stock Settings
 	:return: The derived key. If no prefix is given, an empty string is returned
 	"""
-	if not unicode(prefix):
+	if not text_type(prefix):
 		return ''
 	else:
 		return prefix.upper() + '.#####'
@@ -86,7 +87,7 @@
 	def autoname(self):
 		"""Generate random ID for batch if not specified"""
 		if not self.batch_id:
-			create_new_batch, batch_number_series = frappe.db.get_value('Item', self.item, 
+			create_new_batch, batch_number_series = frappe.db.get_value('Item', self.item,
 				['create_new_batch', 'batch_number_series'])
 
 			if create_new_batch:
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index a0d94bf..5669552 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -703,15 +703,14 @@
                         frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'):
 			return
 		if self.has_variants:
-			updated = []
 			variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name})
-			for d in variants:
-				variant = frappe.get_doc("Item", d)
-				copy_attributes_to_variant(self, variant)
-				variant.save()
-				updated.append(d.item_code)
-			if updated:
-				frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
+			if variants:
+				if len(variants) <= 30:
+					update_variants(variants, self, publish_progress=False)
+					frappe.msgprint(_("Item Variants updated"))
+				else:
+					frappe.enqueue("erpnext.stock.doctype.item.item.update_variants",
+						variants=variants, template=self, now=frappe.flags.in_test, timeout=600)
 
 	def validate_has_variants(self):
 		if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"):
@@ -1000,3 +999,13 @@
 
 	return frappe.get_all("Item Attribute Value", fields = ["attribute_value"],
 		filters = {'parent': parent, 'attribute_value': ("like", "%%%s%%" % attribute_value)})
+
+def update_variants(variants, template, publish_progress=True):
+	count=0
+	for d in variants:
+		variant = frappe.get_doc("Item", d)
+		copy_attributes_to_variant(template, variant)
+		variant.save()
+		count+=1
+		if publish_progress:
+				frappe.publish_progress(count*100/len(variants), title = _("Updating Variants..."))
\ No newline at end of file
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 34a86c9..7a199a4 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -81,9 +81,9 @@
 
 	def set_title(self):
 		'''Set title as comma separated list of items'''
-		items = ', '.join([d.item_name for d in self.items][:4])
-
-		self.title = _('{0} for {1}'.format(self.material_request_type, items))[:100]
+		if not self.title:
+			items = ', '.join([d.item_name for d in self.items][:3])
+			self.title = _('{0} Request for {1}').format(self.material_request_type, items)[:100]
 
 	def on_submit(self):
 		# frappe.db.set(self, 'status', 'Submitted')
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index f006d00..8563d46 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -120,12 +120,12 @@
 			self.company, self.base_grand_total)
 
 		self.update_prevdoc_status()
-		if self.per_billed < 100:
+		if flt(self.per_billed) < 100:
 			self.update_billing_status()
 		else:
 			self.status = "Completed"
 
-		
+
 		# Updating stock ledger should always be called after updating prevdoc status,
 		# because updating ordered qty, reserved_qty_for_subcontract in bin
 		# depends upon updated ordered qty in PO
@@ -311,7 +311,7 @@
 				"\n".join(warehouse_with_no_account))
 
 		return process_gl_map(gl_entries)
-		
+
 	def get_asset_gl_entry(self, gl_entries):
 		for d in self.get("items"):
 			if d.is_fixed_asset:
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 5f0b80e..3012d0b 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -297,8 +297,9 @@
 			total_completed_qty = flt(self.fg_completed_qty) + flt(prod_order.produced_qty)
 			completed_qty = d.completed_qty + (allowance_percentage/100 * d.completed_qty)
 			if total_completed_qty > flt(completed_qty):
-				frappe.throw(_("Row #{0}: Operation {1} is not completed for {2} qty of finished goods in Work Order # {3}. Please update operation status via Time Logs")
-					.format(d.idx, d.operation, total_completed_qty, self.work_order), OperationsNotCompleteError)
+				job_card = frappe.db.get_value('Job Card', {'operation_id': d.name}, 'name')
+				frappe.throw(_("Row #{0}: Operation {1} is not completed for {2} qty of finished goods in Work Order # {3}. Please update operation status via Job Card # {4}")
+					.format(d.idx, d.operation, total_completed_qty, self.work_order, job_card), OperationsNotCompleteError)
 
 	def check_duplicate_entry_for_work_order(self):
 		other_ste = [t[0] for t in frappe.db.get_values("Stock Entry",  {
@@ -918,6 +919,11 @@
 				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)
 			consumed_qty = flt(req_items[0].consumed_qty)
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 9095075..448e2db 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -562,7 +562,7 @@
 		for d in stock_entry.get("items"):
 			if d.item_code != "_Test FG Item 2":
 				rm_cost += flt(d.amount)
-		fg_cost = filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items"))[0].amount
+		fg_cost = list(filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items")))[0].amount
 		self.assertEqual(fg_cost,
 			flt(rm_cost + bom_operation_cost + work_order.additional_operating_cost, 2))
 
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index eb60ce5..a00d279 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -259,6 +259,7 @@
 
 	def submit(self):
 		if len(self.items) > 100:
+			msgprint(_("The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Draft stage"))
 			self.queue_action('submit')
 		else:
 			self._submit()
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index ef63740..da97bc6 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -157,6 +157,8 @@
 	# return warehouses
 	for wh in warehouses:
 		wh["balance"] = get_stock_value_from_bin(warehouse=wh.value)
+		if company:
+			wh["company_currency"] = frappe.db.get_value('Company', company, 'default_currency')
 	return warehouses
 
 @frappe.whitelist()
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 3051d31..4561592 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -16,6 +16,9 @@
 
 from six import string_types, iteritems
 
+sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']
+purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
+
 @frappe.whitelist()
 def get_item_details(args):
 	"""
@@ -232,7 +235,7 @@
 
 	#Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
 	if not args.uom:
-		if args.get('doctype') in ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']:
+		if args.get('doctype') in sales_doctypes:
 			args.uom = item.sales_uom if item.sales_uom else item.stock_uom
 		elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \
 			(args.get('doctype') == 'Material Request' and args.get('material_request_type') == 'Purchase'):
@@ -283,14 +286,15 @@
 		out.conversion_factor = 1.0
 	else:
 		out.conversion_factor = args.conversion_factor or \
-			get_conversion_factor(item.item_code, args.uom).get("conversion_factor")
+			get_conversion_factor(item.name, args.uom).get("conversion_factor")
 
 	args.conversion_factor = out.conversion_factor
 	out.stock_qty = out.qty * out.conversion_factor
 
 	# calculate last purchase rate
-	from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate
-	out.last_purchase_rate = item_last_purchase_rate(args.name, args.conversion_rate, item.item_code, out.conversion_factor)
+	if args.get('doctype') in purchase_doctypes:
+		from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate
+		out.last_purchase_rate = item_last_purchase_rate(args.name, args.conversion_rate, item.name, out.conversion_factor)
 
 	# if default specified in item is for another company, fetch from company
 	for d in [
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.json b/erpnext/stock/report/stock_analytics/stock_analytics.json
index efd5e99..7a2ed2b 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.json
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.json
@@ -1,12 +1,13 @@
 {
- "add_total_row": 0, 
+ "add_total_row": 1, 
  "creation": "2018-10-08 12:11:32.133020", 
+ "disable_prepared_report": 0, 
  "disabled": 0, 
  "docstatus": 0, 
  "doctype": "Report", 
  "idx": 0, 
  "is_standard": "Yes", 
- "modified": "2018-10-08 12:18:42.834270", 
+ "modified": "2019-02-12 14:32:22.874082", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Analytics", 
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 14b1852..5c443d3 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -216,20 +216,28 @@
 	if not items:
 		items = list(set([d.item_code for d in sle]))
 
-	if items:
-		cf_field = cf_join = ""
-		if filters.get("include_uom"):
-			cf_field = ", ucd.`conversion_factor`"
-			cf_join = "LEFT JOIN `tabUOM Conversion Detail` ucd ON ucd.`parent`=item.`name` AND ucd.`uom`=%(include_uom)s"
+	if not items:
+		return item_details
 
-		for item in frappe.db.sql("""
-			SELECT item.`name`, item.`item_name`, item.`description`, item.`item_group`, item.`brand`, item.`stock_uom` {cf_field}
-			FROM `tabItem` item
+	cf_field = cf_join = ""
+	if filters.get("include_uom"):
+		cf_field = ", ucd.conversion_factor"
+		cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom='%s'" \
+			% frappe.db.escape(filters.get("include_uom"))
+
+	item_codes = ', '.join(['"' + frappe.db.escape(i, percent=False) + '"' for i in items])
+	res = frappe.db.sql("""
+		select
+			item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom {cf_field}
+		from
+			`tabItem` item
 			{cf_join}
-			WHERE item.`name` IN ({names}) AND IFNULL(item.`disabled`, 0) = 0
-			""".format(cf_field=cf_field, cf_join=cf_join, names=', '.join([frappe.db.escape(i, percent=False) for i in items])),
-			{"include_uom": filters.get("include_uom")}, as_dict=1):
-				item_details.setdefault(item.name, item)
+		where
+			item.name in ({item_codes}) and ifnull(item.disabled, 0) = 0
+	""".format(cf_field=cf_field, cf_join=cf_join, item_codes=item_codes), as_dict=1)
+
+	for item in res:
+		item_details.setdefault(item.name, item)
 
 	if filters.get('show_variant_attributes', 0) == 1:
 		variant_values = get_variant_values_for(list(item_details))
diff --git a/erpnext/templates/pages/search_help.py b/erpnext/templates/pages/search_help.py
index 4a4b0db..887d8f4 100644
--- a/erpnext/templates/pages/search_help.py
+++ b/erpnext/templates/pages/search_help.py
@@ -3,6 +3,7 @@
 from frappe import _
 from jinja2 import utils
 from html2text import html2text
+from six import text_type
 from frappe.utils import sanitize_html
 from frappe.utils.global_search import search
 
@@ -12,7 +13,7 @@
 		query = str(utils.escape(sanitize_html(frappe.form_dict.q)))
 		context.title = _('Help Results for')
 		context.query = query
-		
+
 		context.route = '/search_help'
 		d = frappe._dict()
 		d.results_sections = get_help_results_sections(query)
@@ -73,7 +74,7 @@
 	for topic in topics_data:
 		route = api.base_url + '/' + (api.post_route  + '/' if api.post_route else "")
 		for key in api.post_route_key_list.split(','):
-			route += unicode(topic[key])
+			route += text_type(topic[key])
 
 		results.append(frappe._dict({
 			'title': topic[api.post_title_key],