Skip to content

Commit

Permalink
TA#72165 [16.0][MIG] project_milestone_spent_hours (#475)
Browse files Browse the repository at this point in the history
* TA#72165 [16.0][MIG] project_milestone_spent_hours

---------

Co-authored-by: Abdellatif BENZBIRIA <[email protected]>
  • Loading branch information
lanto-razafindrabe and abenzbiria authored Dec 16, 2024
1 parent 0bf44a9 commit c892bf3
Show file tree
Hide file tree
Showing 17 changed files with 280 additions and 0 deletions.
1 change: 1 addition & 0 deletions .docker_files/main/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"project_type_advanced",
"project_default_task_stage",
"project_milestone_enhanced",
"project_milestone_spent_hours",
"project_parent_enhanced",
"project_stage_allow_timesheet",
],
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ COPY project_track_end_date /mnt/extra-addons/project_track_end_date
COPY project_type_advanced /mnt/extra-addons/project_type_advanced
COPY project_default_task_stage /mnt/extra-addons/project_default_task_stage
COPY project_milestone_enhanced /mnt/extra-addons/project_milestone_enhanced
COPY project_milestone_spent_hours /mnt/extra-addons/project_milestone_spent_hours



COPY .docker_files/main /mnt/extra-addons/main
Expand Down
34 changes: 34 additions & 0 deletions project_milestone_spent_hours/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Project Milestone Spent Hours
=================================

.. contents:: Table of Contents

Context
-------
Natively, Odoo 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

Description
-----------
Field Total Hours is the sum of timesheets of active tasks associated to the milestone

Overview
--------

I create timesheets and set duration for 2 tasks associated to the same milestone

.. image:: static/description/task1.png

.. image:: static/description/task2.png

I open the milestone, the field Total hours is set with sum of timesheets spent hours of associated tasks

.. image:: static/description/milestone.png


Contributors
------------
* Numigi (tm) and all its contributors (https://bit.ly/numigiens)
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 2023 - today 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
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 2023 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

{
"name": "Project Milestone Spent Hours",
"version": "16.0.1.0.0",
"author": "Numigi",
"maintainer": "Numigi",
"website": "https://bit.ly/numigi-com",
"license": "LGPL-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_enhanced"],
"data": [
"views/project_milestone.xml",
"views/project.xml",
],
"installable": True,
}
36 changes: 36 additions & 0 deletions project_milestone_spent_hours/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_milestone_spent_hours
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-12-07 05:29+0000\n"
"PO-Revision-Date: 2024-12-07 05:29+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"

#. 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 2023 - today 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_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 2023 - today 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 fields, models


class AccountAnalytic_line(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,
)
34 changes: 34 additions & 0 deletions project_milestone_spent_hours/models/project_milestone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2023 - today 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 fields, models, api


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

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

@api.depends(
"task_ids",
"task_ids.active",
"task_ids.milestone_id",
"task_ids.timesheet_ids",
"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.task_ids.filtered(lambda milestone: milestone.active)
.mapped("timesheet_ids")
.mapped("unit_amount")
)
record.total_hours = total_hours
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 2023 - today 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_spent_hours
82 changes: 82 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,82 @@
# Copyright 2023 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo.tests.common import TransactionCase


class TestMilestoneTotalHours(TransactionCase):
def setUp(self):
super().setUp()

self.employee_manager = self.env["hr.employee"].create(
{
"name": "Employee Manager",
"hourly_cost": 808,
}
)

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

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

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

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

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

self.analytic_line_2 = self.env["account.analytic.line"].create(
{
"name": "My Timesheet 2",
"task_id": self.task.id,
"unit_amount": 20,
"project_id": self.project.id,
"employee_id": self.employee_manager.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
16 changes: 16 additions & 0 deletions project_milestone_spent_hours/views/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?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_enhanced.project_active_view_form" />
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='milestone_ids']/tree/field[@name='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_enhanced.project_milestone_view_list" />
<field name="arch" type="xml">
<field name="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.project_milestone_view_form" />
<field name="arch" type="xml">
<field name="is_reached" position="after">
<field name="total_hours" widget="float_time" />
</field>
</field>
</record>
</odoo>

0 comments on commit c892bf3

Please sign in to comment.