diff --git a/README.md b/README.md index 38d3edb887..8a31ff0b9b 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ addon | version | maintainers | summary [project_pivot](project_pivot/) | 16.0.1.0.1 | | Pivot view for projects [project_portal_task_visibility](project_portal_task_visibility/) | 16.0.1.1.0 | | Project Portal Task Visibility [project_purchase_link](project_purchase_link/) | 16.0.1.0.0 | | Project Purchase Link +[project_reviewer](project_reviewer/) | 16.0.1.0.0 | | Add the possibility to assign reviewer to a task [project_risk](project_risk/) | 16.0.1.0.0 | | MOR risk management method [project_role](project_role/) | 16.0.1.0.4 | alexey-pelykh | Project role-based roster [project_sale_order_link](project_sale_order_link/) | 16.0.1.0.0 | EmilioPascual | Sales order linked to project, tasks or employee map diff --git a/project_reviewer/README.rst b/project_reviewer/README.rst new file mode 100644 index 0000000000..867ef4102b --- /dev/null +++ b/project_reviewer/README.rst @@ -0,0 +1,85 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================ +Project Reviewer +================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:b7d9076205c52457b13075dad2302f2b7613d9625d2697957009761e3675ce1b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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%2Fproject-lightgray.png?logo=github + :target: https://github.com/OCA/project/tree/16.0/project_reviewer + :alt: OCA/project +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/project-16-0/project-16-0-project_reviewer + :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/project&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allow to set several reviewers on a project task + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**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 +------- + +* Akretion + +Contributors +------------ + +- Sébastien Beau sebastien.beau@akretion.com + +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. + +This module is part of the `OCA/project `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/project_reviewer/__init__.py b/project_reviewer/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/project_reviewer/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/project_reviewer/__manifest__.py b/project_reviewer/__manifest__.py new file mode 100644 index 0000000000..e51437a161 --- /dev/null +++ b/project_reviewer/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2025 Akretion (https://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +{ + "name": "Project Reviewer", + "summary": "Add the possibility to assign reviewer to a task", + "version": "16.0.1.0.0", + "development_status": "Alpha", + "category": "Project", + "website": "https://github.com/OCA/project", + "author": "Akretion, Odoo Community Association (OCA)", + "license": "AGPL-3", + "external_dependencies": { + "python": [], + "bin": [], + }, + "depends": [ + "project", + ], + "data": [ + "views/project_task_view.xml", + ], + "demo": [], +} diff --git a/project_reviewer/i18n/it.po b/project_reviewer/i18n/it.po new file mode 100644 index 0000000000..2185ad6941 --- /dev/null +++ b/project_reviewer/i18n/it.po @@ -0,0 +1,32 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_reviewer +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-02-12 12:09+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: project_reviewer +#: model_terms:ir.ui.view,arch_db:project_reviewer.view_task_search_form +msgid "My review" +msgstr "Mia revisione" + +#. module: project_reviewer +#: model:ir.model.fields,field_description:project_reviewer.field_project_task__reviewer_ids +msgid "Reviewers" +msgstr "Revisori" + +#. module: project_reviewer +#: model:ir.model,name:project_reviewer.model_project_task +msgid "Task" +msgstr "Lavoro" diff --git a/project_reviewer/i18n/project_reviewer.pot b/project_reviewer/i18n/project_reviewer.pot new file mode 100644 index 0000000000..8f092eb094 --- /dev/null +++ b/project_reviewer/i18n/project_reviewer.pot @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_reviewer +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: project_reviewer +#: model_terms:ir.ui.view,arch_db:project_reviewer.view_task_search_form +msgid "My review" +msgstr "" + +#. module: project_reviewer +#: model:ir.model.fields,field_description:project_reviewer.field_project_task__reviewer_ids +msgid "Reviewers" +msgstr "" + +#. module: project_reviewer +#: model:ir.model,name:project_reviewer.model_project_task +msgid "Task" +msgstr "" diff --git a/project_reviewer/models/__init__.py b/project_reviewer/models/__init__.py new file mode 100644 index 0000000000..edf2d36b9c --- /dev/null +++ b/project_reviewer/models/__init__.py @@ -0,0 +1 @@ +from . import project_task diff --git a/project_reviewer/models/project_task.py b/project_reviewer/models/project_task.py new file mode 100644 index 0000000000..eab490c6cb --- /dev/null +++ b/project_reviewer/models/project_task.py @@ -0,0 +1,14 @@ +# Copyright 2025 Akretion (https://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ProjectTask(models.Model): + _inherit = "project.task" + + reviewer_ids = fields.Many2many( + comodel_name="res.users", string="Reviewers", tracking=True + ) diff --git a/project_reviewer/readme/CONTRIBUTORS.md b/project_reviewer/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..91fcd94cc9 --- /dev/null +++ b/project_reviewer/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +* Sébastien Beau diff --git a/project_reviewer/readme/DESCRIPTION.md b/project_reviewer/readme/DESCRIPTION.md new file mode 100644 index 0000000000..7934b2b4a0 --- /dev/null +++ b/project_reviewer/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module allow to set several reviewers on a project task diff --git a/project_reviewer/static/description/icon.png b/project_reviewer/static/description/icon.png new file mode 100644 index 0000000000..1dcc49c24f Binary files /dev/null and b/project_reviewer/static/description/icon.png differ diff --git a/project_reviewer/static/description/index.html b/project_reviewer/static/description/index.html new file mode 100644 index 0000000000..08826b2992 --- /dev/null +++ b/project_reviewer/static/description/index.html @@ -0,0 +1,435 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Project Reviewer

