Merge branch 'develop' of github.com:frappe/erpnext into lms-beta-v2
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py
index 7042df0..2b2b6af 100644
--- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py
@@ -32,7 +32,7 @@
 	def check_duplicate_terms(self):
 		terms = []
 		for term in self.terms:
-			term_info = (term.credit_days, term.due_date_based_on)
+			term_info = (term.credit_days, term.credit_months, term.due_date_based_on)
 			if term_info in terms:
 				frappe.msgprint(
 					_('The Payment Term at row {0} is possibly a duplicate.').format(term.idx),
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 29ca71b..442b6c2 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import (cstr, validate_email_add, cint, comma_and, has_gravatar, now, getdate, nowdate)
+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
@@ -38,7 +38,7 @@
 
 		if self.email_id:
 			if not self.flags.ignore_email_validation:
-				validate_email_add(self.email_id, True)
+				validate_email_address(self.email_id, True)
 
 			if self.email_id == self.lead_owner:
 				frappe.throw(_("Lead Owner cannot be same as the Lead"))
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index d518cd8..a403c39 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import getdate, validate_email_add, today, add_years, format_datetime
+from frappe.utils import getdate, validate_email_address, today, add_years, format_datetime
 from frappe.model.naming import set_name_by_naming_series
 from frappe import throw, _, scrub
 from frappe.permissions import add_user_permission, remove_user_permission, \
@@ -142,9 +142,9 @@
 
 	def validate_email(self):
 		if self.company_email:
-			validate_email_add(self.company_email, True)
+			validate_email_address(self.company_email, True)
 		if self.personal_email:
-			validate_email_add(self.personal_email, True)
+			validate_email_address(self.personal_email, True)
 
 	def validate_status(self):
 		if self.status == 'Left':
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index ea81fe7..4fc7719 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -7,7 +7,7 @@
 from frappe.model.document import Document
 import frappe
 from frappe import _
-from frappe.utils import comma_and, validate_email_add
+from frappe.utils import comma_and, validate_email_address
 
 sender_field = "email_id"
 
@@ -28,7 +28,7 @@
 	def validate(self):
 		self.check_email_id_is_unique()
 		if self.email_id:
-			validate_email_add(self.email_id, True)
+			validate_email_address(self.email_id, True)
 
 		if not self.applicant_name and self.email_id:
 			guess = self.email_id.split('@')[0]
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 8f7b5a8..6a7a80a 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -561,7 +561,7 @@
    "label": "Earned Leave Frequency",
    "length": 0,
    "no_copy": 0,
-   "options": "Monthly\nQuarterly\nYearly",
+   "options": "Monthly\nQuarterly\nHalf-Yearly\nYearly",
    "permlevel": 0,
    "precision": "",
    "print_hide": 0,
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 0226201..e0b6a51 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -260,7 +260,7 @@
 		fields=["name", "max_leaves_allowed", "earned_leave_frequency", "rounding"],
 		filters={'is_earned_leave' : 1})
 	today = getdate()
-	divide_by_frequency = {"Yearly": 1, "Quarterly": 4, "Monthly": 12}
+	divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
 	if e_leave_types:
 		for e_leave_type in e_leave_types:
 			leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where '{0}'
@@ -297,6 +297,9 @@
 	if frequency == "Quarterly":
 		if not months % 3:
 			return True
+	elif frequency == "Half-Yearly":
+		if not months % 6:
+			return True
 	elif frequency == "Yearly":
 		if not months % 12:
 			return True
diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py
index b9b2dd8..9afaf90 100644
--- a/erpnext/non_profit/doctype/member/member.py
+++ b/erpnext/non_profit/doctype/member/member.py
@@ -17,5 +17,5 @@
 		self.validate_email_type(self.email)
 
 	def validate_email_type(self, email):
