--- myst: html_meta: "title": "Dashboard Module Development" "description": "Complete guide to creating custom dashboards in OpenSPP using OWL framework with charts, cards, and real-time data visualization." "keywords": "OpenSPP, dashboard development, OWL framework, data visualization, charts, metrics, custom dashboard" --- # Dashboards In OpenSPP, dashboards provide a powerful way to visualize key metrics and data at a glance. They are built using the Odoo OWL framework, allowing for dynamic, interactive, and real-time reporting. A custom dashboard is a self-contained module that fetches data from the server and presents it using various UI components like charts and summary cards. This guide will walk you through creating a custom dashboard module from scratch. We will develop the `spp_custom_dashboard` module to build a new dashboard that displays key statistics from the OpenSPP Farmer Registry. By the end of this guide, you will be able to: - Understand the structure of a dashboard module. - Create a server-side method to fetch and prepare data. - Implement a client-side OWL component for the dashboard. - Design the dashboard layout using XML templates. - Use pre-built components like charts and cards. - Register your dashboard to make it accessible from the Odoo menu. ## Prerequisites - Solid understanding of Odoo 17 module development, including Python, XML, XPath, and JavaScript (specifically the OWL framework). - Familiarity with the OpenG2P and OpenSPP core modules, especially `OpenSPP Dashboard (Base)` (`spp_dashboard_base`) and `OpenSPP Farmer Registry (Base)` (`spp_farmer_registry_base`). - To set up OpenSPP for development, please refer to the {doc}`Development Setup Guide <../setup>`. ## Module Structure A typical dashboard module follows a standard Odoo module structure. Here's the complete structure of our example module, `spp_custom_dashboard`: ``` spp_custom_dashboard/ ├── __init__.py ├── __manifest__.py ├── models/ │ ├── __init__.py │ └── res_partner.py # Data-fetching logic ├── static/ │ └── src/ │ └── dashboard/ │ ├── dashboard.js # OWL component for the dashboard │ └── dashboard.xml # XML template for the dashboard layout └── views/ └── dashboard_views.xml # Client action and menu item ``` --- ## Step-by-Step Guide ### Create the Module Scaffold Start by creating a new directory for your module (e.g., `spp_custom_dashboard`) and populate it with the basic Odoo module files and the directory structure shown above. ### Define the Manifest (`__manifest__.py`) The manifest file declares your module's metadata and dependencies. It's crucial to list all the modules your customization will interact with. Our dashboard depends on `spp_dashboard_base` for the core dashboard components and `spp_farmer_registry_base` for the data. ```python # In: spp_custom_dashboard/__manifest__.py { "name": "OpenSPP Custom Dashboard", "summary": "A custom dashboard to display key metrics from the Farmer Registry.", "category": "OpenSPP", "version": "17.0.1.0.0", "author": "OpenSPP.org", "website": "https://github.com/OpenSPP/openspp-modules", "license": "LGPL-3", "depends": [ "spp_dashboard_base", "spp_farmer_registry_base", ], "data": [ "views/dashboard_views.xml", ], "assets": { "web.assets_backend": [ "spp_custom_dashboard/static/src/dashboard/**/*", ], }, "application": True, "installable": True, } ``` ### Prepare the Data on the Server (Python) The dashboard needs data to display. We'll create a method on an existing model to gather and format this data. For our example, we'll extend the `res.partner` model, which represents farms and farmers in the `spp_farmer_registry_base` module. 1. **Create the model file**: In your `models/` directory, create a Python file named `res_partner.py`. Remember to import it in `models/__init__.py`. 2. **Define the data-fetching method**: - Extend the `res.partner` model. - Create a method, for example, `get_farmer_dashboard_data`, that will be called from the client-side component. - This method will search for farms and farmers and aggregate the data into a dictionary. ```python # In: spp_custom_dashboard/models/res_partner.py from odoo import api, models class Partner(models.Model): _inherit = "res.partner" @api.model def get_farmer_dashboard_data(self): """Fetch and prepare data for the farmer registry dashboard.""" farm_kind_id = self.env.ref("spp_farmer_registry_base.kind_farm") farms = self.search([("kind", "=", farm_kind_id.id)]) farmers = self.search([("is_registrant", "=", True), ("is_group", "=", False)]) # Data for a chart: Farms by Type farm_types = { "crop": 0, "livestock": 0, "aquaculture": 0, "mixed": 0, } for farm in farms: if farm.details_farm_type in farm_types: farm_types[farm.details_farm_type] += 1 return { # Data for CardBoard components "total_farms": len(farms), "total_farmers": len(farmers), # Data for ChartComponent "farm_types_data": list(farm_types.values()), "farm_types_labels": [label.capitalize() for label in farm_types.keys()], } ``` ### Create the Dashboard Component (JavaScript) The client-side component is responsible for calling the server to get the data and rendering the dashboard template. 1. **Create the JavaScript file**: In `static/src/dashboard/`, create `dashboard.js`. 2. **Implement the OWL component**: - Import `SppDashboard` from the base dashboard module. - Extend the `SppDashboard` class. - Use the `onWillStart` lifecycle hook to call your Python method using the `orm` service. - Store the fetched data in `this.dashboard_data` to make it available in the template. - Register your new component in the `actions` registry with a unique tag. ```javascript // In: spp_custom_dashboard/static/src/dashboard/dashboard.js /** @odoo-module **/ import { SppDashboard } from "@spp_dashboard_base/dashboard/dashboard"; import { registry } from "@web/core/registry"; export class CustomDashboard extends SppDashboard { setup() { super.setup(); this.dashboard_title = "Farmer Registry Dashboard"; } async onWillStart() { await super.onWillStart(); this.dashboard_data = await this.orm.call( "res.partner", "get_farmer_dashboard_data", [] ); } } CustomDashboard.template = "spp_custom_dashboard.dashboard_page"; registry.category("actions").add("spp_custom_dashboard_tag", CustomDashboard); ``` ### Design the Dashboard Layout (XML) The XML template defines the structure and appearance of your dashboard. It uses the data prepared by the JavaScript component. 1. **Create the XML file**: In `static/src/dashboard/`, create `dashboard.xml`. 2. **Define the template**: - Create a template with a unique name (e.g., `spp_custom_dashboard.dashboard_page`). - Use the `CardBoardComponent` and `ChartComponent` provided by `spp_dashboard_base`. - Pass the data from `dashboard_data` to the components' props. ```xml



``` ### Register the Dashboard Finally, create a client action and a menu item to make your dashboard accessible in the Odoo interface. 1. **Create the view file**: In the `views/` directory, create `dashboard_views.xml`. 2. **Define the action and menu**: - Create an `ir.actions.client` record. The `tag` must match the one you registered in your JavaScript file (`spp_custom_dashboard_tag`). - Create a `menuitem` that calls this client action. ```xml Farmer Dashboard spp_custom_dashboard_tag ``` ### Install and View Your Dashboard 1. Install or upgrade the module through the Apps menu. 2. Refresh your browser. 3. Navigate to the main menu, and you should see a new "Dashboard" menu item. Click it to view your custom dashboard. ## References For more information on extending OpenSPP modules, refer to: - [Odoo 17 Developer Documentation](https://www.odoo.com/documentation/17.0/developer/) - [OpenSPP Dashboard Base Module Source](https://github.com/OpenSPP/openspp-modules/tree/17.0/spp_dashboard_base)