From 6e71321e7d8551e694fd623acb820316dc802010 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 9 Jul 2025 15:53:06 +0530 Subject: [PATCH] fix: convert to system currency and show deal value (cherry picked from commit 4f02f0a4d7c3b947028b193a935eadc7d1c3462f) --- crm/api/dashboard.py | 64 +++++++++++++++++++++----------- frontend/src/pages/Dashboard.vue | 18 ++++----- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/crm/api/dashboard.py b/crm/api/dashboard.py index 3ada6a04..267c34a0 100644 --- a/crm/api/dashboard.py +++ b/crm/api/dashboard.py @@ -223,20 +223,21 @@ def get_average_deal_value(from_date, to_date, user="", conds="", return_result= f""" SELECT AVG(CASE - WHEN creation >= %(from_date)s AND creation < DATE_ADD(%(to_date)s, INTERVAL 1 DAY) AND status != 'Lost' + WHEN d.creation >= %(from_date)s AND d.creation < DATE_ADD(%(to_date)s, INTERVAL 1 DAY) AND d.status != 'Lost' {conds} - THEN deal_value + THEN d.deal_value * IFNULL(e.exchange_rate, 1) ELSE NULL END) as current_month_avg, AVG(CASE - WHEN creation >= %(prev_from_date)s AND creation < %(from_date)s AND status != 'Lost' + WHEN d.creation >= %(prev_from_date)s AND d.creation < %(from_date)s AND d.status != 'Lost' {conds} - THEN deal_value + THEN d.deal_value * IFNULL(e.exchange_rate, 1) ELSE NULL END) as prev_month_avg - FROM `tabCRM Deal` - """, + FROM `tabCRM Deal` d + LEFT JOIN `tabCRM Currency Exchange` e ON d.currency_exchange = e.name + """, { "from_date": from_date, "to_date": to_date, @@ -253,8 +254,8 @@ def get_average_deal_value(from_date, to_date, user="", conds="", return_result= return { "title": _("Avg Deal Value"), "value": current_month_avg, - "tooltip": _("Average value of deals created"), - # "prefix": "$", + "tooltip": _("Average value of deals created (converted to base currency)"), + "prefix": get_base_currency_symbol(), # "suffix": "K", "delta": delta, "deltaSuffix": "%", @@ -405,9 +406,10 @@ def get_deals_by_salesperson(from_date="", to_date="", user="", deal_conds=""): SELECT IFNULL(u.full_name, d.deal_owner) AS salesperson, COUNT(*) AS deals, - SUM(COALESCE(d.deal_value, 0)) AS value + SUM(COALESCE(d.deal_value, 0) * IFNULL(e.exchange_rate, 1)) AS value FROM `tabCRM Deal` AS d LEFT JOIN `tabUser` AS u ON u.name = d.deal_owner + LEFT JOIN `tabCRM Currency Exchange` AS e ON d.currency_exchange = e.name WHERE DATE(d.creation) BETWEEN %(from)s AND %(to)s {deal_conds} GROUP BY d.deal_owner @@ -417,7 +419,10 @@ def get_deals_by_salesperson(from_date="", to_date="", user="", deal_conds=""): as_dict=True, ) - return result or [] + return { + "data": result or [], + "currency_symbol": get_base_currency_symbol(), + } @frappe.whitelist() @@ -443,8 +448,9 @@ def get_deals_by_territory(from_date="", to_date="", user="", deal_conds=""): SELECT IFNULL(d.territory, 'Empty') AS territory, COUNT(*) AS deals, - SUM(COALESCE(d.deal_value, 0)) AS value + SUM(COALESCE(d.deal_value, 0) * IFNULL(e.exchange_rate, 1)) AS value FROM `tabCRM Deal` AS d + LEFT JOIN `tabCRM Currency Exchange` AS e ON d.currency_exchange = e.name WHERE DATE(d.creation) BETWEEN %(from)s AND %(to)s {deal_conds} GROUP BY d.territory @@ -454,7 +460,10 @@ def get_deals_by_territory(from_date="", to_date="", user="", deal_conds=""): as_dict=True, ) - return result or [] + return { + "data": result or [], + "currency_symbol": get_base_currency_symbol(), + } @frappe.whitelist() @@ -508,28 +517,29 @@ def get_forecasted_revenue(user="", deal_conds=""): """ if user: - deal_conds += f" AND deal_owner = '{user}'" + deal_conds += f" AND d.deal_owner = '{user}'" result = frappe.db.sql( f""" SELECT - DATE_FORMAT(close_date, '%Y-%m') AS month, + DATE_FORMAT(d.close_date, '%Y-%m') AS month, SUM( CASE - WHEN status = 'Lost' THEN deal_value - ELSE deal_value * IFNULL(probability, 0) / 100 -- forecasted + WHEN d.status = 'Lost' THEN d.deal_value * IFNULL(e.exchange_rate, 1) + ELSE d.deal_value * IFNULL(d.probability, 0) / 100 * IFNULL(e.exchange_rate, 1) -- forecasted END ) AS forecasted, SUM( CASE - WHEN status = 'Won' THEN deal_value -- actual + WHEN d.status = 'Won' THEN d.deal_value * IFNULL(e.exchange_rate, 1) -- actual ELSE 0 END ) AS actual - FROM `tabCRM Deal` - WHERE close_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) + FROM `tabCRM Deal` AS d + LEFT JOIN `tabCRM Currency Exchange` AS e ON d.currency_exchange = e.name + WHERE d.close_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) {deal_conds} - GROUP BY DATE_FORMAT(close_date, '%Y-%m') + GROUP BY DATE_FORMAT(d.close_date, '%Y-%m') ORDER BY month """, as_dict=True, @@ -541,7 +551,11 @@ def get_forecasted_revenue(user="", deal_conds=""): row["month"] = frappe.utils.get_datetime(row["month"]).strftime("%Y-%m-01") row["forecasted"] = row["forecasted"] or "" row["actual"] = row["actual"] or "" - return result or [] + + return { + "data": result or [], + "currency_symbol": get_base_currency_symbol(), + } @frappe.whitelist() @@ -675,3 +689,11 @@ def get_leads_by_source(from_date="", to_date="", user="", lead_conds=""): ) return result or [] + + +def get_base_currency_symbol(): + """ + Get the base currency symbol from the system settings. + """ + base_currency = frappe.db.get_single_value("System Settings", "currency") or "USD" + return frappe.db.get_value("Currency", base_currency, "symbol") or "" diff --git a/frontend/src/pages/Dashboard.vue b/frontend/src/pages/Dashboard.vue index af17f783..4c76420d 100644 --- a/frontend/src/pages/Dashboard.vue +++ b/frontend/src/pages/Dashboard.vue @@ -331,9 +331,9 @@ const dealsBySalesperson = createResource({ } }, auto: true, - transform(data = []) { + transform(r = { data: [], currency_symbol: '$' }) { return { - data: data, + data: r.data || [], title: __('Deals by Salesperson'), subtitle: 'Number of deals and total value per salesperson', xAxis: { @@ -345,7 +345,7 @@ const dealsBySalesperson = createResource({ title: __('Number of Deals'), }, y2Axis: { - title: __('Deal Value ($)'), + title: __('Deal Value') + ` (${r.currency_symbol})`, }, series: [ { name: 'deals', type: 'bar' as const }, @@ -371,9 +371,9 @@ const dealsByTerritory = createResource({ } }, auto: true, - transform(data = []) { + transform(r = { data: [], currency_symbol: '$' }) { return { - data: data, + data: r.data || [], title: __('Deals by Territory'), subtitle: __('Geographic distribution of deals and revenue'), xAxis: { @@ -385,7 +385,7 @@ const dealsByTerritory = createResource({ title: __('Number of Deals'), }, y2Axis: { - title: __('Deal Value ($)'), + title: __('Deal Value') + ` (${r.currency_symbol})`, }, series: [ { name: 'deals', type: 'bar' as const }, @@ -437,9 +437,9 @@ const forecastedRevenue = createResource({ return { user: filters.user } }, auto: true, - transform(data = []) { + transform(r = { data: [], currency_symbol: '$' }) { return { - data: data, + data: r.data || [], title: __('Revenue Forecast'), subtitle: __('Projected vs actual revenue based on deal probability'), xAxis: { @@ -449,7 +449,7 @@ const forecastedRevenue = createResource({ timeGrain: 'month' as const, }, yAxis: { - title: __('Revenue ($)'), + title: __('Revenue') + ` (${r.currency_symbol})`, }, series: [ { name: 'forecasted', type: 'line' as const, showDataPoints: true },