Skip to content

Commit

Permalink
[ADD] new module project_task_report
Browse files Browse the repository at this point in the history
  • Loading branch information
Clément Mombereau committed Dec 9, 2024
1 parent 5af6c89 commit 557e227
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 0 deletions.
32 changes: 32 additions & 0 deletions project_task_report/README.rst
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
===========

...
1 change: 1 addition & 0 deletions project_task_report/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import wizards
17 changes: 17 additions & 0 deletions project_task_report/__manifest__.py
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"],
}
104 changes: 104 additions & 0 deletions project_task_report/data/project_task_report_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?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="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>
3 changes: 3 additions & 0 deletions project_task_report/security/ir.model.access.csv
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
1 change: 1 addition & 0 deletions project_task_report/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_project_task_report
38 changes: 38 additions & 0 deletions project_task_report/tests/test_project_task_report.py
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,
}
)
line_ids = self.task_report_id._create_line_ids()
self.line_ids = line_ids.sorted(lambda l: l.task_id.name)

self.stage_new = self.env.ref("project.project_stage_0")
self.stage_in_progress = self.env.ref("project.project_stage_1")
self.stage_canceled = self.env.ref("project.project_stage_3")

def test_task_report_no_stage_change(self):
task_line_id = self.line_ids[0]
self.assertEqual(task_line_id.task_id.name, "Task 1")
self.assertEqual(task_line_id.hours_spent, 1)
self.assertEqual(task_line_id.start_stage_id, self.stage_new)
self.assertEqual(task_line_id.end_stage_id, self.stage_new)

def test_task_report_with_stage_change(self):
task_line_id = self.line_ids[1]
self.assertEqual(task_line_id.task_id.name, "Task 2")
self.assertEqual(task_line_id.hours_spent, 12)
self.assertEqual(task_line_id.start_stage_id, self.stage_in_progress)
self.assertEqual(task_line_id.end_stage_id, self.stage_canceled)
1 change: 1 addition & 0 deletions project_task_report/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import project_task_report
84 changes: 84 additions & 0 deletions project_task_report/wizards/project_task_report.py
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"))
82 changes: 82 additions & 0 deletions project_task_report/wizards/project_task_report.xml
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>

0 comments on commit 557e227

Please sign in to comment.