feat: made carry-forward comments/communication configurable and added test cases
diff --git a/erpnext/crm/doctype/crm_settings/crm_settings.json b/erpnext/crm/doctype/crm_settings/crm_settings.json
index 8f0fa31..a2d608b 100644
--- a/erpnext/crm/doctype/crm_settings/crm_settings.json
+++ b/erpnext/crm/doctype/crm_settings/crm_settings.json
@@ -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,23 @@
"fieldname": "quotation_section",
"fieldtype": "Section Break",
"label": "Quotation"
+ },
+ {
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break"
+ },
+ {
+ "default": "0",
+ "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-14 16:51:57.839939",
"modified_by": "Administrator",
"module": "CRM",
"name": "CRM Settings",
@@ -105,6 +117,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",
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 6b4c3d5..a4fd765 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -22,8 +22,9 @@
frappe.get_doc("Lead", self.party_name).set_status(update=True)
if self.opportunity_from in ["Lead", "Prospect"]:
- copy_comments(self.opportunity_from, self.party_name, self)
- add_link_in_communication(self.opportunity_from, self.party_name, self)
+ 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({
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 6e6fed5..1bc58cd 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -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.opportunity.opportunity import make_quotation
+from erpnext.crm.doctype.lead.test_lead import make_lead
+from erpnext.crm.utils import get_linked_communication_list
test_records = frappe.get_test_records('Opportunity')
@@ -28,16 +30,7 @@
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")
@@ -66,6 +59,53 @@
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 +135,20 @@
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()
\ No newline at end of file
diff --git a/erpnext/crm/doctype/prospect/prospect.py b/erpnext/crm/doctype/prospect/prospect.py
index c255310..cc4c1d3 100644
--- a/erpnext/crm/doctype/prospect/prospect.py
+++ b/erpnext/crm/doctype/prospect/prospect.py
@@ -23,9 +23,10 @@
self.unlink_dynamic_links()
def after_insert(self):
- for row in self.get('prospect_lead'):
- copy_comments("Lead", row.lead, self)
- add_link_in_communication("Lead", row.lead, 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'):
diff --git a/erpnext/crm/utils.py b/erpnext/crm/utils.py
index 8ae991f..741df9d 100644
--- a/erpnext/crm/utils.py
+++ b/erpnext/crm/utils.py
@@ -23,7 +23,7 @@
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}, fieldname="*")
+ 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
@@ -32,6 +32,13 @@
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',
{
@@ -39,7 +46,5 @@
"link_name": docname,
"parent": ("not in", communications)
}, pluck="parent")
-
- for communication in communications + communication_links:
- communication_doc = frappe.get_doc("Communication", communication)
- communication_doc.add_link(doc.doctype, doc.name, autosave=True)
+
+ return communications + communication_links
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 2bb9b55..daab6fb 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -36,13 +36,14 @@
make_packing_list(self)
def after_insert(self):
- if self.opportunity:
- copy_comments("Opportunity", self.opportunity, self)
- add_link_in_communication("Opportunity", self.opportunity, 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)
+ 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):