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

[14.0][ADD] project_milestone_spent_hours #1333

Open
wants to merge 1 commit into
base: 14.0
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions project_milestone_spent_hours/__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 AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
20 changes: 20 additions & 0 deletions project_milestone_spent_hours/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Project Milestone Spent Hours",
"version": "14.0.1.0.0",
"author": "Numigi, Odoo Community Association (OCA)",
"maintainer": "Numigi",
"website": "https://github.com/OCA/project",
"license": "AGPL-3",
"category": "Project",
"summary": """Add field Total Hours in milestones which display the sum
of all hours of tasks associated to the milestone""",
"depends": ["hr_timesheet", "project_milestone"],
"data": [
"views/project_milestone.xml",
"views/project.xml",
],
"installable": True,
}
37 changes: 37 additions & 0 deletions project_milestone_spent_hours/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_milestone_spent_hours
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-03-28 15:25+0000\n"
"PO-Revision-Date: 2022-03-28 15:25+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_milestone_spent_hours
#: model:ir.model,name:project_milestone_spent_hours.model_account_analytic_line
msgid "Analytic Line"
msgstr "Ligne analytique"

#. module: project_milestone_spent_hours
#: model:ir.model.fields,field_description:project_milestone_spent_hours.field_account_analytic_line__milestone_id
msgid "Milestone"
msgstr "Jalon"

#. module: project_milestone_spent_hours
#: model:ir.model,name:project_milestone_spent_hours.model_project_milestone
msgid "Project Milestone"
msgstr "Jalon du projet"

#. module: project_milestone_spent_hours
#: model:ir.model.fields,field_description:project_milestone_spent_hours.field_project_milestone__total_hours
msgid "Total Hours"
msgstr "Heures passées"

4 changes: 4 additions & 0 deletions project_milestone_spent_hours/models/__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 AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import project_milestone, account_analytic_line
17 changes: 17 additions & 0 deletions project_milestone_spent_hours/models/account_analytic_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"

milestone_id = fields.Many2one(
"project.milestone",
related="task_id.milestone_id",
string="Milestone",
index=True,
compute_sudo=True,
store=True,
)
46 changes: 46 additions & 0 deletions project_milestone_spent_hours/models/project_milestone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ProjectMilestone(models.Model):
_inherit = "project.milestone"

active = fields.Boolean("Active", default=True)
total_hours = fields.Float(
compute="_compute_total_hours",
string="Total Hours",
compute_sudo=True,
store=True,
)

def write(self, vals):
res = super(ProjectMilestone, self).write(vals)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use simply super()

if "project_id" in vals:
self._remove_task_milestones(vals["project_id"])
return res

def _remove_task_milestones(self, project_id):
self.with_context(active_test=False).mapped("project_task_ids").filtered(
lambda milestone: not project_id or milestone.project_id.id != project_id
).write({"milestone_id": False})

@api.depends(
"project_task_ids",
"project_task_ids.active",
"project_task_ids.milestone_id",
"project_task_ids.timesheet_ids",
"project_task_ids.timesheet_ids.unit_amount",
"active",
)
def _compute_total_hours(self):
for record in self:
total_hours = 0.0
if record.active:
total_hours = sum(
record.project_task_ids.filtered(lambda milestone: milestone.active)
.mapped("timesheet_ids")
.mapped("unit_amount")
)
record.total_hours = total_hours
5 changes: 5 additions & 0 deletions project_milestone_spent_hours/readme/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The module project_milestone allows to define milestones for a project.

Multiple tasks in the project can be linked to a given milestone.

