-
Notifications
You must be signed in to change notification settings - Fork 169
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] new module project_task_report
- Loading branch information
Clément Mombereau
committed
Dec 6, 2024
1 parent
5af6c89
commit a85249f
Showing
10 changed files
with
364 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
=================== | ||
Project Task Report | ||
=================== | ||
|
||
Task wizard to sum up the progress between two dates | ||
|
||
Purpose | ||
======= | ||
|
||
This module does this and that... | ||
|
||
Explain the use case. | ||
|
||
Configuration | ||
============= | ||
|
||
To configure this module, you need to: | ||
|
||
#. Go to ... | ||
|
||
Usage | ||
===== | ||
|
||
To use this module, you need to: | ||
|
||
#. Go to ... | ||
|
||
|
||
How to test | ||
=========== | ||
|
||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import wizards |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright 2024 Akretion | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Project Task Report", | ||
"summary": """Task wizard to sum up the progress between two dates""", | ||
"version": "16.0.1.0.0", | ||
"license": "AGPL-3", | ||
"author": "Akretion", | ||
"website": "http://akretion.com", | ||
"depends": ["project", "hr_timesheet"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"wizards/project_task_report.xml", | ||
], | ||
"demo": ["data/project_task_report_demo.xml"], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo> | ||
<data> | ||
<!-- Tasks --> | ||
<record id="task_1" model="project.task"> | ||
<field name="project_id" ref="project.project_project_1"/> | ||
<field name="name">Task 1</field> | ||
</record> | ||
<record id="task_2" model="project.task"> | ||
<field name="project_id" ref="project.project_project_1"/> | ||
<field name="name">Task 2</field> | ||
<field name="stage_id" ref="project.project_stage_2"/> | ||
<field name="create_date" eval="datetime(2023, 12, 1)"/> | ||
</record> | ||
|
||
<!-- Timesheets --> | ||
<record id="timesheet_11" model="account.analytic.line"> | ||
<field name="name">Timesheet 1.1</field> | ||
<field name="employee_id" ref="hr.employee_qdp"/> | ||
<field name="date" eval="datetime(2024, 3, 2)"/> | ||
<field name="task_id" ref="task_1"/> | ||
<field name="unit_amount">1.00</field> | ||
</record> | ||
<record id="timesheet_21" model="account.analytic.line"> | ||
<field name="name">Timesheet 2.1</field> | ||
<field name="employee_id" ref="hr.employee_qdp"/> | ||
<field name="date" eval="datetime(2024, 2, 1)"/> | ||
<field name="task_id" ref="task_2"/> | ||
</record> | ||
<record id="timesheet_22" model="account.analytic.line"> | ||
<field name="name">Timesheet 2.2</field> | ||
<field name="employee_id" ref="hr.employee_qdp"/> | ||
<field name="date" eval="datetime(2024, 3, 1)"/> | ||
<field name="task_id" ref="task_2"/> | ||
<field name="unit_amount">10.00</field> | ||
</record> | ||
<record id="timesheet_23" model="account.analytic.line"> | ||
<field name="name">Timesheet 2.3</field> | ||
<field name="employee_id" ref="hr.employee_qdp"/> | ||
<field name="date" eval="datetime(2024, 3, 2)"/> | ||
<field name="task_id" ref="task_2"/> | ||
<field name="unit_amount">2.00</field> | ||
</record> | ||
|
||
<!-- Historic stage changes on Task 2 --> | ||
<record id="task_2_mail_message_1" model="mail.message"> | ||
<field name="model">project.task</field> | ||
<field name="res_id" ref="task_2"/> | ||
<field name="message_type">notification</field> | ||
<field name="date" eval="datetime(2024, 1, 1)"/> | ||
<field name="subtype_id" ref="project.mt_task_stage"/> | ||
<field name="author_id" ref="base.partner_admin"/> | ||
</record> | ||
<record id="task_2_mail_message_1_track" model="mail.tracking.value"> | ||
<field name="field" model="ir.model.fields" eval="obj().search([('model', '=', 'project.task'), ('name', '=', 'stage_id')])"/> | ||
<field name="field_desc">Stage</field> | ||
<field name="old_value_char">New</field> | ||
<field name="new_value_char">In Progress</field> | ||
<field name="field_type">many2one</field> | ||
<field name="old_value_integer">1</field> | ||
<field name="new_value_integer">2</field> | ||
<field name="mail_message_id" ref="task_2_mail_message_1"/> | ||
</record> | ||
|
||
<record id="task_2_mail_message_2" model="mail.message"> | ||
<field name="model">project.task</field> | ||
<field name="res_id" ref="task_2"/> | ||
<field name="message_type">notification</field> | ||
<field name="date" eval="datetime(2024, 4, 1)"/> | ||
<field name="subtype_id" ref="project.mt_task_stage"/> | ||
<field name="author_id" ref="base.partner_admin"/> | ||
</record> | ||
<record id="task_2_mail_message_2_track" model="mail.tracking.value"> | ||
<field name="field" model="ir.model.fields" eval="obj().search([('model', '=', 'project.task'), ('name', '=', 'stage_id')])"/> | ||
<field name="field_desc">Stage</field> | ||
<field name="old_value_char">In Progress</field> | ||
<field name="new_value_char">Done</field> | ||
<field name="field_type">many2one</field> | ||
<field name="old_value_integer">2</field> | ||
<field name="new_value_integer">3</field> | ||
<field name="mail_message_id" ref="task_2_mail_message_2"/> | ||
</record> | ||
|
||
<record id="task_2_mail_message_3" model="mail.message"> | ||
<field name="model">project.task</field> | ||
<field name="res_id" ref="task_2"/> | ||
<field name="message_type">notification</field> | ||
<field name="date" eval="datetime(2024, 5, 1)"/> | ||
<field name="subtype_id" ref="project.mt_task_stage"/> | ||
<field name="author_id" ref="base.partner_admin"/> | ||
</record> | ||
<record id="task_2_mail_message_3_track" model="mail.tracking.value"> | ||
<field name="field" model="ir.model.fields" eval="obj().search([('model', '=', 'project.task'), ('name', '=', 'stage_id')])"/> | ||
<field name="field_desc">Stage</field> | ||
<field name="old_value_char">Done</field> | ||
<field name="new_value_char">Canceled</field> | ||
<field name="field_type">many2one</field> | ||
<field name="old_value_integer">3</field> | ||
<field name="new_value_integer">4</field> | ||
<field name="mail_message_id" ref="task_2_mail_message_3"/> | ||
</record> | ||
|
||
|
||
</data> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
project_task_report.access_project_task_report,access_project_task_report,project_task_report.model_project_task_report,base.group_user,1,1,1,1 | ||
project_task_report.access_project_task_report_line,access_project_task_report_line,project_task_report.model_project_task_report_line,base.group_user,1,1,1,1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_project_task_report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Copyright 2024 Akretion | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from datetime import datetime | ||
from odoo.tests.common import TransactionCase | ||
|
||
|
||
class TestProjectTaskReport(TransactionCase): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
self.task_report_id = self.env["project.task.report"].create( | ||
{ | ||
"start_date": datetime(2024, 2, 2), | ||
"end_date": datetime(2024, 6, 1), | ||
"project_ids": self.env.ref("project.project_project_1").ids, | ||
} | ||
) | ||
self.ts_22 = self.env.ref("project_task_report.timesheet_22") | ||
self.ts_23 = self.env.ref("project_task_report.timesheet_23") | ||
|
||
def test_create_task_report_lines(self): | ||
line_ids = self.task_report_id._create_line_ids() | ||
line_ids = line_ids.sorted(lambda l: l.task_id.name) | ||
|
||
self.assertEqual(line_ids[0].task_id.name, "Task 1") | ||
self.assertEqual(line_ids[0].hours_spent, 1) | ||
|
||
self.assertEqual(line_ids[1].task_id.name, "Task 2") | ||
self.assertEqual(line_ids[1].timesheet_ids, self.ts_22 | self.ts_23) | ||
self.assertEqual(line_ids[1].hours_spent, 12) | ||
|
||
self.assertEqual( | ||
line_ids[1].start_stage_id, self.env.ref("project.project_stage_1") | ||
) | ||
self.assertEqual( | ||
line_ids[1].end_stage_id, self.env.ref("project.project_stage_3") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import project_task_report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Copyright 2024 Akretion | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import _, api, fields, models | ||
|
||
|
||
class ProjectTaskReport(models.TransientModel): | ||
_name = "project.task.report" | ||
_description = "Task Report" | ||
|
||
start_date = fields.Date() | ||
end_date = fields.Date() | ||
project_ids = fields.Many2many("project.project", string="Projects") | ||
|
||
def _create_line_ids(self): | ||
line_vals = [] | ||
task_ids = self.env["project.task"].search( | ||
[("project_id", "in", self.project_ids.ids)] | ||
) | ||
field_stage_id = self.env["ir.model.fields"].search( | ||
[("model", "=", "project.task"), ("name", "=", "stage_id")] | ||
) | ||
|
||
for task_id in task_ids: | ||
line_val = {"task_id": task_id.id, "timesheet_ids": []} | ||
|
||
# Catch the timesheets between the start and end dates | ||
for timesheet_id in task_id.timesheet_ids: | ||
if self.start_date < timesheet_id.date < self.end_date: | ||
line_val["timesheet_ids"].append(timesheet_id.id) | ||
|
||
# Catch the historic stage changes between the start and end dates | ||
track_ids = task_id.message_ids.tracking_value_ids.filtered( | ||
lambda t: t.field == field_stage_id | ||
and self.start_date < t.mail_message_id.date.date() < self.end_date | ||
).sorted(lambda t: t.mail_message_id.date) | ||
|
||
if track_ids: | ||
line_val.update( | ||
{ | ||
"start_stage_id": track_ids[0].old_value_integer, | ||
"end_stage_id": track_ids[-1].new_value_integer, | ||
} | ||
) | ||
|
||
if line_val["timesheet_ids"] or line_val.get("start_stage_id"): | ||
# Fill stage fields in case there have been timesheets without stage change | ||
if not line_val.get("start_stage_id"): | ||
line_val.update( | ||
{ | ||
"start_stage_id": task_id.stage_id.id, | ||
"end_stage_id": task_id.stage_id.id, | ||
} | ||
) | ||
line_vals.append(line_val) | ||
|
||
return self.env["project.task.report.line"].create(line_vals) | ||
|
||
def action_view_task_report(self): | ||
self.ensure_one() | ||
|
||
line_ids = self._create_line_ids() | ||
|
||
action_xml_id = "project_task_report.project_task_report_line_act_window" | ||
action = self.env["ir.actions.act_window"]._for_xml_id(action_xml_id) | ||
action.update({"domain": [("id", "in", line_ids.ids)]}) | ||
return action | ||
|
||
|
||
class ProjectTaskReportLine(models.TransientModel): | ||
_name = "project.task.report.line" | ||
_description = "Task Report Line" | ||
|
||
task_id = fields.Many2one("project.task") | ||
start_stage_id = fields.Many2one("project.task.type") | ||
end_stage_id = fields.Many2one("project.task.type") | ||
|
||
timesheet_ids = fields.Many2many("account.analytic.line") | ||
hours_spent = fields.Float(compute="_compute_hours_spent") | ||
|
||
@api.depends("timesheet_ids.unit_amount") | ||
def _compute_hours_spent(self): | ||
for rec in self: | ||
rec.hours_spent = sum(rec.timesheet_ids.mapped("unit_amount")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright 2024 Akretion | ||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> | ||
|
||
<odoo> | ||
|
||
<record id="project_task_report_form_view" model="ir.ui.view"> | ||
<field name="model">project.task.report</field> | ||
<field name="arch" type="xml"> | ||
<form string="Project Task Report"> | ||
<group> | ||
<field name="start_date"/> | ||
<field name="end_date"/> | ||
<field name="project_ids" widget="many2many_tags"/> | ||
</group> | ||
<footer> | ||
<button name="action_view_task_report" | ||
string="Create Task Report" | ||
class="btn-primary" | ||
type="object"/> | ||
<button string="Cancel" | ||
class="btn-default" | ||
special="cancel"/> | ||
</footer> | ||
</form> | ||
</field> | ||
</record> | ||
|
||
<record model="ir.actions.act_window" id="project_task_report_act_window"> | ||
<field name="name">Task Report</field> | ||
<field name="res_model">project.task.report</field> | ||
<field name="view_mode">form</field> | ||
<field name="target">new</field> | ||
</record> | ||
|
||
<record id="project_task_report_line_tree_view" model="ir.ui.view"> | ||
<field name="name">project.task.report.line.tree</field> | ||
<field name="model">project.task.report.line</field> | ||
<field name="arch" type="xml"> | ||
<tree string="Task Report" create="false" delete="false" edit="false"> | ||
<field name="task_id"/> | ||
<field name="start_stage_id"/> | ||
<field name="end_stage_id"/> | ||
<field name="hours_spent" widget="timesheet_uom"/> | ||
</tree> | ||
</field> | ||
</record> | ||
|
||
<record id="project_task_report_line_form_view" model="ir.ui.view"> | ||
<field name="model">project.task.report.line</field> | ||
<field name="arch" type="xml"> | ||
<form string="Project Task Report Line"> | ||
<sheet> | ||
<div class="oe_title"> | ||
<label for="task_id"/> | ||
<h1><field name="task_id"/></h1> | ||
</div> | ||
<group class="col-12 col-lg-6"> | ||
<field name="start_stage_id"/> | ||
<field name="end_stage_id"/> | ||
</group> | ||
<group class="col-12 col-lg-6"> | ||
<field name="timesheet_ids"/> | ||
</group> | ||
</sheet> | ||
</form> | ||
</field> | ||
</record> | ||
|
||
<record model="ir.actions.act_window" id="project_task_report_line_act_window"> | ||
<field name="name">Task Report Line</field> | ||
<field name="res_model">project.task.report.line</field> | ||
<field name="view_mode">tree,form</field> | ||
</record> | ||
|
||
<record model="ir.ui.menu" id="project_task_report_menu"> | ||
<field name="name">Task Report</field> | ||
<field name="parent_id" ref="project.menu_project_report"/> | ||
<field name="action" ref="project_task_report_act_window"/> | ||
<field name="sequence" eval="10"/> | ||
</record> | ||
</odoo> |