1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/sale_timesheet_enterprise/models/project_task.py
2024-12-10 09:04:09 +07:00

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)