diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.json b/crm/fcrm/doctype/crm_deal/crm_deal.json
index e5c973d8c..34a22e35a 100644
--- a/crm/fcrm/doctype/crm_deal/crm_deal.json
+++ b/crm/fcrm/doctype/crm_deal/crm_deal.json
@@ -80,8 +80,7 @@
"fetch_from": ".website",
"fieldname": "website",
"fieldtype": "Data",
- "label": "Website",
- "options": "URL"
+ "label": "Website"
},
{
"fieldname": "close_date",
@@ -339,7 +338,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-06-20 12:55:41.602364",
+ "modified": "2024-09-17 18:34:15.873610",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Deal",
@@ -371,8 +370,10 @@
"write": 1
}
],
+ "show_title_field_in_link": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
+ "title_field": "organization",
"track_changes": 1
}
\ No newline at end of file
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.js b/crm/fcrm/doctype/crm_form_script/crm_form_script.js
index e8ba8b974..2c8c2ff1b 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.js
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.js
@@ -18,6 +18,10 @@ frappe.ui.form.on("CRM Form Script", {
);
}
+ if (!frappe.boot.developer_mode) {
+ frm.toggle_enable("is_standard", 0);
+ }
+
frm.trigger("add_enable_button");
},
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.json b/crm/fcrm/doctype/crm_form_script/crm_form_script.json
index 1cc14d9a3..9246913a0 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.json
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.json
@@ -35,6 +35,7 @@
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
+ "hidden": 1,
"label": "Enabled"
},
{
@@ -64,7 +65,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-09-11 12:56:09.288849",
+ "modified": "2024-09-16 19:40:19.340948",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Form Script",
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.py b/crm/fcrm/doctype/crm_form_script/crm_form_script.py
index 682a97fc2..bb35c851c 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.py
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.py
@@ -14,7 +14,7 @@ def validate(self):
or frappe.flags.in_test
or frappe.flags.in_fixtures
)
- if in_user_env and self.is_standard and not frappe.conf.developer_mode:
+ if in_user_env and not self.is_new() and self.is_standard and not frappe.conf.developer_mode:
# only enabled can be changed for standard form scripts
if self.has_value_changed("enabled"):
enabled_value = self.enabled
diff --git a/crm/fcrm/doctype/crm_lead/crm_lead.json b/crm/fcrm/doctype/crm_lead/crm_lead.json
index ced8e3cb4..786c03a53 100644
--- a/crm/fcrm/doctype/crm_lead/crm_lead.json
+++ b/crm/fcrm/doctype/crm_lead/crm_lead.json
@@ -107,8 +107,7 @@
{
"fieldname": "website",
"fieldtype": "Data",
- "label": "Website",
- "options": "URL"
+ "label": "Website"
},
{
"fieldname": "mobile_no",
@@ -291,7 +290,7 @@
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-02-05 00:58:07.321058",
+ "modified": "2024-09-17 18:36:57.289897",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Lead",
@@ -325,6 +324,7 @@
],
"sender_field": "email",
"sender_name_field": "first_name",
+ "show_title_field_in_link": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
diff --git a/crm/fcrm/doctype/crm_organization/crm_organization.json b/crm/fcrm/doctype/crm_organization/crm_organization.json
index d371ca529..34252d1c6 100644
--- a/crm/fcrm/doctype/crm_organization/crm_organization.json
+++ b/crm/fcrm/doctype/crm_organization/crm_organization.json
@@ -28,8 +28,7 @@
{
"fieldname": "website",
"fieldtype": "Data",
- "label": "Website",
- "options": "URL"
+ "label": "Website"
},
{
"fieldname": "organization_logo",
@@ -80,7 +79,7 @@
"image_field": "organization_logo",
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-09-13 15:52:05.106389",
+ "modified": "2024-09-17 18:37:10.341062",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Organization",
diff --git a/crm/fcrm/doctype/erpnext_crm_settings/__init__.py b/crm/fcrm/doctype/erpnext_crm_settings/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js
new file mode 100644
index 000000000..535e83fbd
--- /dev/null
+++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("ERPNext CRM Settings", {
+ refresh(frm) {
+ if (!frm.doc.enabled) return;
+ frm.add_custom_button(__("Reset ERPNext Form Script"), () => {
+ frappe.confirm(
+ __(
+ "Are you sure you want to reset 'Create Quotation from CRM Deal' Form Script?"
+ ),
+ () => frm.trigger("reset_erpnext_form_script")
+ );
+ });
+ },
+ async reset_erpnext_form_script(frm) {
+ let script = await frm.call("reset_erpnext_form_script");
+ script.message &&
+ frappe.msgprint(__("Form Script updated successfully"));
+ },
+});
diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.json b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.json
new file mode 100644
index 000000000..9a6f0f75e
--- /dev/null
+++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.json
@@ -0,0 +1,124 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2024-07-02 15:23:17.022214",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "enabled",
+ "is_erpnext_in_different_site",
+ "column_break_vfru",
+ "erpnext_company",
+ "section_break_oubd",
+ "erpnext_site_url",
+ "column_break_fllx",
+ "api_key",
+ "api_secret",
+ "section_break_jnbn",
+ "create_customer_on_status_change",
+ "column_break_kbhw",
+ "deal_status"
+ ],
+ "fields": [
+ {
+ "depends_on": "eval:doc.enabled && doc.is_erpnext_in_different_site",
+ "fieldname": "api_key",
+ "fieldtype": "Data",
+ "label": "API Key",
+ "mandatory_depends_on": "is_erpnext_in_different_site"
+ },
+ {
+ "depends_on": "eval:doc.enabled && doc.is_erpnext_in_different_site",
+ "fieldname": "api_secret",
+ "fieldtype": "Password",
+ "label": "API Secret",
+ "mandatory_depends_on": "is_erpnext_in_different_site"
+ },
+ {
+ "depends_on": "enabled",
+ "fieldname": "section_break_oubd",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_fllx",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.enabled && doc.is_erpnext_in_different_site",
+ "fieldname": "erpnext_site_url",
+ "fieldtype": "Data",
+ "label": "ERPNext Site URL",
+ "mandatory_depends_on": "is_erpnext_in_different_site"
+ },
+ {
+ "depends_on": "enabled",
+ "fieldname": "erpnext_company",
+ "fieldtype": "Data",
+ "label": "Company in ERPNext Site",
+ "mandatory_depends_on": "enabled"
+ },
+ {
+ "fieldname": "column_break_vfru",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
+ },
+ {
+ "default": "0",
+ "depends_on": "enabled",
+ "fieldname": "is_erpnext_in_different_site",
+ "fieldtype": "Check",
+ "label": "Is ERPNext installed on a different site?"
+ },
+ {
+ "fieldname": "section_break_jnbn",
+ "fieldtype": "Section Break"
+ },
+ {
+ "default": "0",
+ "depends_on": "enabled",
+ "fieldname": "create_customer_on_status_change",
+ "fieldtype": "Check",
+ "label": "Create customer on status change"
+ },
+ {
+ "fieldname": "column_break_kbhw",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.enabled && doc.create_customer_on_status_change",
+ "fieldname": "deal_status",
+ "fieldtype": "Link",
+ "label": "Deal Status",
+ "mandatory_depends_on": "create_customer_on_status_change",
+ "options": "CRM Deal Status"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2024-09-17 19:21:11.060901",
+ "modified_by": "Administrator",
+ "module": "FCRM",
+ "name": "ERPNext CRM Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py
new file mode 100644
index 000000000..a98f86074
--- /dev/null
+++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py
@@ -0,0 +1,262 @@
+# Copyright (c) 2024, Frappe and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.model.document import Document
+from frappe.frappeclient import FrappeClient
+from frappe.utils import get_url_to_form
+import json
+
+class ERPNextCRMSettings(Document):
+ def validate(self):
+ if self.enabled:
+ self.validate_if_erpnext_installed()
+ self.add_quotation_to_option()
+ self.create_custom_fields()
+ self.create_crm_form_script()
+
+ def validate_if_erpnext_installed(self):
+ if not self.is_erpnext_in_different_site:
+ if "erpnext" not in frappe.get_installed_apps():
+ frappe.throw(_("ERPNext is not installed in the current site"))
+
+ def add_quotation_to_option(self):
+ if not self.is_erpnext_in_different_site:
+ if not frappe.db.exists("Property Setter", {"name": "Quotation-quotation_to-link_filters"}):
+ make_property_setter(
+ doctype="Quotation",
+ fieldname="quotation_to",
+ property="link_filters",
+ value='[["DocType","name","in", ["Customer", "Lead", "Prospect", "Frappe CRM Deal"]]]',
+ property_type="JSON",
+ validate_fields_for_doctype=False,
+ )
+
+ def create_custom_fields(self):
+ if not self.is_erpnext_in_different_site:
+ from erpnext.crm.frappe_crm_api import create_custom_fields_for_frappe_crm
+ create_custom_fields_for_frappe_crm()
+ else:
+ self.create_custom_fields_in_remote_site()
+
+ def create_custom_fields_in_remote_site(self):
+ client = get_erpnext_site_client(self)
+ try:
+ client.post_api("erpnext.crm.frappe_crm_api.create_custom_fields_for_frappe_crm")
+ except Exception:
+ frappe.log_error(
+ frappe.get_traceback(),
+ f"Error while creating custom field in the remote erpnext site: {self.erpnext_site_url}"
+ )
+ frappe.throw("Error while creating custom field in ERPNext, check error log for more details")
+
+ def create_crm_form_script(self):
+ if not frappe.db.exists("CRM Form Script", "Create Quotation from CRM Deal"):
+ script = get_crm_form_script()
+ frappe.get_doc({
+ "doctype": "CRM Form Script",
+ "name": "Create Quotation from CRM Deal",
+ "dt": "CRM Deal",
+ "view": "Form",
+ "script": script,
+ "enabled": 1,
+ "is_standard": 1
+ }).insert()
+
+ @frappe.whitelist()
+ def reset_erpnext_form_script(self):
+ try:
+ if frappe.db.exists("CRM Form Script", "Create Quotation from CRM Deal"):
+ script = get_crm_form_script()
+ frappe.db.set_value("CRM Form Script", "Create Quotation from CRM Deal", "script", script)
+ return True
+ return False
+ except Exception:
+ frappe.log_error(frappe.get_traceback(), "Error while resetting form script")
+ return False
+
+def get_erpnext_site_client(erpnext_crm_settings):
+ site_url = erpnext_crm_settings.erpnext_site_url
+ api_key = erpnext_crm_settings.api_key
+ api_secret = erpnext_crm_settings.get_password("api_secret", raise_exception=False)
+
+ return FrappeClient(
+ site_url, api_key=api_key, api_secret=api_secret
+ )
+
+@frappe.whitelist()
+def get_customer_link(crm_deal):
+ erpnext_crm_settings = frappe.get_single("ERPNext CRM Settings")
+ if not erpnext_crm_settings.enabled:
+ frappe.throw(_("ERPNext is not integrated with the CRM"))
+
+ if not erpnext_crm_settings.is_erpnext_in_different_site:
+ customer_url = get_url_to_form("Customer")
+ customer = frappe.db.exists("Customer", {"crm_deal": crm_deal})
+ if customer:
+ return f"{customer_url}/{customer}"
+ else:
+ return ""
+ else:
+ client = get_erpnext_site_client(erpnext_crm_settings)
+ try:
+ customer = client.get_list("Customer", {"crm_deal": crm_deal})[0]["name"]
+ if customer:
+ return f"{erpnext_crm_settings.erpnext_site_url}/app/customer/{customer}"
+ else:
+ return ""
+ except Exception:
+ frappe.log_error(
+ frappe.get_traceback(),
+ f"Error while fetching customer in remote site: {erpnext_crm_settings.erpnext_site_url}"
+ )
+ frappe.throw(_("Error while fetching customer in ERPNext, check error log for more details"))
+
+
+@frappe.whitelist()
+def get_quotation_url(crm_deal, organization):
+ erpnext_crm_settings = frappe.get_single("ERPNext CRM Settings")
+ if not erpnext_crm_settings.enabled:
+ frappe.throw(_("ERPNext is not integrated with the CRM"))
+
+ if not erpnext_crm_settings.is_erpnext_in_different_site:
+ quotation_url = get_url_to_form("Quotation")
+ return f"{quotation_url}/new?quotation_to=CRM Deal&crm_deal={crm_deal}&party_name={crm_deal}&company={erpnext_crm_settings.erpnext_company}"
+ else:
+ site_url = erpnext_crm_settings.get("erpnext_site_url")
+ quotation_url = f"{site_url}/app/quotation"
+
+ prospect = create_prospect_in_remote_site(crm_deal, erpnext_crm_settings)
+ return f"{quotation_url}/new?quotation_to=Prospect&crm_deal={crm_deal}&party_name={prospect}&company={erpnext_crm_settings.erpnext_company}"
+
+def create_prospect_in_remote_site(crm_deal, erpnext_crm_settings):
+ try:
+ client = get_erpnext_site_client(erpnext_crm_settings)
+ doc = frappe.get_doc("CRM Deal", crm_deal)
+ contacts = get_contacts(doc)
+ address = get_organization_address(doc.organization)
+ return client.post_api("erpnext.crm.frappe_crm_api.create_prospect_against_crm_deal",
+ {
+ "organization": doc.organization,
+ "lead_name": doc.lead_name,
+ "no_of_employees": doc.no_of_employees,
+ "deal_owner": doc.deal_owner,
+ "crm_deal": doc.name,
+ "territory": doc.territory,
+ "industry": doc.industry,
+ "website": doc.website,
+ "annual_revenue": doc.annual_revenue,
+ "contacts": json.dumps(contacts),
+ "erpnext_company": erpnext_crm_settings.erpnext_company,
+ "address": address.as_dict() if address else None
+ },
+ )
+ except Exception:
+ frappe.log_error(
+ frappe.get_traceback(),
+ f"Error while creating prospect in remote site: {erpnext_crm_settings.erpnext_site_url}"
+ )
+ frappe.throw(_("Error while creating prospect in ERPNext, check error log for more details"))
+
+def get_contacts(doc):
+ contacts = []
+ for c in doc.contacts:
+ contacts.append({
+ "contact": c.contact,
+ "full_name": c.full_name,
+ "email": c.email,
+ "mobile_no": c.mobile_no,
+ "gender": c.gender,
+ "is_primary": c.is_primary,
+ })
+ return contacts
+
+def get_organization_address(organization):
+ address = frappe.get_value("CRM Organization", organization, "address")
+ address = frappe.get_doc("Address", address) if address else None
+ return address
+
+def create_customer_in_erpnext(doc, method):
+ erpnext_crm_settings = frappe.get_single("ERPNext CRM Settings")
+ if (
+ not erpnext_crm_settings.enabled
+ or not erpnext_crm_settings.create_customer_on_status_change
+ or doc.status != erpnext_crm_settings.deal_status
+ ):
+ return
+
+ contacts = get_contacts(doc)
+ address = get_organization_address(doc.organization)
+ customer = {
+ "customer_name": doc.organization,
+ "customer_group": "All Customer Groups",
+ "customer_type": "Company",
+ "territory": doc.territory,
+ "default_currency": doc.currency,
+ "industry": doc.industry,
+ "website": doc.website,
+ "crm_deal": doc.name,
+ "contacts": json.dumps(contacts),
+ "address": address.as_dict() if address else None,
+ }
+ if not erpnext_crm_settings.is_erpnext_in_different_site:
+ from erpnext.crm.frappe_crm_api import create_customer
+ create_customer(customer)
+ else:
+ create_customer_in_remote_site(customer, erpnext_crm_settings)
+
+ frappe.publish_realtime("crm_customer_created")
+
+def create_customer_in_remote_site(customer, erpnext_crm_settings):
+ client = get_erpnext_site_client(erpnext_crm_settings)
+ try:
+ client.post_api("erpnext.crm.frappe_crm_api.create_customer", customer)
+ except Exception:
+ frappe.log_error(
+ frappe.get_traceback(),
+ "Error while creating customer in remote site"
+ )
+ frappe.throw(_("Error while creating customer in ERPNext, check error log for more details"))
+
+@frappe.whitelist()
+def get_crm_form_script():
+ return """
+async function setupForm({ doc, call, $dialog, updateField, createToast }) {
+ let actions = [];
+ let is_erpnext_integration_enabled = await call("frappe.client.get_single_value", {doctype: "ERPNext CRM Settings", field: "enabled"});
+ if (!["Lost", "Won"].includes(doc?.status) && is_erpnext_integration_enabled) {
+ actions.push({
+ label: __("Create Quotation"),
+ onClick: async () => {
+ let quotation_url = await call(
+ "crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.get_quotation_url",
+ {
+ crm_deal: doc.name,
+ organization: doc.organization
+ }
+ );
+
+ if (quotation_url) {
+ window.open(quotation_url, '_blank');
+ }
+ }
+ })
+ }
+ if (is_erpnext_integration_enabled) {
+ let customer_url = await call("crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.get_customer_link", {
+ crm_deal: doc.name
+ });
+ if (customer_url) {
+ actions.push({
+ label: __("View Customer"),
+ onClick: () => window.open(customer_url, '_blank')
+ });
+ }
+ }
+ return {
+ actions: actions,
+ };
+}
+"""
diff --git a/crm/fcrm/doctype/erpnext_crm_settings/test_erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/test_erpnext_crm_settings.py
new file mode 100644
index 000000000..17ae02845
--- /dev/null
+++ b/crm/fcrm/doctype/erpnext_crm_settings/test_erpnext_crm_settings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestERPNextCRMSettings(FrappeTestCase):
+ pass
diff --git a/crm/hooks.py b/crm/hooks.py
index e53fc8aa6..fa7e606a8 100644
--- a/crm/hooks.py
+++ b/crm/hooks.py
@@ -152,6 +152,9 @@
"validate": ["crm.api.whatsapp.validate"],
"on_update": ["crm.api.whatsapp.on_update"],
},
+ "CRM Deal": {
+ "on_update": ["crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.create_customer_in_erpnext"],
+ },
}
# Scheduled Tasks
diff --git a/frontend/index.html b/frontend/index.html
index 351990a31..7bb1e8791 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -8,7 +8,7 @@
/>
Frappe CRM
-
+
diff --git a/frontend/src/components/Fields.vue b/frontend/src/components/Fields.vue
index bbf6d2e66..c2bcd3466 100644
--- a/frontend/src/components/Fields.vue
+++ b/frontend/src/components/Fields.vue
@@ -3,7 +3,7 @@
{{ __(field.label) }}
- *
+ *
diff --git a/frontend/src/components/Icons/ERPNextIcon.vue b/frontend/src/components/Icons/ERPNextIcon.vue
new file mode 100644
index 000000000..e512b92db
--- /dev/null
+++ b/frontend/src/components/Icons/ERPNextIcon.vue
@@ -0,0 +1,20 @@
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/ListBulkActions.vue b/frontend/src/components/ListBulkActions.vue
index e37b36c93..7a5c969f7 100644
--- a/frontend/src/components/ListBulkActions.vue
+++ b/frontend/src/components/ListBulkActions.vue
@@ -19,7 +19,7 @@
\ No newline at end of file
diff --git a/frontend/src/components/Settings/SettingsModal.vue b/frontend/src/components/Settings/SettingsModal.vue
index 16487387b..2bbe99223 100644
--- a/frontend/src/components/Settings/SettingsModal.vue
+++ b/frontend/src/components/Settings/SettingsModal.vue
@@ -39,10 +39,12 @@
diff --git a/frontend/src/components/Settings/SidePanelModal.vue b/frontend/src/components/Settings/SidePanelModal.vue
index 401d71cb0..0e3665ad0 100644
--- a/frontend/src/components/Settings/SidePanelModal.vue
+++ b/frontend/src/components/Settings/SidePanelModal.vue
@@ -43,7 +43,11 @@
:class="{ 'border-b': i !== sections.data.length - 1 }"
>
diff --git a/frontend/src/pages/Deal.vue b/frontend/src/pages/Deal.vue
index 27a8f3c57..c9ef4fbb5 100644
--- a/frontend/src/pages/Deal.vue
+++ b/frontend/src/pages/Deal.vue
@@ -8,19 +8,14 @@
-
+
-
+
-
+
- {{ organization?.name || __('Untitled') }}
+ {{ organization.data?.name || __('Untitled') }}
@@ -121,7 +116,7 @@
@@ -166,13 +161,14 @@
@@ -180,8 +176,8 @@
{{ __('Loading...') }}
@@ -279,10 +275,7 @@
v-model:organization="_organization"
:options="{
redirect: false,
- afterInsert: (doc) =>
- updateField('organization', doc.name, () => {
- organizations.reload()
- }),
+ afterInsert: (doc) => updateField('organization', doc.name),
}"
/>
{
+ onSuccess: async (data) => {
+ organization.update({
+ params: { doctype: 'CRM Organization', name: data.organization },
+ })
+ organization.fetch()
let obj = {
doc: data,
$dialog,
+ $socket,
router,
updateField,
createToast,
deleteDoc: deleteDeal,
+ resource: {
+ deal,
+ dealContacts,
+ fieldsLayout,
+ },
call,
}
setupAssignees(data)
- setupCustomStatuses(data, obj)
- setupCustomActions(data, obj)
+ let customization = await setupCustomizations(data, obj)
+ customActions.value = customization.actions || []
+ customStatuses.value = customization.statuses || []
},
})
+const organization = createResource({
+ url: 'frappe.client.get',
+ onSuccess: (data) => (deal.data._organizationObj = data),
+})
+
onMounted(() => {
- if (deal.data) return
+ $socket.on('crm_customer_created', () => {
+ createToast({
+ title: __('Customer created successfully'),
+ icon: 'check',
+ iconClasses: 'text-green-600',
+ })
+ })
+
+ if (deal.data) {
+ organization.data = deal.data._organizationObj
+ return
+ }
deal.fetch()
})
+onBeforeUnmount(() => {
+ $socket.off('crm_customer_created')
+})
+
const reload = ref(false)
const showOrganizationModal = ref(false)
const showAssignmentModal = ref(false)
const showSidePanelModal = ref(false)
const _organization = ref({})
-const organization = computed(() => {
- return deal.data?.organization && getOrganization(deal.data.organization)
-})
-
function updateDeal(fieldname, value, callback) {
value = Array.isArray(fieldname) ? '' : value
@@ -481,7 +501,7 @@ const breadcrumbs = computed(() => {
}
items.push({
- label: organization.value?.name || __('Untitled'),
+ label: organization.data?.name || __('Untitled'),
route: { name: 'Deal', params: { dealId: deal.data.name } },
})
return items
@@ -489,7 +509,7 @@ const breadcrumbs = computed(() => {
usePageMeta(() => {
return {
- title: organization.value?.name || deal.data?.name,
+ title: organization.data?.name || deal.data?.name,
}
})
@@ -595,7 +615,7 @@ async function addContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Contact added'),
icon: 'check',
@@ -610,7 +630,7 @@ async function removeContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Contact removed'),
icon: 'check',
@@ -625,7 +645,7 @@ async function setPrimaryContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Primary contact set'),
icon: 'check',
@@ -634,7 +654,7 @@ async function setPrimaryContact(contact) {
}
}
-const deal_contacts = createResource({
+const dealContacts = createResource({
url: 'crm.fcrm.doctype.crm_deal.api.get_deal_contacts',
params: { name: props.dealId },
cache: ['deal_contacts', props.dealId],
@@ -648,7 +668,7 @@ const deal_contacts = createResource({
})
function triggerCall() {
- let primaryContact = deal_contacts.data?.find((c) => c.is_primary)
+ let primaryContact = dealContacts.data?.find((c) => c.is_primary)
let mobile_no = primaryContact.mobile_no || null
if (!primaryContact) {
@@ -685,3 +705,12 @@ function openEmailBox() {
activities.value.emailBox.show = true
}
+
+
diff --git a/frontend/src/pages/Deals.vue b/frontend/src/pages/Deals.vue
index 1af78c194..1cba6c13c 100644
--- a/frontend/src/pages/Deals.vue
+++ b/frontend/src/pages/Deals.vue
@@ -290,6 +290,7 @@ import {
dateFormat,
dateTooltipFormat,
timeAgo,
+ website,
formatNumberIntoCurrency,
formatTime,
} from '@/utils'
@@ -394,6 +395,8 @@ function parseRows(rows) {
label: deal.organization,
logo: getOrganization(deal.organization)?.organization_logo,
}
+ } else if (row === 'website') {
+ _rows[row] = website(deal.website)
} else if (row == 'annual_revenue') {
_rows[row] = formatNumberIntoCurrency(
deal.annual_revenue,
diff --git a/frontend/src/pages/Lead.vue b/frontend/src/pages/Lead.vue
index d89a9be06..25fedfd5c 100644
--- a/frontend/src/pages/Lead.vue
+++ b/frontend/src/pages/Lead.vue
@@ -8,17 +8,14 @@
-
+
-
+
@@ -108,13 +101,14 @@
@@ -230,10 +224,7 @@
v-model:organization="_organization"
:options="{
redirect: false,
- afterInsert: (doc) =>
- updateField('organization', doc.name, () => {
- organizations.reload()
- }),
+ afterInsert: (doc) => updateField('organization', doc.name),
}"
/>
{
+ onSuccess: async (data) => {
+ organization.update({
+ params: { doctype: 'CRM Organization', name: data.organization },
+ })
+ organization.fetch()
let obj = {
doc: data,
$dialog,
+ $socket,
router,
updateField,
createToast,
deleteDoc: deleteDeal,
+ resource: {
+ deal,
+ dealContacts,
+ fieldsLayout,
+ },
call,
}
setupAssignees(data)
- setupCustomStatuses(data, obj)
- setupCustomActions(data, obj)
+ let customization = await setupCustomizations(data, obj)
+ customActions.value = customization.actions || []
+ customStatuses.value = customization.statuses || []
},
})
+const organization = createResource({
+ url: 'frappe.client.get',
+ onSuccess: (data) => (deal.data._organizationObj = data),
+})
+
onMounted(() => {
if (deal.data) return
deal.fetch()
@@ -347,10 +350,6 @@ const showOrganizationModal = ref(false)
const showAssignmentModal = ref(false)
const _organization = ref({})
-const organization = computed(() => {
- return deal.data?.organization && getOrganization(deal.data.organization)
-})
-
function updateDeal(fieldname, value, callback) {
value = Array.isArray(fieldname) ? '' : value
@@ -419,7 +418,7 @@ const breadcrumbs = computed(() => {
}
items.push({
- label: organization.value?.name || __('Untitled'),
+ label: organization.data?.name || __('Untitled'),
route: { name: 'Deal', params: { dealId: deal.data.name } },
})
return items
@@ -533,7 +532,7 @@ async function addContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Contact added'),
icon: 'check',
@@ -548,7 +547,7 @@ async function removeContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Contact removed'),
icon: 'check',
@@ -563,7 +562,7 @@ async function setPrimaryContact(contact) {
contact,
})
if (d) {
- deal_contacts.reload()
+ dealContacts.reload()
createToast({
title: __('Primary contact set'),
icon: 'check',
@@ -572,7 +571,7 @@ async function setPrimaryContact(contact) {
}
}
-const deal_contacts = createResource({
+const dealContacts = createResource({
url: 'crm.fcrm.doctype.crm_deal.api.get_deal_contacts',
params: { name: props.dealId },
cache: ['deal_contacts', props.dealId],
diff --git a/frontend/src/pages/MobileLead.vue b/frontend/src/pages/MobileLead.vue
index 8237344d3..3ed477bb1 100644
--- a/frontend/src/pages/MobileLead.vue
+++ b/frontend/src/pages/MobileLead.vue
@@ -9,11 +9,7 @@
-
+
-
+