feat: create address and contact after lead creation

This commit is contained in:
Rohan Bansal 2019-08-13 17:15:44 +05:30
parent 638abca498
commit 312210c2b0
3 changed files with 187 additions and 78 deletions

View File

@ -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));
}
}

View File

@ -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",

View File

@ -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
return lead