diff --git a/crm/api/dashboard.py b/crm/api/dashboard.py index b6ca7aff..6bd44755 100644 --- a/crm/api/dashboard.py +++ b/crm/api/dashboard.py @@ -3,6 +3,7 @@ import json import frappe from frappe import _ +from crm.fcrm.doctype.crm_dashboard.crm_dashboard import create_default_manager_dashboard from crm.utils import sales_user_only @@ -22,9 +23,15 @@ def get_dashboard(from_date="", to_date="", user=""): if is_sales_user and not user: user = frappe.session.user - dashboard = frappe.get_cached_doc("CRM Dashboard", "Manager Dashboard", fields=["layout"]) + dashboard = frappe.db.exists("CRM Dashboard", "Manager Dashboard") - layout = json.loads(dashboard.layout) if dashboard and dashboard.layout else [] + layout = [] + + if not dashboard: + layout = json.loads(create_default_manager_dashboard()) + frappe.db.commit() + else: + layout = json.loads(frappe.db.get_value("CRM Dashboard", "Manager Dashboard", "layout") or "[]") for l in layout: method_name = f"get_{l['name']}" @@ -652,7 +659,7 @@ def get_forecasted_revenue(from_date="", to_date="", user=""): return { "data": result or [], - "title": _("Forecasted Revenue"), + "title": _("Forecasted revenue"), "subtitle": _("Projected vs actual revenue based on deal probability"), "xAxis": { "title": _("Month"), @@ -714,7 +721,7 @@ def get_funnel_conversion(from_date="", to_date="", user=""): return { "data": result or [], - "title": _("Funnel Conversion"), + "title": _("Funnel conversion"), "subtitle": _("Lead to deal conversion pipeline"), "xAxis": { "title": _("Stage"), diff --git a/crm/fcrm/doctype/crm_dashboard/crm_dashboard.py b/crm/fcrm/doctype/crm_dashboard/crm_dashboard.py index b1edf4b8..d49b638f 100644 --- a/crm/fcrm/doctype/crm_dashboard/crm_dashboard.py +++ b/crm/fcrm/doctype/crm_dashboard/crm_dashboard.py @@ -1,9 +1,29 @@ # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -# import frappe +import frappe +from frappe import _ from frappe.model.document import Document class CRMDashboard(Document): pass + + +def default_manager_dashboard_layout(): + """ + Returns the default layout for the CRM Manager Dashboard. + """ + return '[{"name": "total_leads", "type": "number_chart", "tooltip": "Total number of leads", "layout": {"x": 0, "y": 0, "w": 4, "h": 2, "i": "total_leads"}}, {"name": "ongoing_deals", "type": "number_chart", "tooltip": "Total number of ongoing deals", "layout": {"x": 4, "y": 0, "w": 4, "h": 2, "i": "ongoing_deals"}}, {"name": "average_ongoing_deal_value", "type": "number_chart", "tooltip": "Average value of ongoing deals", "layout": {"x": 8, "y": 0, "w": 4, "h": 2, "i": "average_ongoing_deal_value"}}, {"name": "won_deals", "type": "number_chart", "tooltip": "Total number of won deals", "layout": {"x": 12, "y": 0, "w": 4, "h": 2, "i": "won_deals"}}, {"name": "average_won_deal_value", "type": "number_chart", "tooltip": "Average value of won deals", "layout": {"x": 16, "y": 0, "w": 4, "h": 2, "i": "average_won_deal_value"}}, {"name": "average_deal_value", "type": "number_chart", "tooltip": "Average deal value of ongoing and won deals", "layout": {"x": 0, "y": 2, "w": 4, "h": 2, "i": "average_deal_value"}}, {"name": "average_time_to_close_a_lead", "type": "number_chart", "tooltip": "Average time taken to close a lead", "layout": {"x": 4, "y": 2, "w": 4, "h": 2, "i": "average_time_to_close_a_lead"}}, {"name": "average_time_to_close_a_deal", "type": "number_chart", "layout": {"x": 8, "y": 2, "w": 4, "h": 2, "i": "average_time_to_close_a_deal"}}, {"name": "blank_card", "type": "blank_card", "layout": {"x": 12, "y": 2, "w": 8, "h": 2, "i": "blank_card"}}, {"name": "sales_trend", "type": "axis_chart", "layout": {"x": 0, "y": 4, "w": 10, "h": 7, "i": "sales_trend"}}, {"name": "forecasted_revenue", "type": "axis_chart", "layout": {"x": 10, "y": 4, "w": 10, "h": 7, "i": "forecasted_revenue"}}, {"name": "funnel_conversion", "type": "axis_chart", "layout": {"x": 0, "y": 11, "w": 10, "h": 7, "i": "funnel_conversion"}}, {"name": "deals_by_stage_axis", "type": "axis_chart", "layout": {"x": 10, "y": 11, "w": 10, "h": 7, "i": "deals_by_stage_axis"}}, {"name": "deals_by_stage_donut", "type": "donut_chart", "layout": {"x": 0, "y": 18, "w": 10, "h": 7, "i": "deals_by_stage_donut"}}, {"name": "lost_deal_reasons", "type": "axis_chart", "layout": {"x": 10, "y": 18, "w": 10, "h": 7, "i": "lost_deal_reasons"}}, {"name": "leads_by_source", "type": "donut_chart", "layout": {"x": 0, "y": 25, "w": 10, "h": 7, "i": "leads_by_source"}}, {"name": "deals_by_source", "type": "donut_chart", "layout": {"x": 10, "y": 25, "w": 10, "h": 7, "i": "deals_by_source"}}, {"name": "deals_by_territory", "type": "axis_chart", "layout": {"x": 0, "y": 32, "w": 10, "h": 7, "i": "deals_by_territory"}}, {"name": "deals_by_salesperson", "type": "axis_chart", "layout": {"x": 10, "y": 32, "w": 10, "h": 7, "i": "deals_by_salesperson"}}]' + + +def create_default_manager_dashboard(): + """ + Creates the default CRM Manager Dashboard if it does not exist. + """ + if not frappe.db.exists("CRM Dashboard", "Manager Dashboard"): + doc = frappe.new_doc("CRM Dashboard") + doc.title = "Manager Dashboard" + doc.layout = default_manager_dashboard_layout() + doc.insert(ignore_permissions=True) + return doc.layout diff --git a/crm/install.py b/crm/install.py index 202ee21d..a35ae42f 100644 --- a/crm/install.py +++ b/crm/install.py @@ -4,6 +4,7 @@ import click import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields +from crm.fcrm.doctype.crm_dashboard.crm_dashboard import create_default_manager_dashboard from crm.fcrm.doctype.crm_products.crm_products import create_product_details_script @@ -23,7 +24,7 @@ def after_install(force=False): add_default_lost_reasons() add_standard_dropdown_items() add_default_scripts() - add_default_manager_dashboard() + create_default_manager_dashboard() frappe.db.commit() @@ -420,12 +421,3 @@ def add_default_scripts(): for doctype in ["CRM Lead", "CRM Deal"]: create_product_details_script(doctype) create_forecasting_script() - - -def add_default_manager_dashboard(): - if frappe.db.exists("CRM Dashboard", "Manager Dashboard"): - return - - doc = frappe.new_doc("CRM Dashboard") - doc.title = "Manager Dashboard" - doc.layout = '[{"name": "total_leads", "type": "number_chart", "tooltip": "Total number of leads", "layout": {"x": 0, "y": 0, "w": 4, "h": 2, "i": "total_leads"}}, {"name": "ongoing_deals", "type": "number_chart", "tooltip": "Total number of ongoing deals", "layout": {"x": 4, "y": 0, "w": 4, "h": 2, "i": "ongoing_deals"}}, {"name": "average_ongoing_deal_value", "type": "number_chart", "tooltip": "Average value of ongoing deals", "layout": {"x": 8, "y": 0, "w": 4, "h": 2, "i": "average_ongoing_deal_value"}}, {"name": "won_deals", "type": "number_chart", "tooltip": "Total number of won deals", "layout": {"x": 12, "y": 0, "w": 4, "h": 2, "i": "won_deals"}}, {"name": "average_won_deal_value", "type": "number_chart", "tooltip": "Average value of won deals", "layout": {"x": 16, "y": 0, "w": 4, "h": 2, "i": "average_won_deal_value"}}, {"name": "average_deal_value", "type": "number_chart", "tooltip": "Average deal value of ongoing and won deals", "layout": {"x": 0, "y": 2, "w": 4, "h": 2, "i": "average_deal_value"}}, {"name": "average_time_to_close_a_lead", "type": "number_chart", "tooltip": "Average time taken to close a lead", "layout": {"x": 4, "y": 2, "w": 4, "h": 2, "i": "average_time_to_close_a_lead"}}, {"name": "average_time_to_close_a_deal", "type": "number_chart", "layout": {"x": 8, "y": 2, "w": 4, "h": 2, "i": "average_time_to_close_a_deal"}}, {"name": "blank_card", "type": "blank_card", "layout": {"x": 12, "y": 2, "w": 8, "h": 2, "i": "blank_card"}}, {"name": "sales_trend", "type": "axis_chart", "layout": {"x": 0, "y": 4, "w": 10, "h": 7, "i": "sales_trend"}}, {"name": "forecasted_revenue", "type": "axis_chart", "layout": {"x": 10, "y": 4, "w": 10, "h": 7, "i": "forecasted_revenue"}}, {"name": "funnel_conversion", "type": "axis_chart", "layout": {"x": 0, "y": 11, "w": 10, "h": 7, "i": "funnel_conversion"}}, {"name": "deals_by_stage_axis", "type": "axis_chart", "layout": {"x": 10, "y": 11, "w": 10, "h": 7, "i": "deals_by_stage_axis"}}, {"name": "deals_by_stage_donut", "type": "donut_chart", "layout": {"x": 0, "y": 18, "w": 10, "h": 7, "i": "deals_by_stage_donut"}}, {"name": "lost_deal_reasons", "type": "axis_chart", "layout": {"x": 10, "y": 18, "w": 10, "h": 7, "i": "lost_deal_reasons"}}, {"name": "leads_by_source", "type": "donut_chart", "layout": {"x": 0, "y": 25, "w": 10, "h": 7, "i": "leads_by_source"}}, {"name": "deals_by_source", "type": "donut_chart", "layout": {"x": 10, "y": 25, "w": 10, "h": 7, "i": "deals_by_source"}}, {"name": "deals_by_territory", "type": "axis_chart", "layout": {"x": 0, "y": 32, "w": 10, "h": 7, "i": "deals_by_territory"}}, {"name": "deals_by_salesperson", "type": "axis_chart", "layout": {"x": 10, "y": 32, "w": 10, "h": 7, "i": "deals_by_salesperson"}}]'