From b4bba58efffbee213ebf89d106705b6545b3a905 Mon Sep 17 00:00:00 2001 From: Abdellatif Benzbiria Date: Mon, 8 Jun 2026 12:27:41 +0000 Subject: [PATCH 1/3] [14.0][ADD] project_timesheet_hours_only --- .docker_files/main/__manifest__.py | 1 + Dockerfile | 1 + .../models/account_analytic_line.py | 2 +- project_timesheet_hours_only/README.rst | 40 ++++++++++++++++++ project_timesheet_hours_only/__init__.py | 4 ++ project_timesheet_hours_only/__manifest__.py | 17 ++++++++ .../models/__init__.py | 4 ++ .../models/project_project.py | 22 ++++++++++ .../static/description/icon.png | Bin 0 -> 7982 bytes .../tests/__init__.py | 2 + .../tests/test_project_timesheet.py | 35 +++++++++++++++ .../views/project_project_views.xml | 6 +++ 12 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 project_timesheet_hours_only/README.rst create mode 100644 project_timesheet_hours_only/__init__.py create mode 100644 project_timesheet_hours_only/__manifest__.py create mode 100644 project_timesheet_hours_only/models/__init__.py create mode 100644 project_timesheet_hours_only/models/project_project.py create mode 100644 project_timesheet_hours_only/static/description/icon.png create mode 100644 project_timesheet_hours_only/tests/__init__.py create mode 100644 project_timesheet_hours_only/tests/test_project_timesheet.py create mode 100644 project_timesheet_hours_only/views/project_project_views.xml diff --git a/.docker_files/main/__manifest__.py b/.docker_files/main/__manifest__.py index abdf532a..0f9b484a 100644 --- a/.docker_files/main/__manifest__.py +++ b/.docker_files/main/__manifest__.py @@ -73,6 +73,7 @@ "project_time_control_wizard_group", "project_time_range", "project_timesheet_analytic_update", + "project_timesheet_hours_only", "project_type", "project_wip", "project_wip_batch_closing", diff --git a/Dockerfile b/Dockerfile index 9c38a1e6..ef90e7af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,6 +74,7 @@ COPY project_time_budget /mnt/extra-addons/project_time_budget COPY project_time_control_wizard_group /mnt/extra-addons/project_time_control_wizard_group COPY project_time_range /mnt/extra-addons/project_time_range COPY project_timesheet_analytic_update /mnt/extra-addons/project_timesheet_analytic_update +COPY project_timesheet_hours_only /mnt/extra-addons/project_timesheet_hours_only COPY project_type /mnt/extra-addons/project_type COPY project_wip /mnt/extra-addons/project_wip COPY project_wip_batch_closing /mnt/extra-addons/project_wip_batch_closing diff --git a/project_task_analytic_lines/models/account_analytic_line.py b/project_task_analytic_lines/models/account_analytic_line.py index 817d145d..84b795a9 100644 --- a/project_task_analytic_lines/models/account_analytic_line.py +++ b/project_task_analytic_lines/models/account_analytic_line.py @@ -86,7 +86,7 @@ def write(self, vals): return True def _propagate_origin_task_to_timesheet_lines(self): - """Backward propagation of origin_task_id to task_id. + """Backward propagation of origin_task_id to task_id.w This allows the system to behave in a more transparent way when manually changing the value of origin_task_id diff --git a/project_timesheet_hours_only/README.rst b/project_timesheet_hours_only/README.rst new file mode 100644 index 00000000..45e989a1 --- /dev/null +++ b/project_timesheet_hours_only/README.rst @@ -0,0 +1,40 @@ +============================ +Project Timesheet Hours Only +============================ + +.. ![]https://img.shields.io/badge/licence-AGPL--3-blue.png) + :target: https://www.gnu.org/licenses/agpl.html + :alt: License: AGPL-3 + +Context +======= +On mixed projects involving both labor (timesheets) and material tracking, Odoo's standard project dashboard aggregates all analytic lines under the "Recorded Hours" smart button. This leads to inaccurate totals since material consumption quantities (often recorded with negative or distinct values) are mixed with actual work hours. + +Description +=========== +This module fixes the project's "Recorded Hours" smart button and its corresponding list view to exclusively display and calculate actual labor hours. It filters out material consumption lines by ensuring that only analytic lines linked to a specific task (``task_id != False``) are included. + +Usage +===== +1. Navigate to the **Project** app. +2. Open any project that contains both timesheets and material consumption lines. +3. The counter on the **Recorded Hours** smart button now strictly shows the total labor hours. +4. Clicking the smart button will only list actual timesheet entries, excluding material logs. + +.. note:: + Material consumption remains fully traceable and searchable via **Project > Reporting > Material** (filtering by project and grouping as needed). + +Installation +============ +No data migration or historical recalculation is strictly required, as the change applies dynamically to the compute method and window action domain. + +Credits +======= + +Authors +------- +* Numigi + +Maintainers +----------- +This module is maintained by Numigi. diff --git a/project_timesheet_hours_only/__init__.py b/project_timesheet_hours_only/__init__.py new file mode 100644 index 00000000..96f21452 --- /dev/null +++ b/project_timesheet_hours_only/__init__.py @@ -0,0 +1,4 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import models \ No newline at end of file diff --git a/project_timesheet_hours_only/__manifest__.py b/project_timesheet_hours_only/__manifest__.py new file mode 100644 index 00000000..468a4f35 --- /dev/null +++ b/project_timesheet_hours_only/__manifest__.py @@ -0,0 +1,17 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Project Timesheet Hours Only", + "summary": "Filter project timesheet smart button to exclude material consumption and show hours only", + "version": "1.0.0", + "category": "Project", + "author": "Numigi", + "website": "https://www.numigi.com", + "license": "AGPL-3", + "depends": ["hr_timesheet", "project"], + "data": [ + "views/project_project_views.xml", + ], + "installable": True, +} diff --git a/project_timesheet_hours_only/models/__init__.py b/project_timesheet_hours_only/models/__init__.py new file mode 100644 index 00000000..232ce6c6 --- /dev/null +++ b/project_timesheet_hours_only/models/__init__.py @@ -0,0 +1,4 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import project_project \ No newline at end of file diff --git a/project_timesheet_hours_only/models/project_project.py b/project_timesheet_hours_only/models/project_project.py new file mode 100644 index 00000000..d3220506 --- /dev/null +++ b/project_timesheet_hours_only/models/project_project.py @@ -0,0 +1,22 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models + + +class ProjectProject(models.Model): + _inherit = "project.project" + + def _compute_total_timesheet_time(self): + for project in self: + project._compute_project_timesheet_time() + + def _compute_project_timesheet_time(self): + project_timesheets = self.timesheet_ids.filtered(lambda t: t.task_id) + total_time = self._calculate_timesheet_total(project_timesheets) + self.total_timesheet_time = int(round(total_time)) + + + def _calculate_timesheet_total(self, timesheets): + total = sum(t.unit_amount * t.product_uom_id.factor_inv for t in timesheets) + return total * self.timesheet_encode_uom_id.factor diff --git a/project_timesheet_hours_only/static/description/icon.png b/project_timesheet_hours_only/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..92a86b10ed6e2f6a40b286805c8c92c5dc775111 GIT binary patch literal 7982 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 + + + [('project_id', '!=', False), ('task_id', '!=', False)] + + \ No newline at end of file From ebd886b8b1ddf989f43e56e53bd5c29d1d23b411 Mon Sep 17 00:00:00 2001 From: Abdellatif Benzbiria Date: Mon, 8 Jun 2026 12:29:29 +0000 Subject: [PATCH 2/3] [14.0][ADD] project_timesheet_hours_only --- project_timesheet_hours_only/__init__.py | 2 +- project_timesheet_hours_only/__manifest__.py | 3 ++- project_timesheet_hours_only/models/__init__.py | 2 +- project_timesheet_hours_only/models/project_project.py | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/project_timesheet_hours_only/__init__.py b/project_timesheet_hours_only/__init__.py index 96f21452..36ffad66 100644 --- a/project_timesheet_hours_only/__init__.py +++ b/project_timesheet_hours_only/__init__.py @@ -1,4 +1,4 @@ # © Numigi (tm) and all its contributors (https://numigi.com/r/home) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from . import models \ No newline at end of file +from . import models diff --git a/project_timesheet_hours_only/__manifest__.py b/project_timesheet_hours_only/__manifest__.py index 468a4f35..68f98c50 100644 --- a/project_timesheet_hours_only/__manifest__.py +++ b/project_timesheet_hours_only/__manifest__.py @@ -3,7 +3,8 @@ { "name": "Project Timesheet Hours Only", - "summary": "Filter project timesheet smart button to exclude material consumption and show hours only", + "summary": "Filter project timesheet smart button to " + "exclude material consumption and show hours only", "version": "1.0.0", "category": "Project", "author": "Numigi", diff --git a/project_timesheet_hours_only/models/__init__.py b/project_timesheet_hours_only/models/__init__.py index 232ce6c6..86e6be36 100644 --- a/project_timesheet_hours_only/models/__init__.py +++ b/project_timesheet_hours_only/models/__init__.py @@ -1,4 +1,4 @@ # © Numigi (tm) and all its contributors (https://numigi.com/r/home) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from . import project_project \ No newline at end of file +from . import project_project diff --git a/project_timesheet_hours_only/models/project_project.py b/project_timesheet_hours_only/models/project_project.py index d3220506..eaa4d60e 100644 --- a/project_timesheet_hours_only/models/project_project.py +++ b/project_timesheet_hours_only/models/project_project.py @@ -16,7 +16,6 @@ def _compute_project_timesheet_time(self): total_time = self._calculate_timesheet_total(project_timesheets) self.total_timesheet_time = int(round(total_time)) - def _calculate_timesheet_total(self, timesheets): total = sum(t.unit_amount * t.product_uom_id.factor_inv for t in timesheets) return total * self.timesheet_encode_uom_id.factor From 3e7ba4d8d220e3357f884b308614d60ba4f8ea14 Mon Sep 17 00:00:00 2001 From: Abdellatif Benzbiria Date: Mon, 8 Jun 2026 13:07:09 +0000 Subject: [PATCH 3/3] [14.0][ADD] project_timesheet_hours_only --- project_timesheet_hours_only/tests/test_project_timesheet.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/project_timesheet_hours_only/tests/test_project_timesheet.py b/project_timesheet_hours_only/tests/test_project_timesheet.py index b93e27a0..7b961db6 100644 --- a/project_timesheet_hours_only/tests/test_project_timesheet.py +++ b/project_timesheet_hours_only/tests/test_project_timesheet.py @@ -5,7 +5,7 @@ from odoo.tests import common -class TestProjectTimesheetHoursOnly(common.TransactionCase): +class TestProjectTimesheetHoursOnly(common.SavepointCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -16,7 +16,6 @@ def setUpClass(cls): }) def test_compute_timesheet_excludes_material(self): - # Création d'une ligne sans tâche (ex: consommation de matériel) self.env["account.analytic.line"].create({ "project_id": self.project.id, "name": "Material", @@ -25,7 +24,6 @@ def test_compute_timesheet_excludes_material(self): self.assertEqual(self.project.total_timesheet_time, 0) def test_compute_timesheet_includes_hours(self): - # Création d'une ligne avec tâche (feuille de temps classique) self.env["account.analytic.line"].create({ "project_id": self.project.id, "task_id": self.task.id,