diff --git a/.docker_files/main/__manifest__.py b/.docker_files/main/__manifest__.py index 539880fc..258735de 100644 --- a/.docker_files/main/__manifest__.py +++ b/.docker_files/main/__manifest__.py @@ -13,6 +13,7 @@ "depends": [ "project", "project_task_date_planned", + "project_task_deadline_from_project", "project_task_full_text_search", "project_type_advanced", "project_default_task_stage", diff --git a/Dockerfile b/Dockerfile index 5396fbbb..a4ca882e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,7 @@ USER odoo COPY project_stage_allow_timesheet mnt/extra-addons/project_stage_allow_timesheet COPY project_task_date_planned /mnt/extra-addons/project_task_date_planned +COPY project_task_deadline_from_project /mnt/extra-addons/project_task_deadline_from_project COPY project_task_full_text_search /mnt/extra-addons/project_task_full_text_search COPY project_type_advanced /mnt/extra-addons/project_type_advanced COPY project_default_task_stage /mnt/extra-addons/project_default_task_stage diff --git a/project_task_deadline_from_project/README.rst b/project_task_deadline_from_project/README.rst new file mode 100644 index 00000000..1df518ed --- /dev/null +++ b/project_task_deadline_from_project/README.rst @@ -0,0 +1,13 @@ +Project Task Deadline From Project +================================== +This module automatically sets the deadline on a task from the project's deadline. + +When changing the task from one project to another, the deadline is automatically changed. + +If the destination project has no deadline, then, the deadline on the task is emptied. + +The deadline on a task can always be changed manually. + +Contributors +------------ +* Numigi (tm) and all its contributors (https://bit.ly/numigiens) diff --git a/project_task_deadline_from_project/__init__.py b/project_task_deadline_from_project/__init__.py new file mode 100644 index 00000000..1a65765b --- /dev/null +++ b/project_task_deadline_from_project/__init__.py @@ -0,0 +1,4 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import models diff --git a/project_task_deadline_from_project/__manifest__.py b/project_task_deadline_from_project/__manifest__.py new file mode 100644 index 00000000..9d7d0881 --- /dev/null +++ b/project_task_deadline_from_project/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Project Task Deadline From Project", + "version": "16.0.1.0.0", + "author": "Numigi", + "maintainer": "Numigi", + "website": "https://bit.ly/numigi-com", + "license": "LGPL-3", + "category": "Project", + "summary": "Propagate the deadline from projects to tasks.", + "depends": ["project"], + "installable": True, +} diff --git a/project_task_deadline_from_project/models/__init__.py b/project_task_deadline_from_project/models/__init__.py new file mode 100644 index 00000000..e07de2bf --- /dev/null +++ b/project_task_deadline_from_project/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import project_task diff --git a/project_task_deadline_from_project/models/project_task.py b/project_task_deadline_from_project/models/project_task.py new file mode 100644 index 00000000..7f482888 --- /dev/null +++ b/project_task_deadline_from_project/models/project_task.py @@ -0,0 +1,29 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import api, models + + +class ProjectTaskWithDeadlineFromProject(models.Model): + _inherit = "project.task" + + @api.model + def create(self, vals): + task = super().create(vals) + should_propagate_deadline = task.project_id and "date_deadline" not in vals + if should_propagate_deadline: + task.date_deadline = task.project_id.date + return task + + def write(self, vals): + should_propagate_deadline = ( + vals.get("project_id") and "date_deadline" not in vals + ) + if should_propagate_deadline: + project = self.env["project.project"].browse(vals["project_id"]) + vals["date_deadline"] = project.date + return super().write(vals) + + @api.onchange("project_id") + def _onchange_project_propagate_deadline(self): + self.date_deadline = self.project_id.date diff --git a/project_task_deadline_from_project/static/description/icon.png b/project_task_deadline_from_project/static/description/icon.png new file mode 100644 index 00000000..92a86b10 Binary files /dev/null and b/project_task_deadline_from_project/static/description/icon.png differ diff --git a/project_task_deadline_from_project/tests/__init__.py b/project_task_deadline_from_project/tests/__init__.py new file mode 100644 index 00000000..4dd930b4 --- /dev/null +++ b/project_task_deadline_from_project/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import test_project_task diff --git a/project_task_deadline_from_project/tests/test_project_task.py b/project_task_deadline_from_project/tests/test_project_task.py new file mode 100644 index 00000000..746bb4cb --- /dev/null +++ b/project_task_deadline_from_project/tests/test_project_task.py @@ -0,0 +1,66 @@ +# Copyright2023 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from datetime import date +from odoo.tests.common import TransactionCase + + +class TestProjectTask(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.deadline = date(2018, 6, 1) + cls.project_with_no_deadline = cls.env["project.project"].create( + { + "name": "Project With No Deadline", + "date": False, + } + ) + cls.project_with_deadline = cls.env["project.project"].create( + { + "name": "Project With Deadline", + "date": cls.deadline, + } + ) + cls.task = cls.env["project.task"].create({"name": "Task 1"}) + + def test_when_creating_task_with_project_then_deadline_is_propagated(self): + task = self.env["project.task"].create( + { + "name": "Task 2", + "project_id": self.project_with_deadline.id, + } + ) + self.assertEqual(task.date_deadline, self.deadline) + + def test_when_creating_task_with_default_project_then_deadline_is_propagated(self): + task = ( + self.env["project.task"] + .with_context(default_project_id=self.project_with_deadline.id) + .create({"name": "Task 2"}) + ) + self.assertEqual(task.date_deadline, self.deadline) + + def test_when_creating_task_if_project_has_no_deadline_then_deadline_is_empty(self): + task = self.env["project.task"].create( + { + "name": "Task 2", + "project_id": self.project_with_no_deadline.id, + } + ) + self.assertFalse(task.date_deadline) + + def test_when_changing_project_then_deadline_is_propagated(self): + self.task.project_id = self.project_with_deadline + self.assertEqual(self.task.date_deadline, self.deadline) + + def test_when_changing_project_if_project_has_no_deadline_then_deadline_is_empty( + self, + ): + self.task.project_id = self.project_with_no_deadline + self.assertFalse(self.task.date_deadline) + + def test_onchange_project_then_deadline_is_propagated_to_task(self): + self.task.project_id = self.project_with_deadline + self.task._onchange_project_propagate_deadline() + self.assertEqual(self.task.date_deadline, self.deadline)