From f2ccbc864fb2a2757987f26c2a5b6ff8bdbc19a0 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 14 Aug 2015 16:51:44 +0530 Subject: [PATCH] [fix] Allow appending to communication, don't pull sent email --- .../doctype/communication/communication.js | 26 ++ .../doctype/communication/communication.json | 422 +++++++++++++++--- .../doctype/communication/communication.py | 9 + frappe/core/notifications.py | 1 + .../doctype/email_account/email_account.py | 12 +- frappe/patches.txt | 2 +- .../communication_status_and_permission.py | 19 + .../js/frappe/form/footer/timeline_item.html | 18 +- .../public/js/frappe/views/communication.js | 8 +- 9 files changed, 441 insertions(+), 76 deletions(-) create mode 100644 frappe/patches/v6_0/communication_status_and_permission.py diff --git a/frappe/core/doctype/communication/communication.js b/frappe/core/doctype/communication/communication.js index e4a93c6656..406352ece2 100644 --- a/frappe/core/doctype/communication/communication.js +++ b/frappe/core/doctype/communication/communication.js @@ -24,6 +24,32 @@ frappe.ui.form.on("Communication", "setup", function(frm) { frappe.ui.form.on("Communication", "refresh", function(frm) { frm.convert_to_click && frm.set_convert_button(); + frm.subject_field = "subject"; + + if(frm.doc.reference_doctype && frm.doc.reference_name) { + frm.add_custom_button(__(frm.doc.reference_name), function() { + frappe.set_route("Form", frm.doc.reference_doctype, frm.doc.reference_name); + }, frappe.boot.doctype_icons[frm.doc.reference_doctype]); + } else { + // if an unlinked communication, set email field + if (frm.doc.sent_or_received==="Received") { + frm.email_field = "sender"; + } else { + frm.email_field = "recipients"; + } + } + + if(frm.doc.status==="Open") { + frm.add_custom_button("Close", function() { + frm.set_value("status", "Closed"); + frm.save(); + }); + } else if (frm.doc.status !== "Linked") { + frm.add_custom_button("Reopen", function() { + frm.set_value("status", "Open"); + frm.save(); + }); + } }); frappe.ui.form.on("Communication", "onload", function(frm) { diff --git a/frappe/core/doctype/communication/communication.json b/frappe/core/doctype/communication/communication.json index 68439e8d01..bbaee4303c 100644 --- a/frappe/core/doctype/communication/communication.json +++ b/frappe/core/doctype/communication/communication.json @@ -1,204 +1,523 @@ { + "allow_copy": 0, "allow_import": 1, + "allow_rename": 0, "autoname": "naming_series:", "creation": "2013-01-29 10:47:14", + "custom": 0, "description": "Keep a track of all communications", "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "fields": [ { + "allow_on_submit": 0, "default": "COMM-", "fieldname": "naming_series", "fieldtype": "Select", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Series", + "no_copy": 0, "options": "COMM-", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sent_or_received", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 1, "label": "Sent or Received", + "no_copy": 0, "options": "Sent\nReceived", "permlevel": 0, - "reqd": 1 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "status", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 1, "label": "Status", - "options": "Open\nReplied\nArchived", + "no_copy": 0, + "options": "Open\nReplied\nClosed\nLinked", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "Integrations can use this field to set email delivery status", "fieldname": "delivery_status", "fieldtype": "Select", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Delivery Status", + "no_copy": 0, "options": "\nSent\nBounced\nOpened\nMarked As Spam\nRejected\nDelayed\nSoft-Bounced\nClicked\nRecipient Unsubscribed", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "subject", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 0, "label": "Subject", + "no_copy": 0, "permlevel": 0, - "reqd": 1 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_5", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "reference_doctype", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Reference DocType", + "no_copy": 0, "options": "DocType", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "reference_name", "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Reference Name", + "no_copy": 0, "options": "reference_doctype", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_8", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "content", "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Content", + "no_copy": 0, "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "400" }, { + "allow_on_submit": 0, "fieldname": "additional_info", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Additional Info", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "recipients", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Recipients", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "phone_no", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Phone No.", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "communication_medium", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 1, "label": "Communication Medium", + "no_copy": 0, "options": "\nChat\nPhone\nEmail\nSMS\nVisit\nOther", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_14", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sender", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Sender", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sender_full_name", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Sender Full Name", + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break2", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "options": "simple", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break4", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "By", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "email_account", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Email Account", + "no_copy": 0, "options": "Email Account", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "__user", "fieldname": "user", "fieldtype": "Link", + "hidden": 0, "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, "label": "User", + "no_copy": 0, "options": "User", "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break5", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "On", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "Today", "fieldname": "communication_date", "fieldtype": "Datetime", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Date", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "_user_tags", "fieldtype": "Data", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "User Tags", "no_copy": 1, "permlevel": 0, - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "0", "fieldname": "unread_notification_sent", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Unread Notification Sent", + "no_copy": 0, "permlevel": 0, "precision": "", - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], + "hide_heading": 0, + "hide_toolbar": 0, "icon": "icon-comment", "idx": 1, + "in_create": 0, "in_dialog": 0, + "is_submittable": 0, "issingle": 0, - "modified": "2015-07-28 17:18:11.664740", + "istable": 0, + "modified": "2015-08-14 17:46:20.902296", "modified_by": "Administrator", "module": "Core", "name": "Communication", @@ -206,62 +525,27 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 1, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Support Team", - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales Manager", - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 1, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "share": 1, - "submit": 0, - "write": 1 - }, - { + "apply_user_permissions": 0, + "cancel": 0, "create": 1, "delete": 1, "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "System Manager", + "set_user_permissions": 0, "share": 1, "submit": 0, "write": 1 } ], + "read_only": 0, + "read_only_onload": 0, "search_fields": "subject", "title_field": "subject" } diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 1115ce9007..ea870509fa 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -16,6 +16,7 @@ class Communication(Document): no_feed_on_delete = True """Communication represents an external communication like Email.""" + def get_parent_doc(self): """Returns document of `reference_doctype`, `reference_doctype`""" if not hasattr(self, "parent_doc"): @@ -25,6 +26,14 @@ class Communication(Document): self.parent_doc = None return self.parent_doc + def validate(self): + if not self.status: + if self.reference_doctype and self.reference_name: + self.status = "Linked" + + else: + self.status = "Open" + def on_update(self): """Update parent status as `Open` or `Replied`.""" self.update_parent() diff --git a/frappe/core/notifications.py b/frappe/core/notifications.py index 96ce779f25..bbe0b3f7a9 100644 --- a/frappe/core/notifications.py +++ b/frappe/core/notifications.py @@ -8,6 +8,7 @@ def get_notification_config(): return { "for_doctype": { "Scheduler Log": {"seen": 0}, + "Communication": {"status": "Open"} }, "for_module_doctypes": { "ToDo": "To Do", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 349017f6ca..57b00c4fb3 100644 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -15,6 +15,8 @@ import markdown2, re from dateutil.relativedelta import relativedelta from datetime import datetime, timedelta +class SentEmailInInbox(Exception): pass + class EmailAccount(Document): def autoname(self): """Set name as `email_account_name` or make title from email id.""" @@ -126,6 +128,9 @@ class EmailAccount(Document): try: communication = self.insert_communication(raw) + except SentEmailInInbox: + frappe.db.rollback() + except Exception: frappe.db.rollback() exceptions.append(frappe.get_traceback()) @@ -140,6 +145,11 @@ class EmailAccount(Document): def insert_communication(self, raw): email = Email(raw) + if email.from_email == self.email_id: + # gmail shows sent emails in inbox + # and we don't want emails sent by us to be pulled back into the system again + raise SentEmailInInbox + communication = frappe.get_doc({ "doctype": "Communication", "subject": email.subject, @@ -227,7 +237,7 @@ class EmailAccount(Document): if parent: parent = frappe.get_doc(self.append_to, parent[0].name) - if not parent and self.append_to: + if not parent and self.append_to and self.append_to!="Communication": # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) diff --git a/frappe/patches.txt b/frappe/patches.txt index fd4848aaed..4fea4ee7d5 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -85,7 +85,7 @@ execute:frappe.permissions.reset_perms("DocType") execute:frappe.db.sql("delete from `tabProperty Setter` where `property` = 'idx'") frappe.patches.v5_2.change_checks_to_not_null frappe.patches.v5_3.rename_chinese_languages - +frappe.patches.v6_0.communication_status_and_permission frappe.patches.v6_0.make_task_log_folder frappe.patches.v6_0.document_type_rename frappe.patches.v6_0.fix_ghana_currency diff --git a/frappe/patches/v6_0/communication_status_and_permission.py b/frappe/patches/v6_0/communication_status_and_permission.py new file mode 100644 index 0000000000..c68ed9b4d6 --- /dev/null +++ b/frappe/patches/v6_0/communication_status_and_permission.py @@ -0,0 +1,19 @@ +from __future__ import unicode_literals +import frappe +from frappe.permissions import reset_perms + +def execute(): + frappe.reload_doctype("Communication") + + # set status = "Linked" + frappe.db.sql("""update `tabCommunication` set status='Linked' + where ifnull(reference_doctype, '')!='' and ifnull(reference_name, '')!=''""") + + frappe.db.sql("""update `tabCommunication` set status='Closed' + where status='Archived'""") + + # reset permissions if owner of all DocPerms is Administrator + if not frappe.db.sql("""select name from `tabDocPerm` + where parent='Communication' and ifnull(owner, '')!='Administrator'"""): + + reset_perms("Communication") diff --git a/frappe/public/js/frappe/form/footer/timeline_item.html b/frappe/public/js/frappe/form/footer/timeline_item.html index e557b3d01c..b26b23bb59 100644 --- a/frappe/public/js/frappe/form/footer/timeline_item.html +++ b/frappe/public/js/frappe/form/footer/timeline_item.html @@ -16,9 +16,11 @@ – {%= data.comment_on %} {% if(data.doctype=="Communication") { %} - + {% if (frappe.model.can_read(\'Communication\')) { %} + {% } %} + {% if (data.delivery_status) { if (in_list(["Sent", "Opened", "Clicked"], data.delivery_status)) { var indicator_class = "green"; @@ -26,13 +28,23 @@ var indicator_class = "red"; } %} + {%= data.delivery_status %} - {% } else { %} {%= __("Details") %} {% } %} + {% } else { %} + {% if (frappe.model.can_read(\'Communication\')) { %} + + {%= __("Details") %} + {% } %} + {% } %} + + {% if (frappe.model.can_read(\'Communication\')) { %} - {%= __("Reply") %} {% } %} diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 52c6bd6007..6d0246456b 100644 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -115,12 +115,16 @@ frappe.views.CommunicationComposer = Class.extend({ // prepend "Re:" if(strip(this.subject.toLowerCase().split(":")[0])!="re") { - this.subject = "Re: " + this.subject; + this.subject = __("Re: {0}", [this.subject]); } } if (!this.subject) { - this.subject = __(this.frm.doctype) + ': ' + this.frm.docname; + if (this.frm.subject_field && this.frm.doc[this.frm.subject_field]) { + this.subject = __("Re: {0}", [this.frm.doc[this.frm.subject_field]]); + } else { + this.subject = __(this.frm.doctype) + ': ' + this.frm.docname; + } } } },