# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, tools from odoo.addons.rating.models.rating_data import RATING_LIMIT_MIN, RATING_TEXT class ReportProjectTaskUser(models.Model): _name = "report.project.task.user" _description = "Tasks Analysis" _order = 'name desc, project_id' _auto = False name = fields.Char(string='Task', readonly=True) user_ids = fields.Many2many('res.users', relation='project_task_user_rel', column1='task_id', column2='user_id', string='Assignees', readonly=True) create_date = fields.Datetime("Create Date", readonly=True) date_assign = fields.Datetime(string='Assignment Date', readonly=True) date_end = fields.Datetime(string='Ending Date', readonly=True) date_deadline = fields.Date(string='Deadline', readonly=True) date_last_stage_update = fields.Datetime(string='Last Stage Update', readonly=True) project_id = fields.Many2one('project.project', string='Project', readonly=True) working_days_close = fields.Float(string='Working Days to Close', digits=(16, 2), readonly=True, group_operator="avg") working_days_open = fields.Float(string='Working Days to Assign', digits=(16, 2), readonly=True, group_operator="avg") delay_endings_days = fields.Float(string='Days to Deadline', digits=(16, 2), group_operator="avg", readonly=True) nbr = fields.Integer('# of Tasks', readonly=True) # TDE FIXME master: rename into nbr_tasks working_hours_open = fields.Float(string='Working Hours to Assign', digits=(16, 2), readonly=True, group_operator="avg") working_hours_close = fields.Float(string='Working Hours to Close', digits=(16, 2), readonly=True, group_operator="avg") rating_last_value = fields.Float('Rating Value (/5)', group_operator="avg", readonly=True, groups="project.group_project_rating") rating_avg = fields.Float('Average Rating', readonly=True, group_operator='avg', groups="project.group_project_rating") priority = fields.Selection([ ('0', 'Low'), ('1', 'High') ], readonly=True, string="Priority") state = fields.Selection([ ('normal', 'In Progress'), ('blocked', 'Blocked'), ('done', 'Ready for Next Stage') ], string='Kanban State', readonly=True) company_id = fields.Many2one('res.company', string='Company', readonly=True) partner_id = fields.Many2one('res.partner', string='Customer', readonly=True) stage_id = fields.Many2one('project.task.type', string='Stage', readonly=True) is_closed = fields.Boolean("Closing Stage", readonly=True, help="Folded in Kanban stages are closing stages.") task_id = fields.Many2one('project.task', string='Tasks', readonly=True) active = fields.Boolean(readonly=True) tag_ids = fields.Many2many('project.tags', relation='project_tags_project_task_rel', column1='project_task_id', column2='project_tags_id', string='Tags', readonly=True) parent_id = fields.Many2one('project.task', string='Parent Task', readonly=True) ancestor_id = fields.Many2one('project.task', string="Ancestor Task", readonly=True) # We are explicitly not using a related field in order to prevent the recomputing caused by the depends as the model is a report. rating_last_text = fields.Selection(RATING_TEXT, string="Rating Last Text", compute="_compute_rating_last_text", search="_search_rating_last_text") personal_stage_type_ids = fields.Many2many('project.task.type', relation='project_task_user_rel', column1='task_id', column2='stage_id', string="Personal Stage", readonly=True) milestone_id = fields.Many2one('project.milestone', readonly=True) milestone_reached = fields.Boolean('Is Milestone Reached', readonly=True) milestone_deadline = fields.Date('Milestone Deadline', readonly=True) def _compute_rating_last_text(self): for task_analysis in self: task_analysis.rating_last_text = task_analysis.task_id.rating_last_text def _search_rating_last_text(self, operator, value): return [('task_id.rating_last_text', operator, value)] def _select(self): return """ (select 1) AS nbr, t.id as id, t.id as task_id, t.active, t.create_date as create_date, t.date_assign as date_assign, t.date_end as date_end, t.date_last_stage_update as date_last_stage_update, t.date_deadline as date_deadline, t.project_id, t.priority, t.name as name, t.company_id, t.partner_id, t.parent_id as parent_id, t.ancestor_id as ancestor_id, t.stage_id as stage_id, t.is_closed as is_closed, t.kanban_state as state, t.milestone_id, pm.is_reached as milestone_reached, pm.deadline as milestone_deadline, NULLIF(t.rating_last_value, 0) as rating_last_value, AVG(rt.rating) as rating_avg, t.working_days_close as working_days_close, t.working_days_open as working_days_open, t.working_hours_open as working_hours_open, t.working_hours_close as working_hours_close, (extract('epoch' from (t.date_deadline-(now() at time zone 'UTC'))))/(3600*24) as delay_endings_days """ def _group_by(self): return """ t.id, t.active, t.create_date, t.date_assign, t.date_end, t.date_last_stage_update, t.date_deadline, t.project_id, t.ancestor_id, t.priority, t.name, t.company_id, t.partner_id, t.parent_id, t.stage_id, t.is_closed, t.kanban_state, t.rating_last_value, t.working_days_close, t.working_days_open, t.working_hours_open, t.working_hours_close, t.milestone_id, pm.is_reached, pm.deadline """ def _from(self): return f""" project_task t LEFT JOIN rating_rating rt ON rt.res_id = t.id AND rt.res_model = 'project.task' AND rt.consumed = True AND rt.rating >= {RATING_LIMIT_MIN} LEFT JOIN project_milestone pm ON pm.id = t.milestone_id """ def _where(self): return """ t.project_id IS NOT NULL """ def init(self): tools.drop_view_if_exists(self._cr, self._table) self._cr.execute(""" CREATE view %s as SELECT %s FROM %s WHERE %s GROUP BY %s """ % (self._table, self._select(), self._from(), self._where(), self._group_by()))