From 25cd0cf3fca681d9d3e286310dc01ccd33d6e7f8 Mon Sep 17 00:00:00 2001 From: Kartik Chavda Date: Tue, 19 Apr 2022 07:14:52 +0000 Subject: [PATCH] [IMP] project_timesheet_holiday: improve feature timesheet created by time off This commit prevent user write on time off timesheets and create timesheet on time off tasks and add test for this feature. task-2826265 Part-of: odoo/odoo#90744 --- .../models/__init__.py | 1 + .../models/account_analytic.py | 18 ++++++++- .../models/project_task.py | 40 +++++++++++++++++++ .../tests/test_timesheet_holidays.py | 15 +++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 addons/project_timesheet_holidays/models/project_task.py diff --git a/addons/project_timesheet_holidays/models/__init__.py b/addons/project_timesheet_holidays/models/__init__.py index 0147ac7d436..f853d0be44f 100644 --- a/addons/project_timesheet_holidays/models/__init__.py +++ b/addons/project_timesheet_holidays/models/__init__.py @@ -4,6 +4,7 @@ from . import res_company # has to be before hr_holidays to create needed columns on res.company from . import account_analytic from . import hr_holidays +from . import project_task from . import res_config_settings from . import resource_calendar_leaves from . import hr_employee diff --git a/addons/project_timesheet_holidays/models/account_analytic.py b/addons/project_timesheet_holidays/models/account_analytic.py index 259ed33d4ae..4f833ed574a 100644 --- a/addons/project_timesheet_holidays/models/account_analytic.py +++ b/addons/project_timesheet_holidays/models/account_analytic.py @@ -10,8 +10,24 @@ class AccountAnalyticLine(models.Model): holiday_id = fields.Many2one("hr.leave", string='Leave Request') global_leave_id = fields.Many2one("resource.calendar.leaves", string="Global Time Off", ondelete='cascade') + task_id = fields.Many2one(domain="[('company_id', '=', company_id), ('project_id.allow_timesheets', '=', True)," + "('project_id', '=?', project_id), ('is_timeoff_task', '=', False)]") @api.ondelete(at_uninstall=False) def _unlink_except_linked_leave(self): if any(line.holiday_id for line in self): - raise UserError(_('You cannot delete timesheets linked to time off. Please, cancel the time off instead.')) + raise UserError(_('You cannot delete timesheets that are linked to time off requests. Please cancel your time off request from the Time Off application instead.')) + + @api.model_create_multi + def create(self, vals_list): + if not self.env.su: + task_ids = [vals['task_id'] for vals in vals_list if vals.get('task_id')] + has_timeoff_task = self.env['project.task'].search_count([('id', 'in', task_ids), ('is_timeoff_task', '=', True)], limit=1) > 0 + if has_timeoff_task: + raise UserError(_('You cannot create timesheets for a task that is linked to a time off type. Please use the Time Off application to request new time off instead.')) + return super().create(vals_list) + + def write(self, vals): + if not self.env.su and self.filtered('holiday_id'): + raise UserError(_('You cannot modify timesheets that are linked to time off requests. Please use the Time Off application to modify your time off requests instead.')) + return super().write(vals) diff --git a/addons/project_timesheet_holidays/models/project_task.py b/addons/project_timesheet_holidays/models/project_task.py new file mode 100644 index 00000000000..a538f326035 --- /dev/null +++ b/addons/project_timesheet_holidays/models/project_task.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, _ + +class Task(models.Model): + _inherit = 'project.task' + + leave_types_count = fields.Integer(compute='_compute_leave_types_count') + is_timeoff_task = fields.Boolean("Is Time off Task", compute="_compute_is_timeoff_task", search="_search_is_timeoff_task") + + def _compute_leave_types_count(self): + time_off_type_read_group = self.env['hr.leave.type']._read_group( + [('timesheet_task_id', 'in', self.ids)], + ['timesheet_task_id'], + ['timesheet_task_id'], + ) + time_off_type_count_per_task = {res['timesheet_task_id'][0]: res['timesheet_task_id_count'] for res in time_off_type_read_group} + for task in self: + task.leave_types_count = time_off_type_count_per_task.get(task.id, 0) + + def _compute_is_timeoff_task(self): + timeoff_tasks = self.filtered(lambda task: task.leave_types_count or task.company_id.leave_timesheet_task_id == task) + timeoff_tasks.is_timeoff_task = True + (self - timeoff_tasks).is_timeoff_task = False + + def _search_is_timeoff_task(self, operator, value): + if operator not in ['=', '!='] or not isinstance(value, bool): + raise NotImplementedError(_('Operation not supported')) + leave_type_read_group = self.env['hr.leave.type']._read_group( + [('timesheet_task_id', '!=', False)], + ['timesheet_task_ids:array_agg(timesheet_task_id)'], + [], + ) + timeoff_task_ids = leave_type_read_group[0]['timesheet_task_ids'] if leave_type_read_group else [] + if self.env.company.leave_timesheet_task_id: + timeoff_task_ids.append(self.env.company.leave_timesheet_task_id.id) + if operator == '!=': + value = not value + return [('id', 'in' if value else 'not in', timeoff_task_ids)] diff --git a/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py b/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py index 5e2f0a4fecd..2f7421e44f7 100644 --- a/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py +++ b/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py @@ -7,6 +7,7 @@ from freezegun import freeze_time from odoo import fields, SUPERUSER_ID +from odoo.exceptions import UserError from odoo.tests import common, new_test_user from odoo.addons.hr_timesheet.tests.test_timesheet import TestCommonTimesheet import time @@ -187,5 +188,19 @@ class TestTimesheetHolidays(TestCommonTimesheet): ('employee_id', '=', self.empl_employee.id), ]) + # should not able to update timeoff timesheets + with self.assertRaises(UserError): + timesheets.with_user(self.empl_employee).write({'task_id': 4}) + + # should not able to create timesheet in timeoff task + with self.assertRaises(UserError): + self.env['account.analytic.line'].with_user(self.empl_employee).create({ + 'name': "my timesheet", + 'project_id': self.internal_project.id, + 'task_id': self.internal_task_leaves.id, + 'date': '2021-10-04', + 'unit_amount': 8.0, + }) + self.assertEqual(len(timesheets.filtered('holiday_id')), 4, "4 timesheet should be linked to employee's timeoff") self.assertEqual(len(timesheets.filtered('global_leave_id')), 1, '1 timesheet should be linked to global leave')