fix: convert to system currency and show deal value

This commit is contained in:
Shariq Ansari 2025-07-09 15:53:06 +05:30
parent f4b81b3761
commit 4f02f0a4d7
2 changed files with 52 additions and 30 deletions

View File

@ -223,20 +223,21 @@ def get_average_deal_value(from_date, to_date, user="", conds="", return_result=
f""" f"""
SELECT SELECT
AVG(CASE 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} {conds}
THEN deal_value THEN d.deal_value * IFNULL(e.exchange_rate, 1)
ELSE NULL ELSE NULL
END) as current_month_avg, END) as current_month_avg,
AVG(CASE 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} {conds}
THEN deal_value THEN d.deal_value * IFNULL(e.exchange_rate, 1)
ELSE NULL ELSE NULL
END) as prev_month_avg 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, "from_date": from_date,
"to_date": to_date, "to_date": to_date,
@ -253,8 +254,8 @@ def get_average_deal_value(from_date, to_date, user="", conds="", return_result=
return { return {
"title": _("Avg Deal Value"), "title": _("Avg Deal Value"),
"value": current_month_avg, "value": current_month_avg,
"tooltip": _("Average value of deals created"), "tooltip": _("Average value of deals created (converted to base currency)"),
# "prefix": "$", "prefix": get_base_currency_symbol(),
# "suffix": "K", # "suffix": "K",
"delta": delta, "delta": delta,
"deltaSuffix": "%", "deltaSuffix": "%",
@ -405,9 +406,10 @@ def get_deals_by_salesperson(from_date="", to_date="", user="", deal_conds=""):
SELECT SELECT
IFNULL(u.full_name, d.deal_owner) AS salesperson, IFNULL(u.full_name, d.deal_owner) AS salesperson,
COUNT(*) AS deals, 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 FROM `tabCRM Deal` AS d
LEFT JOIN `tabUser` AS u ON u.name = d.deal_owner 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 WHERE DATE(d.creation) BETWEEN %(from)s AND %(to)s
{deal_conds} {deal_conds}
GROUP BY d.deal_owner GROUP BY d.deal_owner
@ -417,7 +419,10 @@ def get_deals_by_salesperson(from_date="", to_date="", user="", deal_conds=""):
as_dict=True, as_dict=True,
) )
return result or [] return {
"data": result or [],
"currency_symbol": get_base_currency_symbol(),
}
@frappe.whitelist() @frappe.whitelist()
@ -443,8 +448,9 @@ def get_deals_by_territory(from_date="", to_date="", user="", deal_conds=""):
SELECT SELECT
IFNULL(d.territory, 'Empty') AS territory, IFNULL(d.territory, 'Empty') AS territory,
COUNT(*) AS deals, 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 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 WHERE DATE(d.creation) BETWEEN %(from)s AND %(to)s
{deal_conds} {deal_conds}
GROUP BY d.territory GROUP BY d.territory
@ -454,7 +460,10 @@ def get_deals_by_territory(from_date="", to_date="", user="", deal_conds=""):
as_dict=True, as_dict=True,
) )
return result or [] return {
"data": result or [],
"currency_symbol": get_base_currency_symbol(),
}
@frappe.whitelist() @frappe.whitelist()
@ -508,28 +517,29 @@ def get_forecasted_revenue(user="", deal_conds=""):
""" """
if user: if user:
deal_conds += f" AND deal_owner = '{user}'" deal_conds += f" AND d.deal_owner = '{user}'"
result = frappe.db.sql( result = frappe.db.sql(
f""" f"""
SELECT SELECT
DATE_FORMAT(close_date, '%Y-%m') AS month, DATE_FORMAT(d.close_date, '%Y-%m') AS month,
SUM( SUM(
CASE CASE
WHEN status = 'Lost' THEN deal_value WHEN d.status = 'Lost' THEN d.deal_value * IFNULL(e.exchange_rate, 1)
ELSE deal_value * IFNULL(probability, 0) / 100 -- forecasted ELSE d.deal_value * IFNULL(d.probability, 0) / 100 * IFNULL(e.exchange_rate, 1) -- forecasted
END END
) AS forecasted, ) AS forecasted,
SUM( SUM(
CASE CASE
WHEN status = 'Won' THEN deal_value -- actual WHEN d.status = 'Won' THEN d.deal_value * IFNULL(e.exchange_rate, 1) -- actual
ELSE 0 ELSE 0
END END
) AS actual ) AS actual
FROM `tabCRM Deal` FROM `tabCRM Deal` AS d
WHERE close_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) 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} {deal_conds}
GROUP BY DATE_FORMAT(close_date, '%Y-%m') GROUP BY DATE_FORMAT(d.close_date, '%Y-%m')
ORDER BY month ORDER BY month
""", """,
as_dict=True, 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["month"] = frappe.utils.get_datetime(row["month"]).strftime("%Y-%m-01")
row["forecasted"] = row["forecasted"] or "" row["forecasted"] = row["forecasted"] or ""
row["actual"] = row["actual"] or "" row["actual"] = row["actual"] or ""
return result or []
return {
"data": result or [],
"currency_symbol": get_base_currency_symbol(),
}
@frappe.whitelist() @frappe.whitelist()
@ -675,3 +689,11 @@ def get_leads_by_source(from_date="", to_date="", user="", lead_conds=""):
) )
return result or [] 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 ""

