From 5e8c31ceda6e0414fb67193321cfbeea0bf92daf Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Sep 2024 18:08:16 +0530 Subject: [PATCH 1/5] fix: also pass company while creating quotation --- crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py index 1e80014a..0cc95686 100644 --- a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py +++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py @@ -82,13 +82,13 @@ def get_quotation_url(crm_deal, organization): 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}" + 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}" + 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: From 2336cc768b5584cbf629caeaa9b735be887aff35 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Sep 2024 18:08:44 +0530 Subject: [PATCH 2/5] fix: show 'View Customer' button when customer is created --- .../erpnext_crm_settings.py | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py index 0cc95686..32ec2fe4 100644 --- a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py +++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py @@ -74,6 +74,35 @@ def get_erpnext_site_client(erpnext_crm_settings): 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") @@ -202,7 +231,15 @@ async function setupForm({ doc, call, $dialog, updateField, createToast }) { } }) } - + if (is_erpnext_integration_enabled) { + let customer_url = await call("crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.get_customer_link", doc.name); + if (customer_url) { + actions.push({ + label: __("View Customer"), + onClick: () => window.open(customer_url, '_blank') + }); + } + } return { actions: actions, }; From 01411cde43ff9b781d5ed2516b88758607596518 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Sep 2024 18:27:53 +0530 Subject: [PATCH 3/5] fix: added reset form script button to reset erpnext form script --- .../erpnext_crm_settings.js | 32 +++++++++++++++++++ .../erpnext_crm_settings.py | 1 + 2 files changed, 33 insertions(+) diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js index e69de29b..becfd559 100644 --- a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js +++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js @@ -0,0 +1,32 @@ +// 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("update_form_script") + ); + }); + }, + async update_form_script() { + let script = await frappe.call( + "crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.get_crm_form_script" + ); + if (script.message) { + let form_script = await frappe.db.set_value( + "CRM Form Script", + "Create Quotation from CRM Deal", + "script", + script.message + ); + if (form_script.message) { + frappe.msgprint(__("Form Script updated successfully")); + } + } + }, +}); diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py index 32ec2fe4..7304d792 100644 --- a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py +++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py @@ -208,6 +208,7 @@ def create_customer_in_remote_site(customer, erpnext_crm_settings): ) 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 }) { From c9a9d1973c558db21c3739149b7a44dec0749854 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Sep 2024 18:48:53 +0530 Subject: [PATCH 4/5] fix: incorrect syntax --- crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py index 7304d792..454af653 100644 --- a/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py +++ b/crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py @@ -233,7 +233,9 @@ async function setupForm({ doc, call, $dialog, updateField, createToast }) { }) } if (is_erpnext_integration_enabled) { - let customer_url = await call("crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.get_customer_link", doc.name); + 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"), From 8bf88a2b1d8bf2df9d4d3806e0d8d352fe078e2b Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Sep 2024 18:49:28 +0530 Subject: [PATCH 5/5] fix: remove website validation --- crm/fcrm/doctype/crm_deal/crm_deal.json | 5 ++--- crm/fcrm/doctype/crm_lead/crm_lead.json | 5 ++--- .../doctype/crm_organization/crm_organization.json | 5 ++--- frontend/src/pages/Deals.vue | 3 +++ frontend/src/pages/Leads.vue | 10 +++++++++- frontend/src/pages/Organizations.vue | 5 +---- frontend/src/utils/index.js | 7 +++++++ 7 files changed, 26 insertions(+), 14 deletions(-) diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.json b/crm/fcrm/doctype/crm_deal/crm_deal.json index 6338f56d..34a22e35 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-09-16 19:44:19.553715", + "modified": "2024-09-17 18:34:15.873610", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Deal", diff --git a/crm/fcrm/doctype/crm_lead/crm_lead.json b/crm/fcrm/doctype/crm_lead/crm_lead.json index e9e77c89..786c03a5 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-09-16 19:46:01.307171", + "modified": "2024-09-17 18:36:57.289897", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Lead", diff --git a/crm/fcrm/doctype/crm_organization/crm_organization.json b/crm/fcrm/doctype/crm_organization/crm_organization.json index d371ca52..34252d1c 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/frontend/src/pages/Deals.vue b/frontend/src/pages/Deals.vue index 1af78c19..1cba6c13 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/Leads.vue b/frontend/src/pages/Leads.vue index 5b9b716c..405efb43 100644 --- a/frontend/src/pages/Leads.vue +++ b/frontend/src/pages/Leads.vue @@ -307,7 +307,13 @@ import { globalStore } from '@/stores/global' import { usersStore } from '@/stores/users' import { statusesStore } from '@/stores/statuses' import { callEnabled } from '@/composables/settings' -import { dateFormat, dateTooltipFormat, timeAgo, formatTime } from '@/utils' +import { + dateFormat, + dateTooltipFormat, + timeAgo, + website, + formatTime, +} from '@/utils' import { Avatar, Tooltip, Dropdown } from 'frappe-ui' import { useRoute } from 'vue-router' import { ref, computed, reactive, h } from 'vue' @@ -411,6 +417,8 @@ function parseRows(rows) { } } else if (row == 'organization') { _rows[row] = lead.organization + } else if (row === 'website') { + _rows[row] = website(lead.website) } else if (row == 'status') { _rows[row] = { label: lead.status, diff --git a/frontend/src/pages/Organizations.vue b/frontend/src/pages/Organizations.vue index 543c0434..601fb482 100644 --- a/frontend/src/pages/Organizations.vue +++ b/frontend/src/pages/Organizations.vue @@ -82,6 +82,7 @@ import { dateFormat, dateTooltipFormat, timeAgo, + website, formatNumberIntoCurrency, } from '@/utils' import { ref, computed } from 'vue' @@ -130,8 +131,4 @@ const rows = computed(() => { return _rows }) }) - -function website(url) { - return url && url.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '') -} diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 72f61538..2fca77dd 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -72,9 +72,16 @@ export function taskPriorityOptions(action, data) { } export function openWebsite(url) { + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = 'https://' + url + } window.open(url, '_blank') } +export function website(url) { + return url && url.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '') +} + export function htmlToText(html) { const div = document.createElement('div') div.innerHTML = html