forked from Mapan/odoo17e
119 lines
6.7 KiB
Python
119 lines
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import _, api, fields, models
|
|
|
|
from odoo.addons.sale_timesheet_enterprise.models.sale import DEFAULT_INVOICED_TIMESHEET
|
|
|
|
|
|
PROJECT_TASK_READABLE_FIELDS_TO_MAP = {
|
|
'remaining_hours': 'portal_remaining_hours',
|
|
'effective_hours': 'portal_effective_hours',
|
|
'total_hours_spent': 'portal_total_hours_spent',
|
|
'subtask_effective_hours': 'portal_subtask_effective_hours',
|
|
'progress': 'portal_progress',
|
|
}
|
|
|
|
class ProjectTask(models.Model):
|
|
_inherit = 'project.task'
|
|
|
|
# Project Sharing fields
|
|
portal_remaining_hours = fields.Float(compute='_compute_project_sharing_timesheets', help="Total remaining time, can be re-estimated periodically by the assignee of the task.")
|
|
portal_effective_hours = fields.Float(compute='_compute_project_sharing_timesheets', help="Time spent on this task, excluding its sub-tasks.")
|
|
portal_total_hours_spent = fields.Float(compute='_compute_project_sharing_timesheets', help="Time spent on this task, including its sub-tasks.")
|
|
portal_subtask_effective_hours = fields.Float(compute='_compute_project_sharing_timesheets', help="Time spent on the sub-tasks (and their own sub-tasks) of this task.")
|
|
portal_progress = fields.Float(compute='_compute_project_sharing_timesheets', group_operator="avg", help="Display progress of current task.")
|
|
|
|
@property
|
|
def SELF_READABLE_FIELDS(self):
|
|
return super().SELF_READABLE_FIELDS | set(PROJECT_TASK_READABLE_FIELDS_TO_MAP.values()) - set(PROJECT_TASK_READABLE_FIELDS_TO_MAP.keys())
|
|
|
|
@api.depends('allocated_hours')
|
|
def _compute_project_sharing_timesheets(self):
|
|
is_portal_user = self.user_has_groups('base.group_portal')
|
|
timesheets_per_task = None
|
|
if is_portal_user:
|
|
subtask_ids_per_task_id = self.sudo().with_context(active_test=False)._get_subtask_ids_per_task_id()
|
|
# Say `self.ids` is [1, 2, 3] and `_get_subtask_ids_per_task_id()` returns {1: [2, 4], 2: [4], 3: []}.
|
|
# We want to merge all subtask ids and add `self.ids` to it.
|
|
# Unpacking `subtask_ids_per_task_id` values in `set.union` seems to be the appropriate method:
|
|
# >>> set.union({}, [2, 4], [4], [], [1, 2, 3]) = {2, 4, 1, 3}
|
|
all_task_ids = set.union(set(), *subtask_ids_per_task_id.values(), self.ids)
|
|
timesheet_read_group = self.env['account.analytic.line']._read_group(
|
|
[
|
|
('project_id', '!=', False),
|
|
('task_id', 'in', list(all_task_ids)),
|
|
('validated', 'in', [True, self.env['ir.config_parameter'].sudo().get_param('sale.invoiced_timesheet', DEFAULT_INVOICED_TIMESHEET) == 'approved'])
|
|
],
|
|
['task_id'],
|
|
['unit_amount:sum'],
|
|
)
|
|
timesheets_per_task = {task.id: unit_amount_sum for task, unit_amount_sum in timesheet_read_group}
|
|
for task in self:
|
|
remaining_hours = effective_hours = total_hours_spent = subtask_effective_hours = progress = 0.0
|
|
if not is_portal_user:
|
|
remaining_hours = task.remaining_hours
|
|
effective_hours = task.effective_hours
|
|
total_hours_spent = task.total_hours_spent
|
|
subtask_effective_hours = task.subtask_effective_hours
|
|
progress = task.progress
|
|
elif timesheets_per_task:
|
|
effective_hours = timesheets_per_task.get(task.id, 0.0)
|
|
subtask_effective_hours = sum(timesheets_per_task.get(subtask_id, 0.0) for subtask_id in subtask_ids_per_task_id.get(task.id, []))
|
|
total_hours_spent = effective_hours + subtask_effective_hours
|
|
remaining_hours = task.allocated_hours - total_hours_spent
|
|
if task.allocated_hours > 0:
|
|
progress = 100 if max(total_hours_spent - task.allocated_hours, 0) else round(total_hours_spent / task.allocated_hours * 100, 2)
|
|
task.portal_remaining_hours = remaining_hours
|
|
task.portal_effective_hours = effective_hours
|
|
task.portal_subtask_effective_hours = subtask_effective_hours
|
|
task.portal_total_hours_spent = total_hours_spent
|
|
task.portal_progress = progress
|
|
|
|
def read(self, fields=None, load='_classic_read'):
|
|
""" Override read method to filter timesheets in the task(s) is the user is portal user
|
|
and the sale.invoiced_timesheet configuration is set to 'approved'
|
|
Then we need to give the id of timesheets which is validated.
|
|
"""
|
|
result = super().read(fields=fields, load=load)
|
|
if fields and 'timesheet_ids' in fields and self.env.user.has_group('base.group_portal'):
|
|
# We need to check if configuration
|
|
param_invoiced_timesheet = self.env['ir.config_parameter'].sudo().get_param('sale.invoiced_timesheet', DEFAULT_INVOICED_TIMESHEET)
|
|
if param_invoiced_timesheet == 'approved':
|
|
timesheets_read_group = self.env['account.analytic.line']._read_group(
|
|
[('task_id', 'in', self.ids), ('validated', '=', True)],
|
|
['task_id'],
|
|
['id:array_agg'],
|
|
)
|
|
timesheets_dict = {task.id: ids for task, ids in timesheets_read_group}
|
|
for record_read in result:
|
|
record_read['timesheet_ids'] = timesheets_dict.get(record_read['id'], [])
|
|
return result
|
|
|
|
def _gantt_progress_bar_sale_line_id(self, res_ids):
|
|
if not self.env['sale.order.line'].check_access_rights('read', raise_exception=False):
|
|
return {}
|
|
uom_hour = self.env.ref('uom.product_uom_hour')
|
|
planned_hours_per_sol = self.env['project.task']._read_group([
|
|
('sale_line_id', 'in', res_ids),
|
|
], ['sale_line_id'], ['planned_hours:sum'])
|
|
planned_hours_per_sol_mapped = {
|
|
sale_line.id: planned_hours_sum
|
|
for sale_line, planned_hours_sum in planned_hours_per_sol
|
|
}
|
|
return {
|
|
sol.id: {
|
|
'value': planned_hours_per_sol_mapped.get(sol.id, 0.0),
|
|
'max_value': sol.product_uom._compute_quantity(sol.product_uom_qty, uom_hour),
|
|
}
|
|
for sol in self.env['sale.order.line'].search([('id', 'in', res_ids)])
|
|
}
|
|
|
|
def _gantt_progress_bar(self, field, res_ids, start, stop):
|
|
if field == 'sale_line_id':
|
|
return dict(
|
|
self._gantt_progress_bar_sale_line_id(res_ids),
|
|
warning=_("This Sale Order Item doesn't have a target value of planned hours. Planned hours :")
|
|
)
|
|
return super()._gantt_progress_bar(field, res_ids, start, stop)
|