feat: auto assign lead/opportunity to lead owner, customer account manager

This commit is contained in:
Rushabh Mehta 2019-04-12 09:04:17 +05:30
parent 0ff5a7b30f
commit 4f49ce4124
6 changed files with 1673 additions and 1497 deletions

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ from frappe.model.mapper import get_mapped_doc
from erpnext.setup.utils import get_exchange_rate
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.accounts.party import get_party_account_currency
from frappe.desk.form import assign_to
subject_field = "title"
sender_field = "contact_email"
@ -153,6 +154,9 @@ class Opportunity(TransactionBase):
def on_update(self):
self.add_calendar_event()
# assign to customer account manager or lead owner
assign_to_user(self, subject_field)
def add_calendar_event(self, opts=None, force=False):
if not opts:
opts = frappe._dict()
@ -329,3 +333,19 @@ def auto_close_opportunity():
doc.flags.ignore_permissions = True
doc.flags.ignore_mandatory = True
doc.save()
def assign_to_user(doc, subject_field):
assign_user = None
if doc.customer:
assign_user = frappe.db.get_value('Customer', doc.customer, 'account_manager')
elif doc.lead:
assign_user = frappe.db.get_value('Lead', doc.lead, 'lead_owner')
if assign_user:
if not assign_to.get(dict(doctype = doc.doctype, name = doc.name)):
assign_to.add({
"assign_to": assign_user,
"doctype": doc.doctype,
"name": doc.name,
"description": doc.get(subject_field)
})

View File

