Merge pull request #28458 from anupamvs/crm-carry-forward-communication-comments

feat: carry forward communication and comments throughout the sales c…
This commit is contained in:
rohitwaghchaure 2022-01-03 10:19:56 +05:30 committed by GitHub
commit 650b388bc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 21 deletions

View File

@ -17,7 +17,9 @@
"column_break_9",
"create_event_on_next_contact_date_opportunity",
"quotation_section",
"default_valid_till"
"default_valid_till",
"section_break_13",
"carry_forward_communication_and_comments"
],
"fields": [
{
@ -85,13 +87,25 @@
"fieldname": "quotation_section",
"fieldtype": "Section Break",
"label": "Quotation"
},
{
"fieldname": "section_break_13",
"fieldtype": "Section Break",
"label": "Other Settings"
},
{
"default": "0",
"description": "All the Comments and Emails will be copied from one document to another newly created document(Lead -> Opportunity -> Quotation) throughout the CRM documents.",
"fieldname": "carry_forward_communication_and_comments",
"fieldtype": "Check",
"label": "Carry Forward Communication and Comments"
}
],
"icon": "fa fa-cog",
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-11-03 10:00:36.883496",
"modified": "2021-12-20 12:51:38.894252",
"modified_by": "Administrator",
"module": "CRM",
"name": "CRM Settings",
@ -105,6 +119,26 @@
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Sales Master Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",

View File

@ -11,6 +11,7 @@ from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import DocType
from frappe.utils import cint, cstr, flt, get_fullname
from erpnext.crm.utils import add_link_in_communication, copy_comments
from erpnext.setup.utils import get_exchange_rate
from erpnext.utilities.transaction_base import TransactionBase
@ -20,6 +21,11 @@ class Opportunity(TransactionBase):
if self.opportunity_from == "Lead":
frappe.get_doc("Lead", self.party_name).set_status(update=True)
if self.opportunity_from in ["Lead", "Prospect"]:
if frappe.db.get_single_value("CRM Settings", "carry_forward_communication_and_comments"):
copy_comments(self.opportunity_from, self.party_name, self)
add_link_in_communication(self.opportunity_from, self.party_name, self)
def validate(self):
self._prev = frappe._dict({
"contact_date": frappe.db.get_value("Opportunity", self.name, "contact_date") if \

View File

@ -4,10 +4,12 @@
import unittest
import frappe
from frappe.utils import random_string, today
from frappe.utils import now_datetime, random_string, today
from erpnext.crm.doctype.lead.lead import make_customer
from erpnext.crm.doctype.lead.test_lead import make_lead
from erpnext.crm.doctype.opportunity.opportunity import make_quotation
from erpnext.crm.utils import get_linked_communication_list
test_records = frappe.get_test_records('Opportunity')
@ -28,21 +30,11 @@ 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_lead_email_id,
"opportunity_type": "Sales",
"with_items": 0,
"transaction_date": today()
}
# new lead should be created against the new.opportunity@example.com
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
opp_doc = make_opportunity_from_lead()
self.assertTrue(opp_doc.party_name)
self.assertEqual(opp_doc.opportunity_from, "Lead")
self.assertEqual(frappe.db.get_value("Lead", opp_doc.party_name, "email_id"),
new_lead_email_id)
self.assertEqual(frappe.db.get_value("Lead", opp_doc.party_name, "email_id"), opp_doc.contact_email)
# create new customer and create new contact against 'new.opportunity@example.com'
customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True)
@ -54,18 +46,60 @@ class TestOpportunity(unittest.TestCase):
"link_name": customer.name
}]
})
contact.add_email(new_lead_email_id, is_primary=True)
contact.add_email(opp_doc.contact_email, is_primary=True)
contact.insert(ignore_permissions=True)
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
self.assertTrue(opp_doc.party_name)
self.assertEqual(opp_doc.opportunity_from, "Customer")
self.assertEqual(opp_doc.party_name, customer.name)
def test_opportunity_item(self):
opportunity_doc = make_opportunity(with_items=1, rate=1100, qty=2)
self.assertEqual(opportunity_doc.total, 2200)
def test_carry_forward_of_email_and_comments(self):
frappe.db.set_value("CRM Settings", "CRM Settings", "carry_forward_communication_and_comments", 1)
lead_doc = make_lead()
lead_doc.add_comment('Comment', text='Test Comment 1')
lead_doc.add_comment('Comment', text='Test Comment 2')
create_communication(lead_doc.doctype, lead_doc.name, lead_doc.email_id)
create_communication(lead_doc.doctype, lead_doc.name, lead_doc.email_id)
opp_doc = make_opportunity(opportunity_from="Lead", lead=lead_doc.name)
opportunity_comment_count = frappe.db.count("Comment", {"reference_doctype": opp_doc.doctype, "reference_name": opp_doc.name})
opportunity_communication_count = len(get_linked_communication_list(opp_doc.doctype, opp_doc.name))
self.assertEqual(opportunity_comment_count, 2)
self.assertEqual(opportunity_communication_count, 2)
opp_doc.add_comment('Comment', text='Test Comment 3')
opp_doc.add_comment('Comment', text='Test Comment 4')
create_communication(opp_doc.doctype, opp_doc.name, opp_doc.contact_email)
create_communication(opp_doc.doctype, opp_doc.name, opp_doc.contact_email)
quotation_doc = make_quotation(opp_doc.name)
quotation_doc.append('items', {
"item_code": "_Test Item",
"qty": 1
})
quotation_doc.run_method("set_missing_values")
quotation_doc.run_method("calculate_taxes_and_totals")
quotation_doc.save()
quotation_comment_count = frappe.db.count("Comment", {"reference_doctype": quotation_doc.doctype, "reference_name": quotation_doc.name, "comment_type": "Comment"})
quotation_communication_count = len(get_linked_communication_list(quotation_doc.doctype, quotation_doc.name))
self.assertEqual(quotation_comment_count, 4)
self.assertEqual(quotation_communication_count, 4)
def make_opportunity_from_lead():
new_lead_email_id = "new{}@example.com".format(random_string(5))
args = {
"doctype": "Opportunity",
"contact_email": new_lead_email_id,
"opportunity_type": "Sales",
"with_items": 0,
"transaction_date": today()
}
# new lead should be created against the new.opportunity@example.com
opp_doc = frappe.get_doc(args).insert(ignore_permissions=True)
return opp_doc
def make_opportunity(**args):
args = frappe._dict(args)
@ -95,3 +129,20 @@ def make_opportunity(**args):
opp_doc.insert()
return opp_doc
def create_communication(reference_doctype, reference_name, sender, sent_or_received=None, creation=None):
communication = frappe.get_doc({
"doctype": "Communication",
"communication_type": "Communication",
"communication_medium": "Email",
"sent_or_received": sent_or_received or "Sent",
"email_status": "Open",
"subject": "Test Subject",
"sender": sender,
"content": "Test",
"status": "Linked",
"reference_doctype": reference_doctype,
"creation": creation or now_datetime(),
"reference_name": reference_name
})
communication.save()

