Merge pull request #8243 from hrwX/contacts-ref

feat(Contacts): Multiple emails and phones in a contact
This commit is contained in:
mergify[bot] 2019-08-31 18:08:58 +00:00 committed by GitHub
commit 99c73bfae1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 352 additions and 679 deletions

View file

@ -10,7 +10,7 @@ import re
def load_address_and_contact(doc, key=None):
"""Loads address list and contact list in `__onload`"""
from frappe.contacts.doctype.address.address import get_address_display
from frappe.contacts.doctype.address.address import get_address_display, get_condensed_address
filters = [
["Dynamic Link", "link_doctype", "=", doc.doctype],
@ -37,6 +37,23 @@ def load_address_and_contact(doc, key=None):
]
contact_list = frappe.get_all("Contact", filters=filters, fields=["*"])
for contact in contact_list:
contact["email_ids"] = frappe.get_list("Contact Email", filters={
"parenttype": "Contact",
"parent": contact.name,
"is_primary": 0
}, fields=["email_id"])
contact["phone_nos"] = frappe.get_list("Contact Phone", filters={
"parenttype": "Contact",
"parent": contact.name,
"is_primary": 0
}, fields=["phone"])
if contact.address:
address = frappe.get_doc("Address", contact.address)
contact["address"] = get_condensed_address(address)
contact_list = sorted(contact_list,
key = functools.cmp_to_key(lambda a, b:
(int(a.is_primary_contact - b.is_primary_contact)) or

View file

@ -1,666 +1,159 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"beta": 0,
"creation": "2013-01-10 16:34:32",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"field_order": [
"address_details",
"address_title",
"address_type",
"address_line1",
"address_line2",
"city",
"county",
"state",
"country",
"pincode",
"column_break0",
"email_id",
"phone",
"fax",
"is_primary_address",
"is_shipping_address",
"disabled",
"linked_with",
"is_your_company_address",
"links"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "address_details",
"fieldtype": "Section Break",
"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": "",
"length": 0,
"no_copy": 0,
"options": "fa fa-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,
"translatable": 0,
"unique": 0
"options": "fa fa-map-marker"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "address_title",
"fieldtype": "Data",
"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": "Address Title",
"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,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "address_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Address Type",
"length": 0,
"no_copy": 0,
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "address_line1",
"fieldtype": "Data",
"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": "Address Line 1",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "address_line2",
"fieldtype": "Data",
"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": "Address Line 2",
"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,
"translatable": 0,
"unique": 0
"label": "Address Line 2"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "city",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "City/Town",
"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": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "county",
"fieldtype": "Data",
"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": "County",
"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
"label": "County"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "state",
"fieldtype": "Data",
"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": "State",
"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,
"translatable": 0,
"unique": 0
"label": "State"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "country",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Country",
"length": 0,
"no_copy": 0,
"options": "Country",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "pincode",
"fieldtype": "Data",
"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": "Postal Code",
"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": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break0",
"fieldtype": "Column Break",
"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,
"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,
"translatable": 0,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "email_id",
"fieldtype": "Data",
"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": "Email Address",
"length": 0,
"no_copy": 0,
"options": "Email",
"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,
"translatable": 0,
"unique": 0
"options": "Email"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "phone",
"fieldtype": "Data",
"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": "Phone",
"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,
"translatable": 0,
"unique": 0
"label": "Phone"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fax",
"fieldtype": "Data",
"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": "Fax",
"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,
"translatable": 0,
"unique": 0
"label": "Fax"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "",
"fieldname": "is_primary_address",
"fieldtype": "Check",
"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": "Preferred Billing Address",
"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,
"translatable": 0,
"unique": 0
"label": "Preferred Billing Address"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "",
"fieldname": "is_shipping_address",
"fieldtype": "Check",
"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": "Preferred Shipping Address",
"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,
"translatable": 0,
"unique": 0
"label": "Preferred Shipping Address"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"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": "Disabled",
"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
"label": "Disabled"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "linked_with",
"fieldtype": "Section Break",
"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": "Reference",
"length": 0,
"no_copy": 0,
"options": "fa fa-pushpin",
"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,
"translatable": 0,
"unique": 0
"options": "fa fa-pushpin"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "is_your_company_address",
"fieldtype": "Check",
"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": "Is Your Company Address",
"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
"label": "Is Your Company Address"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "links",
"fieldtype": "Table",
"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": "Links",
"length": 0,
"no_copy": 0,
"options": "Dynamic Link",
"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
"options": "Dynamic Link"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-map-marker",
"idx": 5,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-11-27 17:57:22.913973",
"modified": "2019-08-09 14:16:53.343251",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Address",
@ -668,109 +161,61 @@
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Maintenance User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 1,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "country, state",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}
"sort_order": "DESC"
}

View file

@ -143,13 +143,13 @@ def get_list_context(context=None):
}
def get_address_list(doctype, txt, filters, limit_start, limit_page_length = 20, order_by = None):
from frappe.www.list import get_list
user = frappe.session.user
ignore_permissions = False
if is_website_user():
if not filters: filters = []
add_name = []
contact = frappe.db.sql("""
from frappe.www.list import get_list
user = frappe.session.user
ignore_permissions = False
if is_website_user():
if not filters: filters = []
add_name = []
contact = frappe.db.sql("""
select
address.name
from
@ -165,12 +165,12 @@ def get_address_list(doctype, txt, filters, limit_start, limit_page_length = 20,
`tabDynamic Link` as link on contact.name = link.parent
where
contact.user = %s)""",(user))
for c in contact:
add_name.append(c[0])
filters.append(("Address", "name", "in", add_name))
ignore_permissions = True
for c in contact:
add_name.append(c[0])
filters.append(("Address", "name", "in", add_name))
ignore_permissions = True
return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=ignore_permissions)
return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=ignore_permissions)
def has_website_permission(doc, ptype, user, verbose=False):
"""Returns true if there is a related lead or contact related to this document"""
@ -277,3 +277,7 @@ def address_query(doctype, txt, searchfield, start, page_len, filters):
'link_name': link_name,
'link_doctype': link_doctype
})
def get_condensed_address(doc):
fields = ["address_title", "address_line1", "address_line2", "city", "county", "state", "country"]
return ", ".join([doc.get(d) for d in fields if doc.get(d)])

View file

@ -13,14 +13,17 @@
"last_name",
"email_id",
"user",
"address",
"cb00",
"status",
"salutation",
"designation",
"gender",
"phone",
"mobile_no",
"image",
"sb_00",
"email_ids",
"phone_nos",
"contact_details",
"is_primary_contact",
"links",
@ -59,10 +62,12 @@
"fieldname": "email_id",
"fieldtype": "Data",
"in_global_search": 1,
"in_list_view": 1,
"label": "Email Address",
"oldfieldname": "email_id",
"oldfieldtype": "Data",
"options": "Email",
"read_only": 1,
"search_index": 1
},
{
@ -101,18 +106,11 @@
"bold": 1,
"fieldname": "phone",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Phone",
"oldfieldname": "contact_no",
"oldfieldtype": "Data"
},
{
"bold": 1,
"fieldname": "mobile_no",
"fieldtype": "Data",
"in_global_search": 1,
"label": "Mobile No",
"oldfieldname": "mobile_no",
"oldfieldtype": "Data"
"oldfieldtype": "Data",
"read_only": 1
},
{
"fieldname": "image",
@ -182,12 +180,35 @@
"fieldname": "google_contacts_description",
"fieldtype": "Small Text",
"label": "Google Contacts Description"
},
{
"fieldname": "sb_00",
"fieldtype": "Section Break",
"label": "Contact Details"
},
{
"fieldname": "email_ids",
"fieldtype": "Table",
"label": "Email IDs",
"options": "Contact Email"
},
{
"fieldname": "address",
"fieldtype": "Link",
"label": "Address",
"options": "Address"
},
{
"fieldname": "phone_nos",
"fieldtype": "Table",
"label": "Phone Nos",
"options": "Contact Phone"
}
],
"icon": "fa fa-user",
"idx": 1,
"image_field": "image",
"modified": "2019-06-14 20:35:45.300869",
"modified": "2019-08-09 10:23:00.486673",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Contact",

View file

@ -29,10 +29,16 @@ class Contact(Document):
break
def validate(self):
self.set_primary("email_id", "email_ids")
self.set_primary("phone", "phone_nos")
if self.email_id:
self.email_id = self.email_id.strip()
self.set_user()
set_link_title(self)
if self.email_id and not self.image:
self.image = has_gravatar(self.email_id)
@ -61,6 +67,33 @@ class Contact(Document):
if (link.link_doctype, link.link_name) in reference_links:
return True
def add_email(self, email_id, is_primary=0, autosave=False):
self.append("email_ids", {
"email_id": email_id,
"is_primary": is_primary
})
if autosave:
self.save(ignore_permissions=True)
def add_phone(self, phone, is_primary=0, autosave=False):
self.append("phone_nos", {
"phone": phone,
"is_primary": is_primary
})
if autosave:
self.save(ignore_permissions=True)
def set_primary(self, fieldname, child_table):
if len(self.get(child_table)) == 1:
self.get(child_table)[0].is_primary = 1
setattr(self, fieldname, self.get(child_table)[0].get(fieldname))
else:
for d in self.get(child_table):
if d.is_primary == 1:
setattr(self, fieldname, d.get(fieldname))
break
def get_default_contact(doctype, name):
'''Returns default contact for the given doctype, name'''
@ -166,11 +199,12 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters):
def get_contact_with_phone_number(number):
if not number: return
contacts = frappe.get_all('Contact', or_filters={
'phone': ['like', '%{}'.format(number)],
'mobile_no': ['like', '%{}'.format(number)]
}, limit=1)
contacts = frappe.get_all('Contact Phone', filters=[
['phone', 'like', '%{0}'.format(number)]
], fields=["parent"], limit=1)
contact = contacts[0].name if contacts else None
return contacts[0].parent if contacts else None
return contact
def get_contact_name(email_id):
contact = frappe.get_list("Contact Email", filters={"email_id": email_id}, fields=["parent"], limit=1)
return contact[0].parent if contact else None

View file

@ -0,0 +1,37 @@
{
"creation": "2019-08-02 13:08:59.291097",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"email_id",
"is_primary"
],
"fields": [
{
"fieldname": "email_id",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Email ID",
"options": "Email"
},
{
"default": "0",
"fieldname": "is_primary",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Is Primary"
}
],
"istable": 1,
"modified": "2019-08-02 13:14:22.193463",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Contact Email",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class ContactEmail(Document):
pass

View file

@ -0,0 +1,36 @@
{
"creation": "2019-08-02 13:10:37.890214",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"phone",
"is_primary"
],
"fields": [
{
"default": "0",
"fieldname": "is_primary",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Is Primary"
},
{
"fieldname": "phone",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Phone"
}
],
"istable": 1,
"modified": "2019-08-05 11:40:59.104224",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Contact Phone",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class ContactPhone(Document):
pass

View file

@ -9,6 +9,13 @@ frappe.query_reports["Addresses And Contacts"] = {
"label": __("Entity Type"),
"fieldtype": "Link",
"options": "DocType",
"get_query": function() {
return {
"filters": {
"name": ["in", "Contact, Address"],
}
}
}
},
{
"fieldname":"reference_name",

View file

@ -7,8 +7,8 @@ import frappe
from frappe import _
field_map = {
"Contact": [ "first_name", "last_name", "phone", "mobile_no", "email_id", "is_primary_contact" ],
"Address": [ "address_line1", "address_line2", "city", "state", "pincode", "country", "is_primary_address" ]
"Contact": ["first_name", "last_name", "address", "phone", "email_id", "is_primary_contact"],
"Address": ["address_line1", "address_line2", "city", "state", "pincode", "country", "is_primary_address"]
}
def execute(filters=None):
@ -27,8 +27,8 @@ def get_columns(filters):
"Is Primary Address:Check",
"First Name",
"Last Name",
"Address",
"Phone",
"Mobile No",
"Email Id",
"Is Primary Contact:Check"
]
@ -49,7 +49,7 @@ def get_reference_addresses_and_contact(reference_doctype, reference_name):
return []
if reference_name:
filters = { "name": reference_name }
filters = {"name": reference_name}
reference_list = [d[0] for d in frappe.get_list(reference_doctype, filters=filters, fields=["name"], as_list=True)]

View file

@ -67,20 +67,23 @@ def create_linked_address(link_list):
address.insert()
frappe.flags.test_address_created = True
def create_linked_contact(link_list):
return address.name
def create_linked_contact(link_list, address):
if frappe.flags.test_contact_created:
return
contact = frappe.get_doc({
"doctype": "Contact",
"salutation": "Mr",
"email_id": "test_contact@example.com",
"first_name": "_Test First Name",
"last_name": "_Test Last Name",
"is_primary_contact": 1,
"phone": "+91 0000000000",
"address": address,
"status": "Open"
})
contact.add_email("test_contact@example.com")
contact.add_phone("+91 0000000000")
for name in link_list:
contact.append("links",{
@ -88,7 +91,7 @@ def create_linked_contact(link_list):
'link_name': name
})
contact.insert()
contact.insert(ignore_permissions=True)
frappe.flags.test_contact_created = True
@ -96,11 +99,11 @@ class TestAddressesAndContacts(unittest.TestCase):
def test_get_data(self):
linked_docs = [get_custom_doc_for_address_and_contacts()]
links_list = [item.name for item in linked_docs]
create_linked_contact(links_list)
create_linked_address(links_list)
d = create_linked_address(links_list)
create_linked_contact(links_list, d)
report_data = get_data({"reference_doctype": "Test Custom Doctype"})
for idx, link in enumerate(links_list):
test_item = [link, 'test address line 1', 'test address line 2', 'Milan', None, None, 'Italy', 0, '_Test First Name', '_Test Last Name', '+91 0000000000', None, 'test_contact@example.com', 1]
test_item = [link, 'test address line 1', 'test address line 2', 'Milan', None, None, 'Italy', 0, '_Test First Name', '_Test Last Name', '_Test Address-Billing', '+91 0000000000', 'test_contact@example.com', 1]
self.assertListEqual(test_item, report_data[idx])
def tearDown(self):

View file

@ -15,6 +15,7 @@ from frappe.core.doctype.comment.comment import update_comment_in_doc
from email.utils import parseaddr
from six.moves.urllib.parse import unquote
from collections import Counter
from frappe.contacts.doctype.contact.contact import get_contact_name
exclude_from_linked_with = True
@ -334,14 +335,15 @@ def get_contacts(email_strings):
contacts = []
for email in email_addrs:
email = get_email_without_link(email)
contact_name = frappe.db.get_value('Contact', {'email_id': email})
contact_name = get_contact_name(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)
"doctype": "Contact",
"first_name": frappe.unscrub(email.split("@")[0]),
})
contact.add_email(email)
contact.insert(ignore_permissions=True)
contact_name = contact.name
contacts.append(contact_name)

View file

@ -100,21 +100,24 @@ class TestCommunication(unittest.TestCase):
def test_contacts_attached(self):
contact_sender = frappe.get_doc({
"doctype": "Contact",
"first_name": frappe.generate_hash(length=10),
"email_id": "comm_sender@example.com"
}).insert(ignore_permissions=True)
"first_name": "contact_sender",
})
contact_sender.add_email("comm_sender@example.com")
contact_sender.insert(ignore_permissions=True)
contact_recipient = frappe.get_doc({
"doctype": "Contact",
"first_name": frappe.generate_hash(length=10),
"email_id": "comm_recipient@example.com"
}).insert(ignore_permissions=True)
"first_name": "contact_recipient",
})
contact_recipient.add_email("comm_recipient@example.com")
contact_recipient.insert(ignore_permissions=True)
contact_cc = frappe.get_doc({
"doctype": "Contact",
"first_name": frappe.generate_hash(length=10),
"email_id": "comm_cc@example.com"
}).insert(ignore_permissions=True)
"first_name": "contact_cc",
})
contact_cc.add_email("comm_cc@example.com")
contact_cc.insert(ignore_permissions=True)
comm = frappe.get_doc({
"doctype": "Communication",

View file

@ -1038,16 +1038,23 @@ def create_contact(user, ignore_links=False, ignore_mandatory=False):
if user.name in ["Administrator", "Guest"]: return
if not frappe.db.get_value("Contact", {"email_id": user.email}):
frappe.get_doc({
contact = frappe.get_doc({
"doctype": "Contact",
"first_name": user.first_name,
"last_name": user.last_name,
"email_id": user.email,
"user": user.name,
"gender": user.gender,
"phone": user.phone,
"mobile_no": user.mobile_no
}).insert(ignore_permissions=True, ignore_links=ignore_links, ignore_mandatory=ignore_mandatory)
})
if user.email:
contact.add_email(user.email)
if user.phone:
contact.add_phone(user.phone)
if user.mobile_no:
contact.add_phone(user.mobile_no)
contact.insert(ignore_permissions=True, ignore_links=ignore_links, ignore_mandatory=ignore_mandatory)
@frappe.whitelist()

View file

@ -261,7 +261,11 @@ user_privacy_documents = [
{
'doctype': 'Contact',
'match_field': 'email_id',
'personal_fields': ['first_name', 'last_name', 'phone', 'mobile_no'],
'personal_fields': ['first_name', 'last_name', 'phone'],
},
{
'doctype': 'Contact Email',
'match_field': 'email_id',
},
{
'doctype': 'Address',

View file

@ -136,24 +136,25 @@ def sync(g_contact=None):
for name in connection.get("names"):
if name.get("metadata").get("primary"):
if connection.get("emailAddresses"):
for email in connection.get("emailAddresses"):
if not frappe.db.exists("Contact", {"email_id": email.get("value")}):
contacts_updated += 1
contact = frappe.get_doc({
"doctype": "Contact",
"salutation": name.get("honorificPrefix") or "",
"first_name": name.get("givenName") or "",
"middle_name": name.get("middleName") or "",
"last_name": name.get("familyName") or "",
"designation": get_indexed_value(connection.get("organizations"), 0, "title"),
"source": "Google Contacts",
"google_contacts_description": get_indexed_value(connection.get("organizations"), 0, "name")
})
for email in connection.get("emailAddresses", []):
contact.add_email(email_id=email.get("value"), is_primary=1 if email.get("primary") else 0)
for phone in connection.get("phoneNumbers", []):
contact.add_phone(phone=phone.get("value"), is_primary=1 if phone.get("primary") else 0)
contact.insert(ignore_permissions=True)
frappe.get_doc({
"doctype": "Contact",
"salutation": name.get("honorificPrefix") if name.get("honorificPrefix") else "",
"first_name": name.get("givenName") if name.get("givenName") else "",
"middle_name": name.get("middleName") if name.get("middleName") else "",
"last_name": name.get("familyName") if name.get("familyName") else "",
"email_id": email.get("value") if email.get("value") else "",
"designation": get_indexed_value(connection.get("organizations"), 0, "title"),
"phone": get_indexed_value(connection.get("phoneNumbers"), 0, "value"),
"mobile_no": get_indexed_value(connection.get("phoneNumbers"), 1, "value"),
"source": "Google Contacts",
"google_contacts_description": get_indexed_value(connection.get("organizations"), 0, "name")
}).insert(ignore_permissions=True)
if g_contact:
return _("{0} Google Contacts synced.").format(contacts_updated) if contacts_updated > 0 else _("No new Google Contacts synced.")

View file

@ -248,4 +248,5 @@ frappe.patches.v12_0.move_timeline_links_to_dynamic_links
frappe.patches.v12_0.delete_feedback_request_if_exists #1
frappe.patches.v12_0.rename_events_repeat_on
frappe.patches.v12_0.fix_public_private_files
frappe.patches.v12_0.move_email_and_phone_to_child_table
frappe.patches.v12_0.delete_duplicate_indexes

View file

@ -0,0 +1,31 @@
import frappe
def execute():
contact_details = frappe.get_list("Contact", fields=["name", "email_id", "phone", "mobile_no", "modified_by", "creation", "modified"])
frappe.reload_doc("contacts", "doctype", "contact_email")
frappe.reload_doc("contacts", "doctype", "contact_phone")
frappe.reload_doc("contacts", "doctype", "contact")
for contact_detail in contact_details:
contact_name = frappe.db.escape(contact_detail.name)
if contact_detail.email_id:
frappe.db.sql("""
INSERT INTO `tabContact Email`
(`idx`, `name`, `email_id`, `parentfield`, `parenttype`, `parent`, `is_primary`, `creation`, `modified`, `modified_by`)
VALUES (1, '{0}', '{1}', 'email_ids', 'Contact', {2}, 1, '{3}', '{4}', '{5}')
""".format(frappe.generate_hash(contact_detail.email_id, 10), contact_detail.email_id, contact_name, contact_detail.creation, contact_detail.modified, contact_detail.modified_by))
if contact_detail.phone:
frappe.db.sql("""
INSERT INTO `tabContact Phone`
(`idx`, `name`, `phone`, `parentfield`, `parenttype`, `parent`, `is_primary`, `creation`, `modified`, `modified_by`)
VALUES (1, '{0}', '{1}', 'phone_nos', 'Contact', {2}, 1, '{3}', '{4}', '{5}')
""".format(frappe.generate_hash(contact_detail.phone, 10), contact_detail.phone, contact_name, contact_detail.creation, contact_detail.modified, contact_detail.modified_by))
if contact_detail.mobile_no:
frappe.db.sql("""
INSERT INTO `tabContact Phone`
(`idx`, `name`, `phone`, `parentfield`, `parenttype`, `parent`, `is_primary`, `creation`, `modified`, `modified_by`)
VALUES (2, '{0}', '{1}', 'phone_nos', 'Contact', {2}, 0, '{3}', '{4}', '{5}')
""".format(frappe.generate_hash(contact_detail.mobile_no, 10), contact_detail.mobile_no, contact_name, contact_detail.creation, contact_detail.modified, contact_detail.modified_by))