# -*- coding: utf-8 -*- import logging from datetime import datetime, timedelta, date from odoo import models, fields, api from odoo.addons.resource.models.utils import HOURS_PER_DAY from odoo.tools.float_utils import float_round from odoo.tools.translate import _ logger = logging.getLogger(__name__) DEFAULT_DAYS = 7 class HolidayRequest(models.Model): _inherit = "hr.leave" def _get_duration(self, check_leave_type=True, resource_calendar=None): if self.leave_type_request_unit == "c_day": return self.employee_id.get_all_days_data( self.date_from, self.date_to, self.holiday_status_id.exclude_holidays ) else: return super()._get_duration(check_leave_type, resource_calendar) working_hours_display = fields.Float( "Working hours", help="Working hours amount in selected period", compute="_compute_working_hours_display", copy=False, readonly=True, ) @staticmethod def compute_work_weekends(date_from, date_to, collection): days = set() for event in collection: if ( date_from and event.date_to < date_from.date() or date_to and event.date_from > date_to.date() ): continue start = max(event.date_from, date_from.date()) until = min(event.date_to, date_to.date()) if event.type_transfer_day == "is_workday": for i in range((until - start + timedelta(1)).days): today = start + timedelta(i) days.add(today) else: for i in range((until - start + timedelta(1)).days): today = start + timedelta(i) # weekends check if today.weekday() != 5 and today.weekday() != 6: days.add(today) return timedelta(len(days)).days @api.depends("number_of_days", "date_from", "date_to") def _compute_working_hours_display(self): for holiday in self: calendar = ( holiday.employee_id.resource_calendar_id or self.env.user.company_id.resource_calendar_id ) count_work_weekends = holiday.compute_work_weekends( holiday.date_from, holiday.date_to, self.env["holidays.calendar.leaves"].search( [ ("type_transfer_day", "=", "is_workday"), ] ), ) count_non_working_days = holiday.compute_work_weekends( holiday.date_from, holiday.date_to, self.env["holidays.calendar.leaves"].search( [ ("type_transfer_day", "=", "is_day_off"), ] ), ) count_holidays = holiday.compute_work_weekends( holiday.date_from, holiday.date_to, self.env["holidays.calendar.leaves"].search( [ ("type_transfer_day", "=", "is_holiday"), ] ), ) if holiday.date_from and holiday.date_to: date_start = datetime( year=holiday.date_from.year, month=holiday.date_from.month, day=holiday.date_from.day, hour=0, minute=0, second=0, ) date_end = datetime( year=holiday.date_to.year, month=holiday.date_to.month, day=holiday.date_to.day, hour=23, minute=59, second=59, ) number_of_hours = calendar.get_work_hours_count( date_start, date_end, compute_leaves=False ) holiday.working_hours_display = number_of_hours + HOURS_PER_DAY * ( count_work_weekends - count_non_working_days - count_holidays ) else: holiday.working_hours_display = 0 @api.depends("number_of_hours_display", "number_of_days_display") def _compute_duration_display(self): for leave in self: amount = ( float_round(leave.number_of_hours_display, precision_digits=2) if leave.leave_type_request_unit == "hour" else float_round(leave.number_of_days_display, precision_digits=2) ) if leave.leave_type_request_unit == "c_day": units = _("calendar day(s)") elif leave.leave_type_request_unit == "hour": units = _("hour(s)") else: units = _("working day(s)") leave.duration_display = "%g %s" % (amount, units) @staticmethod def notify_before(leave): """Checks whether days_before_holidays is set, if it's not, use DEFAULT_DAYS""" return leave.holiday_status_id.days_before_holidays or DEFAULT_DAYS def _check_users_holidays(self): """ Method calls every day and checks the planned holidays. If needed, an email notification to the responsible employee will be sent. """ leaves = self.env["hr.leave"].search( [ ("holiday_status_id.notify_before_start_holidays", "=", True), ("holiday_status_id.responsible_employee_to_notify_id", "!=", None), ("date_from", ">=", date.today()), ] ) for leave in leaves: days_before_holidays = self.notify_before(leave) holidays_start_date = leave.date_from if ( holidays_start_date - timedelta(days=days_before_holidays) ).date() == date.today(): template_name = "hr_holidays_ru.holidays_notification_template" template = self.env.ref(template_name) template.send_mail(leave.id) @staticmethod def append_number_by_type(leave, res): if leave.leave_type_request_unit == "c_day": res.append( ( leave.id, _("%s : %.2f Calendar day(s)") % ( leave.name or leave.holiday_status_id.name, leave.number_of_days, ), ) ) elif leave.leave_type_request_unit == "hour": res.append( ( leave.id, _("%s : %.2f hour(s)") % ( leave.name or leave.holiday_status_id.name, leave.number_of_hours_display, ), ) ) else: res.append( ( leave.id, _("%s : %.2f Working day(s)") % ( leave.name or leave.holiday_status_id.name, leave.number_of_days, ), ) ) @staticmethod def append_number_by_type_without_short_name(leave, res): if leave.holiday_type == "company": target = leave.mode_company_id.name elif leave.holiday_type == "department": target = leave.department_id.name elif leave.holiday_type == "category": target = leave.category_id.name else: target = leave.employee_id.name if leave.leave_type_request_unit == "c_day": res.append( ( leave.id, _("%s on %s : %.2f Calendar day(s)") % ( target, leave.holiday_status_id.name, leave.number_of_days, ), ) ) elif leave.leave_type_request_unit == "hour": res.append( ( leave.id, _("%s on %s : %.2f hour(s)") % ( target, leave.holiday_status_id.name, leave.number_of_hours_display, ), ) ) else: res.append( ( leave.id, _("%s on %s : %.2f Working day(s)") % ( target, leave.holiday_status_id.name, leave.number_of_days, ), ) ) def name_get(self): res = [] for leave in self: if self.env.context.get("short_name"): self.append_number_by_type(leave, res) else: self.append_number_by_type_without_short_name(leave, res) return res