mirror of
https://github.com/bringout/oca-ocb-project.git
synced 2026-04-23 07:22:02 +02:00
132 lines
6 KiB
Python
132 lines
6 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import fields, models, _
|
|
|
|
import pytz
|
|
|
|
|
|
class HrLeave(models.Model):
|
|
_inherit = "hr.leave"
|
|
|
|
timesheet_ids = fields.One2many('account.analytic.line', 'holiday_id', string="Analytic Lines")
|
|
|
|
def _validate_leave_request(self):
|
|
self._generate_timesheets()
|
|
return super()._validate_leave_request()
|
|
|
|
def _generate_timesheets(self, ignored_resource_calendar_leaves=None):
|
|
""" Timesheet will be generated on leave validation
|
|
internal_project_id and leave_timesheet_task_id are used.
|
|
The generated timesheet will be attached to this project/task.
|
|
"""
|
|
vals_list = []
|
|
leave_ids = []
|
|
calendar_leaves_data = self.env['resource.calendar.leaves']._read_group([('holiday_id', 'in', self.ids)], ['holiday_id'], ['id:array_agg'])
|
|
mapped_calendar_leaves = {leave: calendar_leave_ids[0] for leave, calendar_leave_ids in calendar_leaves_data}
|
|
for leave in self:
|
|
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 or leave.holiday_status_id.time_type == 'other':
|
|
continue
|
|
|
|
leave_ids.append(leave.id)
|
|
if not leave.employee_id:
|
|
continue
|
|
|
|
calendar = leave.employee_id.resource_calendar_id
|
|
calendar_timezone = pytz.timezone((calendar or leave.employee_id).tz)
|
|
|
|
if calendar.flexible_hours and (leave.request_unit_hours or leave.request_unit_half or leave.date_from.date() == leave.date_to.date()):
|
|
leave_date = leave.date_from.astimezone(calendar_timezone).date()
|
|
if leave.request_unit_hours:
|
|
hours = leave.request_hour_to - leave.request_hour_from
|
|
elif leave.request_unit_half:
|
|
hours = calendar.hours_per_day / 2
|
|
else: # Single-day leave
|
|
hours = calendar.hours_per_day
|
|
work_hours_data = [(leave_date, hours)]
|
|
else:
|
|
ignored_resource_calendar_leaves = ignored_resource_calendar_leaves or []
|
|
if leave in mapped_calendar_leaves:
|
|
ignored_resource_calendar_leaves.append(mapped_calendar_leaves[leave])
|
|
work_hours_data = leave.employee_id._list_work_time_per_day(
|
|
leave.date_from,
|
|
leave.date_to,
|
|
domain=[('id', 'not in', ignored_resource_calendar_leaves)] if ignored_resource_calendar_leaves else None)[leave.employee_id.id]
|
|
|
|
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). Necessary when the function is called to regenerate timesheets.
|
|
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)
|
|
|
|
def _timesheet_prepare_line_values(self, index, work_hours_data, day_date, work_hours_count, project, task):
|
|
self.ensure_one()
|
|
return {
|
|
'name': _("Time Off (%(index)s/%(total)s)", index=index + 1, total=len(work_hours_data)),
|
|
'project_id': project.id,
|
|
'task_id': task.id,
|
|
'account_id': project.sudo().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(self.mapped('date_from'))
|
|
max_date = max(self.mapped('date_to'))
|
|
|
|
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_id)
|
|
|
|
def action_refuse(self):
|
|
""" Remove the timesheets linked to the refused holidays """
|
|
result = super().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=None):
|
|
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
|
|
|
|
def _force_cancel(self, *args, **kwargs):
|
|
super()._force_cancel(*args, **kwargs)
|
|
# override this method to reevaluate timesheets after the leaves are updated via force cancel
|
|
timesheets = self.sudo().timesheet_ids
|
|
timesheets.holiday_id = False
|
|
timesheets.unlink()
|
|
|
|
def write(self, vals):
|
|
res = super().write(vals)
|
|
# reevaluate timesheets after the leaves are wrote in order to remove empty timesheets
|
|
timesheet_ids_to_remove = []
|
|
for leave in self:
|
|
if leave.number_of_days == 0 and leave.sudo().timesheet_ids:
|
|
leave.sudo().timesheet_ids.holiday_id = False
|
|
timesheet_ids_to_remove.extend(leave.timesheet_ids)
|
|
self.env['account.analytic.line'].browse(set(timesheet_ids_to_remove)).sudo().unlink()
|
|
return res
|