Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ta#72157 [16.0][ADD] project_parent_enhanced #473

Merged
merged 7 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .docker_files/main/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"project_track_end_date",
"project_type_advanced",
"project_default_task_stage",
"project_parent_enhanced",
"project_stage_allow_timesheet",
],
"installable": True,
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ RUN gitoo install-all --conf_file /gitoo.yml --destination "${THIRD_PARTY_ADDONS
USER odoo

COPY project_stage_allow_timesheet mnt/extra-addons/project_stage_allow_timesheet
COPY project_parent_enhanced mnt/extra-addons/project_parent_enhanced
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_editable_list_view /mnt/extra-addons/project_task_editable_list_view
Expand Down
1 change: 1 addition & 0 deletions gitoo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- project_timeline
- project_timesheet_time_control
- project_type
- project_parent

- url: https://github.com/OCA/timesheet
branch: "16.0"
Expand Down
40 changes: 40 additions & 0 deletions project_parent_enhanced/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Project Parent Enhanced
=======================

This module enhances the functionality of parent-child relationships between projects and tasks in Odoo. It builds upon the features of the `project_parent` module from OCA, adding new constraints, methods, and views to better manage project hierarchies.

Dependencies
------------
This module depends on the following OCA module:
- `project_parent`: https://github.com/OCA/project/tree/16.0/project_parent

Features
--------

**Enhanced Constraints**
- Prevent a project from being its own parent.
- Ensure that a child project cannot have further child projects.

**Follower Propagation**
- Automatically propagate followers from a parent project to its child projects.

**Search by Parent Projects**
- Add a new filter view to search projects by their parent projects.

.. image:: static/description/task_filter_by_parent.png


**View Adjustments**
- Replace project names with their `display_name` to show the hierarchy in views.

.. image:: static/description/parent_project.png


Contributors
------------
- Numigi (tm) and all its contributors (https://bit.ly/numigiens)

More Information
----------------
For more details, visit:
- https://github.com/OCA/project/tree/16.0/project_parent
4 changes: 4 additions & 0 deletions project_parent_enhanced/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from . import models

Check notice on line 4 in project_parent_enhanced/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

project_parent_enhanced/__init__.py#L4

'.models' imported but unused (F401)
18 changes: 18 additions & 0 deletions project_parent_enhanced/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

{

Check warning on line 4 in project_parent_enhanced/__manifest__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

project_parent_enhanced/__manifest__.py#L4

Statement seems to have no effect
"name": "Project Parent Enhanced",
"version": "16.0.1.0.0",
"author": "Numigi",
"maintainer": "Numigi",
"website": "https://bit.ly/numigi-com",
"license": "LGPL-3",
"category": "Project",
"depends": ["project", "project_parent"],
"data": [
"views/project_project_views.xml",
"views/project_task_views.xml",
],
"installable": True,
}
61 changes: 61 additions & 0 deletions project_parent_enhanced/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_parent_enhanced
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-12-06 13:17+0000\n"
"PO-Revision-Date: 2024-12-06 13:17+0000\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_parent_enhanced
#: model:ir.model.fields,field_description:project_parent_enhanced.field_project_project__is_parent
msgid "Is Parent"
msgstr ""

#. module: project_parent_enhanced
#: model:ir.model.fields,field_description:project_parent_enhanced.field_project_task__parent_project_id
#: model_terms:ir.ui.view,arch_db:project_parent_enhanced.view_task_search_form
msgid "Parent Project"
msgstr ""

#. module: project_parent_enhanced
#: model:ir.model,name:project_parent_enhanced.model_project_project
msgid "Project"
msgstr "Projet"

#. module: project_parent_enhanced
#: model_terms:ir.ui.view,arch_db:project_parent_enhanced.view_project
msgid "Project/Iteration Name"
msgstr ""

#. module: project_parent_enhanced
#: model:ir.model,name:project_parent_enhanced.model_project_task
msgid "Task"
msgstr "Tâche"

#. module: project_parent_enhanced
#. odoo-python
#: code:addons/project_parent_enhanced/models/project_project.py:0
#, python-format
msgid ""
"The project {project_1} can not be the child of {project_2} because "
"{project_2} is a child of {project_3}."
msgstr ""
"Le projet {project_1} ne peut pas être le parent de {project_2} parce que "
"{project_2} est un enfant de {project_3}."


#. module: project_parent_enhanced
#. odoo-python
#: code:addons/project_parent_enhanced/models/project_project.py:0
#, python-format
msgid "The project {project} can not be its own parent."
msgstr "Le projet {project} ne peut pas être son propre parent."
5 changes: 5 additions & 0 deletions project_parent_enhanced/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from . import project_project

Check notice on line 4 in project_parent_enhanced/models/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

project_parent_enhanced/models/__init__.py#L4

'.project_project' imported but unused (F401)
from . import project_task

Check notice on line 5 in project_parent_enhanced/models/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

project_parent_enhanced/models/__init__.py#L5

'.project_task' imported but unused (F401)
79 changes: 79 additions & 0 deletions project_parent_enhanced/models/project_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError


class ProjectProject(models.Model):

_inherit = "project.project"

@api.depends("child_ids")
def _compute_is_parent(self):
for project in self:
project.is_parent = bool(project.child_ids)

@api.constrains("parent_id", "child_ids_count")
def _check_child_project_has_no_child(self):
child_projects_with_children = self.filtered(
lambda p: p.parent_id and p.child_ids
)

for project in child_projects_with_children:
raise ValidationError(
_(
"The project [{project_1}] can not be the child of [{project_2}] "
"because [{project_2}] is a child of [{project_3}]."
).format(
project_1=project.child_ids[0].display_name,
project_2=project.display_name,
project_3=project.parent_id.display_name,
)
)

@api.constrains("parent_id")
def _check_parent_id_is_not_its_own_parent(self):
for project in self:
if project.parent_id == project:
raise ValidationError(
_("The project {project} can not be its own parent.").format(
project=project
)
)

@api.onchange("parent_id")
def _onchange_parent_set_default_partner(self):
if self.parent_id:
self.partner_id = self.parent_id.partner_id

def write(self, vals):
super().write(vals)
if vals.get("parent_id"):
for project in self:
project._propagate_followers_from_parent()
return True

def name_get(self):
"""Add the parent project before the name of the iteration.

Check the access rights for the projects to read.
Then, bypass access checks to prevent errors related to the parent project.
"""
self.check_access_rights("read")
self.check_access_rule("read")
self = self.sudo()

iterations = self.filtered(lambda p: p.parent_id)
other_projects = self.filtered(lambda p: not p.parent_id)
res = super(ProjectProject, other_projects).name_get()
res.extend((p.id, ", ".join([p.parent_id.name, p.name])) for p in iterations)
return res

is_parent = fields.Boolean(
"Is Parent", compute="_compute_is_parent", store=True, compute_sudo=True
)

def _propagate_followers_from_parent(self):
self.message_unsubscribe(self.message_partner_ids.ids)
self.message_subscribe(self.parent_id.message_partner_ids.ids)
33 changes: 33 additions & 0 deletions project_parent_enhanced/models/project_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).


