Email inbox based off of frappe email inbox pr (#7308)

* email inbox

* inbox fixes

* separate email-inbox to pass tests

* separate email-inbox to pass tests

* fix import

* add more info to contact and address
This commit is contained in:
robert schouten 2017-01-13 17:21:09 +08:00 committed by Rushabh Mehta
parent b251cd4ccb
commit 7a3d418aa5
14 changed files with 465 additions and 9 deletions

View File

@ -165,6 +165,9 @@ doc_events = {
"Address": {
"validate": "erpnext.shopping_cart.cart.set_customer_in_address"
},
"Communication":{
"after_insert":"erpnext.utilities.doctype.contact.match_email_to_contact"
},
# bubble transaction notification on master
('Opportunity', 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',

View File

@ -2,7 +2,7 @@
<div class="clearfix"></div>
{% for(var i=0, l=addr_list.length; i<l; i++) { %}
<p class="h6">
{%= i+1 %}. {%= addr_list[i].address_type %}
{%= i+1 %}. {%= addr_list[i].address_type!="Other" ? addr_list[i].address_type : addr_list[i].address_title %}
{% if(addr_list[i].is_primary_address) { %}
<span class="text-muted">({%= __("Primary") %})</span>{% } %}
{% if(addr_list[i].is_shipping_address) { %}

View File

@ -8,7 +8,9 @@
{% if(contact_list[i].is_primary_contact) { %}
<span class="text-muted">({%= __("Primary") %})</span>
{% } %}
{% if(contact_list[i].designation){ %}
<span class="text-muted">&ndash; {%= contact_list[i].designation %}</span>
{% } %}
<a href="#Form/Contact/{%= encodeURIComponent(contact_list[i].name) %}"
class="btn btn-xs btn-default pull-right">
{%= __("Edit") %}</a>

View File

@ -595,6 +595,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "organisation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Organisation",
"length": 0,
"no_copy": 0,
"options": "Organisation",
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -750,7 +779,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-11-07 05:47:06.911933",
"modified": "2016-12-22 13:49:22.968498",
"modified_by": "Administrator",
"module": "Utilities",
"name": "Address",

View File

@ -19,7 +19,7 @@ class Address(Document):
def autoname(self):
if not self.address_title:
self.address_title = self.customer \
or self.supplier or self.sales_partner or self.lead
or self.supplier or self.sales_partner or self.lead or self.organisation
if self.address_title:
self.name = (cstr(self.address_title).strip() + "-" + cstr(self.address_type).strip())
@ -30,7 +30,7 @@ class Address(Document):
throw(_("Address Title is mandatory."))
def validate(self):
self.link_fields = ("customer", "supplier", "sales_partner", "lead")
self.link_fields = ("customer", "supplier", "sales_partner", "lead", "organisation")
self.link_address()
self.validate_primary_address()
self.validate_shipping_address()
@ -83,7 +83,7 @@ class Address(Document):
frappe.throw(_("Remove reference of customer, supplier, sales partner and lead, as it is your company address"))
def _unset_other(self, is_address_type):
for fieldname in ["customer", "supplier", "sales_partner", "lead"]:
for fieldname in ["customer", "supplier", "sales_partner", "lead", "organisation"]:
if self.get(fieldname):
frappe.db.sql("""update `tabAddress` set `%s`=0 where `%s`=%s and name!=%s""" %
(is_address_type, fieldname, "%s", "%s"), (self.get(fieldname), self.name))

View File

@ -1 +1,39 @@
from __future__ import unicode_literals
import frappe
def match_email_to_contact(doc,method=None):
if doc.communication_type == "Communication":
origin_contact = frappe.db.sql(
"select name, email_id, supplier, supplier_name, customer, customer_name, user, organisation from `tabContact` where email_id <>''",
as_dict=1)
for comm in origin_contact:
if comm.email_id:
if (doc.sender and doc.sent_or_received == "Received" and doc.sender.find(comm.email_id) > -1) or (
doc.recipients and doc.sent_or_received == "Sent" and doc.recipients.find(
comm.email_id) > -1):
if sum(1 for x in [comm.supplier, comm.customer, comm.user, comm.organisation] if x) > 1:
doc.db_set("timeline_doctype", "Contact")
doc.db_set("timeline_name", comm.name)
doc.db_set("timeline_label", doc.name)
elif comm.supplier:
doc.db_set("timeline_doctype", "Supplier")
doc.db_set("timeline_name", comm.supplier)
doc.db_set("timeline_label", comm.supplier_name)
elif comm.customer:
doc.db_set("timeline_doctype", "Customer")
doc.db_set("timeline_name", comm.customer)
doc.db_set("timeline_label", comm.customer_name)
elif comm.user:
doc.db_set("timeline_doctype", "User")
doc.db_set("timeline_name", comm.user)
doc.db_set("timeline_label", comm.user)
elif comm.organisation:
doc.db_set("timeline_doctype", "Organisation")
doc.db_set("timeline_name", comm.organisation)
doc.db_set("timeline_label", comm.organisation)
else:
doc.db_set("timeline_doctype", None)
doc.db_set("timeline_name", None)
doc.db_set("timeline_label", None)

View File

@ -5,6 +5,21 @@
cur_frm.email_field = "email_id";
frappe.ui.form.on("Contact", {
onload:function(frm){
if(frappe.route_titles["update_contact"])
{
frappe.confirm("change email address from "+cur_frm.doc.email_id+ " to "+frappe.route_titles["update_contact"]["email_id"]
,function(){
cur_frm.doc.email_id = frappe.route_titles["update_contact"]["email_id"];
cur_frm.refresh();
cur_frm.dirty();
delete frappe.route_titles["update_contact"];
},function(){
delete frappe.route_titles["update_contact"];
})
}
},
refresh: function(frm) {
if(!frm.doc.user && !frm.is_new() && frm.perm[0].write) {
frm.add_custom_button(__("Invite as User"), function() {
@ -27,5 +42,24 @@ frappe.ui.form.on("Contact", {
if(name && locals[doctype] && locals[doctype][name])
frappe.model.remove_from_locals(doctype, name);
});
var fieldlist = ["supplier","customer","user","organisation"]
if(frappe.route_titles["create_contact"]==1&&!($.map(fieldlist,function(v){return frm.doc[v]?true:false}).indexOf(true)!=-1)){
$.each(fieldlist,function(i,v){
cur_frm.set_df_property(v,"reqd",1);
})
} else {
$.each(fieldlist,function(i,v){
cur_frm.set_df_property(v,"reqd",0);
})
}
},
after_save:function(frm){
if (frappe.route_titles["create_contact"])
{
delete frappe.route_titles["create_contact"]
frappe.set_route("email_inbox");
frappe.pages['email_inbox'].Inbox.run()
}
}
});
});

View File

@ -469,6 +469,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "organisation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Organisation",
"length": 0,
"no_copy": 0,
"options": "Organisation",
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -653,7 +682,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-11-07 05:30:56.576752",
"modified": "2016-12-22 13:46:02.655141",
"modified_by": "Administrator",
"module": "Utilities",
"name": "Contact",

View File

@ -15,7 +15,7 @@ class Contact(StatusUpdater):
[cstr(self.get(f)).strip() for f in ["first_name", "last_name"]]))
# concat party name if reqd
for fieldname in ("customer", "supplier", "sales_partner"):
for fieldname in ("customer", "supplier", "sales_partner", "organisation"):
if self.get(fieldname):
self.name = self.name + "-" + cstr(self.get(fieldname)).strip()
break
@ -26,6 +26,7 @@ class Contact(StatusUpdater):
self.set_user()
if self.email_id:
self.image = has_gravatar(self.email_id)
self.contact_update_communication_ref()
def set_user(self):
if not self.user and self.email_id:
@ -61,6 +62,88 @@ class Contact(StatusUpdater):
frappe.db.sql("""update `tabIssue` set contact='' where contact=%s""",
self.name)
def contact_update_communication_ref(self):
origin_communication = frappe.db.sql("select name, sender,recipients,sent_or_received from `tabCommunication`",
as_dict=1)
if self.email_id:
self.email_id = self.email_id.lower()
comm = frappe._dict({"email_id": self.email_id,
"name": self.name,
"supplier": self.supplier,
"supplier_name": self.supplier_name,
"customer": self.customer,
"customer_name": self.customer_name,
"user": self.user,
"organisation": self.organisation
})
for communication in origin_communication:
sender = communication.sender
recipients = communication.recipients
if comm.email_id:
if (sender and communication.sent_or_received == "Received" and sender.find(
comm.email_id) > -1) or (
recipients and communication.sent_or_received == "Sent" and recipients.find(
comm.email_id) > -1):
if sum(1 for x in [comm.supplier, comm.customer, comm.user, comm.organisation] if x) > 1:
frappe.db.sql("""update `tabCommunication`
set timeline_doctype = %(timeline_doctype)s,
timeline_name = %(timeline_name)s,
timeline_label = %(timeline_label)s
where name = %(name)s""", {
"timeline_doctype": "Contact",
"timeline_name": comm.name,
"timeline_label": self.name,
"name": communication.name
})
elif comm.supplier:
frappe.db.sql("""update `tabCommunication`
set timeline_doctype = %(timeline_doctype)s,
timeline_name = %(timeline_name)s,
timeline_label = %(timeline_label)s
where name = %(name)s""", {
"timeline_doctype": "Supplier",
"timeline_name": comm.supplier,
"timeline_label": comm.supplier_name,
"name": communication.name
})
elif comm.customer:
frappe.db.sql("""update `tabCommunication`
set timeline_doctype = %(timeline_doctype)s,
timeline_name = %(timeline_name)s,
timeline_label = %(timeline_label)s
where name = %(name)s""", {
"timeline_doctype": "Customer",
"timeline_name": comm.customer,
"timeline_label": comm.customer_name,
"name": communication.name
})
elif comm.user:
frappe.db.sql("""update `tabCommunication`
set timeline_doctype = %(timeline_doctype)s,
timeline_name = %(timeline_name)s,
timeline_label = %(timeline_label)s
where name = %(name)s""", {
"timeline_doctype": "User",
"timeline_name": comm.user,
"timeline_label": comm.user,
"name": communication.name
})
elif comm.organisation:
frappe.db.sql("""update `tabCommunication`
set timeline_doctype = %(timeline_doctype)s,
timeline_name = %(timeline_name)s,
timeline_label = %(timeline_label)s
where name = %(name)s""", {
"timeline_doctype": "Organisation",
"timeline_name": comm.organisation,
"timeline_label": comm.organisation,
"name": communication.name
})
@frappe.whitelist()
def invite_user(contact):
contact = frappe.get_doc("Contact", contact)

View File

@ -0,0 +1,14 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Organisation', {
refresh: function(frm) {
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if(!frm.doc.__islocal) {
erpnext.utils.render_address_and_contact(frm);
} else {
erpnext.utils.clear_address_and_contact(frm);
}
}
});

View File

@ -0,0 +1,199 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:organisation_name",
"beta": 0,
"creation": "2016-08-22 11:08:27.151412",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 0,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "organisation_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Name",
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Address and Contact",
"length": 0,
"no_copy": 0,
"options": "icon-map-marker",
"permlevel": 0,
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Address HTML",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"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,
"unique": 0,
"width": "50%"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Contact HTML",
"length": 0,
"no_copy": 0,
"oldfieldtype": "HTML",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-12-23 08:33:29.997375",
"modified_by": "Administrator",
"module": "Utilities",
"name": "Organisation",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Email User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from erpnext.utilities.address_and_contact import load_address_and_contact
class Organisation(Document):
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self, "organisation")

View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Organisation')
class TestOrganisation(unittest.TestCase):
pass