From 28c3d24b862d90b1122c4357ee643fb271a7d321 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 29 May 2026 13:26:31 +0530 Subject: [PATCH] refactor(lead): move mapping functions to mapper.py --- erpnext/crm/doctype/lead/lead.py | 163 +--------------------------- erpnext/crm/doctype/lead/mapper.py | 169 +++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 161 deletions(-) create mode 100644 erpnext/crm/doctype/lead/mapper.py diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index b4dbf719a12..e5a6ce7632d 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -7,11 +7,7 @@ from frappe.contacts.address_and_contact import ( delete_contact_and_address, load_address_and_contact, ) -from frappe.contacts.doctype.address.address import get_default_address -from frappe.contacts.doctype.contact.contact import get_default_contact -from frappe.email.inbox import link_communication_to_document from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc from frappe.utils import comma_and, get_link_to_form, has_gravatar, validate_email_address from frappe.utils.data import DateTimeLikeObject @@ -20,6 +16,8 @@ from erpnext.controllers.selling_controller import SellingController from erpnext.crm.utils import CRMNote, copy_comments, link_communications, link_open_events from erpnext.selling.doctype.customer.customer import parse_full_name +from .mapper import make_customer, make_lead_from_communication, make_opportunity, make_quotation + class Lead(SellingController, CRMNote): # begin: auto-generated types @@ -322,134 +320,6 @@ class Lead(SellingController, CRMNote): return None -@frappe.whitelist() -def make_customer(source_name: str, target_doc: str | Document | None = 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: - target.customer_type = "Company" - target.customer_name = source.company_name - else: - target.customer_type = "Individual" - target.customer_name = source.lead_name - - if not target.customer_group: - target.customer_group = frappe.db.get_default("Customer Group") - - address = get_default_address("Lead", source.name) - contact = get_default_contact("Lead", source.name) - if address: - target.customer_primary_address = address - if contact: - target.customer_primary_contact = contact - - doclist = get_mapped_doc( - "Lead", - source_name, - { - "Lead": { - "doctype": "Customer", - "field_map": { - "name": "lead_name", - "company_name": "customer_name", - "contact_no": "phone_1", - "fax": "fax_1", - }, - "field_no_map": ["disabled"], - } - }, - target_doc, - set_missing_values, - ignore_permissions=ignore_permissions, - ) - - return doclist - - -@frappe.whitelist() -def make_opportunity(source_name: str, target_doc: str | Document | None = None): - def set_missing_values(source, target): - _set_missing_values(source, target) - - target_doc = get_mapped_doc( - "Lead", - source_name, - { - "Lead": { - "doctype": "Opportunity", - "field_map": { - "doctype": "opportunity_from", - "name": "party_name", - "lead_name": "contact_display", - "company_name": "customer_name", - "email_id": "contact_email", - "mobile_no": "contact_mobile", - "lead_owner": "opportunity_owner", - "notes": "notes", - }, - } - }, - target_doc, - set_missing_values, - ) - - return target_doc - - -@frappe.whitelist() -def make_quotation(source_name: str, target_doc: str | Document | None = None): - def set_missing_values(source, target): - _set_missing_values(source, target) - - target_doc = get_mapped_doc( - "Lead", - source_name, - {"Lead": {"doctype": "Quotation", "field_map": {"name": "party_name"}}}, - target_doc, - set_missing_values, - ) - - target_doc.quotation_to = "Lead" - target_doc.run_method("set_missing_values") - target_doc.run_method("set_other_charges") - target_doc.run_method("calculate_taxes_and_totals") - - return target_doc - - -def _set_missing_values(source, target): - address = frappe.get_all( - "Dynamic Link", - { - "link_doctype": source.doctype, - "link_name": source.name, - "parenttype": "Address", - }, - ["parent"], - limit=1, - ) - - contact = frappe.get_all( - "Dynamic Link", - { - "link_doctype": source.doctype, - "link_name": source.name, - "parenttype": "Contact", - }, - ["parent"], - limit=1, - ) - - if address: - target.customer_address = address[0].parent - - if contact: - target.contact_person = contact[0].parent - - @frappe.whitelist() def get_lead_details( lead: str, @@ -494,35 +364,6 @@ def get_lead_details( return out -@frappe.whitelist() -def make_lead_from_communication(communication: str, ignore_communication_links: bool = False): - """raise a issue from email""" - - doc = frappe.get_doc("Communication", communication) - lead_name = None - if doc.sender: - lead_name = frappe.db.get_value("Lead", {"email_id": doc.sender}) - if not lead_name and doc.phone_no: - lead_name = frappe.db.get_value("Lead", {"mobile_no": doc.phone_no}) - if not lead_name: - lead = frappe.get_doc( - { - "doctype": "Lead", - "lead_name": doc.sender_full_name, - "email_id": doc.sender, - "mobile_no": doc.phone_no, - } - ) - lead.flags.ignore_mandatory = True - lead.flags.ignore_permissions = True - lead.insert() - - lead_name = lead.name - - link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links) - return lead_name - - def get_lead_with_phone_number(number): if not number: return diff --git a/erpnext/crm/doctype/lead/mapper.py b/erpnext/crm/doctype/lead/mapper.py new file mode 100644 index 00000000000..b90fba19a79 --- /dev/null +++ b/erpnext/crm/doctype/lead/mapper.py @@ -0,0 +1,169 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe +from frappe import _ +from frappe.contacts.doctype.address.address import get_default_address +from frappe.contacts.doctype.contact.contact import get_default_contact +from frappe.email.inbox import link_communication_to_document +from frappe.model.document import Document +from frappe.model.mapper import get_mapped_doc + + +@frappe.whitelist() +def make_customer(source_name: str, target_doc: str | Document | None = None): + return _make_customer(source_name, target_doc) + + +def _make_customer( + source_name: str, target_doc: str | Document | None = None, ignore_permissions: bool = False +): + def set_missing_values(source, target): + if source.company_name: + target.customer_type = "Company" + target.customer_name = source.company_name + else: + target.customer_type = "Individual" + target.customer_name = source.lead_name + + if not target.customer_group: + target.customer_group = frappe.db.get_default("Customer Group") + + address = get_default_address("Lead", source.name) + contact = get_default_contact("Lead", source.name) + if address: + target.customer_primary_address = address + if contact: + target.customer_primary_contact = contact + + doclist = get_mapped_doc( + "Lead", + source_name, + { + "Lead": { + "doctype": "Customer", + "field_map": { + "name": "lead_name", + "company_name": "customer_name", + "contact_no": "phone_1", + "fax": "fax_1", + }, + "field_no_map": ["disabled"], + } + }, + target_doc, + set_missing_values, + ignore_permissions=ignore_permissions, + ) + + return doclist + + +@frappe.whitelist() +def make_opportunity(source_name: str, target_doc: str | Document | None = None): + def set_missing_values(source, target): + _set_missing_values(source, target) + + target_doc = get_mapped_doc( + "Lead", + source_name, + { + "Lead": { + "doctype": "Opportunity", + "field_map": { + "doctype": "opportunity_from", + "name": "party_name", + "lead_name": "contact_display", + "company_name": "customer_name", + "email_id": "contact_email", + "mobile_no": "contact_mobile", + "lead_owner": "opportunity_owner", + "notes": "notes", + }, + } + }, + target_doc, + set_missing_values, + ) + + return target_doc + + +@frappe.whitelist() +def make_quotation(source_name: str, target_doc: str | Document | None = None): + def set_missing_values(source, target): + _set_missing_values(source, target) + + target_doc = get_mapped_doc( + "Lead", + source_name, + {"Lead": {"doctype": "Quotation", "field_map": {"name": "party_name"}}}, + target_doc, + set_missing_values, + ) + + target_doc.quotation_to = "Lead" + target_doc.run_method("set_missing_values") + target_doc.run_method("set_other_charges") + target_doc.run_method("calculate_taxes_and_totals") + + return target_doc + + +@frappe.whitelist() +def make_lead_from_communication(communication: str, ignore_communication_links: bool = False): + """raise a issue from email""" + + doc = frappe.get_doc("Communication", communication) + lead_name = None + if doc.sender: + lead_name = frappe.db.get_value("Lead", {"email_id": doc.sender}) + if not lead_name and doc.phone_no: + lead_name = frappe.db.get_value("Lead", {"mobile_no": doc.phone_no}) + if not lead_name: + lead = frappe.get_doc( + { + "doctype": "Lead", + "lead_name": doc.sender_full_name, + "email_id": doc.sender, + "mobile_no": doc.phone_no, + } + ) + lead.flags.ignore_mandatory = True + lead.flags.ignore_permissions = True + lead.insert() + + lead_name = lead.name + + link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links) + return lead_name + + +def _set_missing_values(source, target): + address = frappe.get_all( + "Dynamic Link", + { + "link_doctype": source.doctype, + "link_name": source.name, + "parenttype": "Address", + }, + ["parent"], + limit=1, + ) + + contact = frappe.get_all( + "Dynamic Link", + { + "link_doctype": source.doctype, + "link_name": source.name, + "parenttype": "Contact", + }, + ["parent"], + limit=1, + ) + + if address: + target.customer_address = address[0].parent + + if contact: + target.contact_person = contact[0].parent