from odoo import api, fields, models


class ProjectTask(models.Model):
"""Add parent_project_id to tasks.

This field is used to navigate to the tasks from a parent project.
"""

_inherit = "project.task"

parent_project_id = fields.Many2one(
"project.project",
"Parent Project",
compute="_compute_parent_project_id",
store=True,
index=True,
compute_sudo=True,
)

@api.depends("project_id", "project_id.is_parent", "project_id.parent_id")
def _compute_parent_project_id(self):
"""Compute the parent projects of a task."""
for task in self:
task.parent_project_id = (
task.project_id
if task.project_id.is_parent
else task.project_id.parent_id
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions project_parent_enhanced/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from . import test_project_iteration
52 changes: 52 additions & 0 deletions project_parent_enhanced/tests/test_project_iteration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

import pytest
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase


class TestProjectIteration(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.project_1 = cls.env["project.project"].create({"name": "Project 1"})
cls.project_2 = cls.env["project.project"].create({"name": "Project 2"})

cls.iteration_1 = cls.env["project.project"].create(
{
"name": "Iteration 1",
"parent_id": cls.project_1.id,
}
)
cls.iteration_2 = cls.env["project.project"].create(
{
"name": "Iteration 2",
"parent_id": cls.project_1.id,
}
)

def test_project_child_ids_count(self):
assert self.project_1.child_ids_count == 2
assert self.project_2.child_ids_count == 0

def test_project_is_parent(self):
assert self.project_1.is_parent

def test_iteration_is_not_parent(self):
assert not self.iteration_1.is_parent

def test_project_with_no_children_is_not_parent(self):
assert not self.project_2.is_parent

def test_project_with_children_removed_is_not_parent(self):
self.project_1.write({"child_ids": [(5, 0)]})
assert not self.project_1.is_parent

def test_parent_project_can_not_have_parent(self):
with pytest.raises(ValidationError):
self.project_1.parent_id = self.project_2

def test_iteration_can_not_have_child_projects(self):
with self.assertRaises(ValidationError):
self.iteration_2.parent_id = self.iteration_1.id
27 changes: 27 additions & 0 deletions project_parent_enhanced/views/project_project_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<record id="view_project_project_filter" model="ir.ui.view">
<field name="name">Project Search With Parent Project</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter" />
<field name="arch" type="xml">
<field name="name" position="attributes">
<attribute name="filter_domain">['|', ('name', 'ilike', self), ('parent_id',
'ilike', self)]</attribute>
</field>
</field>
</record>

<record id="view_project" model="ir.ui.view">
<field name="name">Project List With Display Name instead of Name</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project"/>
<field name="arch" type="xml">
<field name="name" position="replace">
<field name="display_name" string="Project/Iteration Name"/>
</field>
</field>
</record>

</odoo>
15 changes: 15 additions & 0 deletions project_parent_enhanced/views/project_task_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<record id="view_task_search_form" model="ir.ui.view">
<field name="name">Task Search With Parent Projects</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form"/>
<field name="arch" type="xml">
<filter name="unassigned" position="after">
<filter string="Parent Project" name="group_by_parent_project_id" context="{'group_by': 'parent_project_id'}"/>
</filter>
</field>
</record>

</odoo>
Loading