Compare commits
No commits in common. "f6d00205154737ccc75eca5425720c7019a5d0f9" and "1445afc1d5e9b2e53feaf0da9d79439eff014f45" have entirely different histories.
f6d0020515
...
1445afc1d5
|
@ -1,6 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import api, SUPERUSER_ID
|
|
||||||
|
|
||||||
from . import models
|
|
||||||
from . import wizard
|
|
|
@ -1,36 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
{
|
|
||||||
"name": "hr_holidays_ru",
|
|
||||||
"summary": """
|
|
||||||
Adds possibility to count leaves in calendar days as is customary in Russian Federation.
|
|
||||||
""",
|
|
||||||
"description": """
|
|
||||||
In Russian Federation leaves are counted in calendar days instead of working days.
|
|
||||||
Also there are not working days and public holidays which are taken into account in different ways.
|
|
||||||
This module implements these features to correctly count leaves in RF.
|
|
||||||
""",
|
|
||||||
"author": "RYDLAB",
|
|
||||||
"website": "http://rydlab.ru",
|
|
||||||
"license": "Other proprietary",
|
|
||||||
"category": "Localization/Payroll",
|
|
||||||
"version": "17.0.1.3",
|
|
||||||
"depends": ["base", "hr_holidays", "resource", "calendar", "web"],
|
|
||||||
"data": [
|
|
||||||
"security/ir.model.access.csv",
|
|
||||||
"data/holidays_template.xml",
|
|
||||||
"data/holidays_cron.xml",
|
|
||||||
"data/holidays_notification_template.xml",
|
|
||||||
"views/hr_holidays_views.xml",
|
|
||||||
"views/hr_leave_views.xml",
|
|
||||||
"views/hr_holidays_menus_view.xml",
|
|
||||||
"views/hr_leave_report_calendar_view.xml",
|
|
||||||
"views/hr_leave_allocation_views.xml",
|
|
||||||
],
|
|
||||||
"assets": {
|
|
||||||
"web.assets_backend": [
|
|
||||||
"hr_holidays_ru/static/src/css/*.css",
|
|
||||||
"hr_holidays_ru/static/src/views/calendar/**/*.xml",
|
|
||||||
"hr_holidays_ru/static/src/views/calendar/**/*.js",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<odoo>
|
|
||||||
<record id="ir_cron_notification_about_paid_holidays" model="ir.cron">
|
|
||||||
<field name="name">HR Holidays: Notify about employee holiday</field>
|
|
||||||
<field name="model_id" ref="model_hr_leave"/>
|
|
||||||
<field name="state">code</field>
|
|
||||||
<field name="code">model._check_users_holidays()</field>
|
|
||||||
<field name="interval_number">1</field>
|
|
||||||
<field name="interval_type">days</field>
|
|
||||||
<field name="numbercall">-1</field>
|
|
||||||
<field name="active">True</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<record id="holidays_notification_template" model="mail.template">
|
|
||||||
<field name="name">HR holidays: Holidays start notification</field>
|
|
||||||
<field name="email_to">{{ object.holiday_status_id.responsible_employee_to_notify_id.work_email }}</field>
|
|
||||||
<field name="subject">Reminder of the holidays start</field>
|
|
||||||
<field name="model_id" ref="hr_holidays_ru.model_hr_leave"/>
|
|
||||||
<field name="lang">{{ object.holiday_status_id.responsible_employee_to_notify_id.lang }}</field>
|
|
||||||
<field name="body_html" type="html">
|
|
||||||
<p>Dear <t t-out="object.holiday_status_id.responsible_employee_to_notify_id.name or ''"/>,</p>
|
|
||||||
<p>A reminder that the employee <t t-out="object.employee_id.name"/> begins his vacation in <t t-out="object.holiday_status_id.days_before_holidays"/> days.</p>
|
|
||||||
<p>A vacation from <t t-out="object.date_from.strftime('%d.%m.%Y')"/> to <t t-out="object.date_to.strftime('%d.%m.%Y')"/>. Duration of holidays: <t t-out="(object.date_to.date() - object.date_from.date()).days + 1"/> day(s). </p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,63 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<record id="holidays_template_2022" model="holidays.calendar">
|
|
||||||
<field name="name">Weekends and holidays 2022</field>
|
|
||||||
<field name="year">2022</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="new_year_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">New Year</field>
|
|
||||||
<field name="date_from">2022-01-01</field>
|
|
||||||
<field name="date_to">2022-01-08</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="23_feb_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">23 February</field>
|
|
||||||
<field name="date_from">2022-02-23</field>
|
|
||||||
<field name="date_to">2022-02-23</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="8_march_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">8 March</field>
|
|
||||||
<field name="date_from">2022-03-08</field>
|
|
||||||
<field name="date_to">2022-03-08</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="1_may_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">1 May</field>
|
|
||||||
<field name="date_from">2022-05-01</field>
|
|
||||||
<field name="date_to">2022-05-01</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="9_may_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">9 May</field>
|
|
||||||
<field name="date_from">2022-05-09</field>
|
|
||||||
<field name="date_to">2022-05-09</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="12_june_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">12 June</field>
|
|
||||||
<field name="date_from">2022-06-12</field>
|
|
||||||
<field name="date_to">2022-06-12</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="4_nov_2022" model="holidays.calendar.leaves">
|
|
||||||
<field name="name">4 November</field>
|
|
||||||
<field name="date_from">2022-11-04</field>
|
|
||||||
<field name="date_to">2022-11-04</field>
|
|
||||||
<field name="type_transfer_day">is_holiday</field>
|
|
||||||
<field name="calendar_id" ref="holidays_template_2022"/>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
507
i18n/ru.po
507
i18n/ru.po
|
@ -1,507 +0,0 @@
|
||||||
# Translation of Odoo Server.
|
|
||||||
# This file contains the translation of the following modules:
|
|
||||||
# * hr_holidays_ru
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: Odoo Server 17.0-20241029\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2024-11-20 10:45+0000\n"
|
|
||||||
"PO-Revision-Date: 2024-11-20 10:45+0000\n"
|
|
||||||
"Last-Translator: \n"
|
|
||||||
"Language-Team: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: \n"
|
|
||||||
"Plural-Forms: \n"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_type.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid " days"
|
|
||||||
msgstr "дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_type.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid " hours"
|
|
||||||
msgstr "часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_type.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%g remaining "
|
|
||||||
msgstr "%g осталось "
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/holidays.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s (Copy)"
|
|
||||||
msgstr "%s (Копия)"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s : %.2f Calendar day(s)"
|
|
||||||
msgstr "%s : %.2f Календарных дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s : %.2f Working day(s)"
|
|
||||||
msgstr "%s : %.2f Рабочих дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s : %.2f hour(s)"
|
|
||||||
msgstr "%s : %.2f часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s on %s : %.2f Calendar day(s)"
|
|
||||||
msgstr "%s из %s : %.2f Календарных дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s on %s : %.2f Working day(s)"
|
|
||||||
msgstr "%s из %s : %.2f Рабочих дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s on %s : %.2f hour(s)"
|
|
||||||
msgstr "%s из %s : %.2f часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:mail.template,body_html:hr_holidays_ru.holidays_notification_template
|
|
||||||
msgid ""
|
|
||||||
"<p>Dear <t t-out=\"object.holiday_status_id.responsible_employee_to_notify_id.name or ''\"></t>,</p>\n"
|
|
||||||
" <p>A reminder that the employee <t t-out=\"object.employee_id.name\"></t> begins his vacation in <t t-out=\"object.holiday_status_id.days_before_holidays\"></t> days.</p>\n"
|
|
||||||
" <p>A vacation from <t t-out=\"object.date_from.strftime('%d.%m.%Y')\"></t> to <t t-out=\"object.date_to.strftime('%d.%m.%Y')\"></t>. Duration of holidays: <t t-out=\"(object.date_to.date() - object.date_from.date()).days + 1\"></t> day(s). </p>\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
|
||||||
"<p>Уважаемый(ая) <t "
|
|
||||||
"t-out=\"object.holiday_status_id.responsible_employee_to_notify_id.name or "
|
|
||||||
"''\"></t>,</p><p>Напоминаем вам о том, что сотрудник <t "
|
|
||||||
"t-out=\"object.employee_id.name\"></t> уходит в отпуск через <t "
|
|
||||||
"t-out=\"object.holiday_status_id.days_before_holidays\"></t> "
|
|
||||||
"дня/дней.</p><p>Отпуск с <t "
|
|
||||||
"t-out=\"object.date_from.strftime('%d.%m.%Y')\"></t> по <t "
|
|
||||||
"t-out=\"object.date_to.strftime('%d.%m.%Y')\"></t>. Продолжительность "
|
|
||||||
"отпуска: <t t-out=\"(object.date_to.date() - object.date_from.date()).days +"
|
|
||||||
" 1\"></t> дня/дней. </p>"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_allocation_view_form_inherit
|
|
||||||
msgid ""
|
|
||||||
"<span class=\"ml8\" invisible=\"type_request_unit != 'c_day'\">Calendar days</span>\n"
|
|
||||||
" <span class=\"ml8\" invisible=\"type_request_unit != 'day'\">Working days</span>\n"
|
|
||||||
" <span class=\"ml8\" invisible=\"type_request_unit != 'hour'\">Hours</span>"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_form_inherit
|
|
||||||
msgid "<span class=\"ml8\">Calendar days</span>"
|
|
||||||
msgstr "<span class=\"ml8\">Календарных дней</span>"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_form_inherit
|
|
||||||
msgid "<span class=\"ml8\">Hours</span>"
|
|
||||||
msgstr "<span class=\"ml8\">Часов</span>"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_form_inherit
|
|
||||||
msgid "<span class=\"ml8\">Working days</span>"
|
|
||||||
msgstr "<span class=\"ml8\">Рабочих дней</span>"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_form_inh
|
|
||||||
msgid "<span>Days</span>"
|
|
||||||
msgstr "<span>Дней</span>"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__calendar_id
|
|
||||||
msgid "Calendar"
|
|
||||||
msgstr "Календарь"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__hr_leave_allocation__type_request_unit__c_day
|
|
||||||
msgid "Calendar Days"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__hr_leave_type__request_unit__c_day
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_kanban_inherit
|
|
||||||
msgid "Calendar days"
|
|
||||||
msgstr "Календарные дни"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_hr_leave_type__exclude_holidays
|
|
||||||
msgid "Check this box to exclude holidays from calendar days amount."
|
|
||||||
msgstr ""
|
|
||||||
"Установите этот флажок, чтобы исключить праздники из количества календарных "
|
|
||||||
"дней."
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__create_uid
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__create_uid
|
|
||||||
msgid "Created by"
|
|
||||||
msgstr "Кем создано"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__create_date
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__create_date
|
|
||||||
msgid "Created on"
|
|
||||||
msgstr "Когда создано"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_type__days_before_holidays
|
|
||||||
msgid "Days before holidays"
|
|
||||||
msgstr "Дней до отпуска"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__display_name
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__display_name
|
|
||||||
msgid "Display Name"
|
|
||||||
msgstr "Отображаемое имя"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_type__responsible_employee_to_notify_id
|
|
||||||
msgid "Employee to notify"
|
|
||||||
msgstr "Сотрудник, которого необходимо уведомить"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__date_to
|
|
||||||
msgid "End Date"
|
|
||||||
msgstr "Дата окончания"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_type__exclude_holidays
|
|
||||||
msgid "Exclude holidays"
|
|
||||||
msgstr "Исключить праздники"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/wizard/hr_holidays_summary_department.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "Form content is missing, this report cannot be printed."
|
|
||||||
msgstr "Содержимое формы отсутствует, этот отчет не может быть распечатан."
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__global_leave_ids
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.open_view_holiday_settings_form
|
|
||||||
msgid "Global Leaves"
|
|
||||||
msgstr "Глобальные отпуска"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.actions.server,name:hr_holidays_ru.ir_cron_notification_about_paid_holidays_ir_actions_server
|
|
||||||
msgid "HR Holidays: Notify about employee holiday"
|
|
||||||
msgstr "HR holidays: Уведомить об отпуске сотрудника"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:mail.template,name:hr_holidays_ru.holidays_notification_template
|
|
||||||
msgid "HR holidays: Holidays start notification"
|
|
||||||
msgstr "HR holidays: уведомление о начале каникул"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__holidays_calendar_leaves__type_transfer_day__is_holiday
|
|
||||||
msgid "Holiday"
|
|
||||||
msgstr "Праздник"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_report_hr_holidays_report_holidayssummary
|
|
||||||
msgid "Holidays Summary Report"
|
|
||||||
msgstr "Сводный отчет о праздниках"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.actions.act_window,name:hr_holidays_ru.open_view_holiday_settings
|
|
||||||
#: model:ir.ui.menu,name:hr_holidays_ru.hr_holidays_status_menu_configuration
|
|
||||||
msgid "Holidays and non-working days"
|
|
||||||
msgstr "Праздничные и нерабочие дни"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__hr_leave_type__request_unit__hour
|
|
||||||
msgid "Hours"
|
|
||||||
msgstr "Часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_hr_leave_type__days_before_holidays
|
|
||||||
msgid ""
|
|
||||||
"How many days before it is necessary to notify the responsible employee "
|
|
||||||
"about the start of the holidays."
|
|
||||||
msgstr ""
|
|
||||||
"За сколько дней до начала отпуска необходимо уведомить ответственного "
|
|
||||||
"сотрудника?"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__id
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__id
|
|
||||||
msgid "ID"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_hr_leave_type__notify_before_start_holidays
|
|
||||||
msgid ""
|
|
||||||
"Is it necessary to notify the responsible employee before the start of the "
|
|
||||||
"holidays?"
|
|
||||||
msgstr "Нужно ли уведомлять ответственного сотрудника о начале отпуска?"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__write_uid
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__write_uid
|
|
||||||
msgid "Last Updated by"
|
|
||||||
msgstr "Кем обновлено"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__write_date
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__write_date
|
|
||||||
msgid "Last Updated on"
|
|
||||||
msgstr "Когда обновлено"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__holidays_calendar_leaves__time_type__leave
|
|
||||||
msgid "Leave"
|
|
||||||
msgstr "Отгул"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__holidays_calendar_leaves__type_transfer_day__is_day_off
|
|
||||||
#, python-format
|
|
||||||
msgid "Non-working day"
|
|
||||||
msgstr "Нерабочий день"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.edit_holiday_status_form_inherit
|
|
||||||
msgid "Notification about holidays"
|
|
||||||
msgstr "Уведомления о начале отпуска"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_type__notify_before_start_holidays
|
|
||||||
msgid "Notify about start holidays"
|
|
||||||
msgstr "Уведомлять о начале отпуска?"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#, python-format
|
|
||||||
msgid "Number of days"
|
|
||||||
msgstr "Количество дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__holidays_calendar_leaves__time_type__other
|
|
||||||
msgid "Other"
|
|
||||||
msgstr "Другое"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#, python-format
|
|
||||||
msgid "Public Holiday"
|
|
||||||
msgstr "Праздничный день"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__name
|
|
||||||
msgid "Reason"
|
|
||||||
msgstr "Причина"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:mail.template,subject:hr_holidays_ru.holidays_notification_template
|
|
||||||
msgid "Reminder of the holidays start"
|
|
||||||
msgstr "Напоминание о начале отпуска"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__holidays_calendar_leaves__type_transfer_day__is_workday
|
|
||||||
msgid "Rescheduled work day"
|
|
||||||
msgstr "Перенесенный рабочий день"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_resource_mixin
|
|
||||||
msgid "Resource Mixin"
|
|
||||||
msgstr "Смешанный ресурс"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_resource_calendar
|
|
||||||
msgid "Resource Working Time"
|
|
||||||
msgstr "Рабочее время"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__date_from
|
|
||||||
msgid "Start Date"
|
|
||||||
msgstr "Дата начала"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_type__request_unit
|
|
||||||
msgid "Take Leaves in"
|
|
||||||
msgstr "Отпуск берется в"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__name
|
|
||||||
msgid "Template name"
|
|
||||||
msgstr "Имя шаблона"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/holidays.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "The date's year %s mismatch the template year"
|
|
||||||
msgstr "Год даты %s не соответствует году шаблона"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_hr_leave_type__responsible_employee_to_notify_id
|
|
||||||
msgid "The employee who needs to be notified"
|
|
||||||
msgstr "Сотрудник, который должен быть уведомлен"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/holidays.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "The start date of the leave must be not later than end date."
|
|
||||||
msgstr "Дата начала отпуска должна быть не позднее даты окончания."
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_hr_leave
|
|
||||||
msgid "Time Off"
|
|
||||||
msgstr "Отпуск"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_hr_leave_allocation
|
|
||||||
msgid "Time Off Allocation"
|
|
||||||
msgstr "Распределение отпусков"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_hr_leave_type
|
|
||||||
msgid "Time Off Type"
|
|
||||||
msgstr "Тип отсутсвия"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__time_type
|
|
||||||
msgid "Time Type"
|
|
||||||
msgstr "Тип времени"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave_allocation__type_request_unit
|
|
||||||
msgid "Type Request Unit"
|
|
||||||
msgstr "Тип Запрос Единица измерения"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar_leaves__type_transfer_day
|
|
||||||
msgid "Type of day"
|
|
||||||
msgstr "Тип дня"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_holidays_calendar_leaves__type_transfer_day
|
|
||||||
msgid ""
|
|
||||||
"Type of day for right calculate count of working hours and vacation days"
|
|
||||||
msgstr "Тип дня для правильного подсчета рабочих часов и дней отпуска"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.open_view_holiday_settings_tree
|
|
||||||
msgid "Weekends"
|
|
||||||
msgstr "Выходные"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_holidays_calendar_leaves__time_type
|
|
||||||
msgid ""
|
|
||||||
"Whether this should be computed as a holiday or as work time (eg: formation)"
|
|
||||||
msgstr "Должен ли он рассчитываться как выходной или как рабочее время"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.open_view_holiday_settings_form
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.open_view_holiday_settings_tree
|
|
||||||
msgid "Working Time"
|
|
||||||
msgstr "Рабочее время"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields.selection,name:hr_holidays_ru.selection__hr_leave_type__request_unit__day
|
|
||||||
#: model_terms:ir.ui.view,arch_db:hr_holidays_ru.hr_leave_view_kanban_inherit
|
|
||||||
msgid "Working days"
|
|
||||||
msgstr "День"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_hr_leave__working_hours_display
|
|
||||||
msgid "Working hours"
|
|
||||||
msgstr "Кол-во рабочих часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,help:hr_holidays_ru.field_hr_leave__working_hours_display
|
|
||||||
msgid "Working hours amount in selected period"
|
|
||||||
msgstr "Сумма рабочих часов за выбранный период"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model.fields,field_description:hr_holidays_ru.field_holidays_calendar__year
|
|
||||||
msgid "Year"
|
|
||||||
msgstr "Год"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_allocation.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "calendar day(s)"
|
|
||||||
msgstr "кол-во календарных дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#, python-format
|
|
||||||
msgid "continuous days:"
|
|
||||||
msgstr "календарных:"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_holidays_calendar
|
|
||||||
msgid "holidays.calendar"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#: model:ir.model,name:hr_holidays_ru.model_holidays_calendar_leaves
|
|
||||||
msgid "holidays.calendar.leaves"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_allocation.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "hour(s)"
|
|
||||||
msgstr "кол-во часов"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#, python-format
|
|
||||||
msgid "non-working days and holidays:"
|
|
||||||
msgstr "вых./праздн.:"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave.py:0
|
|
||||||
#: code:addons/hr_holidays_ru/models/hr_leave_allocation.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "working day(s)"
|
|
||||||
msgstr "кол-во рабочих дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays_ru
|
|
||||||
#. odoo-javascript
|
|
||||||
#: code:addons/hr_holidays_ru/static/src/views/calendar/filter_panel/calendar_filter_panel.xml:0
|
|
||||||
#, python-format
|
|
||||||
msgid "working days:"
|
|
||||||
msgstr "кол-во рабочих дней"
|
|
||||||
|
|
||||||
#. module: hr_holidays
|
|
||||||
#: model:ir.ui.menu,name:hr_holidays.hr_holidays_menu_manager_approve_allocations
|
|
||||||
msgid "Allocations"
|
|
||||||
msgstr "Начисления дней отпуска"
|
|
|
@ -1,7 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import hr_leave
|
|
||||||
from . import hr_leave_allocation
|
|
||||||
from . import hr_leave_type
|
|
||||||
from . import holidays
|
|
||||||
from . import resource
|
|
|
@ -1,197 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import logging
|
|
||||||
from datetime import datetime, date, timedelta
|
|
||||||
|
|
||||||
from odoo import _, api, models, fields
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class HolidaysCalendar(models.Model):
|
|
||||||
_name = "holidays.calendar"
|
|
||||||
|
|
||||||
name = fields.Char(string="Template name", required=True)
|
|
||||||
year = fields.Selection(
|
|
||||||
string="Year",
|
|
||||||
selection="_compute_years_selection",
|
|
||||||
default=lambda self: str(datetime.today().year),
|
|
||||||
)
|
|
||||||
|
|
||||||
global_leave_ids = fields.One2many(
|
|
||||||
"holidays.calendar.leaves",
|
|
||||||
"calendar_id",
|
|
||||||
"Global Leaves",
|
|
||||||
copy="true",
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.returns("self", lambda value: value.id)
|
|
||||||
def copy(self, default=None):
|
|
||||||
default = dict(default or {})
|
|
||||||
if "name" not in default:
|
|
||||||
default["name"] = _("%s (Copy)", self.name)
|
|
||||||
return super().copy(default=default)
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def create(self, values):
|
|
||||||
if values:
|
|
||||||
self._validate_years(values)
|
|
||||||
return super(HolidaysCalendar, self).create(values)
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def get_all_holidays(self, range_start, range_end):
|
|
||||||
"""The function gets all the holiday dates that are specified in the production calendars for the current displayed year"""
|
|
||||||
range_start_date = datetime.strptime(range_start, "%Y-%m-%d").date()
|
|
||||||
range_end_date = datetime.strptime(range_end, "%Y-%m-%d").date()
|
|
||||||
production_calendars = self.env["holidays.calendar"].search(
|
|
||||||
[
|
|
||||||
("year", "in", [range_start_date.year, range_end_date.year]),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
holidays = []
|
|
||||||
non_working_days = []
|
|
||||||
rescheduled_work_days = []
|
|
||||||
for calendar in production_calendars:
|
|
||||||
self._separate_holidays(
|
|
||||||
calendar,
|
|
||||||
holidays,
|
|
||||||
non_working_days,
|
|
||||||
rescheduled_work_days,
|
|
||||||
range_start_date,
|
|
||||||
range_end_date,
|
|
||||||
)
|
|
||||||
return holidays, non_working_days, rescheduled_work_days
|
|
||||||
|
|
||||||
def write(self, values=None):
|
|
||||||
if values:
|
|
||||||
self._validate_years(values)
|
|
||||||
return super(HolidaysCalendar, self).write(values)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _check_year(user_date, year):
|
|
||||||
user_year = (
|
|
||||||
datetime.strptime(user_date, "%Y-%m-%d").year
|
|
||||||
if isinstance(user_date, str)
|
|
||||||
else user_date.year
|
|
||||||
)
|
|
||||||
if int(year) != user_year:
|
|
||||||
raise ValidationError(
|
|
||||||
_("The date's year %s mismatch the template year") % user_year
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.onchange("year")
|
|
||||||
def _change_years(self):
|
|
||||||
for event in self.global_leave_ids:
|
|
||||||
event.date_to = date(
|
|
||||||
year=int(self.year), month=event.date_to.month, day=event.date_to.day
|
|
||||||
)
|
|
||||||
event.date_from = date(
|
|
||||||
year=int(self.year),
|
|
||||||
month=event.date_from.month,
|
|
||||||
day=event.date_from.day,
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _compute_years_selection():
|
|
||||||
current_year = datetime.today().year
|
|
||||||
result = [
|
|
||||||
("{}".format(year), "{}".format(year))
|
|
||||||
for year in range(current_year - 5, current_year + 10)
|
|
||||||
]
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _fill_day_gaps(self, start_date, end_date):
|
|
||||||
"""The function fills in the date gaps between the beginning and the end of the period"""
|
|
||||||
current_date = start_date
|
|
||||||
dates_list = []
|
|
||||||
while current_date <= end_date:
|
|
||||||
dates_list.append(current_date.strftime("%Y-%m-%d"))
|
|
||||||
current_date += timedelta(days=1)
|
|
||||||
return dates_list
|
|
||||||
|
|
||||||
def _get_days_from_holidays(self, day, range_start_date, range_end_date):
|
|
||||||
"""The function gets the value of the start date and the end date of the period returns a list of dates in a string representation with filled intervals"""
|
|
||||||
start_date = day.date_from
|
|
||||||
end_date = day.date_to
|
|
||||||
if range_start_date <= start_date and end_date <= range_end_date:
|
|
||||||
days_list = self._fill_day_gaps(start_date, end_date)
|
|
||||||
elif range_start_date >= start_date and end_date <= range_end_date:
|
|
||||||
days_list = self._fill_day_gaps(range_start_date, end_date)
|
|
||||||
elif range_start_date <= start_date and end_date >= range_end_date:
|
|
||||||
days_list = self._fill_day_gaps(start_date, range_end_date)
|
|
||||||
elif range_start_date >= start_date and end_date >= range_end_date:
|
|
||||||
days_list = self._fill_day_gaps(range_start_date, range_end_date)
|
|
||||||
else:
|
|
||||||
days_list = []
|
|
||||||
return days_list
|
|
||||||
|
|
||||||
def _separate_holidays(
|
|
||||||
self,
|
|
||||||
calendar,
|
|
||||||
holidays,
|
|
||||||
non_working_days,
|
|
||||||
rescheduled_work_days,
|
|
||||||
range_start_date,
|
|
||||||
range_end_date,
|
|
||||||
):
|
|
||||||
"""The function sorts the dates in the production calendar according to the category of the day"""
|
|
||||||
days = calendar.global_leave_ids
|
|
||||||
for day in days:
|
|
||||||
days_list = self._get_days_from_holidays(
|
|
||||||
day, range_start_date, range_end_date
|
|
||||||
)
|
|
||||||
if day.type_transfer_day == "is_holiday":
|
|
||||||
holidays.extend(days_list)
|
|
||||||
elif day.type_transfer_day == "is_day_off":
|
|
||||||
non_working_days.extend(days_list)
|
|
||||||
elif day.type_transfer_day == "is_workday":
|
|
||||||
rescheduled_work_days.extend(days_list)
|
|
||||||
|
|
||||||
def _validate_years(self, values):
|
|
||||||
if type(values) != list:
|
|
||||||
values = [values]
|
|
||||||
for value in values:
|
|
||||||
year = value.get("year", self.year)
|
|
||||||
events = value.get("global_leave_ids", [])
|
|
||||||
|
|
||||||
for event in events:
|
|
||||||
changes = event[2]
|
|
||||||
if changes:
|
|
||||||
if changes.get("date_from"):
|
|
||||||
self._check_year(changes.get("date_from"), year)
|
|
||||||
if changes.get("date_to"):
|
|
||||||
self._check_year(changes.get("date_to"), year)
|
|
||||||
|
|
||||||
|
|
||||||
class HolidaysCalendarLeaves(models.Model):
|
|
||||||
_name = "holidays.calendar.leaves"
|
|
||||||
_order = "date_from asc"
|
|
||||||
|
|
||||||
name = fields.Char("Reason")
|
|
||||||
|
|
||||||
type_transfer_day = fields.Selection(
|
|
||||||
[
|
|
||||||
("is_holiday", "Holiday"),
|
|
||||||
("is_day_off", "Non-working day"),
|
|
||||||
("is_workday", "Rescheduled work day"),
|
|
||||||
],
|
|
||||||
string="Type of day",
|
|
||||||
required=True,
|
|
||||||
help="Type of day for right calculate count of working hours and vacation days",
|
|
||||||
)
|
|
||||||
|
|
||||||
calendar_id = fields.Many2one("holidays.calendar")
|
|
||||||
date_from = fields.Date("Start Date", required=True)
|
|
||||||
date_to = fields.Date("End Date", required=True)
|
|
||||||
time_type = fields.Selection(
|
|
||||||
[("leave", "Leave"), ("other", "Other")],
|
|
||||||
default="leave",
|
|
||||||
help="Whether this should be computed as a holiday or as work time (eg: formation)",
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.constrains("date_from", "date_to")
|
|
||||||
def check_dates(self):
|
|
||||||
if self.filtered(lambda leave: leave.date_from > leave.date_to):
|
|
||||||
raise ValidationError(
|
|
||||||
_("The start date of the leave must be not later than end date.")
|
|
||||||
)
|
|
|
@ -1,259 +0,0 @@
|
||||||
# -*- 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
|
|
|
@ -1,31 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, api, fields
|
|
||||||
from odoo.tools.float_utils import float_round
|
|
||||||
from odoo.tools.translate import _
|
|
||||||
|
|
||||||
|
|
||||||
class HolidaysAllocation(models.Model):
|
|
||||||
_inherit = "hr.leave.allocation"
|
|
||||||
|
|
||||||
type_request_unit = fields.Selection(
|
|
||||||
selection_add=[
|
|
||||||
("c_day", "Calendar Days"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.depends("number_of_hours_display", "number_of_days_display")
|
|
||||||
def _compute_duration_display(self):
|
|
||||||
for allocation in self:
|
|
||||||
amount = (
|
|
||||||
float_round(allocation.number_of_hours_display, precision_digits=2)
|
|
||||||
if allocation.type_request_unit == "hour"
|
|
||||||
else float_round(allocation.number_of_days_display, precision_digits=2)
|
|
||||||
)
|
|
||||||
if allocation.type_request_unit == "c_day":
|
|
||||||
units = _("calendar day(s)")
|
|
||||||
elif allocation.type_request_unit == "hour":
|
|
||||||
units = _("hour(s)")
|
|
||||||
else:
|
|
||||||
units = _("working day(s)")
|
|
||||||
allocation.duration_display = "%g %s" % (amount, units)
|
|
|
@ -1,63 +0,0 @@
|
||||||
import logging
|
|
||||||
from collections import defaultdict
|
|
||||||
from datetime import time, timedelta
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from odoo import api, fields, models
|
|
||||||
from odoo.tools.translate import _
|
|
||||||
from odoo.tools.float_utils import float_round
|
|
||||||
from odoo.addons.resource.models.utils import Intervals
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class HolidaysType(models.Model):
|
|
||||||
_inherit = "hr.leave.type"
|
|
||||||
|
|
||||||
request_unit = fields.Selection(
|
|
||||||
[
|
|
||||||
("c_day", "Calendar days"),
|
|
||||||
("day", "Working days"),
|
|
||||||
("hour", "Hours"),
|
|
||||||
],
|
|
||||||
default="c_day",
|
|
||||||
string="Take Leaves in",
|
|
||||||
required=True,
|
|
||||||
)
|
|
||||||
exclude_holidays = fields.Boolean(
|
|
||||||
"Exclude holidays",
|
|
||||||
help="Check this box to exclude holidays from calendar days amount.",
|
|
||||||
)
|
|
||||||
|
|
||||||
notify_before_start_holidays = fields.Boolean(
|
|
||||||
"Notify about start holidays",
|
|
||||||
help="Is it necessary to notify the responsible employee before the start of the holidays?",
|
|
||||||
)
|
|
||||||
responsible_employee_to_notify_id = fields.Many2one(
|
|
||||||
"res.users",
|
|
||||||
string="Employee to notify",
|
|
||||||
help="The employee who needs to be notified",
|
|
||||||
)
|
|
||||||
days_before_holidays = fields.Integer(
|
|
||||||
string="Days before holidays",
|
|
||||||
help="How many days before it is necessary to notify the responsible employee about the start of the holidays.",
|
|
||||||
)
|
|
||||||
|
|
||||||
def name_get(self):
|
|
||||||
if not self._context.get("employee_id"):
|
|
||||||
# leave counts is based on employee_id, would be inaccurate if not based on correct employee
|
|
||||||
return super(HolidaysType, self).name_get()
|
|
||||||
res = []
|
|
||||||
for record in self:
|
|
||||||
name = record.name
|
|
||||||
name = "%(name)s (%(count)s)" % {
|
|
||||||
"name": name,
|
|
||||||
"count": _("%g remaining ")
|
|
||||||
% (
|
|
||||||
float_round(record.virtual_remaining_leaves, precision_digits=2)
|
|
||||||
or 0.0,
|
|
||||||
)
|
|
||||||
+ (_(" hours") if record.request_unit == "hour" else _(" days")),
|
|
||||||
}
|
|
||||||
res.append((record.id, name))
|
|
||||||
return res
|
|
|
@ -1,390 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
|
||||||
from datetime import timedelta
|
|
||||||
from pytz import timezone, utc
|
|
||||||
from datetime import datetime, time
|
|
||||||
from collections import defaultdict
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
import pytz
|
|
||||||
|
|
||||||
from odoo import models, fields
|
|
||||||
from odoo.addons.resource.models.utils import HOURS_PER_DAY
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Employee(models.Model):
|
|
||||||
_inherit = "hr.employee"
|
|
||||||
|
|
||||||
def _get_consumed_leaves(self, leave_types, target_date=False, ignore_future=False):
|
|
||||||
employees = self or self._get_contextual_employee()
|
|
||||||
leaves_domain = [
|
|
||||||
("holiday_status_id", "in", leave_types.ids),
|
|
||||||
("employee_id", "in", employees.ids),
|
|
||||||
("state", "in", ["confirm", "validate1", "validate"]),
|
|
||||||
]
|
|
||||||
if self.env.context.get("ignored_leave_ids"):
|
|
||||||
leaves_domain.append(
|
|
||||||
("id", "not in", self.env.context.get("ignored_leave_ids"))
|
|
||||||
)
|
|
||||||
|
|
||||||
if not target_date:
|
|
||||||
target_date = fields.Date.today()
|
|
||||||
if ignore_future:
|
|
||||||
leaves_domain.append(("date_from", "<=", target_date))
|
|
||||||
leaves = self.env["hr.leave"].search(leaves_domain)
|
|
||||||
leaves_per_employee_type = defaultdict(
|
|
||||||
lambda: defaultdict(lambda: self.env["hr.leave"])
|
|
||||||
)
|
|
||||||
for leave in leaves:
|
|
||||||
leaves_per_employee_type[leave.employee_id][
|
|
||||||
leave.holiday_status_id
|
|
||||||
] |= leave
|
|
||||||
|
|
||||||
allocations = (
|
|
||||||
self.env["hr.leave.allocation"]
|
|
||||||
.with_context(active_test=False)
|
|
||||||
.search(
|
|
||||||
[
|
|
||||||
("employee_id", "in", employees.ids),
|
|
||||||
("holiday_status_id", "in", leave_types.ids),
|
|
||||||
("state", "=", "validate"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
.filtered(lambda al: al.active or not al.employee_id.active)
|
|
||||||
)
|
|
||||||
allocations_per_employee_type = defaultdict(
|
|
||||||
lambda: defaultdict(lambda: self.env["hr.leave.allocation"])
|
|
||||||
)
|
|
||||||
for allocation in allocations:
|
|
||||||
allocations_per_employee_type[allocation.employee_id][
|
|
||||||
allocation.holiday_status_id
|
|
||||||
] |= allocation
|
|
||||||
|
|
||||||
# _get_consumed_leaves returns a tuple of two dictionnaries.
|
|
||||||
# 1) The first is a dictionary to map the number of days/hours of leaves taken per allocation
|
|
||||||
# The structure is the following:
|
|
||||||
# - KEYS:
|
|
||||||
# allocation_leaves_consumed
|
|
||||||
# |--employee_id
|
|
||||||
# |--holiday_status_id
|
|
||||||
# |--allocation
|
|
||||||
# |--virtual_leaves_taken
|
|
||||||
# |--leaves_taken
|
|
||||||
# |--virtual_remaining_leaves
|
|
||||||
# |--remaining_leaves
|
|
||||||
# |--max_leaves
|
|
||||||
# |--accrual_bonus
|
|
||||||
# - VALUES:
|
|
||||||
# Integer representing the number of (virtual) remaining leaves, (virtual) leaves taken or max leaves
|
|
||||||
# for each allocation.
|
|
||||||
# leaves_taken and remaining_leaves only take into account validated leaves, while the "virtual" equivalent are
|
|
||||||
# also based on leaves in "confirm" or "validate1" state.
|
|
||||||
# Accrual bonus gives the amount of additional leaves that will have been granted at the given
|
|
||||||
# target_date in comparison to today.
|
|
||||||
# The unit is in hour or days depending on the leave type request unit
|
|
||||||
# 2) The second is a dictionary mapping the remaining days per employee and per leave type that are either
|
|
||||||
# not taken into account by the allocations, mainly because accruals don't take future leaves into account.
|
|
||||||
# This is used to warn the user if the leaves they takes bring them above their available limit.
|
|
||||||
# - KEYS:
|
|
||||||
# allocation_leaves_consumed
|
|
||||||
# |--employee_id
|
|
||||||
# |--holiday_status_id
|
|
||||||
# |--to_recheck_leaves
|
|
||||||
# |--excess_days
|
|
||||||
# |--exceeding_duration
|
|
||||||
# - VALUES:
|
|
||||||
# "to_recheck_leaves" stores every leave that is not yet taken into account by the "allocation_leaves_consumed" dictionary.
|
|
||||||
# "excess_days" represents the excess amount that somehow isn't taken into account by the first dictionary.
|
|
||||||
# "exceeding_duration" sum up the to_recheck_leaves duration and compares it to the maximum allocated for that time period.
|
|
||||||
allocations_leaves_consumed = defaultdict(
|
|
||||||
lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: 0)))
|
|
||||||
)
|
|
||||||
|
|
||||||
to_recheck_leaves_per_leave_type = defaultdict(
|
|
||||||
lambda: defaultdict(
|
|
||||||
lambda: {
|
|
||||||
"excess_days": defaultdict(
|
|
||||||
lambda: {
|
|
||||||
"amount": 0,
|
|
||||||
"is_virtual": True,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
"exceeding_duration": 0,
|
|
||||||
"to_recheck_leaves": self.env["hr.leave"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for allocation in allocations:
|
|
||||||
allocation_data = allocations_leaves_consumed[allocation.employee_id][
|
|
||||||
allocation.holiday_status_id
|
|
||||||
][allocation]
|
|
||||||
future_leaves = 0
|
|
||||||
if allocation.allocation_type == "accrual":
|
|
||||||
future_leaves = allocation._get_future_leaves_on(target_date)
|
|
||||||
max_leaves = (
|
|
||||||
allocation.number_of_hours_display
|
|
||||||
if allocation.type_request_unit in ["hour"]
|
|
||||||
else allocation.number_of_days_display
|
|
||||||
)
|
|
||||||
max_leaves += future_leaves
|
|
||||||
allocation_data.update(
|
|
||||||
{
|
|
||||||
"max_leaves": max_leaves,
|
|
||||||
"accrual_bonus": future_leaves,
|
|
||||||
"virtual_remaining_leaves": max_leaves,
|
|
||||||
"remaining_leaves": max_leaves,
|
|
||||||
"leaves_taken": 0,
|
|
||||||
"virtual_leaves_taken": 0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
for employee in employees:
|
|
||||||
for leave_type in leave_types:
|
|
||||||
allocations_with_date_to = self.env["hr.leave.allocation"]
|
|
||||||
allocations_without_date_to = self.env["hr.leave.allocation"]
|
|
||||||
for leave_allocation in allocations_per_employee_type[employee][
|
|
||||||
leave_type
|
|
||||||
]:
|
|
||||||
if leave_allocation.date_to:
|
|
||||||
allocations_with_date_to |= leave_allocation
|
|
||||||
else:
|
|
||||||
allocations_without_date_to |= leave_allocation
|
|
||||||
sorted_leave_allocations = (
|
|
||||||
allocations_with_date_to.sorted(key="date_to")
|
|
||||||
+ allocations_without_date_to
|
|
||||||
)
|
|
||||||
|
|
||||||
if leave_type.request_unit in ["c_day", "day", "half_day"]:
|
|
||||||
leave_duration_field = "number_of_days"
|
|
||||||
leave_unit = "days"
|
|
||||||
else:
|
|
||||||
leave_duration_field = "number_of_hours_display"
|
|
||||||
leave_unit = "hours"
|
|
||||||
|
|
||||||
leave_type_data = allocations_leaves_consumed[employee][leave_type]
|
|
||||||
for leave in leaves_per_employee_type[employee][leave_type].sorted(
|
|
||||||
"date_from"
|
|
||||||
):
|
|
||||||
leave_duration = leave[leave_duration_field]
|
|
||||||
skip_excess = False
|
|
||||||
|
|
||||||
if (
|
|
||||||
sorted_leave_allocations.filtered(
|
|
||||||
lambda alloc: alloc.allocation_type == "accrual"
|
|
||||||
)
|
|
||||||
and leave.date_from.date() > target_date
|
|
||||||
):
|
|
||||||
to_recheck_leaves_per_leave_type[employee][leave_type][
|
|
||||||
"to_recheck_leaves"
|
|
||||||
] |= leave
|
|
||||||
skip_excess = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if leave_type.requires_allocation == "yes":
|
|
||||||
for allocation in sorted_leave_allocations:
|
|
||||||
# We don't want to include future leaves linked to accruals into the total count of available leaves.
|
|
||||||
# However, we'll need to check if those leaves take more than what will be accrued in total of those days
|
|
||||||
# to give a warning if the total exceeds what will be accrued.
|
|
||||||
if allocation.date_from > leave.date_to.date() or (
|
|
||||||
allocation.date_to
|
|
||||||
and allocation.date_to < leave.date_from.date()
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
interval_start = max(
|
|
||||||
leave.date_from,
|
|
||||||
datetime.combine(allocation.date_from, time.min),
|
|
||||||
)
|
|
||||||
interval_end = min(
|
|
||||||
leave.date_to,
|
|
||||||
datetime.combine(allocation.date_to, time.max)
|
|
||||||
if allocation.date_to
|
|
||||||
else leave.date_to,
|
|
||||||
)
|
|
||||||
duration = leave[leave_duration_field]
|
|
||||||
if (
|
|
||||||
leave.date_from != interval_start
|
|
||||||
or leave.date_to != interval_end
|
|
||||||
):
|
|
||||||
duration_info = employee._get_calendar_attendances(
|
|
||||||
interval_start.replace(tzinfo=pytz.UTC),
|
|
||||||
interval_end.replace(tzinfo=pytz.UTC),
|
|
||||||
)
|
|
||||||
duration = duration_info[
|
|
||||||
"hours" if leave_unit == "hours" else "days"
|
|
||||||
]
|
|
||||||
max_allowed_duration = min(
|
|
||||||
duration,
|
|
||||||
leave_type_data[allocation]["virtual_remaining_leaves"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if not max_allowed_duration:
|
|
||||||
continue
|
|
||||||
|
|
||||||
allocated_time = min(max_allowed_duration, leave_duration)
|
|
||||||
leave_type_data[allocation][
|
|
||||||
"virtual_leaves_taken"
|
|
||||||
] += allocated_time
|
|
||||||
leave_type_data[allocation][
|
|
||||||
"virtual_remaining_leaves"
|
|
||||||
] -= allocated_time
|
|
||||||
if leave.state == "validate":
|
|
||||||
leave_type_data[allocation][
|
|
||||||
"leaves_taken"
|
|
||||||
] += allocated_time
|
|
||||||
leave_type_data[allocation][
|
|
||||||
"remaining_leaves"
|
|
||||||
] -= allocated_time
|
|
||||||
|
|
||||||
leave_duration -= allocated_time
|
|
||||||
if not leave_duration:
|
|
||||||
break
|
|
||||||
if round(leave_duration, 2) > 0 and not skip_excess:
|
|
||||||
to_recheck_leaves_per_leave_type[employee][leave_type][
|
|
||||||
"excess_days"
|
|
||||||
][leave.date_to.date()] = {
|
|
||||||
"amount": leave_duration,
|
|
||||||
"is_virtual": leave.state != "validate",
|
|
||||||
"leave_id": leave.id,
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
if leave_unit == "hours":
|
|
||||||
allocated_time = leave.number_of_hours_display
|
|
||||||
else:
|
|
||||||
allocated_time = leave.number_of_days_display
|
|
||||||
leave_type_data[False]["virtual_leaves_taken"] += allocated_time
|
|
||||||
leave_type_data[False]["virtual_remaining_leaves"] = 0
|
|
||||||
leave_type_data[False]["remaining_leaves"] = 0
|
|
||||||
if leave.state == "validate":
|
|
||||||
leave_type_data[False]["leaves_taken"] += allocated_time
|
|
||||||
|
|
||||||
for employee in to_recheck_leaves_per_leave_type:
|
|
||||||
for leave_type in to_recheck_leaves_per_leave_type[employee]:
|
|
||||||
content = to_recheck_leaves_per_leave_type[employee][leave_type]
|
|
||||||
consumed_content = allocations_leaves_consumed[employee][leave_type]
|
|
||||||
if content["to_recheck_leaves"]:
|
|
||||||
date_to_simulate = max(
|
|
||||||
content["to_recheck_leaves"].mapped("date_from")
|
|
||||||
).date()
|
|
||||||
latest_accrual_bonus = 0
|
|
||||||
date_accrual_bonus = 0
|
|
||||||
virtual_remaining = 0
|
|
||||||
additional_leaves_duration = 0
|
|
||||||
for allocation in consumed_content:
|
|
||||||
latest_accrual_bonus += (
|
|
||||||
allocation
|
|
||||||
and allocation._get_future_leaves_on(date_to_simulate)
|
|
||||||
)
|
|
||||||
date_accrual_bonus += consumed_content[allocation][
|
|
||||||
"accrual_bonus"
|
|
||||||
]
|
|
||||||
virtual_remaining += consumed_content[allocation][
|
|
||||||
"virtual_remaining_leaves"
|
|
||||||
]
|
|
||||||
for leave in content["to_recheck_leaves"]:
|
|
||||||
additional_leaves_duration += (
|
|
||||||
leave.number_of_hours
|
|
||||||
if leave_type.request_unit == "hours"
|
|
||||||
else leave.number_of_days
|
|
||||||
)
|
|
||||||
latest_remaining = (
|
|
||||||
virtual_remaining - date_accrual_bonus + latest_accrual_bonus
|
|
||||||
)
|
|
||||||
content["exceeding_duration"] = round(
|
|
||||||
min(0, latest_remaining - additional_leaves_duration), 2
|
|
||||||
)
|
|
||||||
|
|
||||||
return (allocations_leaves_consumed, to_recheck_leaves_per_leave_type)
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceMixin(models.AbstractModel):
|
|
||||||
_inherit = "resource.mixin"
|
|
||||||
|
|
||||||
def get_all_days_data(self, date_from, date_to, exclude_holidays):
|
|
||||||
"""
|
|
||||||
Returns days amount as float, like 'get_work_days_data()'
|
|
||||||
"""
|
|
||||||
# Set timezone if no timezone is explicitly given
|
|
||||||
user_tz = timezone(self.env.context.get("tz") or self.tz)
|
|
||||||
if not user_tz:
|
|
||||||
user_tz = utc
|
|
||||||
if not date_from.tzinfo:
|
|
||||||
date_from = user_tz.localize(date_from)
|
|
||||||
if not date_to.tzinfo:
|
|
||||||
date_to = user_tz.localize(date_to)
|
|
||||||
# Bring booth dates to the same timezone
|
|
||||||
if date_from.tzinfo != date_to.tzinfo:
|
|
||||||
date_to = date_to.astimezone(date_from.tzinfo)
|
|
||||||
# Handle holidays in selected period
|
|
||||||
holidays_dur = timedelta(0)
|
|
||||||
if exclude_holidays:
|
|
||||||
holidays_dur = (
|
|
||||||
self.env.user.company_id.resource_calendar_id.get_holidays_duration(
|
|
||||||
date_from, date_to
|
|
||||||
)
|
|
||||||
)
|
|
||||||
duration = date_to.date() - date_from.date() + timedelta(1) - holidays_dur
|
|
||||||
days = float(duration.days)
|
|
||||||
hours = days * HOURS_PER_DAY
|
|
||||||
return (days, hours)
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceCalendar(models.Model):
|
|
||||||
_inherit = "resource.calendar"
|
|
||||||
|
|
||||||
def get_holidays_duration(self, start_dt, end_dt):
|
|
||||||
"""
|
|
||||||
Returns timedelta object which is duration of all holidays included into
|
|
||||||
specified period.
|
|
||||||
"""
|
|
||||||
days = set()
|
|
||||||
holidays_ids = self.env["holidays.calendar.leaves"].search(
|
|
||||||
[("type_transfer_day", "=", "is_holiday")]
|
|
||||||
)
|
|
||||||
|
|
||||||
for holiday in holidays_ids:
|
|
||||||
# Transformation date to datetime
|
|
||||||
date_from = datetime(
|
|
||||||
year=holiday.date_from.year,
|
|
||||||
month=holiday.date_from.month,
|
|
||||||
day=holiday.date_from.day,
|
|
||||||
hour=0,
|
|
||||||
minute=0,
|
|
||||||
second=0,
|
|
||||||
)
|
|
||||||
date_to = datetime(
|
|
||||||
year=holiday.date_to.year,
|
|
||||||
month=holiday.date_to.month,
|
|
||||||
day=holiday.date_to.day,
|
|
||||||
hour=23,
|
|
||||||
minute=59,
|
|
||||||
second=59,
|
|
||||||
)
|
|
||||||
# Dates in database are without timezones, and time in fact for UTC timezone,
|
|
||||||
# so it should be added explicitly.
|
|
||||||
holiday_date_from = utc.localize(date_from) if date_from else None
|
|
||||||
holiday_date_to = utc.localize(date_to) if date_to else None
|
|
||||||
# Bring booth dates to the holiday timezone
|
|
||||||
if holiday_date_from and start_dt.tzinfo != holiday_date_from.tzinfo:
|
|
||||||
start_dt = start_dt.astimezone(holiday_date_from.tzinfo)
|
|
||||||
if holiday_date_to and end_dt.tzinfo != holiday_date_to.tzinfo:
|
|
||||||
end_dt = end_dt.astimezone(holiday_date_to.tzinfo)
|
|
||||||
# Check periods intersection
|
|
||||||
if (
|
|
||||||
holiday_date_from
|
|
||||||
and end_dt < holiday_date_from
|
|
||||||
or holiday_date_to
|
|
||||||
and start_dt > holiday_date_to
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
# Handle this holiday
|
|
||||||
start = start_dt.date()
|
|
||||||
if holiday_date_from:
|
|
||||||
start = max(start, holiday_date_from.date())
|
|
||||||
until = end_dt.date()
|
|
||||||
if holiday_date_to:
|
|
||||||
until = min(until, holiday_date_to.date())
|
|
||||||
for i in range((until - start + timedelta(1)).days):
|
|
||||||
days.add(start + timedelta(i))
|
|
||||||
return timedelta(len(days))
|
|
|
@ -1,5 +0,0 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|
||||||
access_holidays_calendar_manager,access.holidays.calendar.manager,model_holidays_calendar,hr_holidays.group_hr_holidays_manager,1,1,1,1
|
|
||||||
access_holidays_calendar_leaves_manager,access.holidays.calendar.leaves.manager,model_holidays_calendar_leaves,hr_holidays.group_hr_holidays_manager,1,1,1,1
|
|
||||||
access_holidays_calendar_user,access.holidays.calendar.user,model_holidays_calendar,base.group_user,1,0,0,0
|
|
||||||
access_holidays_calendar_leaves_user,access.holidays.calendar.leaves.user,model_holidays_calendar_leaves,base.group_user,1,0,0,0
|
|
|
|
@ -1,63 +0,0 @@
|
||||||
.fc-today-day-number-year {
|
|
||||||
position: relative;
|
|
||||||
color: black !important;
|
|
||||||
}
|
|
||||||
.fc-today-day-number-year::before {
|
|
||||||
content: "\f1db";
|
|
||||||
position: absolute;
|
|
||||||
font-family: FontAwesome;
|
|
||||||
font-size: 2.1em;
|
|
||||||
color: red;
|
|
||||||
line-height: 0.75em;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-today-day-number-month {
|
|
||||||
position: relative;
|
|
||||||
color: black !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-today-day-number-month::before {
|
|
||||||
content: "\f1db";
|
|
||||||
position: absolute;
|
|
||||||
font-family: FontAwesome;
|
|
||||||
font-size: 2em;
|
|
||||||
color: red;
|
|
||||||
line-height: 0.8em;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_holidays_legend {
|
|
||||||
vertical-align: middle;
|
|
||||||
background-color: #e9ecef;
|
|
||||||
font-weight: 600;
|
|
||||||
display: inline-block;
|
|
||||||
width: 24px;
|
|
||||||
height: 30px;
|
|
||||||
margin: 0 3px;
|
|
||||||
padding: 3px 0;
|
|
||||||
text-align: center;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_non_working_legend {
|
|
||||||
vertical-align: middle;
|
|
||||||
background-color: #e9ecef;
|
|
||||||
display: inline-block;
|
|
||||||
width: 24px;
|
|
||||||
height: 30px;
|
|
||||||
margin: 0 3px;
|
|
||||||
padding: 3px 0;
|
|
||||||
text-align: center;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_holidays_week_days {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
.hr_holiday_calendar {
|
|
||||||
font-weight: bold;
|
|
||||||
color: red !important;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { patch } from '@web/core/utils/patch'
|
|
||||||
|
|
||||||
import { TimeOffCalendarCommonRenderer } from '@hr_holidays/views/calendar/common/calendar_common_renderer'
|
|
||||||
import { onWillStart } from '@odoo/owl'
|
|
||||||
import { useService } from '@web/core/utils/hooks'
|
|
||||||
import { serializeDate } from '@web/core/l10n/dates'
|
|
||||||
|
|
||||||
patch(
|
|
||||||
TimeOffCalendarCommonRenderer.prototype,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Adding onWillStart to load data from the holidays.calendar model to get holidays, non-working days and rescheduled working days.
|
|
||||||
*/
|
|
||||||
setup() {
|
|
||||||
super.setup(...arguments)
|
|
||||||
this.orm = useService('orm')
|
|
||||||
onWillStart(async () => {
|
|
||||||
const rangeStart = serializeDate(
|
|
||||||
this.props.model.rangeStart,
|
|
||||||
'datetime'
|
|
||||||
)
|
|
||||||
const rangeEnd = serializeDate(this.props.model.rangeEnd, 'datetime')
|
|
||||||
const [holidaysList, nonWorkingDaysList, rescheduledWorkDaysList] =
|
|
||||||
await this.orm.call('holidays.calendar', 'get_all_holidays', [
|
|
||||||
rangeStart,
|
|
||||||
rangeEnd
|
|
||||||
])
|
|
||||||
this.holidays = holidaysList
|
|
||||||
this.nonWorkingDays = nonWorkingDaysList
|
|
||||||
this.rescheduledWorkDays = rescheduledWorkDaysList
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redefining onDayRender, adding additional functionality to it to display holidays, non-working days and postponed working days.
|
|
||||||
*/
|
|
||||||
onDayRender(info) {
|
|
||||||
const date = luxon.DateTime.fromJSDate(info.date).toISODate();
|
|
||||||
if (this.props.model.unusualDays.includes(date)) {
|
|
||||||
info.el.classList.add("o_calendar_disabled");
|
|
||||||
}
|
|
||||||
// New code
|
|
||||||
if (this.nonWorkingDays.includes(date)) {
|
|
||||||
info.el.classList.add('o_calendar_disabled')
|
|
||||||
}
|
|
||||||
const element = document.querySelector(
|
|
||||||
`.fc-content-skeleton [data-date=${CSS.escape(date)}]`
|
|
||||||
)
|
|
||||||
if (element && element.classList.contains('fc-today')) {
|
|
||||||
element.classList.remove('fc-today')
|
|
||||||
element.classList.add('fc-today-day-number-month')
|
|
||||||
}
|
|
||||||
if (this.holidays.includes(date)) {
|
|
||||||
if (element) {
|
|
||||||
const day_number = element.querySelector('.fc-day-number')
|
|
||||||
day_number.classList.add('hr_holiday_calendar')
|
|
||||||
info.el.classList.add("o_calendar_disabled");
|
|
||||||
} else {
|
|
||||||
const days_in_week_element = document.querySelector(`.fc-head-container [data-date=${CSS.escape(date)}]`)
|
|
||||||
info.el.classList.add("o_calendar_disabled");
|
|
||||||
days_in_week_element.classList.add('o_holidays_week_days')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.rescheduledWorkDays.includes(date)) {
|
|
||||||
info.el.classList.remove('o_calendar_disabled')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -1,122 +0,0 @@
|
||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { patch } from '@web/core/utils/patch'
|
|
||||||
|
|
||||||
import { TimeOffCalendarFilterPanel } from '@hr_holidays/views/calendar/filter_panel/calendar_filter_panel'
|
|
||||||
import { serializeDate } from '@web/core/l10n/dates'
|
|
||||||
import { onWillStart, onWillUpdateProps } from '@odoo/owl'
|
|
||||||
|
|
||||||
patch(TimeOffCalendarFilterPanel.prototype, {
|
|
||||||
/**
|
|
||||||
* Add onWillStart to load data from the holidays.calendar model to the dates displayed in the calendar, add onWillUpdateProps to update data when switching month, week or year
|
|
||||||
*/
|
|
||||||
setup() {
|
|
||||||
super.setup(...arguments)
|
|
||||||
onWillStart(this.countHolidays)
|
|
||||||
onWillUpdateProps(this.countHolidays)
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function counts the number of working days and days off
|
|
||||||
*/
|
|
||||||
async countHolidays() {
|
|
||||||
const rangeStart = this.props.model.rangeStart
|
|
||||||
const rangeEnd = this.props.model.rangeEnd
|
|
||||||
const firstDay = await this.getFirstMonthDay(rangeStart, rangeEnd)
|
|
||||||
if (!this.weekScale) {
|
|
||||||
const lastDay = await this.getLastMonthDay(firstDay, rangeStart, rangeEnd)
|
|
||||||
this.daysTotalAmount =
|
|
||||||
(new Date(lastDay) - new Date(firstDay)) / (1000 * 60 * 60 * 24) + 1
|
|
||||||
const unusualDays = this.getUnusualDaysList(firstDay, lastDay)
|
|
||||||
await this.getAllHolidays(firstDay, lastDay)
|
|
||||||
const nonWorkingDaysAndHolidaysSet = new Set([
|
|
||||||
...unusualDays,
|
|
||||||
...this.nonWorkingDays,
|
|
||||||
...this.holidays
|
|
||||||
])
|
|
||||||
const nonWorkingDaysAndHolidaysSetWithoutRescheduled = new Set(
|
|
||||||
[...nonWorkingDaysAndHolidaysSet].filter(
|
|
||||||
value => !new Set(this.rescheduledWorkDays).has(value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
this.workingDaysAmount =
|
|
||||||
this.daysTotalAmount -
|
|
||||||
nonWorkingDaysAndHolidaysSetWithoutRescheduled.size
|
|
||||||
this.nonWorkingDaysAndHolidays =
|
|
||||||
nonWorkingDaysAndHolidaysSetWithoutRescheduled.size
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function counts the number of working days, holidays and non-working days
|
|
||||||
*/
|
|
||||||
async getAllHolidays(firstDay, lastDay) {
|
|
||||||
const [holidaysList, nonWorkingDaysList, rescheduledWorkDaysList] =
|
|
||||||
await this.orm.call('holidays.calendar', 'get_all_holidays', [
|
|
||||||
firstDay,
|
|
||||||
lastDay
|
|
||||||
])
|
|
||||||
this.holidays = holidaysList
|
|
||||||
this.nonWorkingDays = nonWorkingDaysList
|
|
||||||
this.rescheduledWorkDays = rescheduledWorkDaysList
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function defines the first day of the month
|
|
||||||
*/
|
|
||||||
getFirstMonthDay(rangeStart, rangeEnd) {
|
|
||||||
if ((rangeEnd - rangeStart) / (1000 * 60 * 60 * 24) > 7) {
|
|
||||||
this.weekScale = false
|
|
||||||
let newRangeStartMonth = 1
|
|
||||||
let newRangeStartYear = rangeStart.year
|
|
||||||
if (rangeStart.month + 1 <= 12) {
|
|
||||||
newRangeStartMonth =
|
|
||||||
rangeStart.month + 1 > 9
|
|
||||||
? `${rangeStart.month + 1}`
|
|
||||||
: `0${rangeStart.month + 1}`
|
|
||||||
} else {
|
|
||||||
newRangeStartMonth = '01'
|
|
||||||
newRangeStartYear += 1
|
|
||||||
}
|
|
||||||
return rangeStart.day === 1
|
|
||||||
? serializeDate(rangeStart, 'datetime')
|
|
||||||
: `${newRangeStartYear}-${newRangeStartMonth}-01`
|
|
||||||
} else {
|
|
||||||
this.weekScale = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function determines the last day of the month
|
|
||||||
*/
|
|
||||||
getLastMonthDay(firstDay, rangeStart, rangeEnd) {
|
|
||||||
let lastDay = new Date(firstDay)
|
|
||||||
// 42 is the number of days displayed on the calendar on a monthly scale.
|
|
||||||
// In this case, we check that the scale of the year is displayed
|
|
||||||
if ((rangeEnd - rangeStart) / (1000 * 60 * 60 * 24) > 42) {
|
|
||||||
return serializeDate(rangeEnd, 'datetime')
|
|
||||||
} else {
|
|
||||||
lastDay.setMonth(lastDay.getMonth() + 1)
|
|
||||||
lastDay.setDate(0)
|
|
||||||
const newLastDayMonth =
|
|
||||||
lastDay.getMonth() + 1 > 9
|
|
||||||
? `${lastDay.getMonth() + 1}`
|
|
||||||
: `0${lastDay.getMonth() + 1}`
|
|
||||||
return `${lastDay.getFullYear()}-${newLastDayMonth}-${lastDay.getDate()}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function gets a list of days off in a given period
|
|
||||||
*/
|
|
||||||
getUnusualDaysList(firstDay, lastDay) {
|
|
||||||
const newFirstDay = new Date(firstDay)
|
|
||||||
const newLastDay = new Date(lastDay)
|
|
||||||
const unusualDaysList = this.props.model.unusualDays
|
|
||||||
const unusualDaysFiltered = unusualDaysList.filter(day => {
|
|
||||||
const newDate = new Date(day)
|
|
||||||
return (newDate >= newFirstDay) & (newDate <= newLastDay)
|
|
||||||
})
|
|
||||||
return unusualDaysFiltered
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<templates>
|
|
||||||
<t t-inherit="hr_holidays.CalendarFilterPanel" t-inherit-mode="extension" owl="1">
|
|
||||||
<xpath expr="//div[@class='d-flex flex-column']" position="inside">
|
|
||||||
<span><span class="o_holidays_legend">13</span> Public Holiday</span>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//div[@class='d-flex flex-column']" position="inside">
|
|
||||||
<span><span class="o_non_working_legend">13</span> Non-working day</span>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//div[@class='d-flex flex-column mt-4']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//div[@class='d-flex flex-column mt-4']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//div[@class='o_calendar_filter mt-4']/div[last()]" position="after">
|
|
||||||
<div t-if="!weekScale" class="d-flex flex-column mt-4">
|
|
||||||
<h5>Number of days</h5>
|
|
||||||
<ul class="ps-2">
|
|
||||||
<li class="mt-2 list-unstyled">
|
|
||||||
<p>
|
|
||||||
<span><span class="text-odoo">continuous days: </span><t t-out="daysTotalAmount"/></span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span><span class="text-odoo">working days: </span><t t-out="workingDaysAmount"/></span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<span><span class="text-odoo">non-working days and holidays: </span><t t-out="nonWorkingDaysAndHolidays"/></span>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
</t>
|
|
||||||
</templates>
|
|
|
@ -1,66 +0,0 @@
|
||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { patch } from '@web/core/utils/patch'
|
|
||||||
|
|
||||||
import { TimeOffCalendarYearRenderer } from '@hr_holidays/views/calendar/year/calendar_year_renderer'
|
|
||||||
import { onWillStart } from '@odoo/owl'
|
|
||||||
import { serializeDate } from '@web/core/l10n/dates'
|
|
||||||
|
|
||||||
patch(
|
|
||||||
TimeOffCalendarYearRenderer.prototype,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* We add onWillStart to load data from the holidays.calendar model to get holidays, non-working days and rescheduled working days.
|
|
||||||
*/
|
|
||||||
setup() {
|
|
||||||
super.setup(...arguments)
|
|
||||||
onWillStart(async () => {
|
|
||||||
const rangeStart = serializeDate(
|
|
||||||
this.props.model.rangeStart,
|
|
||||||
'datetime'
|
|
||||||
)
|
|
||||||
const rangeEnd = serializeDate(this.props.model.rangeEnd, 'datetime')
|
|
||||||
const [holidaysList, nonWorkingDaysList, rescheduledWorkDaysList] =
|
|
||||||
await this.orm.call('holidays.calendar', 'get_all_holidays', [
|
|
||||||
rangeStart,
|
|
||||||
rangeEnd
|
|
||||||
])
|
|
||||||
this.holidays = holidaysList
|
|
||||||
this.nonWorkingDays = nonWorkingDaysList
|
|
||||||
this.rescheduledWorkDay = rescheduledWorkDaysList
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redefining onDayRender, adding additional functionality to it to display holidays, non-working days and postponed working days.
|
|
||||||
*/
|
|
||||||
onDayRender(info) {
|
|
||||||
const date = luxon.DateTime.fromJSDate(info.date).toISODate()
|
|
||||||
if (this.props.model.unusualDays.includes(date)) {
|
|
||||||
info.el.classList.add('o_calendar_disabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
// New code
|
|
||||||
if (this.nonWorkingDays.includes(date)) {
|
|
||||||
info.el.classList.add('o_calendar_disabled')
|
|
||||||
}
|
|
||||||
const element = document.querySelector(
|
|
||||||
`.fc-content-skeleton [data-date=${CSS.escape(date)}]`
|
|
||||||
)
|
|
||||||
if (element && element.classList.contains('fc-today')) {
|
|
||||||
element.classList.remove('fc-today')
|
|
||||||
element.classList.add('fc-today-day-number-year')
|
|
||||||
}
|
|
||||||
if (this.holidays.includes(date)) {
|
|
||||||
if (element) {
|
|
||||||
const day_number = element.querySelector('.fc-day-number')
|
|
||||||
day_number.classList.add('hr_holiday_calendar')
|
|
||||||
info.el.classList.add("o_calendar_disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.rescheduledWorkDay.includes(date)) {
|
|
||||||
info.el.classList.remove('o_calendar_disabled')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8' ?>
|
|
||||||
<odoo>
|
|
||||||
<menuitem id="hr_holidays.hr_holidays_public_time_off_menu_configuration"
|
|
||||||
active="False"/>
|
|
||||||
|
|
||||||
<menuitem id="hr_holidays.hr_holidays_mandatory_day_menu_configuration"
|
|
||||||
active="False"/>
|
|
||||||
|
|
||||||
<record id="hr_holidays.menu_open_allocation" model="ir.ui.menu">
|
|
||||||
<field name="groups_id" eval="[(4,ref('hr_holidays.group_hr_holidays_user'))]" />
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,170 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<record id="open_view_holiday_settings_tree" model="ir.ui.view">
|
|
||||||
<field name="name">hr.holidays.settings_tree</field>
|
|
||||||
<field name="model">holidays.calendar</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Working Time">
|
|
||||||
<field name="name" string="Weekends"/>
|
|
||||||
<field name="year"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="open_view_holiday_settings_form" model="ir.ui.view">
|
|
||||||
<field name="name">hr.holidays.settings_form</field>
|
|
||||||
<field name="model">holidays.calendar</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Working Time">
|
|
||||||
<sheet string="Working Time">
|
|
||||||
<h1>
|
|
||||||
<field name="name"/>
|
|
||||||
</h1>
|
|
||||||
<group>
|
|
||||||
<field name="year"/>
|
|
||||||
</group>
|
|
||||||
<notebook>
|
|
||||||
<page string="Global Leaves">
|
|
||||||
<field name="global_leave_ids">
|
|
||||||
<tree editable="top">
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="date_from"/>
|
|
||||||
<field name="date_to"/>
|
|
||||||
<field name="type_transfer_day"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</page>
|
|
||||||
</notebook>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Your Action Window Definition -->
|
|
||||||
<record id="open_view_holiday_settings" model="ir.actions.act_window">
|
|
||||||
<field name="name">Holidays and non-working days</field>
|
|
||||||
<field name="res_model">holidays.calendar</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Adds "Calendar days" and "Working days" units of measures in Leave form. -->
|
|
||||||
<record id="hr_leave_view_form_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">hr_holidays_ru.hr_leave_view_form_inherit</field>
|
|
||||||
<field name="model">hr.leave</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.hr_leave_view_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//sheet/div/div/group" position="before">
|
|
||||||
<div>
|
|
||||||
<div invisible="leave_type_request_unit != 'hour'">
|
|
||||||
<field name="number_of_hours_display" nolabel="1" class="oe_inline"/>
|
|
||||||
<span class="ml8">Hours</span>
|
|
||||||
</div>
|
|
||||||
<div invisible="leave_type_request_unit != 'c_day'">
|
|
||||||
<field name="number_of_days_display" nolabel="1" class="oe_inline"/>
|
|
||||||
<span class="ml8">Calendar days</span>
|
|
||||||
</div>
|
|
||||||
<div invisible="leave_type_request_unit != 'day'">
|
|
||||||
<field name="number_of_days_display" nolabel="1" class="oe_inline"/>
|
|
||||||
<span class="ml8">Working days</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//label[@for='request_date_from']" position="before">
|
|
||||||
<field name="working_hours_display" invisible="leave_type_request_unit != 'c_day'"/>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//field[@name='request_unit_half']" position="replace">
|
|
||||||
<field
|
|
||||||
name="request_unit_half"
|
|
||||||
readonly="state not in ('draft', 'confirm')"
|
|
||||||
invisible="leave_type_request_unit == 'c_day'"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//label[@for='request_unit_half']" position="replace">
|
|
||||||
<label for="request_unit_half"
|
|
||||||
invisible="leave_type_request_unit == 'c_day'"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Adds "Calendar days" and "Working days" units of measures in Leaves kanban view -->
|
|
||||||
<record id="hr_leave_view_kanban_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">hr_holidays_ru.hr_leave_view_kanban_inherit</field>
|
|
||||||
<field name="model">hr.leave</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.hr_leave_view_kanban"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//span[hasclass('rounded-pill')]" position="replace">
|
|
||||||
<field name="leave_type_request_unit" invisible="1"/>
|
|
||||||
<span class="badge badge-pill float-right mt4 mr16" invisible="leave_type_request_unit != 'c_day'">
|
|
||||||
<t t-esc="record.number_of_days.value"/> Calendar days
|
|
||||||
</span>
|
|
||||||
<span class="badge badge-pill float-right mt4 mr16" invisible="leave_type_request_unit == 'c_day'">
|
|
||||||
<t t-esc="record.number_of_days.value"/> Working days
|
|
||||||
</span>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="hr_leave_allocation_view_form_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">hr_holidays_ru.hr_leave_allocation_view_form_inherit</field>
|
|
||||||
<field name="model">hr.leave.allocation</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//div[@name='duration_display']" position="replace">
|
|
||||||
<div>
|
|
||||||
<field name="number_of_days_display" class="oe_inline" nolabel="1"
|
|
||||||
readonly="state not in ('draft', 'confirm')"
|
|
||||||
invisible="type_request_unit == 'hour'"/>
|
|
||||||
<field name="number_of_hours_display" class="oe_inline" nolabel="1"
|
|
||||||
readonly="state not in ('draft', 'confirm')"
|
|
||||||
invisible="type_request_unit != 'hour'"/>
|
|
||||||
<span class="ml8" invisible="type_request_unit != 'c_day'">Calendar days</span>
|
|
||||||
<span class="ml8" invisible="type_request_unit != 'day'">Working days</span>
|
|
||||||
<span class="ml8" invisible="type_request_unit != 'hour'">Hours</span>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Adds "Exclude holidays" checkbox in Leave type form. -->
|
|
||||||
<!-- Adds notification for holidays settings -->
|
|
||||||
<record id="edit_holiday_status_form_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">hr_holidays_ru.edit_holiday_status_form_inherit</field>
|
|
||||||
<field name="model">hr.leave.type</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.edit_holiday_status_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//field[@name='request_unit']" position="after">
|
|
||||||
<field name="exclude_holidays" invisible="request_unit != 'c_day'"/>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//group[@id='visual']" position="before">
|
|
||||||
<group name="notifications" id="notifications">
|
|
||||||
<group string="Notification about holidays">
|
|
||||||
<field name="notify_before_start_holidays"/>
|
|
||||||
<field name="responsible_employee_to_notify_id" invisible="notify_before_start_holidays == False"/>
|
|
||||||
<field name="days_before_holidays" invisible="notify_before_start_holidays == False"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<menuitem
|
|
||||||
action="open_view_holiday_settings"
|
|
||||||
id="hr_holidays_status_menu_configuration"
|
|
||||||
parent="hr_holidays.menu_hr_holidays_configuration"
|
|
||||||
name="Holidays and non-working days"
|
|
||||||
groups="hr_holidays.group_hr_holidays_manager"
|
|
||||||
sequence="4"/>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8' ?>
|
|
||||||
<odoo>
|
|
||||||
<record id="hr_holidays.hr_leave_allocation_action_approve_department"
|
|
||||||
model="ir.actions.act_window">
|
|
||||||
<field name="context">{'search_default_approve': 1}</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8' ?>
|
|
||||||
<odoo>
|
|
||||||
<record id="hr_holidays.action_hr_holidays_dashboard"
|
|
||||||
model="ir.actions.act_window">
|
|
||||||
<field name="context">{'hide_employee_name': 1, 'search_default_department': 1}</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8' ?>
|
|
||||||
<odoo>
|
|
||||||
<record id="hr_leave_view_form_inh" model="ir.ui.view">
|
|
||||||
<field name="name">hr.leave.view.form.inh</field>
|
|
||||||
<field name="model">hr.leave</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.hr_leave_view_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//group/label[@for='request_unit_half']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//label[@for='number_of_days_display']" position="replace">
|
|
||||||
<field name="number_of_days_display" invisible="1" />
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//div[@name='duration_display']" position="replace">
|
|
||||||
<div name="duration_display">
|
|
||||||
<div class="o_row">
|
|
||||||
<div groups="!hr_holidays.group_hr_holidays_manager" invisible="1">
|
|
||||||
<field name="number_of_days_display" nolabel="1" readonly="1" class="oe_inline"/>
|
|
||||||
<span>Days</span>
|
|
||||||
</div>
|
|
||||||
<div groups="hr_holidays.group_hr_holidays_manager" class="o_row" invisible="1">
|
|
||||||
<field name="number_of_days" nolabel="1" class="oe_inline"/>
|
|
||||||
<span>Days</span>
|
|
||||||
</div>
|
|
||||||
<div invisible="1" class="o_row">
|
|
||||||
<field name="number_of_hours_text" nolabel="1" class="oe_inline"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="hr_holidays.hr_leave_action_action_approve_department"
|
|
||||||
model="ir.actions.act_window">
|
|
||||||
<field name="context">{
|
|
||||||
'hide_employee_name': 1,
|
|
||||||
'holiday_status_name_get': False}</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="hr_leave_view_tree_inh" model="ir.ui.view">
|
|
||||||
<field name="name">hr.leave.view.tree.inh</field>
|
|
||||||
<field name="model">hr.leave</field>
|
|
||||||
<field name="inherit_id" ref="hr_holidays.hr_leave_view_tree"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//field[@name='employee_id']" position="replace">
|
|
||||||
<field name="employee_id" widget="many2one_avatar"/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
|
@ -1,3 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import hr_holidays_summary_department
|
|
|
@ -1,180 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
|
|
||||||
from odoo import api, fields, models, _
|
|
||||||
from odoo.exceptions import UserError
|
|
||||||
|
|
||||||
|
|
||||||
class HrHolidaySummaryReport(models.AbstractModel):
|
|
||||||
_inherit = "report.hr_holidays.report_holidayssummary"
|
|
||||||
|
|
||||||
def _get_header_info(self, start_date, end_date, holiday_type):
|
|
||||||
st_date = fields.Date.from_string(start_date)
|
|
||||||
end_date_ = (
|
|
||||||
fields.Date.from_string(end_date)
|
|
||||||
if end_date
|
|
||||||
else fields.Date.from_string(start_date + relativedelta(days=59))
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"start_date": fields.Date.to_string(st_date),
|
|
||||||
"end_date": fields.Date.to_string(end_date_),
|
|
||||||
"holiday_type": "Confirmed and Approved"
|
|
||||||
if holiday_type == "both"
|
|
||||||
else holiday_type,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _get_months(self, start_date, end_date):
|
|
||||||
# it works for geting month name between two dates.
|
|
||||||
res = []
|
|
||||||
start_date = fields.Date.from_string(start_date)
|
|
||||||
# end_date = start_date + relativedelta(days=59)
|
|
||||||
end_date_ = (
|
|
||||||
fields.Date.from_string(end_date)
|
|
||||||
if end_date
|
|
||||||
else fields.Date.from_string(start_date + relativedelta(days=59))
|
|
||||||
)
|
|
||||||
while start_date <= end_date_:
|
|
||||||
last_date = start_date + relativedelta(day=1, months=+1, days=-1)
|
|
||||||
if last_date > end_date_:
|
|
||||||
last_date = end_date_
|
|
||||||
month_days = (last_date - start_date).days + 1
|
|
||||||
res.append({"month_name": start_date.strftime("%B"), "days": month_days})
|
|
||||||
start_date += relativedelta(day=1, months=+1)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _get_day(self, start_date, end_date):
|
|
||||||
res = []
|
|
||||||
start_date = fields.Date.from_string(start_date)
|
|
||||||
end_date_ = fields.Date.from_string(end_date)
|
|
||||||
for x in range((end_date_ - start_date).days + 1):
|
|
||||||
color = "#ababab" if self._date_is_day_off(start_date) else ""
|
|
||||||
res.append(
|
|
||||||
{
|
|
||||||
"day_str": start_date.strftime("%a"),
|
|
||||||
"day": start_date.day,
|
|
||||||
"color": color,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
start_date = start_date + relativedelta(days=1)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _get_data_from_report(self, data):
|
|
||||||
res = []
|
|
||||||
Employee = self.env["hr.employee"]
|
|
||||||
if "depts" in data:
|
|
||||||
for department in self.env["hr.department"].browse(data["depts"]):
|
|
||||||
res.append(
|
|
||||||
{
|
|
||||||
"dept": department.name,
|
|
||||||
"data": [],
|
|
||||||
"color": self._get_day(data["date_from"], data["date_to"]),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
for emp in Employee.search([("department_id", "=", department.id)]):
|
|
||||||
res[len(res) - 1]["data"].append(
|
|
||||||
{
|
|
||||||
"emp": emp.name,
|
|
||||||
"display": self._get_leaves_summary(
|
|
||||||
data["date_from"],
|
|
||||||
data["date_to"],
|
|
||||||
emp.id,
|
|
||||||
data["holiday_type"],
|
|
||||||
),
|
|
||||||
"sum": self.sum,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
elif "emp" in data:
|
|
||||||
res.append({"data": []})
|
|
||||||
for emp in Employee.browse(data["emp"]):
|
|
||||||
res[0]["data"].append(
|
|
||||||
{
|
|
||||||
"emp": emp.name,
|
|
||||||
"display": self._get_leaves_summary(
|
|
||||||
data["date_from"],
|
|
||||||
data["date_to"],
|
|
||||||
emp.id,
|
|
||||||
data["holiday_type"],
|
|
||||||
),
|
|
||||||
"sum": self.sum,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _get_leaves_summary(self, start_date, end_date, empid, holiday_type):
|
|
||||||
res = []
|
|
||||||
count = 0
|
|
||||||
start_date = fields.Date.from_string(start_date)
|
|
||||||
end_date_ = (
|
|
||||||
fields.Date.from_string(end_date)
|
|
||||||
if end_date
|
|
||||||
else fields.Date.from_string(start_date + relativedelta(days=59))
|
|
||||||
)
|
|
||||||
for index in range((end_date_ - start_date).days + 1):
|
|
||||||
current = start_date + timedelta(index)
|
|
||||||
res.append({"day": current.day, "color": ""})
|
|
||||||
if self._date_is_day_off(current):
|
|
||||||
res[index]["color"] = "#ababab"
|
|
||||||
# count and get leave summary details.
|
|
||||||
holiday_type = (
|
|
||||||
["confirm", "validate"]
|
|
||||||
if holiday_type == "both"
|
|
||||||
else ["confirm"]
|
|
||||||
if holiday_type == "Confirmed"
|
|
||||||
else ["validate"]
|
|
||||||
)
|
|
||||||
holidays = self.env["hr.leave"].search(
|
|
||||||
[
|
|
||||||
("employee_id", "=", empid),
|
|
||||||
("state", "in", holiday_type),
|
|
||||||
("date_from", "<=", str(end_date_)),
|
|
||||||
("date_to", ">=", str(start_date)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
for holiday in holidays:
|
|
||||||
# Convert date to user timezone, otherwise the report will not be consistent with the
|
|
||||||
# value displayed in the interface.
|
|
||||||
date_from = fields.Datetime.from_string(holiday.date_from)
|
|
||||||
date_from = fields.Datetime.context_timestamp(holiday, date_from).date()
|
|
||||||
date_to = fields.Datetime.from_string(holiday.date_to)
|
|
||||||
date_to = fields.Datetime.context_timestamp(holiday, date_to).date()
|
|
||||||
for index in range(0, ((date_to - date_from).days + 1)):
|
|
||||||
if date_from >= start_date and date_from <= end_date_:
|
|
||||||
res[(date_from - start_date).days][
|
|
||||||
"color"
|
|
||||||
] = holiday.holiday_status_id.color_name
|
|
||||||
date_from += timedelta(1)
|
|
||||||
count += holiday.number_of_days
|
|
||||||
self.sum = count
|
|
||||||
return res
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def _get_report_values(self, docids, data=None):
|
|
||||||
if not data.get("form"):
|
|
||||||
raise UserError(
|
|
||||||
_("Form content is missing, this report cannot be printed.")
|
|
||||||
)
|
|
||||||
|
|
||||||
holidays_report = self.env["ir.actions.report"]._get_report_from_name(
|
|
||||||
"hr_holidays.report_holidayssummary"
|
|
||||||
)
|
|
||||||
holidays = self.env["hr.leave"].browse(self.ids)
|
|
||||||
return {
|
|
||||||
"doc_ids": self.ids,
|
|
||||||
"doc_model": holidays_report.model,
|
|
||||||
"docs": holidays,
|
|
||||||
"get_header_info": self._get_header_info(
|
|
||||||
data["form"]["date_from"],
|
|
||||||
data["form"]["date_to"],
|
|
||||||
data["form"]["holiday_type"],
|
|
||||||
),
|
|
||||||
"get_day": self._get_day(
|
|
||||||
data["form"]["date_from"], data["form"]["date_to"]
|
|
||||||
),
|
|
||||||
"get_months": self._get_months(
|
|
||||||
data["form"]["date_from"], data["form"]["date_to"]
|
|
||||||
),
|
|
||||||
"get_data_from_report": self._get_data_from_report(data["form"]),
|
|
||||||
"get_holidays_status": self._get_holidays_status(),
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user