From efa7e86aa1fbf38895d0806af3f7c1c1c2351f3b Mon Sep 17 00:00:00 2001 From: gerard Date: Mon, 29 Jun 2026 07:35:27 +0000 Subject: [PATCH] [ADD] spreadsheet_dashboard_helpdesk_oca: helpdesk dashboard --- oca_dependencies.txt | 1 + spreadsheet_dashboard_helpdesk_oca/README.rst | 88 ++ .../__init__.py | 1 + .../__manifest__.py | 13 + .../data/dashboards.xml | 27 + .../data/files/helpdesk_dashboard.json | 894 ++++++++++++++++++ .../models/__init__.py | 1 + .../models/helpdesk_ticket.py | 33 + .../pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 1 + .../readme/DESCRIPTION.md | 1 + .../static/description/icon.png | Bin 0 -> 36748 bytes .../static/description/index.html | 431 +++++++++ .../tests/__init__.py | 1 + .../tests/test_helpdesk_ticket_metrics.py | 30 + 15 files changed, 1525 insertions(+) create mode 100644 oca_dependencies.txt create mode 100644 spreadsheet_dashboard_helpdesk_oca/README.rst create mode 100644 spreadsheet_dashboard_helpdesk_oca/__init__.py create mode 100644 spreadsheet_dashboard_helpdesk_oca/__manifest__.py create mode 100644 spreadsheet_dashboard_helpdesk_oca/data/dashboards.xml create mode 100644 spreadsheet_dashboard_helpdesk_oca/data/files/helpdesk_dashboard.json create mode 100644 spreadsheet_dashboard_helpdesk_oca/models/__init__.py create mode 100644 spreadsheet_dashboard_helpdesk_oca/models/helpdesk_ticket.py create mode 100644 spreadsheet_dashboard_helpdesk_oca/pyproject.toml create mode 100644 spreadsheet_dashboard_helpdesk_oca/readme/CONTRIBUTORS.md create mode 100644 spreadsheet_dashboard_helpdesk_oca/readme/DESCRIPTION.md create mode 100644 spreadsheet_dashboard_helpdesk_oca/static/description/icon.png create mode 100644 spreadsheet_dashboard_helpdesk_oca/static/description/index.html create mode 100644 spreadsheet_dashboard_helpdesk_oca/tests/__init__.py create mode 100644 spreadsheet_dashboard_helpdesk_oca/tests/test_helpdesk_ticket_metrics.py diff --git a/oca_dependencies.txt b/oca_dependencies.txt new file mode 100644 index 00000000..941c76e0 --- /dev/null +++ b/oca_dependencies.txt @@ -0,0 +1 @@ +helpdesk diff --git a/spreadsheet_dashboard_helpdesk_oca/README.rst b/spreadsheet_dashboard_helpdesk_oca/README.rst new file mode 100644 index 00000000..39ce056e --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/README.rst @@ -0,0 +1,88 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================================== +Spreadsheet dashboard for helpdesk +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:ae03011402cac074f10571f3194b90d3a005fda27d1ce6dda6c057380e5f7583 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fspreadsheet-lightgray.png?logo=github + :target: https://github.com/OCA/spreadsheet/tree/19.0/spreadsheet_dashboard_helpdesk_oca + :alt: OCA/spreadsheet +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/spreadsheet-19-0/spreadsheet-19-0-spreadsheet_dashboard_helpdesk_oca + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/spreadsheet&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Spreadsheet dashboard for helpdesk tickets. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Domatix + +Contributors +------------ + +- Domatix + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-domatix| image:: https://github.com/domatix.png?size=40px + :target: https://github.com/domatix + :alt: domatix + +Current `maintainer `__: + +|maintainer-domatix| + +This module is part of the `OCA/spreadsheet `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/spreadsheet_dashboard_helpdesk_oca/__init__.py b/spreadsheet_dashboard_helpdesk_oca/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/spreadsheet_dashboard_helpdesk_oca/__manifest__.py b/spreadsheet_dashboard_helpdesk_oca/__manifest__.py new file mode 100644 index 00000000..7dcc70ca --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/__manifest__.py @@ -0,0 +1,13 @@ +{ + "name": "Spreadsheet dashboard for helpdesk", + "category": "Hidden", + "depends": ["spreadsheet_dashboard", "helpdesk_mgmt"], + "version": "19.0.1.0.0", + "website": "https://github.com/OCA/spreadsheet", + "author": "Domatix, Odoo Community Association (OCA)", + "maintainers": ["domatix"], + "data": ["data/dashboards.xml"], + "installable": True, + "auto_install": ["helpdesk_mgmt"], + "license": "AGPL-3", +} diff --git a/spreadsheet_dashboard_helpdesk_oca/data/dashboards.xml b/spreadsheet_dashboard_helpdesk_oca/data/dashboards.xml new file mode 100644 index 00000000..80d64957 --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/data/dashboards.xml @@ -0,0 +1,27 @@ + + + + + Helpdesk + + + + + 100 + True + + diff --git a/spreadsheet_dashboard_helpdesk_oca/data/files/helpdesk_dashboard.json b/spreadsheet_dashboard_helpdesk_oca/data/files/helpdesk_dashboard.json new file mode 100644 index 00000000..1ba68e10 --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/data/files/helpdesk_dashboard.json @@ -0,0 +1,894 @@ +{ + "version": "18.4.14", + "sheets": [ + { + "id": "sheet1", + "name": "Dashboard", + "colNumber": 7, + "rowNumber": 55, + "rows": { + "6": {"size": 40}, + "22": {"size": 40}, + "23": {"size": 40}, + "24": {"size": 30}, + "25": {"size": 30}, + "26": {"size": 30}, + "27": {"size": 30}, + "28": {"size": 30}, + "29": {"size": 30}, + "30": {"size": 30}, + "31": {"size": 30}, + "32": {"size": 30}, + "33": {"size": 30}, + "34": {"size": 30}, + "35": {"size": 40}, + "36": {"size": 40}, + "37": {"size": 30}, + "38": {"size": 30}, + "39": {"size": 30}, + "40": {"size": 30}, + "41": {"size": 30}, + "42": {"size": 30}, + "43": {"size": 30}, + "44": {"size": 30}, + "45": {"size": 30}, + "46": {"size": 30}, + "47": {"size": 30} + }, + "cols": { + "0": {"size": 275}, + "1": {"size": 103}, + "2": {"size": 100}, + "3": {"size": 50}, + "4": {"size": 275}, + "5": {"size": 103}, + "6": {"size": 100} + }, + "merges": [], + "cells": { + "A7": "[Tickets by Stage](odoo://view/{\"viewType\":\"graph\",\"action\":{\"domain\":[],\"context\":{\"group_by\":[\"stage_id\"],\"graph_measure\":\"__count\",\"graph_mode\":\"pie\",\"graph_groupbys\":[\"stage_id\"]},\"modelName\":\"helpdesk.ticket\",\"views\":[[false,\"graph\"],[false,\"pivot\"],[false,\"list\"],[false,\"search\"]]},\"threshold\":0,\"name\":\"Tickets Analysis\"})", + "E7": "[Tickets by Team](odoo://view/{\"viewType\":\"graph\",\"action\":{\"domain\":[],\"context\":{\"group_by\":[\"stage_id\",\"team_id\"],\"graph_measure\":\"__count\",\"graph_mode\":\"bar\",\"graph_groupbys\":[\"stage_id\",\"team_id\"]},\"modelName\":\"helpdesk.ticket\",\"views\":[[false,\"graph\"],[false,\"pivot\"],[false,\"list\"],[false,\"search\"]]},\"threshold\":0,\"name\":\"Tickets Analysis\"})", + "A23": "[Top Customers](odoo://view/{\"viewType\":\"pivot\",\"action\":{\"domain\":[[\"partner_id\",\"!=\",false]],\"context\":{\"group_by\":[],\"pivot_measures\":[\"__count\"],\"pivot_column_groupby\":[],\"pivot_row_groupby\":[\"partner_id\"]},\"modelName\":\"helpdesk.ticket\",\"views\":[[false,\"graph\"],[false,\"pivot\"],[false,\"list\"],[false,\"search\"]]},\"threshold\":0,\"name\":\"Tickets Analysis\"})", + "A24": "=_t(\"Customer\")", + "A25": "=PIVOT.HEADER(4,\"#partner_id\",1)", + "A26": "=PIVOT.HEADER(4,\"#partner_id\",2)", + "A27": "=PIVOT.HEADER(4,\"#partner_id\",3)", + "A28": "=PIVOT.HEADER(4,\"#partner_id\",4)", + "A29": "=PIVOT.HEADER(4,\"#partner_id\",5)", + "A30": "=PIVOT.HEADER(4,\"#partner_id\",6)", + "A31": "=PIVOT.HEADER(4,\"#partner_id\",7)", + "A32": "=PIVOT.HEADER(4,\"#partner_id\",8)", + "A33": "=PIVOT.HEADER(4,\"#partner_id\",9)", + "A34": "=PIVOT.HEADER(4,\"#partner_id\",10)", + "B24": "=_t(\"Tickets\")", + "B25": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",1)", + "B26": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",2)", + "B27": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",3)", + "B28": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",4)", + "B29": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",5)", + "B30": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",6)", + "B31": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",7)", + "B32": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",8)", + "B33": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",9)", + "B34": "=PIVOT.VALUE(4,\"__count\",\"#partner_id\",10)", + "E23": "[Top Assignees](odoo://view/{\"viewType\":\"pivot\",\"action\":{\"domain\":[[\"user_id\",\"!=\",false]],\"context\":{\"group_by\":[],\"pivot_measures\":[\"__count\"],\"pivot_column_groupby\":[],\"pivot_row_groupby\":[\"user_id\"]},\"modelName\":\"helpdesk.ticket\",\"views\":[[false,\"graph\"],[false,\"pivot\"],[false,\"list\"],[false,\"search\"]]},\"threshold\":0,\"name\":\"Tickets Analysis\"})", + "E24": "=_t(\"Assignee\")", + "E25": "=PIVOT.HEADER(1,\"#user_id\",1)", + "E26": "=PIVOT.HEADER(1,\"#user_id\",2)", + "E27": "=PIVOT.HEADER(1,\"#user_id\",3)", + "E28": "=PIVOT.HEADER(1,\"#user_id\",4)", + "E29": "=PIVOT.HEADER(1,\"#user_id\",5)", + "E30": "=PIVOT.HEADER(1,\"#user_id\",6)", + "E31": "=PIVOT.HEADER(1,\"#user_id\",7)", + "E32": "=PIVOT.HEADER(1,\"#user_id\",8)", + "E33": "=PIVOT.HEADER(1,\"#user_id\",9)", + "E34": "=PIVOT.HEADER(1,\"#user_id\",10)", + "F24": "=_t(\"Tickets\")", + "F25": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",1)", + "F26": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",2)", + "F27": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",3)", + "F28": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",4)", + "F29": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",5)", + "F30": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",6)", + "F31": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",7)", + "F32": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",8)", + "F33": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",9)", + "F34": "=PIVOT.VALUE(1,\"__count\",\"#user_id\",10)", + "A36": "[Tickets by Tags](odoo://view/{\"viewType\":\"pivot\",\"action\":{\"domain\":[[\"tag_ids\",\"!=\",false]],\"context\":{\"group_by\":[\"tag_ids\"],\"pivot_measures\":[\"__count\"],\"pivot_column_groupby\":[],\"pivot_row_groupby\":[\"tag_ids\"]},\"modelName\":\"helpdesk.ticket\",\"views\":[[false,\"graph\"],[false,\"pivot\"],[false,\"list\"],[false,\"search\"]]},\"threshold\":0,\"name\":\"Tickets Analysis\"})", + "A37": "=_t(\"Tag\")", + "A38": "=PIVOT.HEADER(3,\"#tag_ids\",1)", + "A39": "=PIVOT.HEADER(3,\"#tag_ids\",2)", + "A40": "=PIVOT.HEADER(3,\"#tag_ids\",3)", + "A41": "=PIVOT.HEADER(3,\"#tag_ids\",4)", + "A42": "=PIVOT.HEADER(3,\"#tag_ids\",5)", + "A43": "=PIVOT.HEADER(3,\"#tag_ids\",6)", + "A44": "=PIVOT.HEADER(3,\"#tag_ids\",7)", + "A45": "=PIVOT.HEADER(3,\"#tag_ids\",8)", + "A46": "=PIVOT.HEADER(3,\"#tag_ids\",9)", + "A47": "=PIVOT.HEADER(3,\"#tag_ids\",10)", + "B37": "=_t(\"Tickets\")", + "B38": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",1)", + "B39": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",2)", + "B40": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",3)", + "B41": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",4)", + "B42": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",5)", + "B43": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",6)", + "B44": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",7)", + "B45": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",8)", + "B46": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",9)", + "B47": "=PIVOT.VALUE(3,\"__count\",\"#tag_ids\",10)" + }, + "styles": { + "A7": 1, + "A23": 1, + "A36": 1, + "E7": 1, + "E23": 1, + "A24": 2, + "A37": 2, + "E24": 2, + "E37": 2, + "A25:C34": 3, + "A38:C47": 3, + "E25:G34": 3, + "E38:G47": 3, + "B24:C24": 4, + "B37:C37": 4, + "F24:G24": 4, + "F37:G37": 4 + }, + "formats": {}, + "borders": { + "A7:C7": 1, + "A23:C23": 1, + "A36:C36": 1, + "E7:G7": 1, + "E23:G23": 1, + "E36:G36": 1, + "A8:C8": 2, + "A24:C24": 2, + "A37:C37": 2, + "E8:G8": 2, + "E24:G24": 2, + "E37:G37": 2, + "A25:C25": 3, + "A38:C38": 3, + "E25:G25": 3, + "E38:G38": 3, + "A26:C33": 4, + "A39:C46": 4, + "E26:G33": 4, + "E39:G46": 4, + "A34:C34": 5, + "A47:C47": 5, + "E34:G34": 5, + "E47:G47": 5, + "A35:C35": 6, + "A48:C48": 6, + "E35:G35": 6, + "E48:G48": 6 + }, + "conditionalFormats": [ + { + "rule": {"type": "DataBarRule", "color": 15531509, "rangeValues": "B25:B34"}, + "id": "62781980-687b-452e-bf4b-1d95aa74b206", + "ranges": ["A25:A34"] + }, + { + "rule": {"type": "DataBarRule", "color": 15726335, "rangeValues": "F25:F34"}, + "id": "fa3cf786-7e59-4040-b972-a8ea6adfa84a", + "ranges": ["E25:E34"] + }, + { + "rule": {"type": "DataBarRule", "color": 16775149, "rangeValues": "B38:B47"}, + "id": "4da45c58-2120-47f1-9c38-efc72705ce1e", + "ranges": ["A38:A47"] + } + ], + "dataValidationRules": [], + "figures": [ + { + "id": "26f09a19-26d7-4d7d-b8d9-9eda7661ef5a", + "width": 475, + "height": 344, + "tag": "chart", + "data": { + "title": {"text": ""}, + "background": "#FFFFFF", + "legendPosition": "top", + "metaData": { + "groupBy": ["stage_id", "team_id"], + "measure": "__count", + "order": null, + "resModel": "helpdesk.ticket", + "mode": "bar", + "cumulatedStart": false + }, + "searchParams": { + "comparison": null, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [], + "groupBy": ["stage_id", "team_id"], + "orderBy": [] + }, + "type": "odoo_bar", + "dataSets": [], + "verticalAxisPosition": "left", + "stacked": true, + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + } + }, + "offset": {"x": 525, "y": 178}, + "col": 0, + "row": 0 + }, + { + "id": "70a88eff-8ce0-4392-8905-156ef2771086", + "width": 480, + "height": 344, + "tag": "chart", + "data": { + "title": {"text": ""}, + "background": "#FFFFFF", + "legendPosition": "top", + "metaData": { + "groupBy": ["stage_id"], + "measure": "__count", + "order": null, + "resModel": "helpdesk.ticket", + "mode": "pie", + "cumulatedStart": false + }, + "searchParams": { + "comparison": null, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [], + "groupBy": ["stage_id"], + "orderBy": [] + }, + "type": "odoo_pie", + "dataSets": [], + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + } + }, + "offset": {"x": 0, "y": 178}, + "col": 0, + "row": 0 + }, + { + "id": "8eae55ae-5435-49ee-ad58-dae822bbd9dd", + "width": 200, + "height": 108, + "tag": "chart", + "data": { + "baselineColorDown": "#DC6965", + "baselineColorUp": "#00A04A", + "baselineMode": "difference", + "title": {"text": "Tickets", "bold": true, "color": "#434343"}, + "type": "scorecard", + "background": "#EFF6FF", + "keyValue": "Data!D2", + "humanize": false, + "fieldMatching": {}, + "baseline": "Data!E2" + }, + "offset": {"x": 0, "y": 10}, + "col": 0, + "row": 0 + }, + { + "id": "746a2799-0dc9-4bce-b309-4cedffa67a3a", + "width": 200, + "height": 108, + "tag": "chart", + "data": { + "baselineColorDown": "#DC6965", + "baselineColorUp": "#00A04A", + "baselineMode": "percentage", + "title": {"text": "Open Tickets", "bold": true, "color": "#434343"}, + "type": "scorecard", + "background": "#FEF2F2", + "baseline": "Data!E3", + "baselineDescr": {"text": "since last period"}, + "keyValue": "Data!D3", + "humanize": false, + "fieldMatching": {} + }, + "offset": {"x": 210, "y": 10}, + "col": 0, + "row": 0 + }, + { + "id": "488da38e-01db-46a0-b4b0-e2fafc4ad390", + "width": 200, + "height": 108, + "tag": "chart", + "data": { + "baselineColorDown": "#DC6965", + "baselineColorUp": "#00A04A", + "baselineMode": "difference", + "title": {"text": "Time to Assign", "bold": true, "color": "#434343"}, + "type": "scorecard", + "background": "#FEF2F2", + "baseline": "Data!E4", + "baselineDescr": {"text": "last period"}, + "keyValue": "Data!D4", + "humanize": false, + "fieldMatching": {} + }, + "offset": {"x": 420, "y": 10}, + "col": 0, + "row": 0 + }, + { + "id": "ce7e17ea-eed0-493e-9968-5905c0969ca9", + "width": 200, + "height": 108, + "tag": "chart", + "data": { + "baselineColorDown": "#DC6965", + "baselineColorUp": "#00A04A", + "baselineMode": "difference", + "title": {"text": "Time to Close", "color": "#434343", "bold": true}, + "type": "scorecard", + "background": "#FEF2F2", + "baseline": "Data!E5", + "baselineDescr": {"text": "last period"}, + "keyValue": "Data!D5", + "humanize": false, + "fieldMatching": {} + }, + "offset": {"x": 629, "y": 10}, + "col": 0, + "row": 0 + } + ], + "tables": [ + { + "range": "A24:C34", + "type": "static", + "config": { + "hasFilters": false, + "totalRow": false, + "firstColumn": false, + "lastColumn": false, + "numberOfHeaders": 1, + "bandedRows": true, + "bandedColumns": false, + "automaticAutofill": true, + "styleId": "None" + } + }, + { + "range": "A37:C47", + "type": "static", + "config": { + "hasFilters": false, + "totalRow": false, + "firstColumn": false, + "lastColumn": false, + "numberOfHeaders": 1, + "bandedRows": true, + "bandedColumns": false, + "automaticAutofill": true, + "styleId": "None" + } + }, + { + "range": "E24:G34", + "type": "static", + "config": { + "hasFilters": false, + "totalRow": false, + "firstColumn": false, + "lastColumn": false, + "numberOfHeaders": 1, + "bandedRows": true, + "bandedColumns": false, + "automaticAutofill": true, + "styleId": "None" + } + }, + { + "range": "E37:G47", + "type": "static", + "config": { + "hasFilters": false, + "totalRow": false, + "firstColumn": false, + "lastColumn": false, + "numberOfHeaders": 1, + "bandedRows": true, + "bandedColumns": false, + "automaticAutofill": true, + "styleId": "None" + } + } + ], + "areGridLinesVisible": true, + "isVisible": true, + "headerGroups": {"ROW": [], "COL": []}, + "comments": {} + }, + { + "id": "add7aca3-0196-4975-a083-1a0ad034c57d", + "name": "Data", + "colNumber": 26, + "rowNumber": 90, + "rows": {}, + "cols": { + "0": {"size": 119}, + "1": {"size": 119}, + "2": {"size": 97}, + "3": {"size": 144}, + "4": {"size": 138} + }, + "merges": [], + "cells": { + "A1": "=_t(\"KPI\")", + "A2": "=_t(\"Tickets\")", + "A3": "=_t(\"Open tickets\")", + "A4": "=_t(\"Time to Assign\")", + "A5": "=_t(\"Time to Close\")", + "B1": "=_t(\"Current\")", + "B2": "=PIVOT.VALUE(5,\"__count\")", + "B3": "=PIVOT.VALUE(7,\"__count\")", + "B4": "=PIVOT.VALUE(5,\"hours_to_assign\")", + "B5": "=PIVOT.VALUE(5,\"hours_to_close\")", + "C1": "=_t(\"Previous\")", + "C2": "=PIVOT.VALUE(6,\"__count\")", + "C3": "=PIVOT.VALUE(8,\"__count\")", + "C4": "=PIVOT.VALUE(6,\"hours_to_assign\")", + "C5": "=PIVOT.VALUE(6,\"hours_to_close\")", + "D1": "=_t(\"Current\")", + "D2": "=FORMAT.LARGE.NUMBER(B2)", + "D3": "=FORMAT.LARGE.NUMBER(B3)", + "D4": "=CONCATENATE(ROUND(B4),_t(\" hours\"))", + "D5": "=CONCATENATE(ROUND(B5),_t(\" hours\"))", + "E1": "=_t(\"Previous\")", + "E2": "=FORMAT.LARGE.NUMBER(C2)", + "E3": "=FORMAT.LARGE.NUMBER(C3)", + "E4": "=ROUND(C4)", + "E5": "=ROUND(C5)" + }, + "styles": {"A1:C1": 5, "D1:E1": 6, "D2:E3": 7, "D4:E5": 8}, + "formats": {}, + "borders": {}, + "conditionalFormats": [], + "dataValidationRules": [], + "figures": [], + "tables": [], + "areGridLinesVisible": true, + "isVisible": true, + "headerGroups": {"ROW": [], "COL": []}, + "comments": {} + } + ], + "styles": { + "1": {"textColor": "#01666b", "fontSize": 16, "bold": true}, + "2": {"textColor": "#434343", "bold": true, "fontSize": 11}, + "3": {"textColor": "#434343", "verticalAlign": "middle"}, + "4": {"textColor": "#434343", "bold": true, "fontSize": 11, "align": "center"}, + "5": {"bold": true}, + "6": {"bold": true, "fillColor": "#f2f2f2"}, + "7": {"fillColor": "#f2f2f2"}, + "8": {"align": "right", "fillColor": "#f2f2f2"} + }, + "formats": {}, + "borders": { + "1": {"bottom": {"style": "thin", "color": "#CCCCCC"}}, + "2": {"top": {"style": "thin", "color": "#CCCCCC"}}, + "3": {"bottom": {"style": "thick", "color": "#FFFFFF"}}, + "4": { + "top": {"style": "thick", "color": "#FFFFFF"}, + "bottom": {"style": "thick", "color": "#FFFFFF"} + }, + "5": { + "top": {"style": "thick", "color": "#FFFFFF"}, + "bottom": {"style": "thin", "color": "#FFFFFF"} + }, + "6": {"top": {"style": "thin", "color": "#FFFFFF"}} + }, + "revisionId": "START_REVISION", + "uniqueFigureIds": true, + "settings": { + "locale": { + "name": "English (US)", + "code": "en_US", + "thousandsSeparator": ",", + "decimalSeparator": ".", + "dateFormat": "mm/dd/yyyy", + "timeFormat": "hh:mm:ss", + "formulaArgSeparator": ",", + "weekStart": 7 + } + }, + "pivots": { + "1": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["user_id", "!=", false]], + "id": "1", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "Tickets by Assignee", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "1", + "columns": [], + "rows": [{"fieldName": "user_id"}] + }, + "2": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["team_id", "!=", false]], + "id": "2", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "Tickets by Team", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "2", + "columns": [], + "rows": [{"fieldName": "team_id"}] + }, + "3": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["tag_ids", "!=", false]], + "id": "3", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "Tickets by Tags", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "3", + "columns": [], + "rows": [{"fieldName": "tag_ids"}] + }, + "4": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["partner_id", "!=", false]], + "id": "4", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "Tickets by Customer", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "4", + "columns": [], + "rows": [{"fieldName": "partner_id"}] + }, + "5": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [], + "id": "5", + "measures": [ + {"id": "__count", "fieldName": "__count"}, + {"id": "hours_to_assign", "fieldName": "hours_to_assign"}, + {"id": "hours_to_close", "fieldName": "hours_to_close"} + ], + "model": "helpdesk.ticket", + "name": "stats - current", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "5", + "columns": [], + "rows": [] + }, + "6": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": -1 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [], + "id": "6", + "measures": [ + {"id": "__count", "fieldName": "__count"}, + {"id": "hours_to_assign", "fieldName": "hours_to_assign"}, + {"id": "hours_to_close", "fieldName": "hours_to_close"} + ], + "model": "helpdesk.ticket", + "name": "stats - previous", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "6", + "columns": [], + "rows": [] + }, + "7": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": 0 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["closed", "=", false]], + "id": "7", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "open tickets - current", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "7", + "columns": [], + "rows": [] + }, + "8": { + "type": "ODOO", + "fieldMatching": { + "83b5c62c-1c67-4477-a057-c0ec29edd595": { + "chain": "create_date", + "type": "datetime", + "offset": -1 + }, + "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d": { + "chain": "user_id", + "type": "many2one" + }, + "3fc9b370-1aae-436e-b77e-6bbc5f10f56c": { + "chain": "team_id", + "type": "many2one" + }, + "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9": { + "chain": "tag_ids", + "type": "many2many" + }, + "9c9461c3-974d-41c1-8cbd-2fa8e89de148": { + "chain": "partner_id", + "type": "many2one" + } + }, + "context": {"group_by": [], "graph_measure": "__count__"}, + "domain": [["closed", "=", false]], + "id": "8", + "measures": [{"id": "__count", "fieldName": "__count"}], + "model": "helpdesk.ticket", + "name": "open tickets - previous", + "sortedColumn": {"measure": "__count", "order": "desc", "domain": []}, + "formulaId": "8", + "columns": [], + "rows": [] + } + }, + "pivotNextId": 9, + "customTableStyles": {}, + "globalFilters": [ + { + "id": "83b5c62c-1c67-4477-a057-c0ec29edd595", + "type": "date", + "label": "Period", + "defaultValue": "last_30_days" + }, + { + "id": "fb7f6ae2-e19c-40d5-9976-7a05b1f18c2d", + "type": "relation", + "label": "Agent", + "modelName": "res.users", + "defaultValueDisplayNames": [] + }, + { + "id": "3fc9b370-1aae-436e-b77e-6bbc5f10f56c", + "type": "relation", + "label": "Team", + "modelName": "helpdesk.ticket.team", + "defaultValueDisplayNames": [] + }, + { + "id": "cfccbf2c-c86e-4915-a73d-c1e8ae69abe9", + "type": "relation", + "label": "Tags", + "modelName": "helpdesk.ticket.tag", + "defaultValueDisplayNames": [] + }, + { + "id": "9c9461c3-974d-41c1-8cbd-2fa8e89de148", + "type": "relation", + "label": "Customer", + "modelName": "res.partner", + "defaultValueDisplayNames": [] + } + ], + "lists": {}, + "listNextId": 1, + "chartOdooMenusReferences": { + "26f09a19-26d7-4d7d-b8d9-9eda7661ef5a": "helpdesk_mgmt.helpdesk_ticket_main_menu", + "70a88eff-8ce0-4392-8905-156ef2771086": "helpdesk_mgmt.helpdesk_ticket_main_menu", + "8eae55ae-5435-49ee-ad58-dae822bbd9dd": "helpdesk_mgmt.helpdesk_ticket_main_menu", + "746a2799-0dc9-4bce-b309-4cedffa67a3a": "helpdesk_mgmt.helpdesk_ticket_main_menu", + "488da38e-01db-46a0-b4b0-e2fafc4ad390": "helpdesk_mgmt.helpdesk_ticket_main_menu", + "ce7e17ea-eed0-493e-9968-5905c0969ca9": "helpdesk_mgmt.helpdesk_ticket_main_menu" + } +} diff --git a/spreadsheet_dashboard_helpdesk_oca/models/__init__.py b/spreadsheet_dashboard_helpdesk_oca/models/__init__.py new file mode 100644 index 00000000..8e082e7c --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/models/__init__.py @@ -0,0 +1 @@ +from . import helpdesk_ticket diff --git a/spreadsheet_dashboard_helpdesk_oca/models/helpdesk_ticket.py b/spreadsheet_dashboard_helpdesk_oca/models/helpdesk_ticket.py new file mode 100644 index 00000000..65ff64bc --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/models/helpdesk_ticket.py @@ -0,0 +1,33 @@ +# Copyright 2026 Domatix +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class HelpdeskTicket(models.Model): + _inherit = "helpdesk.ticket" + + hours_to_assign = fields.Float( + compute="_compute_hours_metrics", + store=True, + aggregator="avg", + ) + hours_to_close = fields.Float( + compute="_compute_hours_metrics", + store=True, + aggregator="avg", + ) + + @api.depends("create_date", "assigned_date", "closed_date") + def _compute_hours_metrics(self): + for ticket in self: + hours_to_assign = 0.0 + hours_to_close = 0.0 + if ticket.create_date and ticket.assigned_date: + delta = ticket.assigned_date - ticket.create_date + hours_to_assign = delta.total_seconds() / 3600 + if ticket.create_date and ticket.closed_date: + delta = ticket.closed_date - ticket.create_date + hours_to_close = delta.total_seconds() / 3600 + ticket.hours_to_assign = hours_to_assign + ticket.hours_to_close = hours_to_close diff --git a/spreadsheet_dashboard_helpdesk_oca/pyproject.toml b/spreadsheet_dashboard_helpdesk_oca/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/spreadsheet_dashboard_helpdesk_oca/readme/CONTRIBUTORS.md b/spreadsheet_dashboard_helpdesk_oca/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..6ab0fbbc --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Domatix diff --git a/spreadsheet_dashboard_helpdesk_oca/readme/DESCRIPTION.md b/spreadsheet_dashboard_helpdesk_oca/readme/DESCRIPTION.md new file mode 100644 index 00000000..5d743a0c --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/readme/DESCRIPTION.md @@ -0,0 +1 @@ +Spreadsheet dashboard for helpdesk tickets. diff --git a/spreadsheet_dashboard_helpdesk_oca/static/description/icon.png b/spreadsheet_dashboard_helpdesk_oca/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b3ad914af95726eb8aaa6cf891f268c9a3b3bc5d GIT binary patch literal 36748 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 Ssu-340000 + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Spreadsheet dashboard for helpdesk

