Skip to content

Commit 7f73663

Browse files
[ADD] project_task_prioritize
This module enhances Odoo's Project module by adding a flexible task prioritization system. It allows you to define custom prioritization criteria and automatically calculate task priorities based on multiple factors.
1 parent 6ecb623 commit 7f73663

26 files changed

+1493
-0
lines changed

project_task_prioritize/README.rst

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
=======================
2+
Project Task Prioritize
3+
=======================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:5aff01d38fa5ec9f8c3f15740d4a504fbda95d4e2cb95458c98b20ccf582073a
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github
20+
:target: https://github.com/OCA/project/tree/18.0/project_task_prioritize
21+
:alt: OCA/project
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/project-18-0/project-18-0-project_task_prioritize
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=18.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module enhances project module by adding a flexible task
32+
prioritization system. It allows you to define custom prioritization
33+
criteria and automatically calculate task priorities based on multiple
34+
factors.
35+
36+
Key Features
37+
============
38+
39+
- Define custom prioritization categories (e.g., Impact, Urgency,
40+
Strategic Value)
41+
- Create weighted scoring criteria for each category
42+
- Configure custom priority calculation formulas
43+
- Easy-to-use matrix interface for setting task priorities
44+
- Automatic priority calculation based on defined criteria
45+
- Demo data included with common prioritization templates
46+
47+
Demo Data
48+
=========
49+
50+
The module includes demo data with the following prioritization
51+
categories:
52+
53+
- **Organizational Impact**: Measures how widely the task affects the
54+
organization
55+
- **Frequency of Use**: How often the task or its results are used
56+
- **Risk / Consequences of Not Doing It**: The impact of not completing
57+
the task
58+
- **Strategic Value**: How well the task aligns with strategic goals
59+
- **Productivity Benefit**: The expected productivity gain from
60+
completing the task
61+
62+
**Table of contents**
63+
64+
.. contents::
65+
:local:
66+
67+
Configuration
68+
=============
69+
70+
1. **Set Up Categories**:
71+
72+
- Navigate to Project > Configuration > Prioritizer > Categories
73+
- Create categories that are relevant to your prioritization needs
74+
- Define the possible values for each category with appropriate
75+
weights
76+
77+
2. **Configure Projects**:
78+
79+
- Open a project and go to the "Prioritizer Configuration" tab
80+
- Select the prioritization categories to use for tasks in this
81+
project
82+
- Optionally, customize the priority calculation formula
83+
84+
3. **Prioritize Tasks**:
85+
86+
- Select tasks in the task list view
87+
- Click on "Prioritize Tasks"
88+
- Set the appropriate values for each category in the matrix view
89+
- Click "Validate" to save the priorities
90+
91+
Usage
92+
=====
93+
94+
Priority Calculation
95+
--------------------
96+
97+
The module calculates task priorities using a configurable formula. The
98+
default formula is:
99+
100+
::
101+
102+
prioritizer_sum / (allocated_hours * (max_value - prioritizer_sum + 1))
103+
104+
Available variables in the formula:
105+
106+
- ``prioritizer_sum``: Sum of all selected prioritizer values
107+
- ``max_value``: Sum of maximum values from all selected categories
108+
- ``allocated_hours``: Number of hours allocated to the task
109+
- ``rec``: The task record itself
110+
111+
Bug Tracker
112+
===========
113+
114+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/project/issues>`_.
115+
In case of trouble, please check there if your issue has already been reported.
116+
If you spotted it first, help us to smash it by providing a detailed and welcomed
117+
`feedback <https://github.com/OCA/project/issues/new?body=module:%20project_task_prioritize%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
118+
119+
Do not contact contributors directly about support or help with technical issues.
120+
121+
Credits
122+
=======
123+
124+
Authors
125+
-------
126+
127+
* ForgeFlow
128+
129+
Contributors
130+
------------
131+
132+
- David Jimenez [email protected]
133+
134+
Maintainers
135+
-----------
136+
137+
This module is maintained by the OCA.
138+
139+
.. image:: https://odoo-community.org/logo.png
140+
:alt: Odoo Community Association
141+
:target: https://odoo-community.org
142+
143+
OCA, or the Odoo Community Association, is a nonprofit organization whose
144+
mission is to support the collaborative development of Odoo features and
145+
promote its widespread use.
146+
147+
This module is part of the `OCA/project <https://github.com/OCA/project/tree/18.0/project_task_prioritize>`_ project on GitHub.
148+
149+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import models
2+
from . import wizards
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Project Task Prioritize",
5+
"summary": "Allows to define a task prioritizer format.",
6+
"version": "18.0.1.0.0",
7+
"category": "Project",
8+
"author": "ForgeFlow, Odoo Community Association (OCA)",
9+
"contributors": ["DavidJForgeFlow"],
10+
"website": "https://github.com/OCA/project",
11+
"license": "AGPL-3",
12+
"depends": ["project", "web_widget_x2many_2d_matrix"],
13+
"data": [
14+
"security/ir.model.access.csv",
15+
"wizards/project_task_prioritizer_view.xml",
16+
"views/project_view.xml",
17+
"views/prioritizer_category_views.xml",
18+
],
19+
"demo": ["demo/prioritizer_category_data.xml"],
20+
"installable": True,
21+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!--
3+
Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
4+
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
5+
-->
6+
<odoo noupdate="1">
7+
<!-- Prioritizer Categories -->
8+
<record id="pc_organizational_impact" model="prioritizer.category">
9+
<field name="name">Organizational Impact</field>
10+
</record>
11+
<record id="pc_frequency_use" model="prioritizer.category">
12+
<field name="name">Frequency of Use</field>
13+
</record>
14+
<record id="pc_risk" model="prioritizer.category">
15+
<field name="name">Risk / Consequences of Not Doing It</field>
16+
</record>
17+
<record id="pc_strategic_value" model="prioritizer.category">
18+
<field name="name">Strategic Value</field>
19+
</record>
20+
<record id="pc_productivity_benefit" model="prioritizer.category">
21+
<field name="name">Productivity Benefit</field>
22+
</record>
23+
24+
<!-- Prioritizer Categories Lines-->
25+
<record id="pcl_organizational_impact_0" model="prioritizer.category.line">
26+
<field name="prioritizer_category_id" ref="pc_organizational_impact" />
27+
<field name="name">Affects only one user</field>
28+
<field name="value">0</field>
29+
</record>
30+
<record id="pcl_organizational_impact_1" model="prioritizer.category.line">
31+
<field name="prioritizer_category_id" ref="pc_organizational_impact" />
32+
<field name="name">Affects one full department</field>
33+
<field name="value">1</field>
34+
</record>
35+
<record id="pcl_organizational_impact_2" model="prioritizer.category.line">
36+
<field name="prioritizer_category_id" ref="pc_organizational_impact" />
37+
<field name="name">Affects multiple departments / customers</field>
38+
<field name="value">2</field>
39+
</record>
40+
<record id="pcl_frequency_use_0" model="prioritizer.category.line">
41+
<field name="prioritizer_category_id" ref="pc_frequency_use" />
42+
<field name="name">Used sporadically (less than once a month)</field>
43+
<field name="value">0</field>
44+
</record>
45+
<record id="pcl_frequency_use_1" model="prioritizer.category.line">
46+
<field name="prioritizer_category_id" ref="pc_frequency_use" />
47+
<field name="name">Used regularly (about once a week)</field>
48+
<field name="value">1</field>
49+
</record>
50+
<record id="pcl_frequency_use_2" model="prioritizer.category.line">
51+
<field name="prioritizer_category_id" ref="pc_frequency_use" />
52+
<field name="name">Used daily</field>
53+
<field name="value">2</field>
54+
</record>
55+
<record id="pcl_risk_0" model="prioritizer.category.line">
56+
<field name="prioritizer_category_id" ref="pc_risk" />
57+
<field name="name">Low risk, only minor inconvenience</field>
58+
<field name="value">0</field>
59+
</record>
60+
<record id="pcl_risk_1" model="prioritizer.category.line">
61+
<field name="prioritizer_category_id" ref="pc_risk" />
62+
<field name="name">Medium risk, frequent errors or inefficiency</field>
63+
<field name="value">1</field>
64+
</record>
65+
<record id="pcl_risk_2" model="prioritizer.category.line">
66+
<field name="prioritizer_category_id" ref="pc_risk" />
67+
<field name="name">High risk, affects finances, customers, or compliance</field>
68+
<field name="value">2</field>
69+
</record>
70+
<record id="pcl_strategic_value_0" model="prioritizer.category.line">
71+
<field name="prioritizer_category_id" ref="pc_strategic_value" />
72+
<field name="name">Minor improvement, not related to strategic goals</field>
73+
<field name="value">0</field>
74+
</record>
75+
<record id="pcl_strategic_value_1" model="prioritizer.category.line">
76+
<field name="prioritizer_category_id" ref="pc_strategic_value" />
77+
<field name="name">Aligned with internal improvement objectives</field>
78+
<field name="value">1</field>
79+
</record>
80+
<record id="pcl_strategic_value_2" model="prioritizer.category.line">
81+
<field name="prioritizer_category_id" ref="pc_strategic_value" />
82+
<field name="name">Aligned with business strategic goals</field>
83+
<field name="value">2</field>
84+
</record>
85+
<record id="pcl_productivity_benefit_0" model="prioritizer.category.line">
86+
<field name="prioritizer_category_id" ref="pc_productivity_benefit" />
87+
<field name="name">Savings &lt; 1h/month</field>
88+
<field name="value">0</field>
89+
</record>
90+
<record id="pcl_productivity_benefit_1" model="prioritizer.category.line">
91+
<field name="prioritizer_category_id" ref="pc_productivity_benefit" />
92+
<field name="name">Savings 1–10h/month</field>
93+
<field name="value">1</field>
94+
</record>
95+
<record id="pcl_productivity_benefit_2" model="prioritizer.category.line">
96+
<field name="prioritizer_category_id" ref="pc_productivity_benefit" />
97+
<field name="name">Savings > 10h/month</field>
98+
<field name="value">2</field>
99+
</record>
100+
</odoo>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from . import project
2+
from . import project_task
3+
from . import prioritizer_category_line
4+
from . import prioritizer_category
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import api, fields, models
4+
5+
6+
class PrioritizerCategory(models.Model):
7+
_name = "prioritizer.category"
8+
_description = "Prioritizer Category"
9+
10+
name = fields.Char()
11+
prioritizer_category_line_ids = fields.One2many(
12+
"prioritizer.category.line", inverse_name="prioritizer_category_id"
13+
)
14+
max_value = fields.Integer(compute="_compute_max_value", store=True)
15+
16+
@api.depends("prioritizer_category_line_ids")
17+
def _compute_max_value(self):
18+
for rec in self:
19+
rec.max_value = (
20+
max([pcl.value for pcl in rec.prioritizer_category_line_ids])
21+
if rec.prioritizer_category_line_ids
22+
else 1
23+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import fields, models
4+
5+
6+
class PrioritizerCategoryLine(models.Model):
7+
_name = "prioritizer.category.line"
8+
_description = "Prioritizer Category Line"
9+
10+
name = fields.Char()
11+
value = fields.Integer()
12+
prioritizer_category_id = fields.Many2one(comodel_name="prioritizer.category")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import fields, models
4+
5+
6+
class ProjectProject(models.Model):
7+
_inherit = "project.project"
8+
9+
prioritizer_category_ids = fields.Many2many("prioritizer.category")
10+
prioritizer_formula = fields.Text(
11+
default=lambda self: (
12+
"# Python expression to calculate prioritizer_value\n"
13+
"# Available variables:\n"
14+
"# - prioritizer_sum: sum of prioritizer line values\n"
15+
"# - max_value: sum of max values from prioritizer categories\n"
16+
"# - allocated_hours: hours allocated to the project/task\n"
17+
"# - rec: current record (project/task)\n"
18+
"\n"
19+
"# Example:\n"
20+
"prioritizer_sum / (allocated_hours * (max_value - prioritizer_sum + 1)) "
21+
),
22+
help="Define a Python expression to compute the prioritizer value.",
23+
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2025 ForgeFlow S.L. (https://www.forgeflow.com)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import api, fields, models
4+
from odoo.tools.safe_eval import safe_eval
5+
6+
7+
class ProjectTask(models.Model):
8+
_inherit = "project.task"
9+
10+
prioritizer_value = fields.Float(compute="_compute_prioritizer_value", store=True)
11+
prioritizer_line_ids = fields.Many2many("prioritizer.category.line")
12+
13+
@api.depends("prioritizer_line_ids", "allocated_hours")
14+
def _compute_prioritizer_value(self):
15+
for rec in self:
16+
prioritizer_sum = sum([pcl.value for pcl in rec.prioritizer_line_ids])
17+
max_value = sum(
18+
[pc.max_value for pc in rec.project_id.prioritizer_category_ids]
19+
)
20+
locals_dict = {
21+
"prioritizer_sum": prioritizer_sum,
22+
"max_value": max_value,
23+
"allocated_hours": rec.allocated_hours,
24+
"rec": rec,
25+
}
26+
formula = rec.project_id.prioritizer_formula or "0"
27+
try:
28+
rec.prioritizer_value = safe_eval(formula, locals_dict=locals_dict)
29+
except Exception:
30+
rec.prioritizer_value = 0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"

0 commit comments

Comments
 (0)