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']
+ }
+ ]
+ }