+ +

Beta License: AGPL-3 OCA/spreadsheet Translate me on Weblate Try me on Runboat

+

Spreadsheet dashboard for helpdesk tickets.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Domatix
  • +
+
+
+

Contributors

+
    +
  • Domatix
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

domatix

+

This module is part of the OCA/spreadsheet project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/spreadsheet_dashboard_helpdesk_oca/tests/__init__.py b/spreadsheet_dashboard_helpdesk_oca/tests/__init__.py new file mode 100644 index 00000000..89f9d092 --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/tests/__init__.py @@ -0,0 +1 @@ +from . import test_helpdesk_ticket_metrics diff --git a/spreadsheet_dashboard_helpdesk_oca/tests/test_helpdesk_ticket_metrics.py b/spreadsheet_dashboard_helpdesk_oca/tests/test_helpdesk_ticket_metrics.py new file mode 100644 index 00000000..1cc5cedc --- /dev/null +++ b/spreadsheet_dashboard_helpdesk_oca/tests/test_helpdesk_ticket_metrics.py @@ -0,0 +1,30 @@ +# Copyright 2026 Domatix +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from odoo import fields +from odoo.tests import tagged + +from odoo.addons.helpdesk_mgmt.tests.common import TestHelpdeskTicketBase + + +@tagged("post_install", "-at_install") +class TestHelpdeskTicketMetrics(TestHelpdeskTicketBase): + def test_hours_metrics(self): + now = fields.Datetime.now() + ticket = self.env["helpdesk.ticket"].create( + { + "name": "Broken printer", + "description": "

Test

", + "team_id": self.team_a.id, + } + ) + ticket.write( + { + "assigned_date": now + timedelta(hours=2), + "closed_date": now + timedelta(hours=5), + } + ) + self.assertAlmostEqual(ticket.hours_to_assign, 2.0, places=2) + self.assertAlmostEqual(ticket.hours_to_close, 5.0, places=2)