View File

@ -6,6 +6,8 @@ from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from erpnext.crm.utils import add_link_in_communication, copy_comments
class Prospect(Document):
def onload(self):
@ -20,6 +22,12 @@ class Prospect(Document):
def on_trash(self):
self.unlink_dynamic_links()
def after_insert(self):
if frappe.db.get_single_value("CRM Settings", "carry_forward_communication_and_comments"):
for row in self.get('prospect_lead'):
copy_comments("Lead", row.lead, self)
add_link_in_communication("Lead", row.lead, self)
def update_lead_details(self):
for row in self.get('prospect_lead'):
lead = frappe.get_value('Lead', row.lead, ['lead_name', 'status', 'email_id', 'mobile_no'], as_dict=True)

View File

@ -21,3 +21,30 @@ def update_lead_phone_numbers(contact, method):
lead = frappe.get_doc("Lead", contact_lead)
lead.db_set("phone", phone)
lead.db_set("mobile_no", mobile_no)
def copy_comments(doctype, docname, doc):
comments = frappe.db.get_values("Comment", filters={"reference_doctype": doctype, "reference_name": docname, "comment_type": "Comment"}, fieldname="*")
for comment in comments:
comment = frappe.get_doc(comment.update({"doctype":"Comment"}))
comment.name = None
comment.reference_doctype = doc.doctype
comment.reference_name = doc.name
comment.insert()
def add_link_in_communication(doctype, docname, doc):
communication_list = get_linked_communication_list(doctype, docname)
for communication in communication_list:
communication_doc = frappe.get_doc("Communication", communication)
communication_doc.add_link(doc.doctype, doc.name, autosave=True)
def get_linked_communication_list(doctype, docname):
communications = frappe.get_all("Communication", filters={"reference_doctype": doctype, "reference_name": docname}, pluck='name')
communication_links = frappe.get_all('Communication Link',
{
"link_doctype": doctype,
"link_name": docname,
"parent": ("not in", communications)
}, pluck="parent")
return communications + communication_links

View File

@ -8,6 +8,7 @@ from frappe.model.mapper import get_mapped_doc
from frappe.utils import flt, getdate, nowdate
from erpnext.controllers.selling_controller import SellingController
from erpnext.crm.utils import add_link_in_communication, copy_comments
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@ -34,6 +35,16 @@ class Quotation(SellingController):
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
make_packing_list(self)
def after_insert(self):
if frappe.db.get_single_value("CRM Settings", "carry_forward_communication_and_comments"):
if self.opportunity:
copy_comments("Opportunity", self.opportunity, self)
add_link_in_communication("Opportunity", self.opportunity, self)
elif self.quotation_to == "Lead" and self.party_name:
copy_comments("Lead", self.party_name, self)
add_link_in_communication("Lead", self.party_name, self)
def validate_valid_till(self):
if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
frappe.throw(_("Valid till date cannot be before transaction date"))