View File

@ -331,9 +331,9 @@ const dealsBySalesperson = createResource({
} }
}, },
auto: true, auto: true,
transform(data = []) { transform(r = { data: [], currency_symbol: '$' }) {
return { return {
data: data, data: r.data || [],
title: __('Deals by Salesperson'), title: __('Deals by Salesperson'),
subtitle: 'Number of deals and total value per salesperson', subtitle: 'Number of deals and total value per salesperson',
xAxis: { xAxis: {
@ -345,7 +345,7 @@ const dealsBySalesperson = createResource({
title: __('Number of Deals'), title: __('Number of Deals'),
}, },
y2Axis: { y2Axis: {
title: __('Deal Value ($)'), title: __('Deal Value') + ` (${r.currency_symbol})`,
}, },
series: [ series: [
{ name: 'deals', type: 'bar' as const }, { name: 'deals', type: 'bar' as const },
@ -371,9 +371,9 @@ const dealsByTerritory = createResource({
} }
}, },
auto: true, auto: true,
transform(data = []) { transform(r = { data: [], currency_symbol: '$' }) {
return { return {
data: data, data: r.data || [],
title: __('Deals by Territory'), title: __('Deals by Territory'),
subtitle: __('Geographic distribution of deals and revenue'), subtitle: __('Geographic distribution of deals and revenue'),
xAxis: { xAxis: {
@ -385,7 +385,7 @@ const dealsByTerritory = createResource({
title: __('Number of Deals'), title: __('Number of Deals'),
}, },
y2Axis: { y2Axis: {
title: __('Deal Value ($)'), title: __('Deal Value') + ` (${r.currency_symbol})`,
}, },
series: [ series: [
{ name: 'deals', type: 'bar' as const }, { name: 'deals', type: 'bar' as const },
@ -437,9 +437,9 @@ const forecastedRevenue = createResource({
return { user: filters.user } return { user: filters.user }
}, },
auto: true, auto: true,
transform(data = []) { transform(r = { data: [], currency_symbol: '$' }) {
return { return {
data: data, data: r.data || [],
title: __('Revenue Forecast'), title: __('Revenue Forecast'),
subtitle: __('Projected vs actual revenue based on deal probability'), subtitle: __('Projected vs actual revenue based on deal probability'),
xAxis: { xAxis: {
@ -449,7 +449,7 @@ const forecastedRevenue = createResource({
timeGrain: 'month' as const, timeGrain: 'month' as const,
}, },
yAxis: { yAxis: {
title: __('Revenue ($)'), title: __('Revenue') + ` (${r.currency_symbol})`,
}, },
series: [ series: [
{ name: 'forecasted', type: 'line' as const, showDataPoints: true }, { name: 'forecasted', type: 'line' as const, showDataPoints: true },