diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index f2f393763f7..2b3b5a90f97 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -11,6 +11,7 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ }, 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" } @@ -61,10 +62,21 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ method: "erpnext.crm.doctype.lead.lead.make_quotation", frm: cur_frm }) + }, + + organization_lead: function() { + if (this.frm.doc.organization_lead == 1) { + this.frm.set_df_property('company_name', 'reqd', 1); + } else { + this.frm.set_df_property('company_name', 'reqd', 0); + } + }, + + company_name: function() { + if (this.frm.doc.organization_lead == 1) { + this.frm.set_value("lead_name", this.frm.doc.company_name); + } } }); $.extend(cur_frm.cscript, new erpnext.LeadController({frm: cur_frm})); - - - diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index c9d04ac1fc6..ad61abd5c1f 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -12,6 +12,37 @@ "document_type": "Document", "editable_grid": 0, "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "organization_lead", + "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": "Lead is an Organization", + "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": 1, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -80,6 +111,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.organization_lead", "fieldname": "lead_name", "fieldtype": "Data", "hidden": 0, @@ -673,6 +705,38 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:doc.organization_lead", + "fieldname": "contact_html", + "fieldtype": "HTML", + "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": "Contact HTML", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:!doc.organization_lead", "fieldname": "phone", "fieldtype": "Data", "hidden": 0, @@ -704,6 +768,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.organization_lead", "fieldname": "salutation", "fieldtype": "Link", "hidden": 0, @@ -735,6 +800,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.organization_lead", "fieldname": "mobile_no", "fieldtype": "Data", "hidden": 0, @@ -766,6 +832,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.organization_lead", "fieldname": "fax", "fieldtype": "Data", "hidden": 0, @@ -1147,7 +1214,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-21 02:28:21.581948", + "modified": "2017-11-24 11:10:56.485917", "modified_by": "Administrator", "module": "CRM", "name": "Lead", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index eb6e8763e14..a5dfc5c5d34 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -23,6 +23,7 @@ class Lead(SellingController): load_address_and_contact(self) 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, @@ -98,6 +99,10 @@ class Lead(SellingController): "status": "Lost" }) + def set_lead_name(self): + if not self.lead_name: + frappe.db.set_value("Lead", self.name, "lead_name", self.organization_name) + @frappe.whitelist() def make_customer(source_name, target_doc=None): return _make_customer(source_name, target_doc) @@ -124,11 +129,12 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False): } }}, target_doc, set_missing_values, ignore_permissions=ignore_permissions) + print(doclist) return doclist @frappe.whitelist() def make_opportunity(source_name, target_doc=None): - target_doc = get_mapped_doc("Lead", source_name, + target_doc = get_mapped_doc("Lead", source_name, {"Lead": { "doctype": "Opportunity", "field_map": { diff --git a/erpnext/crm/doctype/lead/test_lead.js b/erpnext/crm/doctype/lead/test_lead.js index 66d33379ad1..0d92b4e2a7e 100644 --- a/erpnext/crm/doctype/lead/test_lead.js +++ b/erpnext/crm/doctype/lead/test_lead.js @@ -1,7 +1,7 @@ QUnit.module("sales"); QUnit.test("test: lead", function (assert) { - assert.expect(4); + assert.expect(10); let done = assert.async(); let lead_name = frappe.utils.get_random(10); frappe.run_serially([ @@ -40,4 +40,53 @@ QUnit.test("test: lead", function (assert) { () => done() ]); + frappe.run_serially([ + // test lead creation + () => frappe.set_route("List", "Lead"), + () => frappe.new_doc("Lead"), + () => frappe.timeout(1), + () => cur_frm.set_value("organization_lead", "1"), + () => cur_frm.set_value("organization_name", lead_name), + () => cur_frm.save(), + () => frappe.timeout(1), + () => { + assert.ok(cur_frm.doc.lead_name.includes(lead_name), + 'name correctly set'); + frappe.lead_name = cur_frm.doc.name; + }, + // create address and contact + () => frappe.click_link('Address & Contact'), + () => frappe.click_button('New Address'), + () => frappe.timeout(1), + () => frappe.set_control('address_line1', 'Gateway'), + () => frappe.set_control('city', 'Mumbai'), + () => cur_frm.save(), + () => frappe.timeout(3), + () => assert.equal(frappe.get_route()[1], 'Lead', + 'back to lead form'), + () => frappe.click_link('Address & Contact'), + () => assert.ok($('.address-box').text().includes('Mumbai'), + 'city is seen in address box'), + + () => frappe.click_button('New Contact'), + () => frappe.timeout(1), + () => frappe.set_control('first_name', 'John'), + () => frappe.set_control('last_name', 'Doe'), + () => cur_frm.save(), + () => frappe.timeout(3), + () => assert.equal(frappe.get_route()[1], 'Lead', + 'back to lead form'), + () => frappe.click_link('Address & Contact'), + () => assert.ok($('.address-box').text().includes('John'), + 'contact is seen in contact box'), + + // make customer + () => frappe.click_button('Make'), + () => frappe.click_link('customer'), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.lead_name, frappe.lead_name, + 'lead name correctly mapped'), + + () => done() + ]); }); diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index 763e5335ce7..2781076e26e 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -21,3 +21,14 @@ class TestLead(unittest.TestCase): customer.company = "_Test Company" customer.customer_group = "_Test Customer Group" customer.insert() + + def test_make_customer_from_organization(self): + from erpnext.crm.doctype.lead.lead import make_customer + + customer = make_customer("_T-Lead-00002") + self.assertEquals(customer.doctype, "Customer") + self.assertEquals(customer.lead_name, "_T-Lead-00002") + + customer.company = "_Test Company" + customer.customer_group = "_Test Customer Group" + customer.insert() diff --git a/erpnext/crm/doctype/lead/test_records.json b/erpnext/crm/doctype/lead/test_records.json index 01b0a992d2c..590e200cf98 100644 --- a/erpnext/crm/doctype/lead/test_records.json +++ b/erpnext/crm/doctype/lead/test_records.json @@ -23,5 +23,13 @@ "email_id": "test_lead3@example.com", "lead_name": "_Test Lead 3", "status": "Converted" - } +}, +{ + "doctype": "Lead", + "email_id": "test_lead4@example.com", + "organization_lead": 1, + "lead_name": "_Test Lead 4", + "organization_name": "_Test Lead 4", + "status": "Open" +} ] diff --git a/erpnext/docs/user/manual/en/CRM/lead.md b/erpnext/docs/user/manual/en/CRM/lead.md index 15b1159d8de..2a48166f8b3 100644 --- a/erpnext/docs/user/manual/en/CRM/lead.md +++ b/erpnext/docs/user/manual/en/CRM/lead.md @@ -43,6 +43,9 @@ A Lead is a potential Customer, someone who can give you business. A Customer is organization or individual who has given you business before (and has an Account in your system). A Contact is a person who belongs to the Customer. +A Lead can sometimes be an organization you are trying to make a deal with. In this case you can select "Lead is an Organization" and add as many contacts within this organization as you want. +It is useful if you are establishing a relationship with several people within the same organization. + A Lead can be converted to a Customer by selecting “Customer” from the **Make** dropdown. Once the Customer is created, the Lead becomes “Converted” and any further Opportunities from the same source can be created against this diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index a24f4a368e3..8e459212785 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -88,30 +88,44 @@ class Customer(TransactionBase): address.append('links', dict(link_doctype='Customer', link_name=self.name)) address.save() - lead = frappe.db.get_value("Lead", self.lead_name, ["lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True) + lead = frappe.db.get_value("Lead", self.lead_name, ["organization_lead", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True) if not lead.lead_name: frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name)) - lead.lead_name = lead.lead_name.split(" ") - lead.first_name = lead.lead_name[0] - lead.last_name = " ".join(lead.lead_name[1:]) + if lead.organization_lead: + contact_names = frappe.get_all('Dynamic Link', filters={ + "parenttype":"Contact", + "link_doctype":"Lead", + "link_name":self.lead_name + }, fields=["parent as name"]) - # create contact from lead - contact = frappe.new_doc('Contact') - contact.first_name = lead.first_name - contact.last_name = lead.last_name - contact.gender = lead.gender - contact.salutation = lead.salutation - contact.email_id = lead.email_id - contact.phone = lead.phone - contact.mobile_no = lead.mobile_no - contact.is_primary_contact = 1 - contact.append('links', dict(link_doctype='Customer', link_name=self.name)) - contact.flags.ignore_permissions = self.flags.ignore_permissions - contact.autoname() - if not frappe.db.exists("Contact", contact.name): - contact.insert() + for contact_name in contact_names: + contact = frappe.get_doc('Contact', contact_name.get('name')) + if not contact.has_link('Customer', self.name): + contact.append('links', dict(link_doctype='Customer', link_name=self.name)) + contact.save() + + else: + lead.lead_name = lead.lead_name.split(" ") + lead.first_name = lead.lead_name[0] + lead.last_name = " ".join(lead.lead_name[1:]) + + # create contact from lead + contact = frappe.new_doc('Contact') + contact.first_name = lead.first_name + contact.last_name = lead.last_name + contact.gender = lead.gender + contact.salutation = lead.salutation + contact.email_id = lead.email_id + contact.phone = lead.phone + contact.mobile_no = lead.mobile_no + contact.is_primary_contact = 1 + contact.append('links', dict(link_doctype='Customer', link_name=self.name)) + contact.flags.ignore_permissions = self.flags.ignore_permissions + contact.autoname() + if not frappe.db.exists("Contact", contact.name): + contact.insert() def validate_name_with_customer_group(self): if frappe.db.exists("Customer Group", self.name): @@ -231,4 +245,4 @@ def get_credit_limit(customer, company): if not credit_limit: credit_limit = frappe.db.get_value("Company", company, "credit_limit") - return flt(credit_limit) \ No newline at end of file + return flt(credit_limit)