feat: Communication refactor initial bringup
This commit is contained in:
parent
fc9803553c
commit
8381e0048a
6 changed files with 260 additions and 57 deletions
|
|
@ -54,7 +54,15 @@ frappe.ui.form.on("Communication", {
|
|||
frm.trigger('show_relink_dialog');
|
||||
});
|
||||
|
||||
if(frm.doc.communication_type=="Communication"
|
||||
frm.add_custom_button(__("Add link"), function() {
|
||||
frm.trigger('show_add_link_dialog');
|
||||
});
|
||||
|
||||
frm.add_custom_button(__("Remove link"), function() {
|
||||
frm.trigger('show_remove_link_dialog');
|
||||
});
|
||||
|
||||
if(frm.doc.communication_type=="Communication"
|
||||
&& frm.doc.communication_medium == "Email"
|
||||
&& frm.doc.sent_or_received == "Received") {
|
||||
|
||||
|
|
@ -90,7 +98,7 @@ frappe.ui.form.on("Communication", {
|
|||
}
|
||||
}
|
||||
|
||||
if(frm.doc.communication_type=="Communication"
|
||||
if(frm.doc.communication_type=="Communication"
|
||||
&& frm.doc.communication_medium == "Phone"
|
||||
&& frm.doc.sent_or_received == "Received"){
|
||||
|
||||
|
|
@ -148,6 +156,74 @@ frappe.ui.form.on("Communication", {
|
|||
d.show();
|
||||
},
|
||||
|
||||
show_add_link_dialog: function(frm){
|
||||
var d = new frappe.ui.Dialog ({
|
||||
title: __("Add new link to Communication"),
|
||||
fields: [{
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"label": __("Document Type"),
|
||||
"fieldname": "link_doctype",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldtype": "Dynamic Link",
|
||||
"options": "link_doctype",
|
||||
"label": __("Document Name"),
|
||||
"fieldname": "link_name",
|
||||
"reqd": 1
|
||||
}],
|
||||
primary_action: ({ link_doctype, link_name }) => {
|
||||
d.hide();
|
||||
frm.call('add_link', {
|
||||
link_doctype,
|
||||
link_name,
|
||||
autosave: true
|
||||
}).then(() => frm.refresh());
|
||||
},
|
||||
primary_action_label: __('Add Link')
|
||||
});
|
||||
d.fields_dict.link_doctype.get_query = function() {
|
||||
return {
|
||||
"filters": {
|
||||
"name": ["!=", "Communication"],
|
||||
}
|
||||
};
|
||||
};
|
||||
d.show();
|
||||
},
|
||||
|
||||
show_remove_link_dialog: function(frm){
|
||||
let options = '';
|
||||
|
||||
for(var link in frm.doc.dynamic_links){
|
||||
let dynamic_link = frm.doc.dynamic_links[link];
|
||||
options += '\n' + dynamic_link.link_doctype + ': ' + dynamic_link.link_name;
|
||||
}
|
||||
|
||||
var d = new frappe.ui.Dialog ({
|
||||
title: __("Remove link from Communication"),
|
||||
fields: [{
|
||||
"fieldtype": "Select",
|
||||
"options": options,
|
||||
"label": __("Link"),
|
||||
"fieldname": "link",
|
||||
"reqd": 1
|
||||
}],
|
||||
primary_action: ({ link }) => {
|
||||
d.hide();
|
||||
frm.call('remove_link', {
|
||||
link_doctype: link.split(":")[0].trim(),
|
||||
link_name: link.split(":")[1].trim(),
|
||||
autosave: true,
|
||||
ignore_permissions: false
|
||||
}).then(() => frm.refresh());
|
||||
},
|
||||
primary_action_label: __('Remove Link')
|
||||
});
|
||||
d.show();
|
||||
},
|
||||
|
||||
mark_as_read_unread: function(frm) {
|
||||
var action = frm.doc.seen? "Unread": "Read";
|
||||
var flag = "(\\SEEN)";
|
||||
|
|
@ -185,7 +261,7 @@ frappe.ui.form.on("Communication", {
|
|||
|
||||
forward_mail: function(frm) {
|
||||
var args = frm.events.get_mail_args(frm)
|
||||
$.extend(args, {
|
||||
$.extend(args, {
|
||||
forward: true,
|
||||
subject: __("Fw: {0}", [frm.doc.subject]),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"allow_import": 1,
|
||||
"creation": "2013-01-29 10:47:14",
|
||||
"description": "Keep a track of all communications",
|
||||
"description": "Keeps track of all communications",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
|
|
@ -43,12 +43,11 @@
|
|||
"email_template",
|
||||
"link_doctype",
|
||||
"link_name",
|
||||
"timeline_doctype",
|
||||
"timeline_name",
|
||||
"timeline_label",
|
||||
"unread_notification_sent",
|
||||
"seen",
|
||||
"_user_tags",
|
||||
"timeline_links_sections",
|
||||
"dynamic_links",
|
||||
"email_inbox",
|
||||
"message_id",
|
||||
"uid",
|
||||
|
|
@ -298,25 +297,6 @@
|
|||
"options": "link_doctype",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "timeline_doctype",
|
||||
"fieldtype": "Link",
|
||||
"label": "Timeline DocType",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "timeline_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Timeline Name",
|
||||
"options": "timeline_doctype",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "timeline_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Timeline field Name"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "unread_notification_sent",
|
||||
|
|
@ -398,11 +378,22 @@
|
|||
"label": "Email Template",
|
||||
"options": "Email Template",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "timeline_links_sections",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Timeline Links"
|
||||
},
|
||||
{
|
||||
"fieldname": "dynamic_links",
|
||||
"fieldtype": "Table",
|
||||
"label": "Dynamic Links",
|
||||
"options": "Dynamic Link"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-comment",
|
||||
"idx": 1,
|
||||
"modified": "2019-05-04 15:36:35.818714",
|
||||
"modified": "2019-05-13 19:55:35.757242",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Communication",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from frappe.model.document import Document
|
|||
from frappe.utils import validate_email_address, get_fullname, strip_html, cstr
|
||||
from frappe.core.doctype.communication.email import (validate_email,
|
||||
notify, _notify, update_parent_mins_to_first_response)
|
||||
from frappe.core.utils import get_parent_doc, set_timeline_doc
|
||||
from frappe.core.utils import get_parent_doc
|
||||
from frappe.utils.bot import BotReply
|
||||
from frappe.utils import parse_addr
|
||||
from frappe.core.doctype.comment.comment import update_comment_in_doc
|
||||
|
|
@ -58,7 +58,6 @@ class Communication(Document):
|
|||
self.set_sender_full_name()
|
||||
|
||||
validate_email(self)
|
||||
set_timeline_doc(self)
|
||||
|
||||
def validate_reference(self):
|
||||
if self.reference_doctype and self.reference_name:
|
||||
|
|
@ -231,26 +230,86 @@ class Communication(Document):
|
|||
if commit:
|
||||
frappe.db.commit()
|
||||
|
||||
# Timeline Links
|
||||
def deduplicate_dynamic_links(self):
|
||||
if self.dynamic_links:
|
||||
links, duplicate = [], False
|
||||
|
||||
for l in self.dynamic_links:
|
||||
t = (l.link_doctype, l.link_name)
|
||||
if not t in links:
|
||||
links.append(t)
|
||||
else:
|
||||
duplicate = True
|
||||
|
||||
if duplicate:
|
||||
del self.dynamic_links[:] # make it python 2 compatible as list.clear() is python 3 only
|
||||
for l in links:
|
||||
self.add_link(link_doctype=l[0], link_name=l[1])
|
||||
|
||||
def validate_circular_links(self):
|
||||
for dynamic_link in self.dynamic_links:
|
||||
# Prevent circular linking of Communication DocTypes
|
||||
if dynamic_link.link_doctype == "Communication":
|
||||
circular_linking = False
|
||||
circular_level_1 = get_timeline_parent_doc(dynamic_link.link_doctype, dynamic_link.link_name)
|
||||
|
||||
# Level 1
|
||||
if circular_level_1:
|
||||
for link in circular_level_1.dynamic_links:
|
||||
if link.link_doctype == "Communication":
|
||||
circular_level_2 = get_timeline_parent_doc(link.link_doctype, link.link_name)
|
||||
|
||||
# Level 2
|
||||
if circular_level_2:
|
||||
for ref_link in circular_level_2.dynamic_links:
|
||||
if ref_link.link_doctype == "Communication":
|
||||
circular_level_3 = get_timeline_parent_doc(ref_link.link_doctype, ref_link.link_name)
|
||||
|
||||
# Level 3
|
||||
if circular_level_3:
|
||||
if circular_level_3.name == self.name:
|
||||
circular_linking = True
|
||||
break
|
||||
if circular_linking:
|
||||
frappe.throw(_("Please make sure the Timeline Communication Docs are not circularly linked."), frappe.CircularLinkingError)
|
||||
|
||||
def add_link(self, link_doctype, link_name, autosave=False):
|
||||
self.append("dynamic_links",
|
||||
{
|
||||
"link_doctype": link_doctype,
|
||||
"link_name": link_name
|
||||
}
|
||||
)
|
||||
|
||||
if autosave:
|
||||
self.save(ignore_permissions=True)
|
||||
|
||||
def get_links(self):
|
||||
return self.dynamic_links
|
||||
|
||||
def remove_link(self, link_doctype, link_name, autosave=False, ignore_permissions=True):
|
||||
for l in self.dynamic_links:
|
||||
if l.link_doctype == link_doctype and l.link_name == link_name:
|
||||
self.dynamic_links.remove(l)
|
||||
|
||||
if autosave:
|
||||
self.save(ignore_permissions=ignore_permissions)
|
||||
|
||||
def on_doctype_update():
|
||||
"""Add indexes in `tabCommunication`"""
|
||||
frappe.db.add_index("Communication", ["reference_doctype", "reference_name"])
|
||||
frappe.db.add_index("Communication", ["timeline_doctype", "timeline_name"])
|
||||
frappe.db.add_index("Communication", ["link_doctype", "link_name"])
|
||||
frappe.db.add_index("Communication", ["status", "communication_type"])
|
||||
|
||||
def has_permission(doc, ptype, user):
|
||||
if ptype=="read":
|
||||
if (doc.reference_doctype == "Communication" and doc.reference_name == doc.name) \
|
||||
or (doc.timeline_doctype == "Communication" and doc.timeline_name == doc.name):
|
||||
return
|
||||
if doc.reference_doctype == "Communication" and doc.reference_name == doc.name:
|
||||
return
|
||||
|
||||
if doc.reference_doctype and doc.reference_name:
|
||||
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name):
|
||||
return True
|
||||
if doc.timeline_doctype and doc.timeline_name:
|
||||
if frappe.has_permission(doc.timeline_doctype, ptype="read", doc=doc.timeline_name):
|
||||
return True
|
||||
|
||||
def get_permission_query_conditions_for_communication(user):
|
||||
if not user: user = frappe.session.user
|
||||
|
|
@ -270,3 +329,9 @@ def get_permission_query_conditions_for_communication(user):
|
|||
email_accounts = [ '"%s"'%account.get("email_account") for account in accounts ]
|
||||
return """tabCommunication.email_account in ({email_accounts})"""\
|
||||
.format(email_accounts=','.join(email_accounts))
|
||||
|
||||
def get_timeline_parent_doc(link_doctype, link_name):
|
||||
"""Returns document of `link_doctype`, `link_name`"""
|
||||
if link_doctype and link_name:
|
||||
parent_doc = frappe.get_doc(link_doctype, link_name)
|
||||
return parent_doc if parent_doc else None
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import frappe.email.smtp
|
|||
import time
|
||||
from frappe import _
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
from email.utils import parseaddr
|
||||
|
||||
@frappe.whitelist()
|
||||
def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent",
|
||||
|
|
@ -78,6 +79,15 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
|
|||
# if no reference given, then send it against the communication
|
||||
comm.db_set(dict(reference_doctype='Communication', reference_name=comm.name))
|
||||
|
||||
# contacts = get_contacts([sender, recipients, cc, bcc])
|
||||
# for contact_name in contacts:
|
||||
# comm.add_link('Contact', contact_name)
|
||||
|
||||
# #link contact's dynamic links to communication
|
||||
# add_contact_links_to_communication(comm, contact_name)
|
||||
|
||||
# comm.save(ignore_permissions=True)
|
||||
|
||||
if isinstance(attachments, string_types):
|
||||
attachments = json.loads(attachments)
|
||||
|
||||
|
|
@ -559,3 +569,38 @@ def mark_email_as_seen(name=None):
|
|||
frappe.response["filename"] = "imaginary_pixel.png"
|
||||
frappe.response["filecontent"] = buffered_obj.getvalue()
|
||||
|
||||
def get_contacts(email_strings):
|
||||
email_addrs = []
|
||||
|
||||
for email_string in email_strings:
|
||||
if email_string:
|
||||
for email in email_string.split(","):
|
||||
parsed_email = parseaddr(email)[1]
|
||||
if parsed_email:
|
||||
email_addrs.append(parsed_email)
|
||||
|
||||
contacts = []
|
||||
for email in email_addrs:
|
||||
contact_name = frappe.db.get_value('Contact', {'email_id': email})
|
||||
|
||||
if not contact_name:
|
||||
contact = frappe.get_doc({
|
||||
"doctype": "Contact",
|
||||
"first_name": frappe.unscrub(email.split("@")[0]),
|
||||
"email_id": email
|
||||
}).insert(ignore_permissions=True)
|
||||
contact_name = contact.name
|
||||
|
||||
contacts.append(contact_name)
|
||||
|
||||
return contacts
|
||||
|
||||
def add_contact_links_to_communication(communication, contact_name):
|
||||
contact_links = frappe.get_list("Dynamic Link", filters={
|
||||
"parenttype": "Contact",
|
||||
"parent": contact_name
|
||||
}, fields=["link_doctype", "link_name"])
|
||||
|
||||
if contact_links:
|
||||
for contact_link in contact_links:
|
||||
communication.add_link(contact_link.link_doctype, contact_link.link_name)
|
||||
|
|
@ -161,36 +161,55 @@ def get_communication_data(doctype, name, start=0, limit=20, after=None, fields=
|
|||
group_by=None, as_dict=True):
|
||||
'''Returns list of communications for a given document'''
|
||||
if not fields:
|
||||
fields = '''`name`, `communication_type`,`communication_medium`, `comment_type`,
|
||||
`communication_date`, `content`, `sender`, `sender_full_name`, `cc`, `bcc`,
|
||||
`creation`, `subject`, `delivery_status`, `_liked_by`,
|
||||
`timeline_doctype`, `timeline_name`, `reference_doctype`, `reference_name`,
|
||||
`link_doctype`, `link_name`, `read_by_recipient`, `rating`, 'Communication' AS `doctype`'''
|
||||
fields = '''
|
||||
`tabCommunication`.name, `tabCommunication`.communication_type, `tabCommunication`.communication_medium,
|
||||
`tabCommunication`.comment_type, `tabCommunication`.communication_date, `tabCommunication`.content,
|
||||
`tabCommunication`.sender, `tabCommunication`.sender_full_name, `tabCommunication`.cc, `tabCommunication`.bcc,
|
||||
`tabCommunication`.creation, `tabCommunication`.subject, `tabCommunication`.delivery_status,
|
||||
`tabCommunication`._liked_by, `tabCommunication`.reference_doctype, `tabCommunication`.reference_name,
|
||||
`tabCommunication`.link_doctype, `tabCommunication`.link_name, `tabCommunication`.read_by_recipient,
|
||||
`tabCommunication`.rating, `tabDynamic Link`.link_doctype, `tabDynamic Link`.link_name
|
||||
'''
|
||||
|
||||
conditions = '''communication_type in ('Communication', 'Feedback')
|
||||
and (
|
||||
(reference_doctype=%(doctype)s and reference_name=%(name)s)
|
||||
conditions = '''
|
||||
`tabCommunication`.communication_type in ('Communication', 'Feedback')
|
||||
and (
|
||||
(`tabCommunication`.reference_doctype=%(doctype)s and `tabCommunication`.reference_name=%(name)s)
|
||||
or (
|
||||
(timeline_doctype=%(doctype)s and timeline_name=%(name)s)
|
||||
and (communication_type='Communication')
|
||||
(`tabDynamic Link`.link_doctype=%(doctype)s and `tabDynamic Link`.link_name=%(name)s)
|
||||
and (`tabCommunication`.communication_type='Communication')
|
||||
)
|
||||
)'''
|
||||
|
||||
)
|
||||
'''
|
||||
|
||||
if after:
|
||||
# find after a particular date
|
||||
conditions+= ' and creation > {0}'.format(after)
|
||||
conditions += '''
|
||||
and `tabCommunication`.creation > {0}
|
||||
'''.format(after)
|
||||
|
||||
if doctype=='User':
|
||||
conditions+= " and not (reference_doctype='User' and communication_type='Communication')"
|
||||
conditions += '''
|
||||
and not (`tabCommunication`.reference_doctype='User' and `tabCommunication`.communication_type='Communication')
|
||||
'''
|
||||
|
||||
communications = frappe.db.sql("""select {fields}
|
||||
communications = frappe.db.sql('''
|
||||
select {fields}
|
||||
from `tabCommunication`
|
||||
left join `tabDynamic Link`
|
||||
on `tabCommunication`.name=`tabDynamic Link`.parent
|
||||
where {conditions} {group_by}
|
||||
order by creation desc LIMIT %(limit)s OFFSET %(start)s""".format(
|
||||
fields = fields, conditions=conditions, group_by=group_by or ""),
|
||||
{ "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
|
||||
as_dict=as_dict)
|
||||
order by `tabCommunication`.creation desc
|
||||
limit %(limit)s offset %(start)s'''.format(
|
||||
fields = fields,
|
||||
conditions=conditions,
|
||||
group_by=group_by or ""
|
||||
),{
|
||||
"doctype": doctype,
|
||||
"name": name,
|
||||
"start": frappe.utils.cint(start),
|
||||
"limit": limit
|
||||
}, as_dict=as_dict, debug=True)
|
||||
|
||||
return communications
|
||||
|
||||
|
|
@ -245,4 +264,4 @@ def get_view_logs(doctype, docname):
|
|||
|
||||
if view_logs:
|
||||
logs = view_logs
|
||||
return logs
|
||||
return logs
|
||||
|
|
@ -20,7 +20,7 @@ from datetime import datetime, timedelta
|
|||
from frappe.desk.form import assign_to
|
||||
from frappe.utils.user import get_system_managers
|
||||
from frappe.utils.background_jobs import enqueue, get_jobs
|
||||
from frappe.core.doctype.communication.email import set_incoming_outgoing_accounts
|
||||
from frappe.core.doctype.communication.email import set_incoming_outgoing_accounts, get_contacts, add_contact_links_to_communication
|
||||
from frappe.utils.scheduler import log
|
||||
from frappe.utils.html_utils import clean_email_html
|
||||
|
||||
|
|
@ -386,6 +386,13 @@ class EmailAccount(Document):
|
|||
users = list(set([ user.get("parent") for user in users ]))
|
||||
communication._seen = json.dumps(users)
|
||||
|
||||
# contacts = get_contacts([sender, recipients, cc, bcc])
|
||||
# for contact_name in contacts:
|
||||
# comm.add_link('Contact', contact_name)
|
||||
|
||||
# #link contact's dynamic links to communication
|
||||
# add_contact_links_to_communication(comm, contact_name)
|
||||
|
||||
communication.flags.in_receive = True
|
||||
communication.insert(ignore_permissions = 1)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue