From 312210c2b0bf2dff44c006b26ca1866ae2fe2b5b Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Tue, 13 Aug 2019 17:15:44 +0530 Subject: [PATCH 1/7] feat: create address and contact after lead creation --- erpnext/crm/doctype/lead/lead.js | 55 +++++++------- erpnext/crm/doctype/lead/lead.json | 95 +++++++++++++++++------- erpnext/crm/doctype/lead/lead.py | 115 +++++++++++++++++++++++------ 3 files changed, 187 insertions(+), 78 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 122e2b4eee..0c88d2826f 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt frappe.provide("erpnext"); @@ -7,57 +7,54 @@ cur_frm.email_field = "email_id"; erpnext.LeadController = frappe.ui.form.Controller.extend({ setup: function () { this.frm.make_methods = { + 'Customer': this.make_customer, 'Quotation': this.make_quotation, - 'Opportunity': this.create_opportunity - } - - this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) { - return { query: "erpnext.controllers.queries.customer_query" } - } + 'Opportunity': this.make_opportunity + }; this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead); }, onload: function () { - if (cur_frm.fields_dict.lead_owner.df.options.match(/^User/)) { - cur_frm.fields_dict.lead_owner.get_query = function (doc, cdt, cdn) { - return { query: "frappe.core.doctype.user.user.user_query" } - } - } + this.frm.set_query("customer", function (doc, cdt, cdn) { + return { query: "erpnext.controllers.queries.customer_query" } + }); - if (cur_frm.fields_dict.contact_by.df.options.match(/^User/)) { - cur_frm.fields_dict.contact_by.get_query = function (doc, cdt, cdn) { - return { query: "frappe.core.doctype.user.user.user_query" } - } - } + this.frm.set_query("lead_owner", function (doc, cdt, cdn) { + return { query: "frappe.core.doctype.user.user.user_query" } + }); + + this.frm.set_query("contact_by", function (doc, cdt, cdn) { + return { query: "frappe.core.doctype.user.user.user_query" } + }); }, refresh: function () { - var doc = this.frm.doc; + let doc = this.frm.doc; erpnext.toggle_naming_series(); frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' } - if(!doc.__islocal && doc.__onload && !doc.__onload.is_customer) { - this.frm.add_custom_button(__("Customer"), this.create_customer, __('Create')); - this.frm.add_custom_button(__("Opportunity"), this.create_opportunity, __('Create')); - this.frm.add_custom_button(__("Quotation"), this.make_quotation, __('Create')); + if (!this.frm.is_new() && doc.__onload && !doc.__onload.is_customer) { + this.frm.add_custom_button(__("Customer"), this.make_customer, __("Create")); + this.frm.add_custom_button(__("Opportunity"), this.make_opportunity, __("Create")); + this.frm.add_custom_button(__("Quotation"), this.make_quotation, __("Create")); } - if (!this.frm.doc.__islocal) { - frappe.contacts.render_address_and_contact(cur_frm); + if (!this.frm.is_new()) { + frappe.contacts.render_address_and_contact(this.frm); } else { - frappe.contacts.clear_address_and_contact(cur_frm); + frappe.contacts.clear_address_and_contact(this.frm); } }, - create_customer: function () { + make_customer: function () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_customer", frm: cur_frm }) }, - create_opportunity: function () { + make_opportunity: function () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_opportunity", frm: cur_frm @@ -77,7 +74,7 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ }, company_name: function () { - if (this.frm.doc.organization_lead == 1) { + if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) { this.frm.set_value("lead_name", this.frm.doc.company_name); } }, @@ -85,7 +82,7 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ contact_date: function () { if (this.frm.doc.contact_date) { let d = moment(this.frm.doc.contact_date); - d.add(1, "hours"); + d.add(1, "day"); this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat)); } } diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index eb68c679ba..d2a98b609a 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -16,6 +16,7 @@ "col_break123", "lead_owner", "status", + "salutation", "gender", "source", "customer", @@ -29,16 +30,20 @@ "notes_section", "notes", "contact_info", - "address_desc", "address_html", + "address_title", + "address_line1", + "address_line2", + "city", + "county", + "state", + "country", + "pincode", "column_break2", "contact_html", "phone", - "salutation", "mobile_no", "fax", - "website", - "territory", "more_info", "type", "market_segment", @@ -46,6 +51,8 @@ "request_type", "column_break3", "company", + "website", + "territory", "unsubscribed", "blog_subscriber" ], @@ -73,7 +80,6 @@ "set_only_once": 1 }, { - "depends_on": "eval:!doc.organization_lead", "fieldname": "lead_name", "fieldtype": "Data", "in_global_search": 1, @@ -130,7 +136,6 @@ "search_index": 1 }, { - "depends_on": "eval:!doc.organization_lead", "fieldname": "gender", "fieldtype": "Link", "label": "Gender", @@ -218,19 +223,13 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", "fieldname": "contact_info", "fieldtype": "Section Break", "label": "Address & Contact", "oldfieldtype": "Column Break", "options": "fa fa-map-marker" }, - { - "depends_on": "eval:doc.__islocal", - "fieldname": "address_desc", - "fieldtype": "HTML", - "label": "Address Desc", - "print_hide": 1 - }, { "fieldname": "address_html", "fieldtype": "HTML", @@ -242,14 +241,13 @@ "fieldtype": "Column Break" }, { - "depends_on": "eval:doc.organization_lead", "fieldname": "contact_html", "fieldtype": "HTML", "label": "Contact HTML", "read_only": 1 }, { - "depends_on": "eval:!doc.organization_lead", + "depends_on": "eval: doc.__islocal", "fieldname": "phone", "fieldtype": "Data", "label": "Phone", @@ -257,14 +255,14 @@ "oldfieldtype": "Data" }, { - "depends_on": "eval:!doc.organization_lead", + "depends_on": "eval: doc.__islocal", "fieldname": "salutation", "fieldtype": "Link", "label": "Salutation", "options": "Salutation" }, { - "depends_on": "eval:!doc.organization_lead", + "depends_on": "eval: doc.__islocal", "fieldname": "mobile_no", "fieldtype": "Data", "label": "Mobile No.", @@ -272,7 +270,7 @@ "oldfieldtype": "Data" }, { - "depends_on": "eval:!doc.organization_lead", + "depends_on": "eval: doc.__islocal", "fieldname": "fax", "fieldtype": "Data", "label": "Fax", @@ -361,12 +359,62 @@ "fieldname": "blog_subscriber", "fieldtype": "Check", "label": "Blog Subscriber" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_title", + "fieldtype": "Data", + "label": "Address Title" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_line1", + "fieldtype": "Data", + "label": "Address Line 1" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_line2", + "fieldtype": "Data", + "label": "Address Line 2" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "city", + "fieldtype": "Data", + "label": "City/Town" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "county", + "fieldtype": "Data", + "label": "County" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "state", + "fieldtype": "Data", + "label": "State" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "country", + "fieldtype": "Link", + "label": "Country", + "options": "Country" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "pincode", + "fieldtype": "Data", + "label": "Postal Code", + "options": "Country" } ], "icon": "fa fa-user", "idx": 5, "image_field": "image", - "modified": "2019-09-19 12:49:02.536647", + "modified": "2019-09-20 12:49:02.536647", "modified_by": "Administrator", "module": "CRM", "name": "Lead", @@ -423,15 +471,6 @@ "read": 1, "report": 1, "role": "Sales User" - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Guest", - "share": 1 } ], "search_fields": "lead_name,lead_owner,status", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 1dae4b9fc1..cc2badf984 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -2,18 +2,19 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe -from frappe import _ -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 -from frappe.contacts.address_and_contact import load_address_and_contact +import frappe from erpnext.accounts.party import set_taxes +from erpnext.controllers.selling_controller import SellingController +from frappe import _ +from frappe.contacts.address_and_contact import load_address_and_contact from frappe.email.inbox import link_communication_to_document +from frappe.model.mapper import get_mapped_doc +from frappe.utils import cint, comma_and, cstr, getdate, has_gravatar, nowdate, validate_email_address sender_field = "email_id" + class Lead(SellingController): def get_feed(self): return '{0}: {1}'.format(_(self.status), self.lead_name) @@ -23,15 +24,22 @@ class Lead(SellingController): self.get("__onload").is_customer = customer load_address_and_contact(self) + def before_insert(self): + self.address_doc = self.create_address() + self.contact_doc = self.create_contact() + + def after_insert(self): + self.update_links() + # after the address and contact are created, flush the field values + # to avoid inconsistent reporting in case the documents are changed + self.flush_address_and_contact_fields() + def validate(self): self.set_lead_name() self._prev = frappe._dict({ - "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if \ - (not cint(self.get("__islocal"))) else None, - "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if \ - (not cint(self.get("__islocal"))) else None, - "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if \ - (not cint(self.get("__islocal"))) else None, + "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None, + "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None, + "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None, }) self.set_status() @@ -39,7 +47,7 @@ class Lead(SellingController): if self.email_id: if not self.flags.ignore_email_validation: - validate_email_address(self.email_id, True) + validate_email_address(self.email_id, throw=True) if self.email_id == self.lead_owner: frappe.throw(_("Lead Owner cannot be same as the Lead")) @@ -53,8 +61,7 @@ class Lead(SellingController): if self.contact_date and getdate(self.contact_date) < getdate(nowdate()): frappe.throw(_("Next Contact Date cannot be in the past")) - if self.ends_on and self.contact_date and\ - (self.ends_on < self.contact_date): + if self.ends_on and self.contact_date and (self.ends_on < self.contact_date): frappe.throw(_("Ends On date cannot be before Next Contact Date.")) def on_update(self): @@ -66,8 +73,7 @@ class Lead(SellingController): "starts_on": self.contact_date, "ends_on": self.ends_on or "", "subject": ('Contact ' + cstr(self.lead_name)), - "description": ('Contact ' + cstr(self.lead_name)) + \ - (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '') + "description": ('Contact ' + cstr(self.lead_name)) + (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '') }, force) def check_email_id_is_unique(self): @@ -81,8 +87,7 @@ class Lead(SellingController): .format(comma_and(duplicate_leads)), frappe.DuplicateEntryError) def on_trash(self): - frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", - self.name) + frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name) self.delete_events() @@ -115,10 +120,74 @@ class Lead(SellingController): self.lead_name = self.company_name + def create_address(self): + address_fields = ["address_title", "address_line1", "address_line2", + "city", "county", "state", "country", "pincode"] + info_fields = ["email_id", "phone", "fax"] + + # do not create an address if no fields are available, + # skipping country since the system auto-sets it from system defaults + if not any([self.get(field) for field in address_fields if field != "country"]): + return + + address = frappe.new_doc("Address") + address.update({addr_field: self.get(addr_field) for addr_field in address_fields}) + address.update({info_field: self.get(info_field) for info_field in info_fields}) + address.insert() + + return address + + def create_contact(self): + names = self.lead_name.split(" ") + if len(names) > 1: + first_name, last_name = names[0], " ".join(names[1:]) + else: + first_name, last_name = self.lead_name, None + + contact_fields = ["email_id", "salutation", "gender", "phone", "mobile_no"] + + contact = frappe.new_doc("Contact") + contact.update({contact_field: self.get(contact_field) for contact_field in contact_fields}) + contact.update({ + "first_name": first_name, + "last_name": last_name + }) + contact.insert() + + return contact + + def update_links(self): + # update address links + if self.address_doc: + self.address_doc.append("links", { + "link_doctype": "Lead", + "link_name": self.name, + "link_title": self.lead_name + }) + self.address_doc.save() + + # update contact links + if self.contact_doc: + self.contact_doc.append("links", { + "link_doctype": "Lead", + "link_name": self.name, + "link_title": self.lead_name + }) + self.contact_doc.save() + + def flush_address_and_contact_fields(self): + fields = ['address_line1', 'address_line2', 'address_title', 'city', 'country', + 'county', 'fax', 'mobile_no', 'phone', 'pincode', 'salutation', 'state'] + + for field in fields: + self.set(field, None) + + @frappe.whitelist() def make_customer(source_name, target_doc=None): return _make_customer(source_name, target_doc) + def _make_customer(source_name, target_doc=None, ignore_permissions=False): def set_missing_values(source, target): if source.company_name: @@ -143,6 +212,7 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False): return doclist + @frappe.whitelist() def make_opportunity(source_name, target_doc=None): def set_missing_values(source, target): @@ -164,6 +234,7 @@ def make_opportunity(source_name, target_doc=None): return target_doc + @frappe.whitelist() def make_quotation(source_name, target_doc=None): def set_missing_values(source, target): @@ -205,7 +276,8 @@ def _set_missing_values(source, target): @frappe.whitelist() def get_lead_details(lead, posting_date=None, company=None): - if not lead: return {} + if not lead: + return {} from erpnext.accounts.party import set_address_details out = frappe._dict() @@ -231,6 +303,7 @@ def get_lead_details(lead, posting_date=None, company=None): return out + @frappe.whitelist() def make_lead_from_communication(communication, ignore_communication_links=False): """ raise a issue from email """ @@ -267,4 +340,4 @@ def get_lead_with_phone_number(number): lead = leads[0].name if leads else None - return lead \ No newline at end of file + return lead From f9e2bfcc2940c90868941cfd84548f8e301c4d49 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Thu, 22 Aug 2019 15:03:34 +0530 Subject: [PATCH 2/7] fix: conditionally set lead title as organization or person --- erpnext/crm/doctype/lead/lead.json | 12 ++++++++++-- erpnext/crm/doctype/lead/lead.py | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index d2a98b609a..88a562f720 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -54,7 +54,8 @@ "website", "territory", "unsubscribed", - "blog_subscriber" + "blog_subscriber", + "title" ], "fields": [ { @@ -409,6 +410,13 @@ "fieldtype": "Data", "label": "Postal Code", "options": "Country" + }, + { + "fieldname": "title", + "fieldtype": "Data", + "hidden": 1, + "label": "Title", + "print_hide": 1 } ], "icon": "fa fa-user", @@ -477,5 +485,5 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", - "title_field": "lead_name" + "title_field": "title" } \ No newline at end of file diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index cc2badf984..9e5fdc0e12 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -36,6 +36,7 @@ class Lead(SellingController): def validate(self): self.set_lead_name() + self.set_title() self._prev = frappe._dict({ "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None, "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None, @@ -120,6 +121,12 @@ class Lead(SellingController): self.lead_name = self.company_name + def set_title(self): + if self.organization_lead: + self.title = self.company_name + else: + self.title = self.lead_name + def create_address(self): address_fields = ["address_title", "address_line1", "address_line2", "city", "county", "state", "country", "pincode"] From 75da5af900cb49e509a63433e89830cbb58bd561 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Thu, 22 Aug 2019 15:38:44 +0530 Subject: [PATCH 3/7] fix: set missing values --- erpnext/crm/doctype/lead/lead.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 9e5fdc0e12..bd0c742aa2 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -145,6 +145,9 @@ class Lead(SellingController): return address def create_contact(self): + if not self.lead_name: + self.set_lead_name() + names = self.lead_name.split(" ") if len(names) > 1: first_name, last_name = names[0], " ".join(names[1:]) From 69e3868a9dfcaf02c61defac58df8d39cbf1cb51 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Fri, 6 Sep 2019 13:38:15 +0530 Subject: [PATCH 4/7] patch: set title for old leads --- erpnext/patches.txt | 3 ++- erpnext/patches/v12_0/set_lead_title_field.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v12_0/set_lead_title_field.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 07b646b0f8..0495c02752 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -646,4 +646,5 @@ erpnext.patches.v12_0.set_payment_entry_status erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger -erpnext.patches.v12_0.update_price_or_product_discount \ No newline at end of file +erpnext.patches.v12_0.update_price_or_product_discount +erpnext.patches.v12_0.set_lead_title_field diff --git a/erpnext/patches/v12_0/set_lead_title_field.py b/erpnext/patches/v12_0/set_lead_title_field.py new file mode 100644 index 0000000000..86e00038f6 --- /dev/null +++ b/erpnext/patches/v12_0/set_lead_title_field.py @@ -0,0 +1,11 @@ +import frappe + + +def execute(): + frappe.reload_doc("crm", "doctype", "lead") + frappe.db.sql(""" + UPDATE + `tabLead` + SET + title = IF(organization_lead = 1, company_name, lead_name) + """) From fd46fef857b578515db6d12245d8f01895dc00b1 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Fri, 6 Sep 2019 14:10:20 +0530 Subject: [PATCH 5/7] fix: add designation to Lead --- erpnext/crm/doctype/lead/lead.json | 153 +++++++++++++++-------------- erpnext/crm/doctype/lead/lead.py | 4 +- 2 files changed, 82 insertions(+), 75 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index 88a562f720..c8e9fbc463 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -17,6 +17,7 @@ "lead_owner", "status", "salutation", + "designation", "gender", "source", "customer", @@ -136,6 +137,13 @@ "reqd": 1, "search_index": 1 }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "salutation", + "fieldtype": "Link", + "label": "Salutation", + "options": "Salutation" + }, { "fieldname": "gender", "fieldtype": "Link", @@ -237,6 +245,56 @@ "label": "Address HTML", "read_only": 1 }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_title", + "fieldtype": "Data", + "label": "Address Title" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_line1", + "fieldtype": "Data", + "label": "Address Line 1" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "address_line2", + "fieldtype": "Data", + "label": "Address Line 2" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "city", + "fieldtype": "Data", + "label": "City/Town" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "county", + "fieldtype": "Data", + "label": "County" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "state", + "fieldtype": "Data", + "label": "State" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "country", + "fieldtype": "Link", + "label": "Country", + "options": "Country" + }, + { + "depends_on": "eval: doc.__islocal", + "fieldname": "pincode", + "fieldtype": "Data", + "label": "Postal Code", + "options": "Country" + }, { "fieldname": "column_break2", "fieldtype": "Column Break" @@ -255,13 +313,6 @@ "oldfieldname": "contact_no", "oldfieldtype": "Data" }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "salutation", - "fieldtype": "Link", - "label": "Salutation", - "options": "Salutation" - }, { "depends_on": "eval: doc.__islocal", "fieldname": "mobile_no", @@ -278,22 +329,6 @@ "oldfieldname": "fax", "oldfieldtype": "Data" }, - { - "fieldname": "website", - "fieldtype": "Data", - "label": "Website", - "oldfieldname": "website", - "oldfieldtype": "Data" - }, - { - "fieldname": "territory", - "fieldtype": "Link", - "label": "Territory", - "oldfieldname": "territory", - "oldfieldtype": "Link", - "options": "Territory", - "print_hide": 1 - }, { "collapsible": 1, "fieldname": "more_info", @@ -349,6 +384,22 @@ "options": "Company", "remember_last_selected_value": 1 }, + { + "fieldname": "website", + "fieldtype": "Data", + "label": "Website", + "oldfieldname": "website", + "oldfieldtype": "Data" + }, + { + "fieldname": "territory", + "fieldtype": "Link", + "label": "Territory", + "oldfieldname": "territory", + "oldfieldtype": "Link", + "options": "Territory", + "print_hide": 1 + }, { "default": "0", "fieldname": "unsubscribed", @@ -361,62 +412,18 @@ "fieldtype": "Check", "label": "Blog Subscriber" }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "address_title", - "fieldtype": "Data", - "label": "Address Title" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "address_line1", - "fieldtype": "Data", - "label": "Address Line 1" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "address_line2", - "fieldtype": "Data", - "label": "Address Line 2" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "city", - "fieldtype": "Data", - "label": "City/Town" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "county", - "fieldtype": "Data", - "label": "County" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "state", - "fieldtype": "Data", - "label": "State" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "country", - "fieldtype": "Link", - "label": "Country", - "options": "Country" - }, - { - "depends_on": "eval: doc.__islocal", - "fieldname": "pincode", - "fieldtype": "Data", - "label": "Postal Code", - "options": "Country" - }, { "fieldname": "title", "fieldtype": "Data", "hidden": 1, "label": "Title", "print_hide": 1 + }, + { + "fieldname": "designation", + "fieldtype": "Link", + "label": "Designation", + "options": "Designation" } ], "icon": "fa fa-user", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index bd0c742aa2..c0416092b1 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -154,7 +154,7 @@ class Lead(SellingController): else: first_name, last_name = self.lead_name, None - contact_fields = ["email_id", "salutation", "gender", "phone", "mobile_no"] + contact_fields = ["email_id", "salutation", "gender", "designation", "phone", "mobile_no"] contact = frappe.new_doc("Contact") contact.update({contact_field: self.get(contact_field) for contact_field in contact_fields}) @@ -187,7 +187,7 @@ class Lead(SellingController): def flush_address_and_contact_fields(self): fields = ['address_line1', 'address_line2', 'address_title', 'city', 'country', - 'county', 'fax', 'mobile_no', 'phone', 'pincode', 'salutation', 'state'] + 'county', 'fax', 'mobile_no', 'phone', 'pincode', 'state'] for field in fields: self.set(field, None) From c59ac36378fb720b6bd8562c004ae53fbed1beb7 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 18 Sep 2019 13:46:22 +0530 Subject: [PATCH 6/7] fix: use new Contact schema --- erpnext/crm/doctype/lead/lead.json | 9 +++++++++ erpnext/crm/doctype/lead/lead.py | 31 ++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index c8e9fbc463..2219307caf 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -486,6 +486,15 @@ "read": 1, "report": 1, "role": "Sales User" + }, + { + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Guest", + "share": 1 } ], "search_fields": "lead_name,lead_owner,status", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index c0416092b1..6645c4d001 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -80,8 +80,8 @@ class Lead(SellingController): def check_email_id_is_unique(self): if self.email_id: # validate email is unique - duplicate_leads = frappe.db.sql_list("""select name from tabLead - where email_id=%s and name!=%s""", (self.email_id, self.name)) + duplicate_leads = frappe.get_all("Lead", filters={"email_id": self.email_id, "name": ["!=", self.name]}) + duplicate_leads = [lead.name for lead in duplicate_leads] if duplicate_leads: frappe.throw(_("Email Address must be unique, already exists for {0}") @@ -154,13 +154,28 @@ class Lead(SellingController): else: first_name, last_name = self.lead_name, None - contact_fields = ["email_id", "salutation", "gender", "designation", "phone", "mobile_no"] - contact = frappe.new_doc("Contact") - contact.update({contact_field: self.get(contact_field) for contact_field in contact_fields}) contact.update({ "first_name": first_name, - "last_name": last_name + "last_name": last_name, + "salutation": self.salutation, + "gender": self.gender, + "designation": self.designation, + "email_ids": [ + { + "email_id": self.email_id, + "is_primary": 1 + } + ], + "phone_nos": [ + { + "phone": self.phone, + "is_primary": 1 + }, + { + "phone": self.mobile_no, + } + ] }) contact.insert() @@ -186,8 +201,8 @@ class Lead(SellingController): self.contact_doc.save() def flush_address_and_contact_fields(self): - fields = ['address_line1', 'address_line2', 'address_title', 'city', 'country', - 'county', 'fax', 'mobile_no', 'phone', 'pincode', 'state'] + fields = ['address_line1', 'address_line2', 'address_title', + 'city', 'county', 'country', 'fax', 'pincode', 'state'] for field in fields: self.set(field, None) From d7427919a4d638359de9c7ba4be4832cf4d6011f Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 24 Dec 2019 16:45:09 +0530 Subject: [PATCH 7/7] fix: Address section rearrange and minor bug fixes --- erpnext/crm/doctype/lead/lead.json | 36 +++++++++++++++++++----------- erpnext/crm/doctype/lead/lead.py | 33 ++++++++++++++------------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index 2219307caf..bc007b146f 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_events_in_timeline": 1, "allow_import": 1, "autoname": "naming_series:", @@ -30,18 +31,19 @@ "ends_on", "notes_section", "notes", - "contact_info", + "address_info", "address_html", "address_title", "address_line1", "address_line2", "city", "county", + "column_break2", + "contact_html", "state", "country", "pincode", - "column_break2", - "contact_html", + "contact_section", "phone", "mobile_no", "fax", @@ -230,15 +232,6 @@ "fieldtype": "Text Editor", "label": "Notes" }, - { - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "fieldname": "contact_info", - "fieldtype": "Section Break", - "label": "Address & Contact", - "oldfieldtype": "Column Break", - "options": "fa fa-map-marker" - }, { "fieldname": "address_html", "fieldtype": "HTML", @@ -424,12 +417,29 @@ "fieldtype": "Link", "label": "Designation", "options": "Designation" + }, + { + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "fieldname": "address_info", + "fieldtype": "Section Break", + "label": "Address & Contact", + "oldfieldtype": "Column Break", + "options": "fa fa-map-marker" + }, + { + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "fieldname": "contact_section", + "fieldtype": "Section Break", + "label": "Contact" } ], "icon": "fa fa-user", "idx": 5, "image_field": "image", - "modified": "2019-09-20 12:49:02.536647", + "links": [], + "modified": "2019-12-24 16:00:44.239168", "modified_by": "Administrator", "module": "CRM", "name": "Lead", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 6645c4d001..6cab18dc1c 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -161,22 +161,25 @@ class Lead(SellingController): "salutation": self.salutation, "gender": self.gender, "designation": self.designation, - "email_ids": [ - { - "email_id": self.email_id, - "is_primary": 1 - } - ], - "phone_nos": [ - { - "phone": self.phone, - "is_primary": 1 - }, - { - "phone": self.mobile_no, - } - ] }) + + if self.email_id: + contact.append("email_ids", { + "email_id": self.email_id, + "is_primary": 1 + }) + + if self.phone: + contact.append("phone_nos", { + "phone": self.phone, + "is_primary": 1 + }) + + if self.mobile_no: + contact.append("phone_nos", { + "phone": self.mobile_no + }) + contact.insert() return contact