-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
project_workload: start build a module for managing project workload …
…per week
- Loading branch information
1 parent
2c3ee0c
commit cc829bd
Showing
24 changed files
with
624 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 @@ | ||
from . import models |
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,30 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Project Workload", | ||
"summary": "Ressource Workload Management", | ||
"version": "14.0.1.0.0", | ||
"development_status": "Alpha", | ||
"category": "Uncategorized", | ||
"website": "https://github.com/akretion/ak-odoo-incubator", | ||
"author": " Akretion", | ||
"license": "AGPL-3", | ||
"external_dependencies": { | ||
"python": [], | ||
"bin": [], | ||
}, | ||
"depends": [ | ||
"project_timeline", | ||
], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/project_capacity_unit_view.xml", | ||
"views/project_task_view.xml", | ||
"views/project_project_view.xml", | ||
"views/project_user_capacity_view.xml", | ||
"views/menu_view.xml", | ||
], | ||
"demo": [], | ||
} |
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,54 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import _, api, fields, models | ||
|
||
WORKLOAD_FIELDS = [ | ||
"date_start", | ||
"date_end", | ||
"user_id", | ||
"planned_hours", | ||
] | ||
|
||
|
||
class ProjectTask(models.Model): | ||
_inherit = 'project.task' | ||
|
||
workload_ids = fields.One2many( | ||
'project.task.workload', | ||
'task_id', | ||
'Task') | ||
use_workload = fields.Boolean | ||
related="project_id.use_workload" | ||
) | ||
config_workload_manualy = fields.Boolean() | ||
|
||
def _prepare_workload(self): | ||
return { | ||
"task_id": self.id, | ||
"date_start": self.date_start, | ||
"date_end": self.date_end, | ||
"hours": self.planned_hours, | ||
"user_id": self.user_id.id, | ||
} | ||
|
||
def _sync_workload(self): | ||
# Remove workload and regenerate it | ||
for record in self: | ||
if not record.config_workload_manualy: | ||
vals = self._prepare_workload() | ||
if record.workload_ids: | ||
record.workload.write(vals) | ||
self.env["project.task.workload"].create(vals) | ||
|
||
def create(self, vals_list): | ||
records = super().create(vals_list) | ||
records._sync_workload() | ||
return records | ||
|
||
def write(self, vals): | ||
res = super().write(vals) | ||
if set(vals.keys()).intersection(WORKLOAD_FIELDS): | ||
self._sync_workload() | ||
return res |
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,6 @@ | ||
from . import project_task_workload | ||
from . import project_project | ||
from . import project_task | ||
from . import project_capacity_unit | ||
from . import project_user_capacity | ||
from . import project_user_capacity_line |
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,65 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
|
||
from datetime import datetime | ||
|
||
from odoo import api, fields, models | ||
|
||
WEEK_FORMAT = "%Y-%W" | ||
|
||
|
||
def week_name(value): | ||
if value: | ||
return value.strftime(WEEK_FORMAT) | ||
return None | ||
|
||
|
||
class ProjectCapacityUnit(models.Model): | ||
_name = "project.capacity.unit" | ||
_description = "Project Capacity Unit" | ||
_rec_name = "week" | ||
_order = "week asc" | ||
|
||
week = fields.Char() | ||
capacity_id = fields.Many2one("project.user.capacity", "Capacity") | ||
hours = fields.Float(compute="_compute_capacity", store=True) | ||
|
||
_sql_constraints = [ | ||
( | ||
"week_capacity_uniq", | ||
"unique(week, capacity_id)", | ||
"The week must be uniq per capacity", | ||
), | ||
] | ||
|
||
@api.depends( | ||
"capacity_id.line_ids.hours", | ||
"capacity_id.line_ids.date_start", | ||
"capacity_id.line_ids.date_end", | ||
"capacity_id.line_ids.modulo", | ||
) | ||
def _compute_capacity(self): | ||
for record in self: | ||
hours = 0 | ||
for line in record.capacity_id.line_ids: | ||
start = week_name(line.date_start) | ||
stop = week_name(line.date_end) | ||
if record.week >= start and (not stop or record.week <= stop): | ||
if line.modulo > 1: | ||
nbr_week = round( | ||
( | ||
datetime.strptime( | ||
record.week + "-1", WEEK_FORMAT + "-%w" | ||
).date() | ||
- line.date_start | ||
).days | ||
/ 7 | ||
) | ||
if nbr_week % line.modulo: | ||
# week is not a multi skip it | ||
continue | ||
hours = line.hours | ||
break | ||
record.hours = hours |
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,11 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class ProjectProject(models.Model): | ||
_inherit = "project.project" | ||
|
||
use_workload = fields.Boolean() |
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,51 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models | ||
|
||
WORKLOAD_FIELDS = [ | ||
"date_start", | ||
"date_end", | ||
"user_id", | ||
"planned_hours", | ||
"config_workload_manually", | ||
] | ||
|
||
|
||
class ProjectTask(models.Model): | ||
_inherit = "project.task" | ||
|
||
workload_ids = fields.One2many("project.task.workload", "task_id", "Task") | ||
use_workload = fields.Boolean(related="project_id.use_workload") | ||
config_workload_manually = fields.Boolean() | ||
|
||
def _prepare_workload(self): | ||
return { | ||
"task_id": self.id, | ||
"date_start": self.date_start, | ||
"date_end": self.date_end, | ||
"hours": self.planned_hours, | ||
"user_id": self.user_id.id, | ||
} | ||
|
||
def _sync_workload(self): | ||
for record in self: | ||
if not record.config_workload_manually: | ||
vals = self._prepare_workload() | ||
if record.workload_ids: | ||
record.workload_ids[1:].unlink() | ||
record.workload_ids.write(vals) | ||
else: | ||
self.env["project.task.workload"].create([vals]) | ||
|
||
def create(self, vals_list): | ||
records = super().create(vals_list) | ||
records._sync_workload() | ||
return records | ||
|
||
def write(self, vals): | ||
res = super().write(vals) | ||
if set(vals.keys()).intersection(WORKLOAD_FIELDS): | ||
self._sync_workload() | ||
return res | ||
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 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
|
||
from odoo import fields, models | ||
|
||
|
||
class ProjectTaskWorkload(models.Model): | ||
_name = "project.task.workload" | ||
_description = "Project Task Workload" | ||
|
||
task_id = fields.Many2one("project.task", "Task", required=True) | ||
date_start = fields.Date(required=True) | ||
date_end = fields.Date(required=True) | ||
user_id = fields.Many2one("res.users", "User", required=True) | ||
hours = fields.Float(required=True) |
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,51 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from collections import defaultdict | ||
from datetime import datetime, timedelta | ||
|
||
from odoo import api, fields, models | ||
|
||
from .project_capacity_unit import week_name | ||
|
||
|
||
class ProjectUserCapacity(models.Model): | ||
_name = "project.user.capacity" | ||
_description = "Project User Capacity" | ||
|
||
name = fields.Char(required=True) | ||
user_id = fields.Many2one("res.users", "User", required=True) | ||
filter_id = fields.Many2one("ir.filters", "Domain") | ||
line_ids = fields.One2many("project.user.capacity.line", "capacity_id", "Line") | ||
unit_ids = fields.One2many("project.capacity.unit", "capacity_id", "Capacity Unit") | ||
|
||
@api.model_create_multi | ||
def create(self, vals_list): | ||
records = super().create(vals_list) | ||
records._generate_capacity_unit() | ||
return records | ||
|
||
def _cron_generate_week_report(self, nbr_week=52): | ||
self.env["project.capacity"].search([])._generate_capacity_unit() | ||
|
||
def _generate_capacity_unit(self, nbr_week=52): | ||
now = datetime.now() | ||
items = self.env["project.capacity.unit"].search( | ||
[("week", ">", week_name(now))] | ||
) | ||
weeks_per_capacity = defaultdict(set) | ||
for item in items: | ||
weeks_per_capacity[item.capacity_id.id].add(item.week) | ||
weeks = {week_name(now + timedelta(days=7 * x)) for x in range(nbr_week)} | ||
vals_list = [] | ||
for capacity in self: | ||
missing_weeks = weeks - weeks_per_capacity[capacity.id] | ||
vals_list += [ | ||
{ | ||
"week": week, | ||
"capacity_id": capacity.id, | ||
} | ||
for week in missing_weeks | ||
] | ||
return self.env["project.capacity.unit"].create(vals_list) |
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 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
|
||
from odoo import fields, models | ||
|
||
|
||
class ProjectUserCapacityLine(models.Model): | ||
_name = "project.user.capacity.line" | ||
_description = "Project User Capacity Line" | ||
|
||
capacity_id = fields.Many2one("project.user.capacity") | ||
date_start = fields.Date(required=True, default=fields.Date.today()) | ||
date_end = fields.Date() | ||
hours = fields.Float() | ||
modulo = fields.Integer(default=1, string="Repeat", help="Repeat every X week") |
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 @@ | ||
* BEAU Sébastien <[email protected]> |
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,2 @@ | ||
This module allow to manage load and capacity by project and cross project | ||
Load is managed by week |
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,2 @@ | ||
TODO | ||
- in case of manual workload assignation add a check on date |
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,47 @@ | ||
# Copyright 2023 Akretion (https://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models | ||
|
||
# TODO | ||
|
||
|
||
class ProjectLoadReport(models.Model): | ||
_name = "project.load.report" | ||
_description = "Project Load Report" | ||
|
||
week = fields.Char() | ||
user_id = fields.Many2one("res.users", "User") | ||
total_planned_hours = fields.Float() | ||
project_planned_hours = fields.Float() | ||
project_capacity_hours = fields.Float() | ||
total_capacity_hours = fields.Float() | ||
reserved_capacity_hours = fields.Float() | ||
available_capacity_hours = fields.Float( | ||
help="min(total_capacity-reserved_capacity, project_capacity_hours)" | ||
) | ||
|
||
|
||
# | ||
# """SELECT sum(hours) | ||
# FROM project_task_load_unit | ||
# GROUP BY week | ||
# WHERE project_id in %s""" | ||
# | ||
# """SELECT sum(hours) | ||
# FROM project_user_capacity_unit | ||
# GROUP BY week | ||
# WHERE capacity_id in %s""" | ||
# | ||
# # capacité réservé par autre | ||
# """SELECT sum(hours) | ||
# FROM project_user_capacity_unit | ||
# GROUP BY week | ||
# WHERE capacity_id not in %s""" | ||
# | ||
# # capacité total | ||
# """SELECT sum(hours) | ||
# FROM project_user_capacity_unit | ||
# GROUP BY week | ||
# """ |
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,5 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_edit_project_user_capacity,edit project user capacity,model_project_user_capacity,project.group_project_user,1,1,1,1 | ||
access_edit_project_user_capacity_line,edit project user capacity line,model_project_user_capacity_line,project.group_project_user,1,1,1,1 | ||
access_edit_project_capacity_unit,edit project capacity unit,model_project_capacity_unit,project.group_project_user,1,1,1,1 | ||
access_edit_project_task_workload,edit project task workload,model_project_task_workload,project.group_project_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_workload |
Oops, something went wrong.