From b7bf9f80f2554dc466a108cdcf2e6f929393ac19 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 12 Sep 2024 19:38:30 +0530 Subject: [PATCH] feat: API for crm integration --- erpnext/crm/frappe_crm_api.py | 135 ++++++++++++++++++ .../selling/doctype/quotation/quotation.js | 2 +- .../selling/doctype/quotation/quotation.py | 4 + 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 erpnext/crm/frappe_crm_api.py diff --git a/erpnext/crm/frappe_crm_api.py b/erpnext/crm/frappe_crm_api.py new file mode 100644 index 000000000000..40c0ce8c9c19 --- /dev/null +++ b/erpnext/crm/frappe_crm_api.py @@ -0,0 +1,135 @@ +import json + +import frappe +from frappe import _ +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + + +@frappe.whitelist() +def create_custom_fields_for_frappe_crm(): + frappe.only_for("System Manager") + custom_fields = { + "Quotation": [ + { + "fieldname": "crm_deal", + "fieldtype": "Data", + "label": "Frappe CRM Deal", + "insert_after": "party_name", + } + ], + "Customer": [ + { + "fieldname": "crm_deal", + "fieldtype": "Data", + "label": "Frappe CRM Deal", + "insert_after": "prospect_name", + } + ], + } + create_custom_fields(custom_fields, ignore_validate=True) + + +@frappe.whitelist() +def create_prospect_against_crm_deal(): + frappe.only_for("System Manager") + doc = frappe.form_dict + prospect = frappe.get_doc( + { + "doctype": "Prospect", + "company_name": doc.organization or doc.lead_name, + "no_of_employees": doc.no_of_employees, + "prospect_owner": doc.deal_owner, + "company": doc.erpnext_company, + "crm_deal": doc.crm_deal, + "territory": doc.territory, + "industry": doc.industry, + "website": doc.website, + "annual_revenue": doc.annual_revenue, + } + ) + + try: + prospect_name = frappe.db.get_value("Prospect", {"company_name": prospect.company_name}) + if not prospect_name: + prospect.insert() + prospect_name = prospect.name + except Exception: + frappe.log_error( + frappe.get_traceback(), + f"Error while creating prospect against CRM Deal: {frappe.form_dict.get('crm_deal_id')}", + ) + pass + + create_contacts(json.loads(doc.contacts), prospect.company_name, "Prospect", prospect_name) + frappe.response["message"] = prospect_name + + +def create_contacts(contacts, organization=None, link_doctype=None, link_docname=None): + for c in contacts: + c = frappe._dict(c) + existing_contact = contact_exists(c.email, c.mobile_no) + if existing_contact: + contact = frappe.get_doc("Contact", existing_contact) + else: + contact = frappe.get_doc( + { + "doctype": "Contact", + "first_name": c.get("full_name"), + "gender": c.get("gender"), + "company_name": organization, + } + ) + + if c.get("email"): + contact.append("email_ids", {"email_id": c.get("email"), "is_primary": 1}) + + if c.get("mobile_no"): + contact.append("phone_nos", {"phone": c.get("mobile_no"), "is_primary_mobile_no": 1}) + + link_contact_to_prospect(contact, link_doctype, link_docname) + + contact.save(ignore_permissions=True) + + +def link_contact_to_prospect(contact, link_doctype, link_docname): + already_linked = any( + [(link.link_doctype == link_doctype and link.link_name == link_docname) for link in contact.links] + ) + if not already_linked: + contact.append( + "links", {"link_doctype": link_doctype, "link_name": link_docname, "link_title": link_docname} + ) + + +def contact_exists(email, mobile_no): + email_exist = frappe.db.exists("Contact Email", {"email_id": email}) + mobile_exist = frappe.db.exists("Contact Phone", {"phone": mobile_no}) + + doctype = "Contact Email" if email_exist else "Contact Phone" + name = email_exist or mobile_exist + + if name: + return frappe.db.get_value(doctype, name, "parent") + + return False + + +@frappe.whitelist() +def create_customer(customer_data=None): + frappe.only_for("System Manager") + if not customer_data: + customer_data = frappe.form_dict + + try: + customer_name = frappe.db.exists("Customer", {"customer_name": customer_data.get("customer_name")}) + if not customer_name: + customer = frappe.get_doc({"doctype": "Customer", **customer_data}).insert( + ignore_permissions=True + ) + customer_name = customer.name + + contacts = json.loads(customer_data.get("contacts")) + create_contacts(contacts, customer_name, "Customer", customer_name) + except Exception: + frappe.log_error(frappe.get_traceback(), "Error while creating customer against Frappe CRM Deal") + pass diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 3044d865c0ca..a4c70d7f50f2 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -71,7 +71,7 @@ frappe.ui.form.on("Quotation", { frm.trigger("set_label"); frm.trigger("toggle_reqd_lead_customer"); frm.trigger("set_dynamic_field_label"); - frm.set_value("party_name", ""); + // frm.set_value("party_name", ""); // removed to set party_name from url for crm integration frm.set_value("customer_name", ""); }, diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 1d7d3fcfbe00..337312822e0d 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -220,6 +220,10 @@ def set_customer_name(self): "Lead", self.party_name, ["lead_name", "company_name"] ) self.customer_name = company_name or lead_name + elif self.party_name and self.quotation_to == "Prospect": + self.customer_name = self.party_name + elif self.party_name and self.quotation_to == "CRM Deal": + self.customer_name = frappe.db.get_value("CRM Deal", self.party_name, "organization") def update_opportunity(self, status): for opportunity in set(d.prevdoc_docname for d in self.get("items")):