-		from frappe.utils import validate_email_add
-		validate_email_add(email.strip(), True)
\ No newline at end of file
+		from frappe.utils import validate_email_address
+		validate_email_address(email.strip(), True)
\ No newline at end of file
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index 93423db..9a8af69 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -35,19 +35,6 @@
 			}
 
 			if(!doc.__islocal) {
-				if(frappe.model.can_read("Timesheet")) {
-					frm.add_custom_button(__("Timesheet"), function() {
-						frappe.route_options = {"project": doc.project, "task": doc.name}
-						frappe.set_route("List", "Timesheet");
-					}, __("View"), true);
-				}
-				if(frappe.model.can_read("Expense Claim")) {
-					frm.add_custom_button(__("Expense Claims"), function() {
-						frappe.route_options = {"project": doc.project, "task": doc.name}
-						frappe.set_route("List", "Expense Claim");
-					}, __("View"), true);
-				}
-
 				if(frm.perm[0].write) {
 					if(frm.doc.status!=="Completed" && frm.doc.status!=="Cancelled") {
 						frm.add_custom_button(__("Completed"), function() {
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index d904d70..2602aef 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -83,6 +83,39 @@
    "allow_bulk_edit": 0,
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "issue",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Issue",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Issue",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
    "bold": 1,
    "collapsible": 0,
    "columns": 0,
@@ -217,6 +250,38 @@
    "allow_bulk_edit": 0,
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "color",
+   "fieldtype": "Color",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Color",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
    "bold": 1,
    "collapsible": 0,
    "columns": 0,
@@ -251,11 +316,11 @@
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
-   "collapsible": 0,
-   "collapsible_depends_on": "",
+   "collapsible": 1,
+   "collapsible_depends_on": "eval:doc.__islocal",
    "columns": 0,
    "depends_on": "",
-   "fieldname": "section_break_10",
+   "fieldname": "sb_timeline",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -264,6 +329,7 @@
    "in_global_search": 0,
    "in_list_view": 0,
    "in_standard_filter": 0,
+   "label": "Timeline",
    "length": 0,
    "no_copy": 0,
    "permlevel": 0,
@@ -519,42 +585,10 @@
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
-   "columns": 0,
-   "fieldname": "color",
-   "fieldtype": "Color",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Color",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
    "collapsible_depends_on": "",
    "columns": 0,
    "depends_on": "",
-   "fieldname": "section_break0",
+   "fieldname": "sb_details",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -563,10 +597,11 @@
    "in_global_search": 0,
    "in_list_view": 0,
    "in_standard_filter": 0,
+   "label": "Details",
    "length": 0,
    "no_copy": 0,
    "oldfieldtype": "Section Break",
-   "options": "Simple",
+   "options": "",
    "permlevel": 0,
    "print_hide": 0,
    "print_hide_if_no_value": 0,
@@ -596,7 +631,7 @@
    "in_global_search": 0,
    "in_list_view": 0,
    "in_standard_filter": 0,
-   "label": "Details",
+   "label": "Task Description",
    "length": 0,
    "no_copy": 0,
    "oldfieldname": "description",
@@ -624,7 +659,7 @@
    "collapsible_depends_on": "",
    "columns": 0,
    "depends_on": "",
-   "fieldname": "section_break",
+   "fieldname": "sb_depends_on",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -726,7 +761,7 @@
    "columns": 0,
    "depends_on": "",
    "description": "",
-   "fieldname": "actual",
+   "fieldname": "sb_actual",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -893,10 +928,10 @@
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
-   "collapsible": 0,
+   "collapsible": 1,
    "columns": 0,
    "depends_on": "",
-   "fieldname": "section_break_17",
+   "fieldname": "sb_costing",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -905,6 +940,7 @@
    "in_global_search": 0,
    "in_list_view": 0,
    "in_standard_filter": 0,
+   "label": "Costing",
    "length": 0,
    "no_copy": 0,
    "permlevel": 0,
@@ -1058,9 +1094,9 @@
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
-   "collapsible": 0,
+   "collapsible": 1,
    "columns": 0,
-   "fieldname": "more_details",
+   "fieldname": "sb_more_info",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
@@ -1069,7 +1105,7 @@
    "in_global_search": 0,
    "in_list_view": 0,
    "in_standard_filter": 0,
-   "label": "",
+   "label": "More Info",
    "length": 0,
    "no_copy": 0,
    "permlevel": 0,
diff --git a/erpnext/projects/doctype/task/task_dashboard.py b/erpnext/projects/doctype/task/task_dashboard.py
new file mode 100644
index 0000000..b776b98
--- /dev/null
+++ b/erpnext/projects/doctype/task/task_dashboard.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+
+from frappe import _
+
+
+def get_data():
+	return {
+		'fieldname': 'task',
+		'transactions': [
+			{
+				'label': _('Activity'),
+				'items': ['Timesheet']
+			},
+			{
+				'label': _('Accounting'),
+				'items': ['Expense Claim']
+			}
+		]
+	}
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 5c443d3..5d7c582 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -43,11 +43,11 @@
 				item_map[item]["item_group"],
 				item_map[item]["brand"],
 				item_map[item]["description"], warehouse,
-				item_map[item]["stock_uom"], qty_dict.opening_qty,
+				item_map[item]["stock_uom"], qty_dict.bal_qty,
+				qty_dict.bal_val, qty_dict.opening_qty,
 				qty_dict.opening_val, qty_dict.in_qty,
 				qty_dict.in_val, qty_dict.out_qty,
-				qty_dict.out_val, qty_dict.bal_qty,
-				qty_dict.bal_val, qty_dict.val_rate,
+				qty_dict.out_val, qty_dict.val_rate,
 				item_reorder_level,
 				item_reorder_qty,
 				company
@@ -79,14 +79,14 @@
 		{"label": _("Description"), "fieldname": "description", "width": 140},
 		{"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 100},
 		{"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 90},
+		{"label": _("Balance Qty"), "fieldname": "bal_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
+		{"label": _("Balance Value"), "fieldname": "bal_val", "fieldtype": "Currency", "width": 100},
 		{"label": _("Opening Qty"), "fieldname": "opening_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
 		{"label": _("Opening Value"), "fieldname": "opening_val", "fieldtype": "Float", "width": 110},
 		{"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
 		{"label": _("In Value"), "fieldname": "in_val", "fieldtype": "Float", "width": 80},
 		{"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
 		{"label": _("Out Value"), "fieldname": "out_val", "fieldtype": "Float", "width": 80},
-		{"label": _("Balance Qty"), "fieldname": "bal_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
-		{"label": _("Balance Value"), "fieldname": "bal_val", "fieldtype": "Currency", "width": 100},
 		{"label": _("Valuation Rate"), "fieldname": "val_rate", "fieldtype": "Currency", "width": 90, "convertible": "rate"},
 		{"label": _("Reorder Level"), "fieldname": "reorder_level", "fieldtype": "Float", "width": 80, "convertible": "qty"},
 		{"label": _("Reorder Qty"), "fieldname": "reorder_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index d0a9bf3..ce75304 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -3,14 +3,21 @@
 		frm.email_field = "raised_by";
 	},
 
-	refresh: function(frm) {
-		if(frm.doc.status!=="Closed") {
-			frm.add_custom_button(__("Close"), function() {
+	refresh: function (frm) {
+		if (frm.doc.status !== "Closed") {
+			frm.add_custom_button(__("Close"), function () {
 				frm.set_value("status", "Closed");
 				frm.save();
 			});
+
+			frm.add_custom_button(__("Task"), function () {
+				frappe.model.open_mapped_doc({
+					method: "erpnext.support.doctype.issue.issue.make_task",
+					frm: frm
+				});
+			}, __("Make"));
 		} else {
-			frm.add_custom_button(__("Reopen"), function() {
+			frm.add_custom_button(__("Reopen"), function () {
 				frm.set_value("status", "Open");
 				frm.save();
 			});
@@ -37,7 +44,7 @@
 		if (!frm.timeline.wrapper.find('.btn-split-issue').length) {
 			let split_issue = __("Split Issue")
 			$(`<button class="btn btn-xs btn-link btn-add-to-kb text-muted hidden-xs btn-split-issue pull-right" style="display:inline-block; margin-right: 15px">
-				${split_issue} 
+				${split_issue}
 			</button>`)
 				.appendTo(frm.timeline.wrapper.find('.comment-header .asset-details:not([data-communication-type="Comment"])'))
 			if (!frm.timeline.wrapper.data("split-issue-event-attached")){
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index 21cf2f7..7cb0df2 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
  "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
@@ -349,8 +350,9 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
+   "collapsible_depends_on": "eval:doc.status!=\"Closed\"", 
    "columns": 0, 
-   "fieldname": "section_break_7", 
+   "fieldname": "sb_details", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
@@ -416,7 +418,7 @@
    "bold": 0, 
    "collapsible": 1, 
    "columns": 0, 
-   "fieldname": "response", 
+   "fieldname": "sb_response", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
@@ -511,7 +513,7 @@
    "bold": 0, 
    "collapsible": 1, 
    "columns": 0, 
-   "fieldname": "additional_info", 
+   "fieldname": "sb_additional_info", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
@@ -736,7 +738,7 @@
    "bold": 0, 
    "collapsible": 1, 
    "columns": 0, 
-   "fieldname": "section_break_19", 
+   "fieldname": "sb_resoution", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
@@ -1035,7 +1037,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-08-21 14:44:27.615004", 
+ "modified": "2019-02-14 02:55:47.562611", 
  "modified_by": "Administrator", 
  "module": "Support", 
  "name": "Issue", 
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 0b5eb53..de3d144 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -7,20 +7,24 @@
 from frappe import _
 
 from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
 from frappe.utils import now
 from frappe.utils.user import is_website_user
 
 sender_field = "raised_by"
 
+
 class Issue(Document):
 	def get_feed(self):
 		return "{0}: {1}".format(_(self.status), self.subject)
 
 	def validate(self):
-		if (self.get("__islocal") and self.via_customer_portal):
+		if self.is_new() and self.via_customer_portal:
 			self.flags.create_communication = True
+
 		if not self.raised_by:
 			self.raised_by = frappe.session.user
+
 		self.update_status()
 		self.set_lead_contact(self.raised_by)
 
@@ -29,17 +33,19 @@
 			clear(self.doctype, self.name)
 
 	def on_update(self):
-		# create the communication email and remove the description
-		if (self.flags.create_communication and self.via_customer_portal):
+		# Add a communication in the issue timeline
+		if self.flags.create_communication and self.via_customer_portal:
 			self.create_communication()
 			self.flags.communication_created = None
 
 	def set_lead_contact(self, email_id):
 		import email.utils
+
 		email_id = email.utils.parseaddr(email_id)[1]
 		if email_id:
 			if not self.lead:
 				self.lead = frappe.db.get_value("Lead", {"email_id": email_id})
+
 			if not self.contact and not self.customer:
 				self.contact = frappe.db.get_value("Contact", {"email_id": email_id})
 
@@ -79,24 +85,30 @@
 		communication.ignore_mandatory = True
 		communication.save()
 
-		self.db_set("description", "")
-
 	def split_issue(self, subject, communication_id):
 		# Bug: Pressing enter doesn't send subject
 		from copy import deepcopy
+
 		replicated_issue = deepcopy(self)
 		replicated_issue.subject = subject
 		frappe.get_doc(replicated_issue).insert()
+
 		# Replicate linked Communications
-		# todo get all communications in timeline before this, and modify them to append them to new doc
+		# TODO: get all communications in timeline before this, and modify them to append them to new doc
 		comm_to_split_from = frappe.get_doc("Communication", communication_id)
-		communications = frappe.get_all("Communication", filters={"reference_name": comm_to_split_from.reference_name, "reference_doctype": "Issue", "creation": ('>=', comm_to_split_from.creation)})
+		communications = frappe.get_all("Communication",
+			filters={"reference_doctype": "Issue",
+				"reference_name": comm_to_split_from.reference_name,
+				"creation": ('>=', comm_to_split_from.creation)})
+
 		for communication in communications:
 			doc = frappe.get_doc("Communication", communication.name)
 			doc.reference_name = replicated_issue.name
 			doc.save(ignore_permissions=True)
+
 		return replicated_issue.name
 
+
 def get_list_context(context=None):
 	return {
 		"title": _("Issues"),
@@ -107,11 +119,14 @@
 		'no_breadcrumbs': True
 	}
 
+
 def get_issue_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by=None):
 	from frappe.www.list import get_list
+
 	user = frappe.session.user
 	contact = frappe.db.get_value('Contact', {'user': user}, 'name')
 	customer = None
+
 	if contact:
 		contact_doc = frappe.get_doc('Contact', contact)
 		customer = contact_doc.get_link_for('Customer')
@@ -124,14 +139,23 @@
 
 	return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=ignore_permissions)
 
+
+@frappe.whitelist()
+def set_multiple_status(names, status):
+	names = json.loads(names)
+	for name in names:
+		set_status(name, status)
+
+
 @frappe.whitelist()
 def set_status(name, status):
 	st = frappe.get_doc("Issue", name)
 	st.status = status
 	st.save()
 
+
 def auto_close_tickets():
-	""" auto close the replied support tickets after 7 days """
+	"""Auto-close replied support tickets after 7 days"""
 	auto_close_after_days = frappe.db.get_value("Support Settings", "Support Settings", "close_issue_after_days") or 7
 
 	issues = frappe.db.sql(""" select name from tabIssue where status='Replied' and
@@ -144,11 +168,6 @@
 		doc.flags.ignore_mandatory = True
 		doc.save()
 
-@frappe.whitelist()
-def set_multiple_status(names, status):
-	names = json.loads(names)
-	for name in names:
-		set_status(name, status)
 
 def has_website_permission(doc, ptype, user, verbose=False):
 	from erpnext.controllers.website_list_for_contact import has_website_permission
@@ -160,3 +179,12 @@
 def update_issue(contact, method):
 	"""Called when Contact is deleted"""
 	frappe.db.sql("""UPDATE `tabIssue` set contact='' where contact=%s""", contact.name)
+
+
+@frappe.whitelist()
+def make_task(source_name, target_doc=None):
+	return get_mapped_doc("Issue", source_name, {
+		"Issue": {
+			"doctype": "Task"
+		}
+	}, target_doc)
diff --git a/erpnext/support/doctype/issue/issue_dashboard.py b/erpnext/support/doctype/issue/issue_dashboard.py
new file mode 100644
index 0000000..2ac7c81
--- /dev/null
+++ b/erpnext/support/doctype/issue/issue_dashboard.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+
+from frappe import _
+
+
+def get_data():
+	return {
+		'fieldname': 'issue',
+		'transactions': [
+			{
+				'label': _('Activity'),
+				'items': ['Task']
+			}
+		]
+	}