@ -3,10 +3,11 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import today
from frappe.utils import today, random_string
from erpnext.crm.doctype.lead.lead import make_customer
from erpnext.crm.doctype.opportunity.opportunity import make_quotation
import unittest
from frappe.desk.form import assign_to
test_records = frappe.get_test_records('Opportunity')
@ -27,9 +28,10 @@ class TestOpportunity(unittest.TestCase):
self.assertEqual(doc.status, "Quotation")
def test_make_new_lead_if_required(self):
new_lead_email_id = "new{}@example.com".format(random_string(5))
args = {
"doctype": "Opportunity",
"contact_email":"new.opportunity@example.com",
"contact_email": new_lead_email_id,
"opportunity_type": "Sales",
"with_items": 0,
"transaction_date": today()
@ -40,13 +42,13 @@ class TestOpportunity(unittest.TestCase):
self.assertTrue(opp_doc.lead)
self.assertEqual(opp_doc.enquiry_from, "Lead")
self.assertEqual(frappe.db.get_value("Lead", opp_doc.lead, "email_id"),
'new.opportunity@example.com')
new_lead_email_id)
# create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.lead).insert(ignore_permissions=True)
frappe.get_doc({
"doctype": "Contact",
"email_id": "new.opportunity@example.com",
"email_id": new_lead_email_id,
"first_name": "_Test Opportunity Customer",
"links": [{
"link_doctype": "Customer",
@ -59,6 +61,21 @@ class TestOpportunity(unittest.TestCase):
self.assertEqual(opp_doc.enquiry_from, "Customer")
self.assertEqual(opp_doc.customer, customer.name)
def test_assignment(self):
# assign cutomer account manager
frappe.db.set_value('Customer', '_Test Customer', 'account_manager', 'test1@example.com')
doc = make_opportunity(with_items=0)
self.assertEqual(assign_to.get(dict(doctype = doc.doctype, name = doc.name))[0].get('owner'), 'test1@example.com')
# assign lead owner
frappe.db.set_value('Customer', '_Test Customer', 'account_manager', '')
frappe.db.set_value('Lead', '_T-Lead-00001', 'lead_owner', 'test2@example.com')
doc = make_opportunity(with_items=0, enquiry_from='Lead')
self.assertEqual(assign_to.get(dict(doctype = doc.doctype, name = doc.name))[0].get('owner'), 'test2@example.com')
def make_opportunity(**args):
args = frappe._dict(args)
@ -75,7 +92,7 @@ def make_opportunity(**args):
opp_doc.customer = args.customer or "_Test Customer"
if opp_doc.enquiry_from == 'Lead':
opp_doc.customer = args.lead or "_T-Lead-00001"
opp_doc.lead = args.lead or "_T-Lead-00001"
if args.with_items:
opp_doc.append('items', {

View File

@ -22,6 +22,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "basic_info",
"fieldtype": "Section Break",
"hidden": 0,
@ -56,6 +57,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
@ -89,6 +91,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.customer_type!='Company'",
"fetch_if_empty": 0,
"fieldname": "salutation",
"fieldtype": "Link",
"hidden": 0,
@ -122,6 +125,7 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_name",
"fieldtype": "Data",
"hidden": 0,
@ -156,6 +160,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.customer_type != 'Company'",
"fetch_if_empty": 0,
"fieldname": "gender",
"fieldtype": "Link",
"hidden": 0,
@ -190,6 +195,7 @@
"collapsible": 0,
"columns": 0,
"default": "Company",
"fetch_if_empty": 0,
"fieldname": "customer_type",
"fieldtype": "Select",
"hidden": 0,
@ -224,6 +230,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_bank_account",
"fieldtype": "Link",
"hidden": 0,
@ -257,6 +264,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "lead_name",
"fieldtype": "Link",
"hidden": 0,
@ -291,6 +299,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@ -323,6 +332,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break0",
"fieldtype": "Column Break",
"hidden": 0,
@ -347,6 +357,40 @@
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "account_manager",
"fieldtype": "Link",
"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": "Account Manager",
"length": 0,
"no_copy": 0,
"options": "User",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -355,6 +399,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 0,
@ -390,6 +435,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "territory",
"fieldtype": "Link",
"hidden": 0,
@ -424,6 +470,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "tax_id",
"fieldtype": "Data",
"hidden": 0,
@ -456,6 +503,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "tax_category",
"fieldtype": "Link",
"hidden": 0,
@ -490,6 +538,7 @@
"collapsible": 0,
"columns": 0,
"default": "0",
"fetch_if_empty": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
@ -523,6 +572,7 @@
"collapsible": 0,
"columns": 0,
"default": "0",
"fetch_if_empty": 0,
"fieldname": "is_internal_customer",
"fieldtype": "Check",
"hidden": 0,
@ -556,6 +606,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "is_internal_customer",
"fetch_if_empty": 0,
"fieldname": "represents_company",
"fieldtype": "Link",
"hidden": 0,
@ -590,6 +641,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "represents_company",
"fetch_if_empty": 0,
"fieldname": "allowed_to_transact_section",
"fieldtype": "Section Break",
"hidden": 0,
@ -623,6 +675,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "represents_company",
"fetch_if_empty": 0,
"fieldname": "companies",
"fieldtype": "Table",
"hidden": 0,
@ -656,6 +709,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
"hidden": 0,
@ -688,6 +742,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_currency",
"fieldtype": "Link",
"hidden": 0,
@ -720,6 +775,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
"hidden": 0,
@ -752,6 +808,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_14",
"fieldtype": "Column Break",
"hidden": 0,
@ -783,6 +840,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "language",
"fieldtype": "Link",
"hidden": 0,
@ -817,6 +875,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"fetch_if_empty": 0,
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"hidden": 0,
@ -849,6 +908,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
"hidden": 0,
@ -880,6 +940,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "website",
"fieldtype": "Data",
"hidden": 0,
@ -911,6 +972,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
@ -942,6 +1004,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
"hidden": 0,
@ -975,6 +1038,7 @@
"collapsible": 0,
"columns": 0,
"description": "Select, to make the customer searchable with these fields",
"fetch_if_empty": 0,
"fieldname": "primary_address_and_contact_detail",
"fieldtype": "Section Break",
"hidden": 0,
@ -1008,6 +1072,7 @@
"collapsible": 0,
"columns": 0,
"description": "Reselect, if the chosen contact is edited after save",
"fetch_if_empty": 0,
"fieldname": "customer_primary_contact",
"fieldtype": "Link",
"hidden": 0,
@ -1042,6 +1107,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "customer_primary_contact.mobile_no",
"fetch_if_empty": 0,
"fieldname": "mobile_no",
"fieldtype": "Read Only",
"hidden": 0,
@ -1076,6 +1142,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "customer_primary_contact.email_id",
"fetch_if_empty": 0,
"fieldname": "email_id",
"fieldtype": "Read Only",
"hidden": 0,
@ -1109,6 +1176,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_26",
"fieldtype": "Column Break",
"hidden": 0,
@ -1141,6 +1209,7 @@
"collapsible": 0,
"columns": 0,
"description": "Reselect, if the chosen address is edited after save",
"fetch_if_empty": 0,
"fieldname": "customer_primary_address",
"fieldtype": "Link",
"hidden": 0,
@ -1175,6 +1244,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_if_empty": 0,
"fieldname": "primary_address",
"fieldtype": "Read Only",
"hidden": 0,
@ -1209,6 +1279,7 @@
"collapsible": 1,
"collapsible_depends_on": "",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_receivable_accounts",
"fieldtype": "Section Break",
"hidden": 0,
@ -1242,6 +1313,7 @@
"columns": 0,
"depends_on": "",
"description": "Mention if non-standard receivable account",
"fetch_if_empty": 0,
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
@ -1275,6 +1347,7 @@
"collapsible": 1,
"collapsible_depends_on": "",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "credit_limit_section",
"fieldtype": "Section Break",
"hidden": 0,
@ -1307,6 +1380,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "credit_limit",
"fieldtype": "Currency",
"hidden": 0,
@ -1342,6 +1416,7 @@
"collapsible": 0,
"columns": 0,
"default": "0",
"fetch_if_empty": 0,
"fieldname": "bypass_credit_limit_check_at_sales_order",
"fieldtype": "Check",
"hidden": 0,
@ -1374,6 +1449,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_34",
"fieldtype": "Column Break",
"hidden": 0,
@ -1406,6 +1482,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "payment_terms",
"fieldtype": "Link",
"hidden": 0,
@ -1440,6 +1517,7 @@
"collapsible": 1,
"collapsible_depends_on": "customer_details",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
"hidden": 0,
@ -1474,6 +1552,7 @@
"collapsible": 0,
"columns": 0,
"description": "Additional information regarding the customer.",
"fetch_if_empty": 0,
"fieldname": "customer_details",
"fieldtype": "Text",
"hidden": 0,
@ -1507,6 +1586,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_45",
"fieldtype": "Column Break",
"hidden": 0,
@ -1538,6 +1618,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "market_segment",
"fieldtype": "Link",
"hidden": 0,
@ -1571,6 +1652,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "industry",
"fieldtype": "Link",
"hidden": 0,
@ -1604,6 +1686,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "is_frozen",
"fieldtype": "Check",
"hidden": 0,
@ -1636,6 +1719,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_38",
"fieldtype": "Section Break",
"hidden": 0,
@ -1668,6 +1752,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "loyalty_program",
"fieldtype": "Link",
"hidden": 0,
@ -1701,6 +1786,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "loyalty_program_tier",
"fieldtype": "Data",
"hidden": 0,
@ -1734,6 +1820,7 @@
"collapsible": 1,
"collapsible_depends_on": "default_sales_partner",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_team_section_break",
"fieldtype": "Section Break",
"hidden": 0,
@ -1767,6 +1854,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_sales_partner",
"fieldtype": "Link",
"hidden": 0,
@ -1801,6 +1889,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_commission_rate",
"fieldtype": "Float",
"hidden": 0,
@ -1835,6 +1924,7 @@
"collapsible": 1,
"collapsible_depends_on": "sales_team",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_team_section",
"fieldtype": "Section Break",
"hidden": 0,
@ -1867,6 +1957,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_team",
"fieldtype": "Table",
"hidden": 0,
@ -1901,6 +1992,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_pos_id",
"fieldtype": "Data",
"hidden": 0,
@ -1928,18 +2020,17 @@
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-17 13:10:24.360876",
"menu_index": 0,
"modified": "2019-04-12 08:45:39.357491",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
@ -2120,7 +2211,6 @@
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "customer_name,customer_group,territory, mobile_no,primary_address",
"show_name_in_global_search": 1,
"sort_order": "ASC",
@ -2128,4 +2218,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View File

@ -12,6 +12,7 @@ from datetime import datetime, timedelta
from frappe.model.mapper import get_mapped_doc
from frappe.utils.user import is_website_user
from ..service_level_agreement.service_level_agreement import get_active_service_level_agreement_for
from erpnext.crm.doctype.opportunity.opportunity import assign_to_user
sender_field = "raised_by"
@ -40,6 +41,9 @@ class Issue(Document):
self.create_communication()
self.flags.communication_created = None
# assign to customer account manager or lead owner
assign_to_user(self, 'subject')
def set_lead_contact(self, email_id):
import email.utils

View File

@ -8,8 +8,14 @@ from erpnext.support.doctype.service_level_agreement.test_service_level_agreemen
from frappe.utils import now_datetime
import datetime
from datetime import timedelta
from frappe.desk.form import assign_to
class TestIssue(unittest.TestCase):
def test_assignment(self):
frappe.db.set_value('Customer', '_Test Customer', 'account_manager', 'test1@example.com')
doc = make_issue(customer='_Test Customer')
self.assertEqual(assign_to.get(dict(doctype = doc.doctype, name = doc.name))[0].get('owner'), 'test1@example.com')
def test_response_time_and_resolution_time_based_on_different_sla(self):
make_service_level_agreement()
@ -54,7 +60,7 @@ class TestIssue(unittest.TestCase):
def make_issue(creation, customer=None):
def make_issue(creation=None, customer=None):
issue = frappe.get_doc({
"doctype": "Issue",