diff --git a/project_task_related/README.rst b/project_task_related/README.rst new file mode 100644 index 0000000000..596826b02f --- /dev/null +++ b/project_task_related/README.rst @@ -0,0 +1,92 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +==================== +Project Related Task +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:c8b2f28ccdf9265a66dd10cc12ad66288955ae79474a745855a2b67cde06abce + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fproject-lightgray.png?logo=github + :target: https://github.com/OCA/project/tree/19.0/project_task_related + :alt: OCA/project +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/project-19-0/project-19-0-project_task_related + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Adds a tab on the task view to link tasks that are related but don't +have a parent/child relationship. + +**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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Pedro M. Baeza + - David Bañón + +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-david-banon-tecnativa| image:: https://github.com/david-banon-tecnativa.png?size=40px + :target: https://github.com/david-banon-tecnativa + :alt: david-banon-tecnativa + +Current `maintainer `__: + +|maintainer-david-banon-tecnativa| + +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_task_related/__init__.py b/project_task_related/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/project_task_related/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/project_task_related/__manifest__.py b/project_task_related/__manifest__.py new file mode 100644 index 0000000000..0f4ef0f190 --- /dev/null +++ b/project_task_related/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2025 Tecnativa - David Bañón + +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + "name": "Project Related Task", + "version": "19.0.1.0.0", + "category": "Project", + "author": "Tecnativa,Odoo Community Association (OCA)", + "maintainers": ["david-banon-tecnativa"], + "website": "https://github.com/OCA/project", + "depends": [ + "project", + ], + "data": ["views/project_task_views_related.xml"], + "license": "AGPL-3", + "installable": True, +} diff --git a/project_task_related/i18n/es.po b/project_task_related/i18n/es.po new file mode 100644 index 0000000000..9878b5835f --- /dev/null +++ b/project_task_related/i18n/es.po @@ -0,0 +1,64 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_task_related +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-04-04 09:34+0000\n" +"PO-Revision-Date: 2025-04-04 11:42+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.6\n" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "My Deadline" +msgstr "Mi fecha límite" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Next Activity" +msgstr "Siguiente actividad" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__reverse_related_task_ids +msgid "Other to self task relation" +msgstr "Relación entre otra y esta tarea" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Project" +msgstr "Proyecto" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Rating" +msgstr "Valoración" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__related_task_ids +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Related Tasks" +msgstr "Tareas Relacionadas" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_project_task_search_inherit_same_customer +msgid "Same customer" +msgstr "Mismo cliente" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__forward_related_task_ids +msgid "Self to other task relation" +msgstr "Relación entre esta tarea y otra" + +#. module: project_task_related +#: model:ir.model,name:project_task_related.model_project_task +msgid "Task" +msgstr "Tarea" diff --git a/project_task_related/i18n/it.po b/project_task_related/i18n/it.po new file mode 100644 index 0000000000..13efca95be --- /dev/null +++ b/project_task_related/i18n/it.po @@ -0,0 +1,63 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_task_related +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-04-11 10:54+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.10.4\n" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "My Deadline" +msgstr "La mia scadenza" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Next Activity" +msgstr "Attività successiva" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__reverse_related_task_ids +msgid "Other to self task relation" +msgstr "Relazione oltre il proprio lavoro" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Project" +msgstr "Progetto" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Rating" +msgstr "Valutazione" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__related_task_ids +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Related Tasks" +msgstr "Lavori relativi" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_project_task_search_inherit_same_customer +msgid "Same customer" +msgstr "Stesso cliente" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__forward_related_task_ids +msgid "Self to other task relation" +msgstr "Relazione propria ad altri lavori" + +#. module: project_task_related +#: model:ir.model,name:project_task_related.model_project_task +msgid "Task" +msgstr "Lavoro" diff --git a/project_task_related/i18n/project_task_related.pot b/project_task_related/i18n/project_task_related.pot new file mode 100644 index 0000000000..51adb4a537 --- /dev/null +++ b/project_task_related/i18n/project_task_related.pot @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_task_related +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "My Deadline" +msgstr "" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Next Activity" +msgstr "" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__reverse_related_task_ids +msgid "Other to self task relation" +msgstr "" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Project" +msgstr "" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Rating" +msgstr "" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__related_task_ids +#: model_terms:ir.ui.view,arch_db:project_task_related.view_task_form_inherit_related_tasks +msgid "Related Tasks" +msgstr "" + +#. module: project_task_related +#: model_terms:ir.ui.view,arch_db:project_task_related.view_project_task_search_inherit_same_customer +msgid "Same customer" +msgstr "" + +#. module: project_task_related +#: model:ir.model.fields,field_description:project_task_related.field_project_task__forward_related_task_ids +msgid "Self to other task relation" +msgstr "" + +#. module: project_task_related +#: model:ir.model,name:project_task_related.model_project_task +msgid "Task" +msgstr "" diff --git a/project_task_related/models/__init__.py b/project_task_related/models/__init__.py new file mode 100644 index 0000000000..edf2d36b9c --- /dev/null +++ b/project_task_related/models/__init__.py @@ -0,0 +1 @@ +from . import project_task diff --git a/project_task_related/models/project_task.py b/project_task_related/models/project_task.py new file mode 100644 index 0000000000..ede7dc81b5 --- /dev/null +++ b/project_task_related/models/project_task.py @@ -0,0 +1,47 @@ +# Copyright 2024 Tecnativa Carolina Fernandez +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import Command, api, fields, models + + +class ProjectTask(models.Model): + _inherit = "project.task" + + forward_related_task_ids = fields.Many2many( + "project.task", + "project_task_relation", + "task_id", + "related_task_id", + string="Self to other task relation", + ) + + # Inverse relation: Task B -> Task A + reverse_related_task_ids = fields.Many2many( + "project.task", + "project_task_relation", + "related_task_id", + "task_id", + string="Other to self task relation", + ) + + # Displayed field: merged bidirectional field + related_task_ids = fields.Many2many( + "project.task", + compute="_compute_related_tasks", + inverse="_inverse_related_tasks", + string="Related Tasks", + domain="[('id', '!=', id)]", + ) + + @api.depends("forward_related_task_ids", "reverse_related_task_ids") + def _compute_related_tasks(self): + for task in self: + task.related_task_ids = task.forward_related_task_ids + task.related_task_ids += self.env["project.task"].search( + [("reverse_related_task_ids", "in", [task.id])] + ) + + def _inverse_related_tasks(self): + for task in self: + task.forward_related_task_ids = [Command.set(task.related_task_ids.ids)] + task.reverse_related_task_ids = [Command.set(task.related_task_ids.ids)] diff --git a/project_task_related/pyproject.toml b/project_task_related/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/project_task_related/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/project_task_related/readme/CONTRIBUTORS.md b/project_task_related/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..4ffd547290 --- /dev/null +++ b/project_task_related/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com): + > - Pedro M. Baeza + > - David Bañón diff --git a/project_task_related/readme/DESCRIPTION.md b/project_task_related/readme/DESCRIPTION.md new file mode 100644 index 0000000000..a0a8353d06 --- /dev/null +++ b/project_task_related/readme/DESCRIPTION.md @@ -0,0 +1 @@ +Adds a tab on the task view to link tasks that are related but don't have a parent/child relationship. diff --git a/project_task_related/static/description/icon.png b/project_task_related/static/description/icon.png new file mode 100644 index 0000000000..1dcc49c24f Binary files /dev/null and b/project_task_related/static/description/icon.png differ diff --git a/project_task_related/static/description/index.html b/project_task_related/static/description/index.html new file mode 100644 index 0000000000..2fa901cdc5 --- /dev/null +++ b/project_task_related/static/description/index.html @@ -0,0 +1,439 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + + +
+ + diff --git a/project_task_related/tests/__init__.py b/project_task_related/tests/__init__.py new file mode 100644 index 0000000000..1a252ec370 --- /dev/null +++ b/project_task_related/tests/__init__.py @@ -0,0 +1 @@ +from . import test_project_task_related diff --git a/project_task_related/tests/test_project_task_related.py b/project_task_related/tests/test_project_task_related.py new file mode 100644 index 0000000000..70f111b8db --- /dev/null +++ b/project_task_related/tests/test_project_task_related.py @@ -0,0 +1,65 @@ +from odoo.tests import tagged + +from odoo.addons.project.tests.test_project_base import TestProjectCommon + + +@tagged("post_install", "-at_install") +class TestTaskRelated(TestProjectCommon): + def test_write_relation(self): + self.task_1.write({"related_task_ids": [(4, self.task_2.id)]}) + self.assertIn( + self.task_2.id, self.task_1.related_task_ids.ids, "Forward relation Failed" + ) + self.assertIn( + self.task_1.id, self.task_2.related_task_ids.ids, "Reverse relation Failed" + ) + + def test_create_with_relation(self): + self.task_custom = ( + self.env["project.task"] + .with_context(mail_create_nolog=True) + .create( + { + "name": "Pigs ManagerTask 2", + "user_ids": self.user_projectmanager, + "project_id": self.project_pigs.id, + "related_task_ids": [(4, self.task_1.id)], + } + ) + ) + self.assertIn( + self.task_1.id, + self.task_custom.related_task_ids.ids, + "Forward relation Failed", + ) + self.assertIn( + self.task_custom.id, + self.task_1.related_task_ids.ids, + "Reverse relation Failed", + ) + + def test_remove_relation(self): + self.task_3 = ( + self.env["project.task"] + .with_context(mail_create_nolog=True) + .create( + { + "name": "Test task 3", + "user_ids": self.user_projectmanager, + "project_id": self.project_pigs.id, + } + ) + ) + + self.task_1.write({"related_task_ids": [(4, self.task_2.id)]}) + self.task_1.write({"related_task_ids": [(4, self.task_3.id)]}) + + self.task_1.write({"related_task_ids": [(3, self.task_2.id)]}) + self.assertNotIn( + self.task_2.id, self.task_1.related_task_ids.ids, "Delete relation failed" + ) + self.assertIn( + self.task_3.id, + self.task_1.related_task_ids.ids, + "Deleted unrelated pairing", + ) diff --git a/project_task_related/views/project_task_views_related.xml b/project_task_related/views/project_task_views_related.xml new file mode 100644 index 0000000000..6f48bc8d91 --- /dev/null +++ b/project_task_related/views/project_task_views_related.xml @@ -0,0 +1,146 @@ + + + + project.task.form.related.tasks + project.task + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project.task.search.same.customer + project.task + + + + + + + +