+ +

Alpha License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

+

This module allow to set several reviewers on a project task

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

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

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

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.

+

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

+

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

+
+
+
+
+ + diff --git a/project_reviewer/views/project_task_view.xml b/project_reviewer/views/project_task_view.xml new file mode 100644 index 0000000000..be3872cdd6 --- /dev/null +++ b/project_reviewer/views/project_task_view.xml @@ -0,0 +1,41 @@ + + + + + project.task + + + + + + + + + + project.task + + + + + +
+ +
+
+
+ + + project.task + + + + + + + + +
diff --git a/project_timeline/__init__.py b/project_timeline/__init__.py index 4a509f6e6c..3f5aab177f 100644 --- a/project_timeline/__init__.py +++ b/project_timeline/__init__.py @@ -2,3 +2,4 @@ from . import models from . import report +from .hooks import uninstall_hook diff --git a/project_timeline/__manifest__.py b/project_timeline/__manifest__.py index 7e0ee9a958..f6a4b360a5 100644 --- a/project_timeline/__manifest__.py +++ b/project_timeline/__manifest__.py @@ -22,4 +22,5 @@ "/project_timeline/static/src/scss/project_timeline.scss" ] }, + "uninstall_hook": "uninstall_hook", } diff --git a/project_timeline/hooks.py b/project_timeline/hooks.py new file mode 100644 index 0000000000..10796e8a93 --- /dev/null +++ b/project_timeline/hooks.py @@ -0,0 +1,33 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import SUPERUSER_ID, api + + +def uninstall_hook(cr, _): + env = api.Environment(cr, SUPERUSER_ID, {}) + _clean_action_view_mode_timeline(env) + + +def _clean_action_view_mode_timeline(env): + models = ["project.project", "project.task", "report.project.task.user"] + domain = [ + ("view_mode", "ilike", "timeline"), + ("res_model", "in", models), + ] + Action = env["ir.actions.act_window"] + for action in Action.search(domain): + view_mode = [ + m for m in action.view_mode.split(",") if m.lower().strip() != "timeline" + ] + # If 'view_mode' is now empty: unlink related menus and the action + if not view_mode: + _unlink_action(env, action) + else: + action.view_mode = ",".join(view_mode) + + +def _unlink_action(env, action): + env["ir.ui.menu"].search( + [("action", "=", "ir.actions.act_window,%d" % action.id)] + ).unlink() + action.unlink() diff --git a/project_timeline/tests/test_project_timeline.py b/project_timeline/tests/test_project_timeline.py index 12f7237166..c52b19d0c2 100644 --- a/project_timeline/tests/test_project_timeline.py +++ b/project_timeline/tests/test_project_timeline.py @@ -12,8 +12,13 @@ class TestProjectTimeline(BaseCommon): @classmethod def setUpClass(cls): super().setUpClass() - cls.project = cls.env.ref("project.project_project_1") - cls.stage = cls.env.ref("project.project_stage_2") + cls.project = cls.env["project.project"].create({"name": "Project Test"}) + cls.stage_done = cls.env["project.task.type"].create( + { + "name": "Done", + "fold": True, + } + ) cls.task = cls.env["project.task"].create( {"name": "test", "user_ids": False, "project_id": cls.project.id} ) @@ -25,7 +30,7 @@ def test_01_flow_filling(self): self.assertFalse(self.task.planned_date_end) self.task.write( { - "stage_id": self.stage.id, + "stage_id": self.stage_done.id, "date_end": fields.Datetime.add(self.task.planned_date_start, days=1), } ) @@ -44,7 +49,7 @@ def test_02_no_filling(self): self.assertEqual( task.planned_date_start, fields.Datetime.from_string("2018-05-01") ) - task.stage_id = self.stage + task.stage_id = self.stage_done self.assertEqual( task.planned_date_end, fields.Datetime.from_string("2018-05-07") ) @@ -64,3 +69,37 @@ def test_invalid_dates(self): self.task.planned_date_end = fields.Datetime.subtract( self.task.planned_date_start, days=1 ) + + def test_uninstall_clean_action(self): + """Test uninstall hook cleans 'timeline' from view_mode of act_window actions. + - Case 1: action with multiple view modes: just remove 'timeline' + - Case 2: action with 'timeline' only: unlink action + related menus + """ + # Test data + Action = self.env["ir.actions.act_window"] + Menu = self.env["ir.ui.menu"] + action1 = Action.create( + { + "name": "Test Action Multi", + "res_model": "project.task", + "view_mode": "tree,timeline,form", + } + ) + action2 = action1.copy({"view_mode": "timeline"}) + menu2 = Menu.create( + { + "name": "Test Menu Solo", + "action": "ir.actions.act_window,%d" % action2.id, + } + ) + + # Run the uninstall hook logic + from ..hooks import _clean_action_view_mode_timeline + + _clean_action_view_mode_timeline(self.env) + + # Case 1: 'timeline' removed, other modes preserved + self.assertEqual(action1.view_mode, "tree,form") + # Case 2: action and its menu are deleted + self.assertFalse(Action.browse(action2.id).exists()) + self.assertFalse(Menu.browse(menu2.id).exists()) diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index c73bc8284f..e18fb0924d 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -16.0.20251209.1 \ No newline at end of file +16.0.20260210.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index a8f46bfe42..6809478186 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -23,6 +23,7 @@ 'odoo-addon-project_pivot>=16.0dev,<16.1dev', 'odoo-addon-project_portal_task_visibility>=16.0dev,<16.1dev', 'odoo-addon-project_purchase_link>=16.0dev,<16.1dev', + 'odoo-addon-project_reviewer>=16.0dev,<16.1dev', 'odoo-addon-project_risk>=16.0dev,<16.1dev', 'odoo-addon-project_role>=16.0dev,<16.1dev', 'odoo-addon-project_sale_order_link>=16.0dev,<16.1dev', diff --git a/setup/project_reviewer/odoo/addons/project_reviewer b/setup/project_reviewer/odoo/addons/project_reviewer new file mode 120000 index 0000000000..143108511e --- /dev/null +++ b/setup/project_reviewer/odoo/addons/project_reviewer @@ -0,0 +1 @@ +../../../../project_reviewer \ No newline at end of file diff --git a/setup/project_reviewer/setup.py b/setup/project_reviewer/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/project_reviewer/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)