147 lines
6.5 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class HolidaysType(models.Model):
_inherit = "hr.leave.type"
timesheet_generate = fields.Boolean(
'Generate Timesheets', compute='_compute_timesheet_generate', store=True, readonly=False,
help="If checked, when validating a time off, timesheet will be generated in the Vacation Project of the company.")
timesheet_project_id = fields.Many2one('project.project', string="Project", domain="[('company_id', 'in', [False, company_id])]",
compute="_compute_timesheet_project_id", store=True, readonly=False)
timesheet_task_id = fields.Many2one(
'project.task', string="Task", compute='_compute_timesheet_task_id',
store=True, readonly=False,
domain="[('project_id', '=', timesheet_project_id),"
"('project_id', '!=', False),"
"('company_id', 'in', [False, company_id])]")
@api.depends('timesheet_task_id', 'timesheet_project_id')
def _compute_timesheet_generate(self):
for leave_type in self:
leave_type.timesheet_generate = not leave_type.company_id or (leave_type.timesheet_task_id and leave_type.timesheet_project_id)
@api.depends('company_id')
def _compute_timesheet_project_id(self):
for leave in self:
leave.timesheet_project_id = leave.company_id.internal_project_id
@api.depends('timesheet_project_id')
def _compute_timesheet_task_id(self):
for leave_type in self:
default_task_id = leave_type.company_id.leave_timesheet_task_id
if default_task_id and default_task_id.project_id == leave_type.timesheet_project_id:
leave_type.timesheet_task_id = default_task_id
else:
leave_type.timesheet_task_id = False
@api.constrains('timesheet_generate', 'timesheet_project_id', 'timesheet_task_id')
def _check_timesheet_generate(self):
for holiday_status in self:
if holiday_status.timesheet_generate and holiday_status.company_id:
if not holiday_status.timesheet_project_id or not holiday_status.timesheet_task_id:
raise ValidationError(_("Both the internal project and task are required to "
"generate a timesheet for the time off %s. If you don't want a timesheet, you should "
"leave the internal project and task empty.", holiday_status.name))
class Holidays(models.Model):
_inherit = "hr.leave"
timesheet_ids = fields.One2many('account.analytic.line', 'holiday_id', string="Analytic Lines")
def _validate_leave_request(self):
""" Timesheet will be generated on leave validation only if timesheet_generate is True
If company is set, timesheet_project_id and timesheet_task_id from leave type are
used as project_id and task_id.
Else, internal_project_id and leave_timesheet_task_id are used.
The generated timesheet will be attached to this project/task.
"""
vals_list = []
leave_ids = []
for leave in self:
if leave.holiday_type != 'employee' or not leave.holiday_status_id.timesheet_generate:
continue
if leave.holiday_status_id.company_id:
project, task = leave.holiday_status_id.timesheet_project_id, leave.holiday_status_id.timesheet_task_id
else:
project, task = leave.employee_id.company_id.internal_project_id, leave.employee_id.company_id.leave_timesheet_task_id
if not project or not task:
continue
leave_ids.append(leave.id)
if not leave.employee_id:
continue
work_hours_data = leave.employee_id.list_work_time_per_day(
leave.date_from,
leave.date_to)
for index, (day_date, work_hours_count) in enumerate(work_hours_data):
vals_list.append(leave._timesheet_prepare_line_values(index, work_hours_data, day_date, work_hours_count, project, task))
# Unlink previous timesheets to avoid doublon (shouldn't happen on the interface but meh)
old_timesheets = self.env["account.analytic.line"].sudo().search([('project_id', '!=', False), ('holiday_id', 'in', leave_ids)])
if old_timesheets:
old_timesheets.holiday_id = False
old_timesheets.unlink()
self.env['account.analytic.line'].sudo().create(vals_list)
return super()._validate_leave_request()
def _timesheet_prepare_line_values(self, index, work_hours_data, day_date, work_hours_count, project, task):
self.ensure_one()
return {
'name': _("Time Off (%s/%s)", index + 1, len(work_hours_data)),
'project_id': project.id,
'task_id': task.id,
'account_id': project.sudo().analytic_account_id.id,
'unit_amount': work_hours_count,
'user_id': self.employee_id.user_id.id,
'date': day_date,
'holiday_id': self.id,
'employee_id': self.employee_id.id,
'company_id': task.sudo().company_id.id or project.sudo().company_id.id,
}
def _check_missing_global_leave_timesheets(self):
if not self:
return
min_date = min([leave.date_from for leave in self])
max_date = max([leave.date_to for leave in self])
global_leaves = self.env['resource.calendar.leaves'].search([
("resource_id", "=", False),
("date_to", ">=", min_date),
("date_from", "<=", max_date),
("company_id.internal_project_id", "!=", False),
("company_id.leave_timesheet_task_id", "!=", False),
])
if global_leaves:
global_leaves._generate_public_time_off_timesheets(self.employee_ids)
def action_refuse(self):
""" Remove the timesheets linked to the refused holidays """
result = super(Holidays, self).action_refuse()
timesheets = self.sudo().mapped('timesheet_ids')
timesheets.write({'holiday_id': False})
timesheets.unlink()
self._check_missing_global_leave_timesheets()
return result
def _action_user_cancel(self, reason):
res = super()._action_user_cancel(reason)
timesheets = self.sudo().timesheet_ids
timesheets.write({'holiday_id': False})
timesheets.unlink()
self._check_missing_global_leave_timesheets()
return res