Field total hours is displayed in form and list view of a project milestone and in tab of milestones of a project
1 change: 1 addition & 0 deletions project_milestone_spent_hours/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Numigi (tm) and all its contributors (https://bit.ly/numigiens)
3 changes: 3 additions & 0 deletions project_milestone_spent_hours/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module adds a new field `Total Hours` on milestone form view.

The field `Total Hours` is the sum of timesheets of active tasks associated to the milestone.
9 changes: 9 additions & 0 deletions project_milestone_spent_hours/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
As a `Project/User`, I create timesheets and set `Duration` for 2 tasks associated to the same Milestone.

![task 1](../static/description/task1.png)

![task 2](../static/description/task2.png)

I open the Milestone, the field `Total Hours` is set with the **sum of timesheets spent hours** of associated tasks.

![milestone](../static/description/milestone.png)
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.
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_milestone_spent_hours/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 AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

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

from odoo.tests.common import SavepointCase


class TestMilestoneTotalHours(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()

cls.project = cls.env["project.project"].create({"name": "My Project"})

cls.milestone_1 = cls.env["project.milestone"].create(
{"name": "My Milestone 1", "project_id": cls.project.id}
)

cls.milestone_2 = cls.env["project.milestone"].create(
{"name": "My Milestone 2", "project_id": cls.project.id}
)

cls.task = cls.env["project.task"].create(
{
"name": "My Task",
"project_id": cls.project.id,
"milestone_id": cls.milestone_1.id,
}
)

cls.analytic_line_1 = cls.env["account.analytic.line"].create(
{
"name": "My Timesheet 1",
"task_id": cls.task.id,
"unit_amount": 10,
"project_id": cls.project.id,
}
)

cls.analytic_line_2 = cls.env["account.analytic.line"].create(
{
"name": "My Timesheet 2",
"task_id": cls.task.id,
"unit_amount": 20,
"project_id": cls.project.id,
}
)

def test_propagate_milestone_on_analytic_line(self):
assert self.task.milestone_id & self.analytic_line_1.milestone_id

def test_update_milestone_total_hours_when_creating_analytic_line(self):
assert self.milestone_1.total_hours == 30

def test_update_milestone_total_hours_when_updating_analytic_line(self):
self.analytic_line_1.unit_amount = 20
assert self.milestone_1.total_hours == 40

def test_update_milestone_total_hours_when_removing_analytic_line(self):
self.analytic_line_1.unlink()
assert self.milestone_1.total_hours == 20

def test_update_milestone_total_hours_when_modifying_milestone_on_task(self):
self.task.milestone_id = self.milestone_2
assert self.milestone_1.total_hours == 0
assert self.milestone_2.total_hours == 30

def test_update_milestone_total_hours_when_task_inactive(self):
self.task.active = 0
assert self.milestone_1.total_hours == 0
assert self.milestone_2.total_hours == 0

def test_update_milestone_total_hours_when_remove_project(self):
self.milestone_1.project_id = False
assert self.milestone_1.total_hours == 0
21 changes: 21 additions & 0 deletions project_milestone_spent_hours/views/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Form View -->
<record id="project_milestone_spent_hours_view_form" model="ir.ui.view">
<field name="name">Project Milestone Spent Hours Form</field>
<field name="model">project.project</field>
<field
name="inherit_id"
ref="project_milestone.project_enhancement_milestone_view_inherit_form"
/>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath
expr="//page[@name='milestone_ids']/group/field[@name='milestone_ids']/tree/field[@name='project_task_ids']"
position="after"
>
<field name="total_hours" />
</xpath>
</field>
</record>
</odoo>
26 changes: 26 additions & 0 deletions project_milestone_spent_hours/views/project_milestone.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- List View-->
<record id="project_milestone_spent_hours_view_list" model="ir.ui.view">
<field name="name">Project Milestone Spent Hours List</field>
<field name="model">project.milestone</field>
<field name="inherit_id" ref="project_milestone.project_milestone_view_list" />
<field name="arch" type="xml">
<field name="project_task_ids" position="after">
<field name="total_hours" widget="float_time" />
</field>
</field>
</record>

<!-- Form View -->
<record id="project_milestone_spent_hours_form" model="ir.ui.view">
<field name="name">Project Milestone Spent Hours Form</field>
<field name="model">project.milestone</field>
<field name="inherit_id" ref="project_milestone.project_milestone_view_form" />
<field name="arch" type="xml">
<field name="target_date" position="after">
<field name="total_hours" widget="float_time" />
</field>
</field>
</record>
</odoo>
6 changes: 6 additions & 0 deletions setup/project_milestone_spent_hours/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Loading