19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:31:00 +01:00
parent a1137a1456
commit e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions

View file

@ -2,7 +2,7 @@
Manage time off requests and allocations
=====================================
========================================
This application controls the time off schedule of your company. It allows employees to request time off. Then, managers can review requests for time off and approve or reject them. This way you can control the overall time off planning for the company or department.
@ -25,37 +25,16 @@ pip install odoo-bringout-oca-ocb-hr_holidays
## Dependencies
This addon depends on:
- hr
- calendar
- resource
## Manifest Information
- **Name**: Time Off
- **Version**: 1.6
- **Category**: Human Resources/Time Off
- **License**: LGPL-3
- **Installable**: True
## Source
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `hr_holidays`.
- Repository: https://github.com/OCA/OCB
- Branch: 19.0
- Path: addons/hr_holidays
## License
This package maintains the original LGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md
This package preserves the original LGPL-3 license.

View file

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
from . import populate
from . import report
from . import wizard

View file

@ -6,11 +6,11 @@
'version': '1.6',
'category': 'Human Resources/Time Off',
'sequence': 85,
'summary': 'Allocate PTOs and follow leaves requests',
'summary': 'Allocate time off and follow leave requests',
'website': 'https://www.odoo.com/app/time-off',
'description': """
Manage time off requests and allocations
=====================================
========================================
This application controls the time off schedule of your company. It allows employees to request time off. Then, managers can review requests for time off and approve or reject them. This way you can control the overall time off planning for the company or department.
@ -29,23 +29,27 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
'data/report_paperformat.xml',
'data/mail_activity_type_data.xml',
'data/mail_message_subtype_data.xml',
'data/hr_holidays_data.xml',
'data/ir_attachment_data.xml',
'data/hr_leave_type_data.xml',
'data/ir_cron_data.xml',
'data/hr_holidays_tour.xml',
'security/hr_holidays_security.xml',
'security/ir.model.access.csv',
'wizard/hr_holidays_cancel_leave_views.xml',
'wizard/hr_holidays_summary_employees_views.xml',
'wizard/hr_leave_generate_multi_wizard_views.xml',
'wizard/hr_leave_allocation_generate_multi_wizard_views.xml',
'views/resource_views.xml',
'views/hr_leave_views.xml',
'views/hr_leave_type_views.xml',
'views/hr_leave_allocation_views.xml',
'views/hr_leave_accrual_views.xml',
'views/hr_leave_stress_day_views.xml',
'views/hr_leave_mandatory_day_views.xml',
'views/mail_activity_views.xml',
'wizard/hr_holidays_cancel_leave_views.xml',
'wizard/hr_holidays_summary_employees_views.xml',
'wizard/hr_departure_wizard_views.xml',
'views/calendar_views.xml',
'report/hr_holidays_templates.xml',
'report/hr_holidays_reports.xml',
@ -62,45 +66,32 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
'installable': True,
'application': True,
'assets': {
'mail.assets_messaging': [
'hr_holidays/static/src/models/*.js',
],
'mail.assets_discuss_public': [
'hr_holidays/static/src/components/*/*',
],
'web.assets_backend': [
'hr_holidays/static/src/views/**/*.js',
'hr_holidays/static/src/views/**/*.scss',
'hr_holidays/static/src/views/**/*.xml',
'hr_holidays/static/src/components/*/*.scss',
'hr_holidays/static/src/components/*/*.xml',
'hr_holidays/static/src/dashboard/**/*.js',
'hr_holidays/static/src/dashboard/**/*.scss',
'hr_holidays/static/src/dashboard/**/*.xml',
'hr_holidays/static/src/leave_stats/**/*.js',
'hr_holidays/static/src/leave_stats/**/*.xml',
'hr_holidays/static/src/scss/*.scss',
'hr_holidays/static/src/tours/*.js',
'hr_holidays/static/src/radio_image_field/*.js',
'hr_holidays/static/src/radio_image_field/*.xml',
'hr_holidays/static/src/**/*',
('remove', 'hr_holidays/static/src/views/graph/**'),
# Don't include dark mode files in light mode
('remove', 'hr_holidays/static/src/views/**/*.dark.scss'),
('remove', 'hr_holidays/static/src/dashboard/**/*.dark.scss'),
('remove', 'hr_holidays/static/src/**/*.dark.scss'),
],
"web.dark_mode_assets_backend": [
'hr_holidays/static/src/views/**/*.dark.scss',
'hr_holidays/static/src/dashboard/**/*.dark.scss',
'web.assets_backend_lazy': [
'hr_holidays/static/src/views/graph/**',
],
'web.tests_assets': [
'hr_holidays/static/tests/helpers/**/*',
"web.assets_web_dark": [
'hr_holidays/static/src/**/*.dark.scss',
],
'web.qunit_suite_tests': [
'hr_holidays/static/tests/qunit_suite_tests/**/*.js',
'im_livechat.assets_embed_core': [
'hr_holidays/static/src/core/common/**/*',
],
'mail.assets_public': [
'hr_holidays/static/src/core/common/**/*',
],
'web.assets_unit_tests': [
'hr_holidays/static/tests/**/*',
('remove', 'hr_holidays/static/tests/tours/**/*'),
],
'web.assets_tests': [
'/hr_holidays/static/tests/tours/**/**.js'
'/hr_holidays/static/tests/tours/**/*'
],
},
'author': 'Odoo S.A.',
'license': 'LGPL-3',
}

View file

@ -7,6 +7,16 @@ from odoo import http
class HrHolidaysController(http.Controller):
@http.route('/leave/approve', type='http', auth='user', methods=['GET'])
def hr_holidays_request_approve(self, res_id, token):
comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.leave', int(res_id), token)
if comparison and record:
try:
record.action_approve()
except Exception:
return MailController._redirect_to_generic_fallback('hr.leave', res_id)
return redirect
@http.route('/leave/validate', type='http', auth='user', methods=['GET'])
def hr_holidays_request_validate(self, res_id, token):
comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.leave', int(res_id), token)

View file

@ -1,316 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="icon_1" model="ir.attachment">
<field name="name">Annual_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Annual_Time_Off.svg</field>
</record>
<record id="icon_2" model="ir.attachment">
<field name="name">Annual_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Annual_Time_Off_2.svg</field>
</record>
<record id="icon_3" model="ir.attachment">
<field name="name">Annual_Time_Off_3.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Annual_Time_Off_3.svg</field>
</record>
<record id="icon_4" model="ir.attachment">
<field name="name">Compensatory_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Compensatory_Time_Off.svg</field>
</record>
<record id="icon_5" model="ir.attachment">
<field name="name">Compensatory_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Compensatory_Time_Off_2.svg</field>
</record>
<record id="icon_6" model="ir.attachment">
<field name="name">Compensatory_Time_Off_3.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Compensatory_Time_Off_3.svg</field>
</record>
<record id="icon_7" model="ir.attachment">
<field name="name">Credit_Time.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Credit_Time.svg</field>
</record>
<record id="icon_8" model="ir.attachment">
<field name="name">Credit_Time_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Credit_Time_2.svg</field>
</record>
<record id="icon_9" model="ir.attachment">
<field name="name">Extra_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Extra_Time_Off.svg</field>
</record>
<record id="icon_10" model="ir.attachment">
<field name="name">Extra_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Extra_Time_Off_2.svg</field>
</record>
<record id="icon_11" model="ir.attachment">
<field name="name">Maternity_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Maternity_Time_Off.svg</field>
</record>
<record id="icon_12" model="ir.attachment">
<field name="name">Maternity_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Maternity_Time_Off_2.svg</field>
</record>
<record id="icon_13" model="ir.attachment">
<field name="name">Maternity_Time_Off_3.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Maternity_Time_Off_3.svg</field>
</record>
<record id="icon_14" model="ir.attachment">
<field name="name">Paid_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Paid_Time_Off.svg</field>
</record>
<record id="icon_15" model="ir.attachment">
<field name="name">Paid_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Paid_Time_Off_2.svg</field>
</record>
<record id="icon_16" model="ir.attachment">
<field name="name">Paid_Time_Off_3.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Paid_Time_Off_3.svg</field>
</record>
<record id="icon_17" model="ir.attachment">
<field name="name">Parental_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Parental_Time_Off.svg</field>
</record>
<record id="icon_18" model="ir.attachment">
<field name="name">Parental_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Parental_Time_Off_2.svg</field>
</record>
<record id="icon_19" model="ir.attachment">
<field name="name">Recovery_Bank_Holiday.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Recovery_Bank_Holiday.svg</field>
</record>
<record id="icon_20" model="ir.attachment">
<field name="name">Recovery_Bank_Holiday_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Recovery_Bank_Holiday_2.svg</field>
</record>
<record id="icon_21" model="ir.attachment">
<field name="name">Sick_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Sick_Time_Off.svg</field>
</record>
<record id="icon_22" model="ir.attachment">
<field name="name">Sick_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Sick_Time_Off_2.svg</field>
</record>
<record id="icon_23" model="ir.attachment">
<field name="name">Small_Unemployement.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Small_Unemployement.svg</field>
</record>
<record id="icon_24" model="ir.attachment">
<field name="name">Small_Unemployement_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Small_Unemployement_2.svg</field>
</record>
<record id="icon_25" model="ir.attachment">
<field name="name">Small_Unemployement_3.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Small_Unemployement_3.svg</field>
</record>
<record id="icon_26" model="ir.attachment">
<field name="name">Training_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Training_Time_Off.svg</field>
</record>
<record id="icon_27" model="ir.attachment">
<field name="name">Training_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Training_Time_Off_2.svg</field>
</record>
<record id="icon_28" model="ir.attachment">
<field name="name">Unpaid_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Unpaid_Time_Off.svg</field>
</record>
<record id="icon_29" model="ir.attachment">
<field name="name">Unpaid_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Unpaid_Time_Off_2.svg</field>
</record>
<record id="icon_30" model="ir.attachment">
<field name="name">Work_Accident_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Work_Accident_Time_Off.svg</field>
</record>
<record id="icon_31" model="ir.attachment">
<field name="name">Work_Accident_Time_Off_2.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Work_Accident_Time_Off_2.svg</field>
</record>
</data>
<data noupdate="1">
<!-- Casual leave -->
<record id="holiday_status_cl" model="hr.leave.type">
<field name="name">Paid Time Off</field>
<field name="requires_allocation">yes</field>
<field name="employee_requests">no</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">officer</field>
<field name="leave_notif_subtype_id" ref="mt_leave"/>
<field name="allocation_notif_subtype_id" ref="mt_leave_allocation"/>
<field name="responsible_id" ref="base.user_admin"/>
<field name="icon_id" ref="hr_holidays.icon_14"/>
<field name="color">2</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="sequence">1</field>
</record>
<!-- Sick leave -->
<record id="holiday_status_sl" model="hr.leave.type">
<field name="name">Sick Time Off</field>
<field name="requires_allocation">no</field>
<field name="color_name">red</field>
<field name="leave_notif_subtype_id" ref="mt_leave_sick"/>
<field name="responsible_id" ref="base.user_admin"/>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_22"/>
<field name="color">3</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="sequence">2</field>
</record>
<!-- Compensatory Days -->
<record id="holiday_status_comp" model="hr.leave.type">
<field name="name">Compensatory Days</field>
<field name="requires_allocation">yes</field>
<field name="employee_requests">yes</field>
<field name="leave_validation_type">manager</field>
<field name="allocation_validation_type">officer</field>
<field name="request_unit">hour</field>
<field name="leave_notif_subtype_id" ref="mt_leave"/>
<field name="responsible_id" ref="base.user_admin"/>
<field name="icon_id" ref="hr_holidays.icon_4"/>
<field name="color">4</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="sequence">4</field>
</record>
<!--Unpaid Leave -->
<record id="holiday_status_unpaid" model="hr.leave.type">
<field name="name">Unpaid</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">officer</field>
<field name="request_unit">hour</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="mt_leave_unpaid"/>
<field name="responsible_id" ref="base.user_admin"/>
<field name="icon_id" ref="hr_holidays.icon_28"/>
<field name="color">5</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="sequence">3</field>
</record>
</data>
</odoo>

View file

@ -3,80 +3,98 @@
<data noupdate="1">
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
<field name="group_ids" eval="[
(3, ref('hr_holidays.group_hr_holidays_responsible')),
(3, ref('hr_holidays.group_hr_holidays_user')),
(3, ref('hr_holidays.group_hr_holidays_manager'))]"/>
</record>
<!--Leave Type-->
<record id="base.default_user_group" model="res.groups">
<field name="implied_ids" eval="[(4, ref('hr_holidays.group_hr_holidays_manager'))]"/>
</record>
<!--Time Off Type-->
<record id="hr_holiday_status_dv" model="hr.leave.type">
<field name="name">Parental Leaves</field>
<field name="requires_allocation">yes</field>
<field name="employee_requests">no</field>
<field name="color_name">brown</field>
<field name="employee_requests">False</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">officer</field>
<field name="responsible_id" ref="base.user_admin"/>
<field name="icon_id" ref="hr_holidays.icon_11"/>
<field name="allocation_validation_type">hr</field>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_17"/>
</record>
<record id="holiday_status_training" model="hr.leave.type">
<field name="name">Training Time Off</field>
<field name="requires_allocation">yes</field>
<field name="employee_requests">no</field>
<field name="color_name">lightyellow</field>
<field name="employee_requests">False</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">officer</field>
<field name="responsible_id" ref="base.user_admin"/>
<field name="allocation_validation_type">hr</field>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_26"/>
<field name="allows_negative" eval="True"/>
<field name="max_allowed_negative" eval="20"/>
</record>
<!-- Accrual Plan -->
<record id="hr_accrual_plan_1" model="hr.leave.accrual.plan">
<field name="name">Seniority Plan</field>
<field name="can_be_carryover">True</field>
</record>
<record id="hr_accrual_level_1" model="hr.leave.accrual.level">
<field name="accrual_plan_id" ref="hr_accrual_plan_1" />
<field name="milestone_date">after</field>
<field name="start_count">1</field>
<field name="start_type">day</field>
<field name="added_value">1</field>
<field name="frequency">yearly</field>
<field name="cap_accrued_time">True</field>
<field name="action_with_unused_accruals">all</field>
<field name="maximum_leave">100</field>
</record>
<record id="hr_accrual_level_2" model="hr.leave.accrual.level">
<field name="accrual_plan_id" ref="hr_accrual_plan_1" />
<field name="milestone_date">after</field>
<field name="start_count">4</field>
<field name="start_type">year</field>
<field name="added_value">2</field>
<field name="frequency">yearly</field>
<field name="cap_accrued_time">True</field>
<field name="action_with_unused_accruals">all</field>
<field name="maximum_leave">100</field>
</record>
<record id="hr_accrual_level_3" model="hr.leave.accrual.level">
<field name="accrual_plan_id" ref="hr_accrual_plan_1" />
<field name="milestone_date">after</field>
<field name="start_count">8</field>
<field name="start_type">year</field>
<field name="added_value">3</field>
<field name="frequency">yearly</field>
<field name="cap_accrued_time">True</field>
<field name="action_with_unused_accruals">all</field>
<field name="maximum_leave">100</field>
</record>
<!-- ++++++++++++++++++++++ Mitchell Admin ++++++++++++++++++++++ -->
<record id="hr_holidays_allocation_cl" model="hr.leave.allocation">
<field name="name">Paid Time Off for Mitchell Admin</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<record id="hr_holidays_int_tour" model="hr.leave.allocation">
<field name="name">International Tour</field>
<field name="holiday_status_id" ref="holiday_status_comp"/>
<field name="holiday_status_id" ref="leave_type_compensatory_days"/>
<field name="number_of_days">7</field>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -86,49 +104,41 @@
<field name="number_of_days">7</field>
<field name="state">confirm</field>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<record id='hr_holidays_cl_allocation' model="hr.leave.allocation">
<field name="name">Compensation</field>
<field name="holiday_status_id" ref="holiday_status_comp"/>
<field name="holiday_status_id" ref="leave_type_compensatory_days"/>
<field name="number_of_days">12</field>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays_allocation_cl'), ref('hr_holidays_int_tour'), ref('hr_holidays_cl_allocation')]"/>
</function>
<!-- leave request -->
<record id="hr_holidays_cl" model="hr.leave">
<field name="name">Trip with Family</field>
<field name="holiday_status_id" ref="holiday_status_comp"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="date_from"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="date_to"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="request_date_from"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_compensatory_days"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(day=1, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(day=1, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
</record>
<record id="hr_holidays_sl" model="hr.leave">
<field name="name">Doctor Appointment</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now() + relativedelta(day=20, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="date_from"/>
<field eval="(datetime.now() + relativedelta(day=20, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="date_to"/>
<field eval="(datetime.now() + relativedelta(day=20, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="request_date_from"/>
<field eval="(datetime.now() + relativedelta(day=20, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(day=20, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(day=20, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_admin"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_admin'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl')"/>
</function>
@ -147,18 +157,20 @@
<record id="hr.employee_jve" model="hr.employee">
<field name="leave_manager_id" ref="base.user_admin"/>
</record>
<record id="hr.employee_stw" model="hr.employee">
<field name="leave_manager_id" ref="base.user_demo"/>
</record>
<!-- ++++++++++++++++++++++ Ronnie Hart ++++++++++++++++++++++ -->
<record id="hr_holidays_allocation_cl_al" model="hr.leave.allocation">
<field name="name">Paid Time Off for Ronnie Hart</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_al"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_al'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -167,9 +179,8 @@
<field name="holiday_status_id" ref="hr_holiday_status_dv"/>
<field name="number_of_days">10</field>
<field name="employee_id" ref="hr.employee_al"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_al'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -178,42 +189,35 @@
<field name="holiday_status_id" ref="holiday_status_training"/>
<field name="number_of_days">12</field>
<field name="employee_id" ref="hr.employee_al"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_al'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays_allocation_cl_al'), ref('hr_holidays_allocation_pl_al'), ref('hr_holidays_vc_al')]"/>
</function>
<!-- leave request -->
<record id="hr_holidays_cl_al" model="hr.leave">
<field name="name">Trip with Friends</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field eval="time.strftime('%Y-%m-04')" name="date_from"/>
<field eval="time.strftime('%Y-%m-10')" name="date_to"/>
<field eval="time.strftime('%Y-%m-04')" name="request_date_from"/>
<field eval="time.strftime('%Y-%m-10')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="request_date_from" eval="time.strftime('%Y-%m-14')"/>
<field name="request_date_to" eval="time.strftime('%Y-%m-20')"/>
<field name="employee_id" ref="hr.employee_al"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_al'))]"/>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_cl_al')"/>
</function>
<record id="hr_holidays_sl_al" model="hr.leave">
<field name="name">Dentist appointment</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now()+relativedelta(months=1, day=17, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=17, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="date_to"/>
<field eval="(datetime.now()+relativedelta(months=1, day=17, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="request_date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=17, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(months=1, day=17, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(months=1, day=17, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_al"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_al'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl_al')"/>
</function>
@ -221,15 +225,14 @@
<record id="hr_holidays_allocation_cl_mit" model="hr.leave.allocation">
<field name="name">Paid Time Off for Anita Oliver</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_mit"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_mit'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays_allocation_cl_mit')]"/>
</function>
@ -239,35 +242,28 @@
<field name="number_of_days">7</field>
<field name="state">confirm</field>
<field name="employee_id" ref="hr.employee_mit"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_mit'))]"/>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<!-- leave request -->
<record id="hr_holidays_cl_mit" model="hr.leave">
<field name="name">Trip to Paris</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field eval="time.strftime('%Y-%m-18')" name="date_from"/>
<field eval="time.strftime('%Y-%m-24')" name="date_to"/>
<field eval="time.strftime('%Y-%m-18')" name="request_date_from"/>
<field eval="time.strftime('%Y-%m-24')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="request_date_from" eval="time.strftime('%Y-%m-22')"/>
<field name="request_date_to" eval="time.strftime('%Y-%m-28')"/>
<field name="employee_id" ref="hr.employee_mit"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_mit'))]"/>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_cl_mit')"/>
</function>
<record id="hr_holidays_cl_mit_2" model="hr.leave">
<field name="name">Trip</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field eval="(datetime.now() + relativedelta(day=5, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="date_from"/>
<field eval="(datetime.now() + relativedelta(day=5, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="date_to"/>
<field eval="(datetime.now() + relativedelta(day=5, weekday=0)).strftime('%Y-%m-%d 04:00:00')" name="request_date_from"/>
<field eval="(datetime.now() + relativedelta(day=5, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 20:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(day=5, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(day=5, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_mit"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_mit'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_approve">
@ -278,12 +274,11 @@
<record id="hr_holidays_allocation_cl_qdp" model="hr.leave.allocation">
<field name="name">Paid Time Off for Marc Demo</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_qdp"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_qdp'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -292,43 +287,36 @@
<field name="holiday_status_id" ref="holiday_status_training"/>
<field name="number_of_days">7</field>
<field name="employee_id" ref="hr.employee_qdp"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_qdp'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays.hr_holidays_allocation_cl_qdp'), ref('hr_holidays.hr_holidays_vc_qdp')]"/>
</function>
<!-- leave request -->
<record id="hr_holidays_cl_qdp" model="hr.leave">
<field name="name">Sick day</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now()+relativedelta(months=1, day=3, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=3, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="date_to"/>
<field eval="(datetime.now()+relativedelta(months=1, day=3, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="request_date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=3, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date()+relativedelta(months=1, day=3, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date()+relativedelta(months=1, day=3, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_qdp"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_qdp'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_cl_qdp')"/>
</function>
<record id="hr_holidays_sl_qdp" model="hr.leave">
<field name="name">Sick day</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="date_from"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0) + relativedelta(days=2)).strftime('%Y-%m-%d 23:00:00')" name="date_to"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="request_date_from"/>
<field eval="(datetime.now() + relativedelta(day=1, weekday=0) + relativedelta(days=2)).strftime('%Y-%m-%d 23:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(day=1, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(day=1, weekday=0) + relativedelta(days=2))"/>
<field name="employee_id" ref="hr.employee_qdp"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_qdp'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl_qdp')"/>
</function>
@ -336,15 +324,14 @@
<record id="hr_holidays_allocation_cl_fpi" model="hr.leave.allocation">
<field name="name">Paid Time Off for Audrey Peterson</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_fpi"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_fpi'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays.hr_holidays_allocation_cl_fpi')]"/>
</function>
@ -353,9 +340,8 @@
<field name="holiday_status_id" ref="holiday_status_training"/>
<field name="number_of_days">7</field>
<field name="employee_id" ref="hr.employee_fpi"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_fpi'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -363,12 +349,11 @@
<record id="hr_holidays_allocation_cl_vad" model="hr.leave.allocation">
<field name="name">Paid Time Off for Olivia</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_niv"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_niv'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -377,42 +362,35 @@
<field name="holiday_status_id" ref="holiday_status_training"/>
<field name="number_of_days">5</field>
<field name="employee_id" ref="hr.employee_niv"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_niv'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<function model="hr.leave.allocation" name="action_validate">
<function model="hr.leave.allocation" name="action_approve">
<value eval="[ref('hr_holidays.hr_holidays_allocation_cl_vad'), ref('hr_holidays.hr_holidays_vc_vad')]"/>
</function>
<record id="hr_holidays_cl_vad" model="hr.leave">
<field name="name">Trip to London</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field eval="time.strftime('%Y-%m-09')" name="date_from"/>
<field eval="time.strftime('%Y-%m-16')" name="date_to"/>
<field eval="time.strftime('%Y-%m-09')" name="request_date_from"/>
<field eval="time.strftime('%Y-%m-16')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="request_date_from" eval="time.strftime('%Y-%m-09')"/>
<field name="request_date_to" eval="time.strftime('%Y-%m-16')"/>
<field name="employee_id" ref="hr.employee_niv"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_niv'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_cl_vad')"/>
</function>
<record id="hr_holidays_sl_vad" model="hr.leave">
<field name="name">Doctor Appointment</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now() + relativedelta(day=25, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="date_from"/>
<field eval="(datetime.now() + relativedelta(day=25, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="date_to"/>
<field eval="(datetime.now() + relativedelta(day=25, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="request_date_from"/>
<field eval="(datetime.now() + relativedelta(day=25, weekday=0) + relativedelta(weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(day=25, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(day=25, weekday=0) + relativedelta(weekday=2))"/>
<field name="employee_id" ref="hr.employee_niv"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_niv'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl_vad')"/>
</function>
@ -420,12 +398,11 @@
<record id="hr_holidays_allocation_cl_kim" model="hr.leave.allocation">
<field name="name">Paid Time Off for Kim</field>
<field name="holiday_status_id" ref="holiday_status_cl"/>
<field name="holiday_status_id" ref="leave_type_paid_time_off"/>
<field name="number_of_days">20</field>
<field name="employee_id" ref="hr.employee_jve"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_jve'))]"/>
<field name="state">confirm</field>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
@ -435,39 +412,32 @@
<field name="number_of_days">5</field>
<field name="state">confirm</field>
<field name="employee_id" ref="hr.employee_jve"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_jve'))]"/>
<field name="date_from" eval="time.strftime('%Y-1-1')"/>
<field name="date_from" eval="time.strftime('%Y-01-01')"/>
<field name="date_to" eval="time.strftime('%Y-12-31')"/>
</record>
<!-- leave request -->
<record id="hr_holidays_sl_kim" model="hr.leave">
<field name="name">Dentist appointment</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now()+relativedelta(months=1, day=1, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=1, weekday=0)).strftime('%Y-%m-%d 23:00:00')" name="date_to"/>
<field eval="(datetime.now()+relativedelta(months=1, day=1, weekday=0)).strftime('%Y-%m-%d 01:00:00')" name="request_date_from"/>
<field eval="(datetime.now()+relativedelta(months=1, day=1, weekday=0)).strftime('%Y-%m-%d 23:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date() + relativedelta(months=1, day=1, weekday=0))"/>
<field name="request_date_to" eval="(datetime.today().date() + relativedelta(months=1, day=1, weekday=0))"/>
<field name="employee_id" ref="hr.employee_jve"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_jve'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl_kim')"/>
</function>
<record id="hr_holidays_sl_kim_2" model="hr.leave">
<field name="name">Second dentist appointment</field>
<field name="holiday_status_id" ref="holiday_status_sl"/>
<field eval="(datetime.now()+relativedelta(months=4, day=1, weekday=2)).strftime('%Y-%m-%d 01:00:00')" name="date_from"/>
<field eval="(datetime.now()+relativedelta(months=4, day=1, weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="date_to"/>
<field eval="(datetime.now()+relativedelta(months=4, day=1, weekday=2)).strftime('%Y-%m-%d 01:00:00')" name="request_date_from"/>
<field eval="(datetime.now()+relativedelta(months=4, day=1, weekday=2)).strftime('%Y-%m-%d 23:00:00')" name="request_date_to"/>
<field name="holiday_status_id" ref="leave_type_sick_time_off"/>
<field name="request_date_from" eval="(datetime.today().date()+relativedelta(months=4, day=1, weekday=2))"/>
<field name="request_date_to" eval="(datetime.today().date()+relativedelta(months=4, day=1, weekday=2))"/>
<field name="employee_id" ref="hr.employee_jve"/>
<field name="employee_ids" eval="[(4, ref('hr.employee_jve'))]"/>
<field name="state">confirm</field>
</record>
<function model="hr.leave" name="action_validate">
<function model="hr.leave" name="action_approve">
<value eval="ref('hr_holidays.hr_holidays_sl_kim_2')"/>
</function>
@ -476,12 +446,12 @@
<field name="name">Public Time Off</field>
<field name="company_id" ref="base.main_company"/>
<field name="calendar_id" ref="resource.resource_calendar_std"/>
<field name="date_from" eval="(datetime.today() + relativedelta(days=+8)).strftime('%Y-%m-%d 05:00:00')"></field>
<field name="date_to" eval="(datetime.today() + relativedelta(days=+8)).strftime('%Y-%m-%d 17:00:00')"></field>
<field name="date_from" eval="time.strftime('%Y-02-13 05:00:00')"/>
<field name="date_to" eval="time.strftime('%Y-02-13 17:00:00')"/>
</record>
<!-- Stress day -->
<record id="hr_leave_stress_day_1" model="hr.leave.stress.day">
<!-- Mandatory day -->
<record id="hr_leave_mandatory_day_1" model="hr.leave.mandatory.day">
<field name="name">Company Celebration</field>
<field name="company_id" ref="base.main_company"/>
<field name="start_date" eval="(datetime.today() + relativedelta(days=+7)).strftime('%Y-%m-%d 07:00:00')"></field>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="hr_holidays_tour" model="web_tour.tour">
<field name="name">hr_holidays_tour</field>
<field name="rainbow_man_message">Congrats, we can see that your request has been validated.</field>
</record>
</odoo>

View file

@ -0,0 +1,707 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<!-- Global Leave Types -->
<record id="leave_type_paid_time_off" model="hr.leave.type">
<field name="name">Paid Time Off</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">False</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">hr</field>
<field name="leave_notif_subtype_id" ref="mt_leave"/>
<field name="allocation_notif_subtype_id" ref="mt_leave_allocation"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_14"/>
<field name="color">2</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="country_id" eval="False"/> <!-- Explicitely set to False for it to be available to all countries -->
<field name="sequence">1</field>
</record>
<record id="leave_type_sick_time_off" model="hr.leave.type">
<field name="name">Sick Time Off</field>
<field name="requires_allocation">False</field>
<field name="leave_notif_subtype_id" ref="mt_leave_sick"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="support_document">True</field>
<field name="hide_on_dashboard">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="color">3</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="country_id" eval="False"/> <!-- Explicitely set to False for it to be available to all countries -->
<field name="sequence">2</field>
</record>
<record id="leave_type_compensatory_days" model="hr.leave.type">
<field name="name">Compensatory Days</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="leave_validation_type">manager</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">day</field>
<field name="leave_notif_subtype_id" ref="mt_leave"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_4"/>
<field name="color">4</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="country_id" eval="False"/> <!-- Explicitely set to False for it to be available to all countries -->
<field name="sequence">4</field>
</record>
<record id="leave_type_unpaid" model="hr.leave.type">
<field name="name">Unpaid</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">both</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">hour</field>
<field name="hide_on_dashboard">True</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="mt_leave_unpaid"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_28"/>
<field name="color">5</field>
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
<field name="country_id" eval="False"/> <!-- Explicitely set to False for it to be available to all countries -->
<field name="sequence">3</field>
</record>
<record id="holiday_status_eto" model="hr.leave.type">
<field name="name">Extra Time Off</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">True</field>
<field name="leave_validation_type">no_validation</field>
<field name="allocation_validation_type">hr</field>
<field name="hide_on_dashboard">True</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="sequence">4</field>
<field name="country_id" eval="False"/>
</record>
<record id="holiday_status_extra_hours" model="hr.leave.type">
<field name="name">Extra Hours</field>
<field name="request_unit">hour</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">manager</field>
<field name="active" eval="True"/>
<field name="hide_on_dashboard">True</field>
<field name="company_id" eval="False"/>
<field name="country_id" eval="False"/>
<field name="icon_id" ref="hr_holidays.icon_4"/>
<field name="sequence">5</field>
</record>
<!-- AE : United Arab Emirates -->
<record id="l10n_ae_leave_type_sick_leave_50" model="hr.leave.type">
<field name="name">Sick Leave 50%</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">hr</field>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.ae"/>
</record>
<record id="l10n_ae_leave_type_sick_leave_0" model="hr.leave.type">
<field name="name">Sick Leave 0%</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">hr</field>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.ae"/>
</record>
<!-- BE : Belgium -->
<record id="l10n_be_leave_type_small_unemployment" model="hr.leave.type">
<field name="name">Small Unemployment</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_maternity" model="hr.leave.type">
<field name="name">Maternity Time Off</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="icon_id" ref="hr_holidays.icon_17"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_unpredictable" model="hr.leave.type">
<field name="name">Unpredictable Reason</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_training" model="hr.leave.type">
<field name="name">Training Time Off</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="icon_id" ref="hr_holidays.icon_26"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_extra_legal" model="hr.leave.type">
<field name="name">Extra Legal Time Off</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="icon_id" ref="hr_holidays.icon_4"/>
<field name="company_id" eval="False"/>
<field name="sequence">6</field>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_recovery" model="hr.leave.type">
<field name="name">Recovery Bank Holiday</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="request_unit">day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_european" model="hr.leave.type">
<field name="name">European Time Off</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">True</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="icon_id" ref="hr_holidays.icon_14"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_credit_time" model="hr.leave.type">
<field name="name">Credit Time</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" eval="ref('hr_holidays.mt_leave')"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_work_accident" model="hr.leave.type">
<field name="name">Work Accident Time Off</field>
<field name="requires_allocation">False</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_strike" model="hr.leave.type">
<field name="name">Strike</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_sick_leave_without_certificate" model="hr.leave.type">
<field name="name">Sick Leave Without Certificate</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<record id="l10n_be_leave_type_small_unemployment_birth" model="hr.leave.type">
<field name="name">Brief Holiday (Birth)</field>
<field name="requires_allocation">yes</field>
<field name="employee_requests">yes</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.be"/>
</record>
<!-- CH: Switzerland -->
<record id="l10n_ch_swissdec_unpaid_lt" model="hr.leave.type">
<field name="name">Unpaid leave</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="company_id" eval="False"/>
<field name="sequence">1</field>
<field name="color">1</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="l10n_ch_swissdec_illness_lt" model="hr.leave.type">
<field name="name">Illness leave</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="sequence">2</field>
<field name="company_id" eval="False"/>
<field name="color">2</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="l10n_ch_swissdec_accident_lt" model="hr.leave.type">
<field name="name">Accident leave</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="sequence">3</field>
<field name="company_id" eval="False"/>
<field name="color">3</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="l10n_ch_swissdec_maternity_lt" model="hr.leave.type">
<field name="name">Maternity / Paternity leave</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="sequence">4</field>
<field name="company_id" eval="False"/>
<field name="color">4</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="l10n_ch_swissdec_military_lt" model="hr.leave.type">
<field name="name">Military leave</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="sequence">4</field>
<field name="company_id" eval="False"/>
<field name="color">5</field>
<field name="country_id" ref="base.ch"/>
</record>
<record id="l10n_ch_swissdec_interruption_of_work_lt" model="hr.leave.type">
<field name="name">Interruption of Work</field>
<field name="employee_requests">False</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">day</field>
<field name="sequence">5</field>
<field name="company_id" eval="False"/>
<field name="color">6</field>
<field name="country_id" ref="base.ch"/>
</record>
<!-- EG: Egypt -->
<record id="l10n_eg_leave_type_marriage" model="hr.leave.type">
<field name="name">Marriage Leave</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.eg"/>
</record>
<record id="l10n_eg_leave_type_maternity" model="hr.leave.type">
<field name="name">Maternity Leave</field>
<field name="requires_allocation">False</field>
<field name="country_id" ref="base.eg"/>
<field name="company_id" eval="False"/>
</record>
<record id="l10n_eg_leave_type_hajj" model="hr.leave.type">
<field name="name">Hajj Leave</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.eg"/>
</record>
<record id="l10n_eg_leave_type_death" model="hr.leave.type">
<field name="name">Death Leave</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.eg"/>
</record>
<record id="l10n_eg_leave_type_paid_sick_time_off" model="hr.leave.type">
<field name="name">Paid Sick time off</field>
<field name="requires_allocation">True</field>
<field name="employee_requests">no</field>
<field name="country_id" ref="base.eg"/>
</record>
<record id="l10n_eg_leave_type_sick_leave_75" model="hr.leave.type">
<field name="name">Sick Leave (75% Paid)</field>
<field name="requires_allocation">True</field>
<field name="country_id" ref="base.eg"/>
</record>
<record id="l10n_eg_leave_type_sick_leave_unpaid" model="hr.leave.type">
<field name="name">Sick Leave (UnPaid)</field>
<field name="requires_allocation">False</field>
<field name="country_id" ref="base.eg"/>
</record>
<!-- HK : Hong Kong -->
<record id="l10n_hk_leave_type_annual_leave" model="hr.leave.type">
<field name="name">HK Annual Leaves</field>
<field name="requires_allocation">True</field>
<field name="request_unit">half_day</field>
<field name="leave_validation_type">no_validation</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_compensation_leave" model="hr.leave.type">
<field name="name">HK Compensation Leaves</field>
<field name="requires_allocation">True</field>
<field name="request_unit">half_day</field>
<field name="leave_validation_type">no_validation</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_sick_leave" model="hr.leave.type">
<field name="name">HK Sick Leaves</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_sick_leave_80" model="hr.leave.type">
<field name="name">HK Sick Leaves 80%</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_unpaid_leave" model="hr.leave.type">
<field name="name">HK Unpaid Leaves</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_marriage_leave" model="hr.leave.type">
<field name="name">HK Marriage Leaves</field>
<field name="requires_allocation">False</field>
<field name="support_document">True</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_maternity_leave" model="hr.leave.type">
<field name="name">HK Maternity Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_maternity_leave_80" model="hr.leave.type">
<field name="name">HK Maternity Leaves 80%</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_paternity_leave" model="hr.leave.type">
<field name="name">HK Paternity Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_paternity_leave_80" model="hr.leave.type">
<field name="name">HK Paternity Leaves 80%</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_compassionate_leave" model="hr.leave.type">
<field name="name">HK Compassionate Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<record id="l10n_hk_leave_type_examination_leave" model="hr.leave.type">
<field name="name">HK Examination Leaves</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.hk"/>
</record>
<!-- ID : Indonesia -->
<record id="l10n_id_leave_type_annual_leave" model="hr.leave.type">
<field name="name">ID Annual Leaves</field>
<field name="requires_allocation">True</field>
<field name="request_unit">half_day</field>
<field name="leave_validation_type">no_validation</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_sick_leave" model="hr.leave.type">
<field name="name">ID Sick Leaves</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="support_document">True</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_unpaid_leave" model="hr.leave.type">
<field name="name">ID Unpaid Leaves</field>
<field name="requires_allocation">False</field>
<field name="request_unit">half_day</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_marriage_leave" model="hr.leave.type">
<field name="name">ID Marriage Leaves</field>
<field name="requires_allocation">False</field>
<field name="support_document">True</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_maternity_leave" model="hr.leave.type">
<field name="name">ID Maternity Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_paternity_leave" model="hr.leave.type">
<field name="name">ID Paternity Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<record id="l10n_id_leave_type_bereavement_leave" model="hr.leave.type">
<field name="name">ID Bereavement Leaves</field>
<field name="requires_allocation">False</field>
<field name="company_id" eval="False" />
<field name="country_id" ref="base.id"/>
</record>
<!-- JO : Jordan -->
<record id="l10n_jo_leave_type_unpaid_sick" model="hr.leave.type">
<field name="name">Sick Leave (Unpaid)</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">hr</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.jo"/>
</record>
<record id="l10n_jo_leave_type_maternity" model="hr.leave.type">
<field name="name">Maternity Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.jo"/>
</record>
<record id="l10n_jo_leave_type_pilgrimage" model="hr.leave.type">
<field name="name">Pilgrimage Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.jo"/>
</record>
<record id="l10n_jo_leave_type_paternity" model="hr.leave.type">
<field name="name">Paternity Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.jo"/>
</record>
<record id="l10n_jo_leave_type_study" model="hr.leave.type">
<field name="name">Study Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.jo"/>
</record>
<!-- LU : Luxemburg -->
<record id="l10n_lu_leave_type_situational_unemployment" model="hr.leave.type">
<field name="name">Unemployment (Weather / Situational)</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">hour</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_28"/>
<field name="color">5</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.lu"/>
</record>
<!-- MX : Mexico -->
<record id="l10n_mx_leave_type_work_risk_imss" model="hr.leave.type">
<field name="name">Work risk (IMSS)</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">day</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_28"/>
<field name="color">5</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.mx"/>
</record>
<record id="l10n_mx_leave_type_maternity_imss" model="hr.leave.type">
<field name="name">Maternity (IMSS)</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">day</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_17"/>
<field name="color">5</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.mx"/>
</record>
<record id="l10n_mx_leave_type_disability_due_to_illness_imss" model="hr.leave.type">
<field name="name">Disability due to illness (IMSS)</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="allocation_validation_type">hr</field>
<field name="request_unit">day</field>
<field name="unpaid" eval="True"/>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
<field name="responsible_ids" eval="[(4, ref('base.user_admin'))]"/>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="color">5</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.mx"/>
</record>
<!-- SA : Saudi Arabia -->
<record id="l10n_sa_leave_type_sick_leave_100" model="hr.leave.type">
<field name="name">Sick Leave (100% Paid)</field>
<field name="requires_allocation">yes</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_sick_leave_75" model="hr.leave.type">
<field name="name">Sick Leave (75% Paid)</field>
<field name="requires_allocation">yes</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_sick_leave_0" model="hr.leave.type">
<field name="name">Sick Leave (UnPaid)</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_marriage" model="hr.leave.type">
<field name="name">Marriage Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_maternity" model="hr.leave.type">
<field name="name">Maternity Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_iddah" model="hr.leave.type">
<field name="name">Iddah Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_hajj" model="hr.leave.type">
<field name="name">Hajj Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_paternity" model="hr.leave.type">
<field name="name">Paternity Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_study" model="hr.leave.type">
<field name="name">Study Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<record id="l10n_sa_leave_type_emergency" model="hr.leave.type">
<field name="name">Emergency Leave</field>
<field name="requires_allocation">no</field>
<field name="leave_validation_type">hr</field>
<field name="country_id" ref="base.sa"/>
</record>
<!-- SK : Slovakia -->
<record id="l10n_sk_leave_type_maternity" model="hr.leave.type">
<field name="name">Maternity Time Off</field>
<field name="requires_allocation">False</field>
<field name="leave_validation_type">no_validation</field>
<field name="request_unit">half_day</field>
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.sk"/>
</record>
<!-- PL : Poland -->
<record id="l10n_pl_leave_type_sick_leave" model="hr.leave.type">
<field name="name">PL Sick Leaves 80% </field>
<field name="requires_allocation">no</field>
<field name="request_unit">half_day</field>
<field name="support_document">True</field>
<field name="icon_id" ref="hr_holidays.icon_21"/>
<field name="color">6</field>
<field name="company_id" eval="False"/>
<field name="country_id" ref="base.pl"/>
</record>
</data></odoo>

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="icon_1" model="ir.attachment">
<field name="name">Annual_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Annual_Time_Off.svg</field>
</record>
<record id="icon_4" model="ir.attachment">
<field name="name">Compensatory_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Compensatory_Time_Off.svg</field>
</record>
<record id="icon_14" model="ir.attachment">
<field name="name">Paid_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Paid_Time_Off.svg</field>
</record>
<record id="icon_17" model="ir.attachment">
<field name="name">Parental_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Parental_Time_Off.svg</field>
</record>
<record id="icon_19" model="ir.attachment">
<field name="name">Recovery_Bank_Holiday.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Recovery_Bank_Holiday.svg</field>
</record>
<record id="icon_21" model="ir.attachment">
<field name="name">Sick_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Sick_Time_Off.svg</field>
</record>
<record id="icon_26" model="ir.attachment">
<field name="name">Training_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Training_Time_Off.svg</field>
</record>
<record id="icon_28" model="ir.attachment">
<field name="name">Unpaid_Time_Off.svg</field>
<field name="res_model">hr.leave.type</field>
<field name="res_field">icon_id</field>
<field name="public" eval="True"/>
<field name="type">url</field>
<field name="url">/hr_holidays/static/src/img/icons/Unpaid_Time_Off.svg</field>
</record>
</data>
</odoo>

View file

@ -8,7 +8,14 @@
<field name="code">model._update_accrual()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="doall" eval="True"/>
</record>
<record id="hr_leave_cron_cancel_invalid" model="ir.cron">
<field name="name">Time Off: Cancel invalid leaves</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="state">code</field>
<field name="code">model._cancel_invalid_leaves()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
</record>
</odoo>

View file

@ -4,11 +4,14 @@
<!-- Leave specific activities -->
<record id="mail_act_leave_approval" model="mail.activity.type">
<field name="name">Time Off Approval</field>
<field name="summary">Time Off Approval</field>
<field name="icon">fa-sun-o</field>
<field name="res_model">hr.leave</field>
<field name="delay_count">15</field>
</record>
<record id="mail_act_leave_second_approval" model="mail.activity.type">
<field name="name">Time Off Second Approve</field>
<field name="summary">Time Off Second Approve</field>
<field name="icon">fa-sun-o</field>
<field name="res_model">hr.leave</field>
</record>
@ -16,11 +19,14 @@
<!-- Leave specific activities -->
<record id="mail_act_leave_allocation_approval" model="mail.activity.type">
<field name="name">Allocation Approval</field>
<field name="summary">Allocation Approval</field>
<field name="icon">fa-sun-o</field>
<field name="res_model">hr.leave.allocation</field>
</record>
<record id="mail_act_leave_allocation_second_approval" model="mail.activity.type">
<field name="name">Allocation Second Approve</field>
<field name="name">Allocation Second Approval</field>
<field name="summary">Allocation Second Approval</field>
<field name="icon">fa-sun-o</field>
<field name="res_model">hr.leave.allocation</field>
</record>

View file

@ -7,11 +7,6 @@
<field name="res_model">hr.leave</field>
<field name="description">Time Off Request</field>
</record>
<record id="mt_leave_home_working" model="mail.message.subtype">
<field name="name">Home Working</field>
<field name="res_model">hr.leave</field>
<field name="description">Home Working</field>
</record>
<record id="mt_leave_sick" model="mail.message.subtype">
<field name="name">Sick Time Off</field>
<field name="res_model">hr.leave</field>
@ -25,7 +20,7 @@
<!-- Allocation-related subtypes for messaging / Chatter -->
<record id="mt_leave_allocation" model="mail.message.subtype">
<field name="name">Allocation</field>
<field name="name">Allocation Request</field>
<field name="res_model">hr.leave.allocation</field>
<field name="description">Allocation Request</field>
</record>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import resource
from . import hr_employee
from . import hr_employee_public
from . import hr_department
from . import hr_leave
from . import hr_leave_allocation
from . import hr_leave_type
from . import hr_leave_accrual_plan_level
from . import hr_leave_accrual_plan
from . import hr_leave_stress_day
from . import hr_leave_mandatory_day
from . import hr_version
from . import mail_activity_type
from . import mail_message_subtype
from . import res_partner
from . import res_users
from . import calendar_event

View file

@ -0,0 +1,17 @@
from odoo import models
class CalendarEvent(models.Model):
_inherit = 'calendar.event'
def _need_video_call(self):
""" Determine if the event needs a video call or not depending
on the model of the event.
This method, implemented and invoked in google_calendar, is necessary
due to the absence of a bridge module between google_calendar and hr_holidays.
"""
self.ensure_one()
if self.res_model == 'hr.leave':
return False
return super()._need_video_call()

View file

@ -1,16 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from datetime import datetime, timezone
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
from odoo.osv import expression
from odoo import fields, models
from odoo.fields import Domain
import ast
class Department(models.Model):
class HrDepartment(models.Model):
_inherit = 'hr.department'
absence_of_today = fields.Integer(
@ -23,26 +22,26 @@ class Department(models.Model):
def _compute_leave_count(self):
Requests = self.env['hr.leave']
Allocations = self.env['hr.leave.allocation']
today_date = datetime.datetime.utcnow().date()
today_date = datetime.now(timezone.utc).date()
today_start = fields.Datetime.to_string(today_date) # get the midnight of the current utc day
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
leave_data = Requests._read_group(
[('department_id', 'in', self.ids),
('state', '=', 'confirm')],
['department_id'], ['department_id'])
['department_id'], ['__count'])
allocation_data = Allocations._read_group(
[('department_id', 'in', self.ids),
('state', '=', 'confirm')],
['department_id'], ['department_id'])
['department_id'], ['__count'])
absence_data = Requests._read_group(
[('department_id', 'in', self.ids), ('state', 'not in', ['cancel', 'refuse']),
[('department_id', 'in', self.ids), ('state', '=', 'validate'),
('date_from', '<=', today_end), ('date_to', '>=', today_start)],
['department_id'], ['department_id'])
['department_id'], ['__count'])
res_leave = dict((data['department_id'][0], data['department_id_count']) for data in leave_data)
res_allocation = dict((data['department_id'][0], data['department_id_count']) for data in allocation_data)
res_absence = dict((data['department_id'][0], data['department_id_count']) for data in absence_data)
res_leave = {department.id: count for department, count in leave_data}
res_allocation = {department.id: count for department, count in allocation_data}
res_absence = {department.id: count for department, count in absence_data}
for department in self:
department.leave_to_approve_count = res_leave.get(department.id, 0)
@ -63,8 +62,7 @@ class Department(models.Model):
action['context'] = {
**self._get_action_context(),
'search_default_active_time_off': 3,
'hide_employee_name': 1,
'holiday_status_name_get': False
'hide_employee_name': 1
}
return action
@ -72,5 +70,5 @@ class Department(models.Model):
action = self.env["ir.actions.actions"]._for_xml_id("hr_holidays.hr_leave_allocation_action_approve_department")
action['context'] = self._get_action_context()
action['context']['search_default_second_approval'] = 3
action['domain'] = expression.AND([ast.literal_eval(action['domain']), [('state', '=', 'confirm')]])
action['domain'] = Domain.AND([ast.literal_eval(action['domain']), [('state', '=', 'confirm')]])
return action

View file

@ -1,87 +1,71 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from ast import literal_eval
from datetime import date, datetime, time, timedelta, timezone
from collections import defaultdict
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_round
from odoo.addons.resource.models.resource import HOURS_PER_DAY
import pytz
class HrEmployeeBase(models.AbstractModel):
_inherit = "hr.employee.base"
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.addons.resource.models.utils import HOURS_PER_DAY
from odoo.tools.float_utils import float_round
class HrEmployee(models.Model):
_inherit = 'hr.employee'
leave_manager_id = fields.Many2one(
'res.users', string='Time Off',
'res.users', string='Time Off Approver',
compute='_compute_leave_manager', store=True, readonly=False,
domain="[('share', '=', False), ('company_ids', 'in', company_id)]",
help='Select the user responsible for approving "Time Off" of this employee.\n'
'If empty, the approval is done by an Administrator or Approver (determined in settings/users).')
remaining_leaves = fields.Float(
compute='_compute_remaining_leaves', string='Remaining Paid Time Off',
help='Total number of paid time off allocated to this employee, change this value to create allocation/time off request. '
'Total based on all the time off types without overriding limit.')
current_leave_id = fields.Many2one('hr.leave.type', compute='_compute_current_leave', string="Current Time Off Type",
groups="hr.group_hr_user")
current_leave_state = fields.Selection(compute='_compute_leave_status', string="Current Time Off Status",
selection=[
('draft', 'New'),
('confirm', 'Waiting Approval'),
('refuse', 'Refused'),
('validate1', 'Waiting Second Approval'),
('validate', 'Approved'),
('cancel', 'Cancelled')
])
leave_date_from = fields.Date('From Date', compute='_compute_leave_status')
('cancel', 'Cancelled'),
], groups="hr.group_hr_user")
leave_date_from = fields.Date('From Date', compute='_compute_leave_status', groups="hr.group_hr_user")
leave_date_to = fields.Date('To Date', compute='_compute_leave_status')
leaves_count = fields.Float('Number of Time Off', compute='_compute_remaining_leaves')
allocation_count = fields.Float('Total number of days allocated.', compute='_compute_allocation_count')
allocations_count = fields.Integer('Total number of allocations', compute="_compute_allocation_count")
allocation_count = fields.Float('Total number of days allocated.', compute='_compute_allocation_count',
groups="hr.group_hr_user")
allocations_count = fields.Integer('Total number of allocations', compute="_compute_allocation_count",
groups="hr.group_hr_user")
show_leaves = fields.Boolean('Able to see Remaining Time Off', compute='_compute_show_leaves')
is_absent = fields.Boolean('Absent Today', compute='_compute_leave_status', search='_search_absent_employee')
allocation_display = fields.Char(compute='_compute_allocation_count')
allocation_display = fields.Char(compute='_compute_allocation_remaining_display')
allocation_remaining_display = fields.Char(compute='_compute_allocation_remaining_display')
hr_icon_display = fields.Selection(selection_add=[('presence_holiday_absent', 'On leave'),
('presence_holiday_present', 'Present but on leave')])
hr_icon_display = fields.Selection(selection_add=[
('presence_holiday_absent', 'On leave'),
('presence_holiday_present', 'Present but on leave')])
def _get_remaining_leaves(self):
""" Helper to compute the remaining leaves for the current employees
:returns dict where the key is the employee id, and the value is the remain leaves
"""
self._cr.execute("""
SELECT
sum(h.number_of_days) AS days,
h.employee_id
FROM
(
SELECT holiday_status_id, number_of_days,
state, employee_id
FROM hr_leave_allocation
UNION ALL
SELECT holiday_status_id, (number_of_days * -1) as number_of_days,
state, employee_id
FROM hr_leave
) h
join hr_leave_type s ON (s.id=h.holiday_status_id)
WHERE
s.active = true AND h.state='validate' AND
s.requires_allocation='yes' AND
h.employee_id in %s
GROUP BY h.employee_id""", (tuple(self.ids),))
return dict((row['employee_id'], row['days']) for row in self._cr.dictfetchall())
def _compute_current_leave(self):
self.current_leave_id = False
def _compute_remaining_leaves(self):
remaining = {}
if self.ids:
remaining = self._get_remaining_leaves()
for employee in self:
value = float_round(remaining.get(employee.id, 0.0), precision_digits=2)
employee.leaves_count = value
employee.remaining_leaves = value
holidays = self.env['hr.leave'].sudo().search([
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('state', '=', 'validate'),
])
for holiday in holidays:
employee = self.filtered(lambda e: e.id == holiday.employee_id.id)
employee.current_leave_id = holiday.holiday_status_id.id
def _compute_presence_state(self):
super()._compute_presence_state()
employees = self.filtered(lambda employee: employee.hr_presence_state != 'present' and employee.is_absent)
employees.update({'hr_presence_state': 'absent'})
def _compute_allocation_count(self):
# Don't get allocations that are expired
current_date = datetime.date.today()
current_date = date.today()
data = self.env['hr.leave.allocation']._read_group([
('employee_id', 'in', self.ids),
('holiday_status_id.active', '=', True),
@ -91,45 +75,63 @@ class HrEmployeeBase(models.AbstractModel):
'|',
('date_to', '=', False),
('date_to', '>=', current_date),
], ['number_of_days:sum', 'employee_id'], ['employee_id'])
rg_results = dict((d['employee_id'][0], {"employee_id_count": d['employee_id_count'], "number_of_days": d['number_of_days']}) for d in data)
], ['employee_id'], ['__count', 'number_of_days:sum'])
rg_results = {employee.id: (count, days) for employee, count, days in data}
for employee in self:
result = rg_results.get(employee.id)
employee.allocation_count = float_round(result['number_of_days'], precision_digits=2) if result else 0.0
employee.allocation_display = "%g" % employee.allocation_count
employee.allocations_count = result['employee_id_count'] if result else 0.0
count, days = rg_results.get(employee.id, (0, 0))
employee.allocation_count = float_round(days, precision_digits=2)
employee.allocations_count = count
def _compute_allocation_remaining_display(self):
current_date = date.today()
allocations = self.env['hr.leave.allocation'].search([('employee_id', 'in', self.ids)])
leaves_taken = allocations.holiday_status_id._get_employees_days_per_allocation(self.ids)
leaves_taken = self._get_consumed_leaves(allocations.holiday_status_id)[0]
for employee in self:
employee_remaining_leaves = 0
for leave_type in leaves_taken[employee.id]:
if leave_type.requires_allocation == 'no':
employee_max_leaves = 0
for leave_type in leaves_taken[employee]:
if leave_type.requires_allocation == 'no' or leave_type.hide_on_dashboard or not leave_type.active:
continue
for allocation in leaves_taken[employee.id][leave_type]:
if allocation:
virtual_remaining_leaves = leaves_taken[employee.id][leave_type][allocation]['virtual_remaining_leaves']
for allocation in leaves_taken[employee][leave_type]:
if allocation and allocation.date_from <= current_date\
and (not allocation.date_to or allocation.date_to >= current_date):
virtual_remaining_leaves = leaves_taken[employee][leave_type][allocation]['virtual_remaining_leaves']
employee_remaining_leaves += virtual_remaining_leaves\
if leave_type.request_unit in ['day', 'half_day']\
else virtual_remaining_leaves / (employee.resource_calendar_id.hours_per_day or HOURS_PER_DAY)
employee_max_leaves += allocation.number_of_days
employee.allocation_remaining_display = "%g" % float_round(employee_remaining_leaves, precision_digits=2)
def _compute_presence_state(self):
super()._compute_presence_state()
employees = self.filtered(lambda employee: employee.hr_presence_state != 'present' and employee.is_absent)
employees.update({'hr_presence_state': 'absent'})
employee.allocation_display = "%g" % float_round(employee_max_leaves, precision_digits=2)
def _compute_presence_icon(self):
super()._compute_presence_icon()
employees_absent = self.filtered(lambda employee:
employee.hr_presence_state != 'present'
and employee.is_absent)
employees_absent.update({'hr_icon_display': 'presence_holiday_absent'})
employees_present = self.filtered(lambda employee:
employee.hr_presence_state == 'present'
and employee.is_absent)
employees_present.update({'hr_icon_display': 'presence_holiday_present'})
employees_absent = self.filtered(
lambda employee: employee.hr_presence_state != 'present' and employee.is_absent)
employees_absent.update({'hr_icon_display': 'presence_holiday_absent', 'show_hr_icon_display': True})
employees_present = self.filtered(
lambda employee: employee.hr_presence_state == 'present' and employee.is_absent)
employees_present.update({'hr_icon_display': 'presence_holiday_present', 'show_hr_icon_display': True})
def _get_first_working_interval(self, dt):
# find the first working interval after a given date
dt = dt.replace(tzinfo=timezone.utc)
lookahead_days = [7, 30, 90, 180, 365, 730]
work_intervals = None
for lookahead_day in lookahead_days:
periods = self._get_calendar_periods(dt, dt + timedelta(days=lookahead_day))
if not periods:
calendar = self.resource_calendar_id or self.company_id.resource_calendar_id
work_intervals = calendar._work_intervals_batch(
dt, dt + timedelta(days=lookahead_day), resources=self.resource_id)
else:
for period in periods[self]:
start, end, calendar = period
calendar = calendar or self.company_id.resource_calendar_id
work_intervals = calendar._work_intervals_batch(
start, end, resources=self.resource_id)
if work_intervals.get(self.resource_id.id) and work_intervals[self.resource_id.id]._items:
# return start time of the earliest interval
return work_intervals[self.resource_id.id]._items[0][0]
def _compute_leave_status(self):
# Used SUPERUSER_ID to forcefully get status of other user's leave, to bypass record rule
@ -137,20 +139,22 @@ class HrEmployeeBase(models.AbstractModel):
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('holiday_status_id.time_type', '=', 'leave'),
('state', '=', 'validate'),
])
leave_data = {}
for holiday in holidays:
leave_data[holiday.employee_id.id] = {}
leave_data[holiday.employee_id.id]['leave_date_from'] = holiday.date_from.date()
leave_data[holiday.employee_id.id]['leave_date_to'] = holiday.date_to.date()
back_on = holiday.employee_id._get_first_working_interval(holiday.date_to)
leave_data[holiday.employee_id.id]['leave_date_to'] = back_on.date() if back_on else None
leave_data[holiday.employee_id.id]['current_leave_state'] = holiday.state
for employee in self:
employee.leave_date_from = leave_data.get(employee.id, {}).get('leave_date_from')
employee.leave_date_to = leave_data.get(employee.id, {}).get('leave_date_to')
employee.current_leave_state = leave_data.get(employee.id, {}).get('current_leave_state')
employee.is_absent = leave_data.get(employee.id) and leave_data.get(employee.id, {}).get('current_leave_state') in ['validate']
employee.is_absent = leave_data.get(employee.id) and leave_data.get(employee.id).get('current_leave_state') == 'validate'
@api.depends('parent_id')
def _compute_leave_manager(self):
@ -163,7 +167,7 @@ class HrEmployeeBase(models.AbstractModel):
employee.leave_manager_id = False
def _compute_show_leaves(self):
show_leaves = self.env['res.users'].has_group('hr_holidays.group_hr_holidays_user')
show_leaves = self.env.user.has_group('hr_holidays.group_hr_holidays_user')
for employee in self:
if show_leaves or employee.user_id == self.env.user:
employee.show_leaves = True
@ -171,21 +175,19 @@ class HrEmployeeBase(models.AbstractModel):
employee.show_leaves = False
def _search_absent_employee(self, operator, value):
if operator not in ('=', '!=') or not isinstance(value, bool):
raise UserError(_('Operation not supported'))
if operator != 'in':
return NotImplemented
# This search is only used for the 'Absent Today' filter however
# this only returns employees that are absent right now.
today_date = datetime.datetime.utcnow().date()
today_start = fields.Datetime.to_string(today_date)
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
today_start = date.today()
today_end = today_start + timedelta(1)
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
('state', '=', 'validate'),
('date_from', '<=', today_end),
('date_from', '<', today_end),
('date_to', '>=', today_start),
])
operator = ['in', 'not in'][(operator == '=') != value]
return [('id', operator, holidays.mapped('employee_id').ids)]
return [('id', 'in', holidays.employee_id.ids)]
@api.model_create_multi
def create(self, vals_list):
@ -200,10 +202,15 @@ class HrEmployeeBase(models.AbstractModel):
if approver_group and vals.get('leave_manager_id'):
group_updates.append((4, vals['leave_manager_id']))
if group_updates:
approver_group.sudo().write({'users': group_updates})
approver_group.sudo().write({'user_ids': group_updates})
return super().create(vals_list)
def write(self, values):
def write(self, vals):
values = vals
# Prevent the resource calendar of leaves to be updated by a write to
# employee. When this module is enabled the resource calendar of
# leaves are determined by those of the contracts.
self = self.with_context(no_leave_resource_calendar_update=True) # noqa: PLW0642
if 'parent_id' in values:
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
if manager:
@ -218,44 +225,51 @@ class HrEmployeeBase(models.AbstractModel):
old_managers -= leave_manager
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
if approver_group and not leave_manager.has_group('hr_holidays.group_hr_holidays_responsible'):
leave_manager.sudo().write({'groups_id': [(4, approver_group.id)]})
leave_manager.sudo().write({'group_ids': [(4, approver_group.id)]})
res = super(HrEmployeeBase, self).write(values)
res = super().write(values)
# remove users from the Responsible group if they are no longer leave managers
old_managers.sudo()._clean_leave_responsible_users()
# Change the resource calendar of the employee's leaves in the future
# Other modules can disable this behavior by setting the context key
# 'no_leave_resource_calendar_update'
if 'resource_calendar_id' in values and not self.env.context.get('no_leave_resource_calendar_update'):
try:
leaves = self.env['hr.leave'].search([
('employee_id', 'in', self.ids),
('resource_calendar_id', '!=', int(values['resource_calendar_id'])),
('date_from', '>', fields.Datetime.now())])
leaves.write({'resource_calendar_id': values['resource_calendar_id']})
non_hourly_leaves = leaves.filtered(lambda l: not l.request_unit_hours)
non_hourly_leaves.with_context(leave_skip_date_check=True, leave_skip_state_check=True)._compute_date_from_to()
non_hourly_leaves.filtered(lambda l: l.state == 'validate')._validate_leave_request()
except ValidationError:
raise ValidationError(_("Changing this working schedule results in the affected employee(s) not having enough "
"leaves allocated to accomodate for their leaves already taken in the future. Please "
"review this employee's leaves and adjust their allocation accordingly."))
if 'parent_id' in values or 'department_id' in values:
today_date = fields.Datetime.now()
hr_vals = {}
if values.get('parent_id') is not None:
hr_vals['manager_id'] = values['parent_id']
if values.get('department_id') is not None:
hr_vals['department_id'] = values['department_id']
holidays = self.env['hr.leave'].sudo().search(['|', ('state', 'in', ['draft', 'confirm']), ('date_from', '>', today_date), ('employee_id', 'in', self.ids)])
holidays = self.env['hr.leave'].sudo().search([
'|',
('state', '=', 'confirm'),
('date_from', '>', today_date),
('employee_id', 'in', self.ids),
])
holidays.write(hr_vals)
allocations = self.env['hr.leave.allocation'].sudo().search([('state', 'in', ['draft', 'confirm']), ('employee_id', 'in', self.ids)])
if values.get('parent_id') is not None:
hr_vals['manager_id'] = values['parent_id']
allocations = self.env['hr.leave.allocation'].sudo().search([
('state', '=', 'confirm'),
('employee_id', 'in', self.ids),
])
allocations.write(hr_vals)
return res
class HrEmployee(models.Model):
_inherit = 'hr.employee'
current_leave_id = fields.Many2one('hr.leave.type', compute='_compute_current_leave', string="Current Time Off Type",
groups="hr.group_hr_user")
def _compute_current_leave(self):
self.current_leave_id = False
holidays = self.env['hr.leave'].sudo().search([
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('state', '=', 'validate'),
])
for holiday in holidays:
employee = self.filtered(lambda e: e.id == holiday.employee_id.id)
employee.current_leave_id = holiday.holiday_status_id.id
def _get_user_m2o_to_empty_on_archived_employees(self):
return super()._get_user_m2o_to_empty_on_archived_employees() + ['leave_manager_id']
@ -271,31 +285,23 @@ class HrEmployee(models.Model):
},
}
def _get_contextual_employee(self):
if self.env.context.get('employee_id'):
return self.browse(self.env.context['employee_id'])
return self.env.user.employee_id
def _is_leave_user(self):
return self == self.env.user.employee_id and self.user_has_groups('hr_holidays.group_hr_holidays_user')
def get_stress_days(self, start_date, end_date):
def get_mandatory_days(self, start_date, end_date):
all_days = {}
self = self or self.env.user.employee_id
stress_days = self._get_stress_days(start_date, end_date)
for stress_day in stress_days:
num_days = (stress_day.end_date - stress_day.start_date).days
mandatory_days = self._get_mandatory_days(start_date, end_date)
for mandatory_day in mandatory_days:
num_days = (mandatory_day.end_date - mandatory_day.start_date).days
for d in range(num_days + 1):
all_days[str(stress_day.start_date + relativedelta(days=d))] = stress_day.color
all_days[str(mandatory_day.start_date + relativedelta(days=d))] = mandatory_day.color
return all_days
@api.model
def get_special_days_data(self, date_start, date_end):
return {
'stressDays': self.get_stress_days_data(date_start, date_end),
'mandatoryDays': self.get_mandatory_days_data(date_start, date_end),
'bankHolidays': self.get_public_holidays_data(date_start, date_end),
}
@ -307,14 +313,30 @@ class HrEmployee(models.Model):
return list(map(lambda bh: {
'id': -bh.id,
'colorIndex': 0,
'end': datetime.datetime.combine(bh.date_to.astimezone(employee_tz), datetime.datetime.max.time()).isoformat(),
'end': datetime.combine(bh.date_to.astimezone(employee_tz), datetime.max.time()).isoformat(),
'endType': "datetime",
'isAllDay': True,
'start': datetime.datetime.combine(bh.date_from.astimezone(employee_tz), datetime.datetime.min.time()).isoformat(),
'start': datetime.combine(bh.date_from.astimezone(employee_tz), datetime.min.time()).isoformat(),
'startType': "datetime",
'title': bh.name,
}, public_holidays))
@api.model
def get_time_off_dashboard_data(self, target_date=None):
dashboard_data = {}
dashboard_data['has_accrual_allocation'] = self.env['hr.leave.type'].has_accrual_allocation()
dashboard_data['allocation_data'] = self.env['hr.leave.type'].get_allocation_data_request(target_date, False)
dashboard_data['allocation_request_amount'] = self.get_allocation_requests_amount()
return dashboard_data
@api.model
def get_allocation_requests_amount(self):
employee = self._get_contextual_employee()
return self.env['hr.leave.allocation'].search_count([
('employee_id', '=', employee.id),
('state', '=', 'confirm'),
])
def _get_public_holidays(self, date_start, date_end):
domain = [
('resource_id', '=', False),
@ -329,37 +351,272 @@ class HrEmployee(models.Model):
return self.env['resource.calendar.leaves'].search(domain)
@api.model
def get_stress_days_data(self, date_start, date_end):
self = self._get_contextual_employee()
stress_days = self._get_stress_days(date_start, date_end).sorted('start_date')
return list(map(lambda sd: {
def get_mandatory_days_data(self, date_start, date_end):
self_with_context = self._get_contextual_employee()
if isinstance(date_start, str):
date_start = datetime.fromisoformat(date_start).replace(tzinfo=None)
elif isinstance(date_start, datetime):
date_start = date_start.replace(tzinfo=None)
if isinstance(date_end, str):
date_end = datetime.fromisoformat(date_end).replace(tzinfo=None)
elif isinstance(date_end, datetime):
date_end = date_end.replace(tzinfo=None)
mandatory_days = self_with_context._get_mandatory_days(date_start, date_end).sorted('start_date')
return [{
'id': -sd.id,
'colorIndex': sd.color,
'end': datetime.datetime.combine(sd.end_date, datetime.datetime.max.time()).isoformat(),
'end': datetime.combine(sd.end_date, datetime.max.time()).isoformat(),
'endType': "datetime",
'isAllDay': True,
'start': datetime.datetime.combine(sd.start_date, datetime.datetime.min.time()).isoformat(),
'start': datetime.combine(sd.start_date, datetime.min.time()).isoformat(),
'startType': "datetime",
'title': sd.name,
}, stress_days))
} for sd in mandatory_days]
def _get_stress_days(self, start_date, end_date):
def _get_mandatory_days(self, start_date, end_date):
domain = [
('start_date', '<=', end_date),
('end_date', '>=', start_date),
('company_id', 'in', self.env.companies.ids),
'|',
('resource_calendar_id', '=', False),
('resource_calendar_id', '=', self.resource_calendar_id.id),
('resource_calendar_id', 'in', self.resource_calendar_id.ids),
]
if self.job_id:
domain += [
('job_ids', 'in', [False] + self.job_id.ids),
]
if self.department_id:
department_ids = self.department_id.ids
domain += [
'|',
('department_ids', '=', False),
('department_ids', 'parent_of', self.department_id.id),
('department_ids', 'parent_of', department_ids),
]
else:
domain += [('department_ids', '=', False)]
return self.env['hr.leave.stress.day'].search(domain)
return self.env['hr.leave.mandatory.day'].search(domain)
@api.model
def _get_contextual_employee(self):
ctx = self.env.context
if self.env.context.get('employee_id') is not None:
return self.browse(ctx.get('employee_id'))
if self.env.context.get('default_employee_id') is not None:
return self.browse(ctx.get('default_employee_id'))
return self.env.user.employee_id
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'),
])
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.holiday_status_id.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 ['day', 'half_day']:
leave_duration_field = 'number_of_days'
leave_unit = 'days'
else:
leave_duration_field = 'number_of_hours'
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 leave.date_from.date() > target_date and sorted_leave_allocations.filtered(lambda a:
a.allocation_type == 'accrual' and
(not a.date_to or a.date_to >= target_date) and
a.date_from <= leave.date_to.date()
):
to_recheck_leaves_per_leave_type[employee][leave_type]['to_recheck_leaves'] |= leave
skip_excess = True
continue
if leave_type.requires_allocation:
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
else:
allocated_time = leave.number_of_days
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 == 'hour' 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)
def _get_hours_per_day(self, date_from):
''' Return 24H to handle the case of Fully Flexible (ones without a working calendar)'''
if not self:
return 0
calendars = self._get_calendars(date_from)
return calendars[self.id].hours_per_day if calendars[self.id] else 24
def _get_store_avatar_card_fields(self, target):
return [*super()._get_store_avatar_card_fields(target), "leave_date_to"]

View file

@ -0,0 +1,69 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, timedelta
from odoo import fields, models
class HrEmployeePublic(models.Model):
_inherit = 'hr.employee.public'
leave_manager_id = fields.Many2one(
'res.users', string='Time Off Approver',
compute='_compute_leave_manager', store=True, readonly=False,
domain="[('share', '=', False), ('company_ids', 'in', company_id)]",
help='Select the user responsible for approving "Time Off" of this employee.\n'
'If empty, the approval is done by an Administrator or Approver (determined in settings/users).')
leave_date_to = fields.Date('To Date', compute='_compute_leave_status')
show_leaves = fields.Boolean('Able to see Remaining Time Off', compute='_compute_show_leaves')
is_absent = fields.Boolean('Absent Today', compute='_compute_leave_status', search='_search_absent_employee')
allocation_display = fields.Char(compute='_compute_allocation_display')
allocation_remaining_display = fields.Char(related='employee_id.allocation_remaining_display')
def _compute_show_leaves(self):
self._compute_from_employee('show_leaves')
def _compute_leave_manager(self):
self._compute_from_employee('leave_manager_id')
def _compute_leave_status(self):
self._compute_from_employee(['leave_date_to', 'is_absent'])
def _search_absent_employee(self, operator, value):
if operator != 'in':
return NotImplemented
# This search is only used for the 'Absent Today' filter however
# this only returns employees that are absent right now.
today_start = date.today()
today_end = today_start + timedelta(1)
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
('state', '=', 'validate'),
('date_from', '<', today_end),
('date_to', '>=', today_start),
])
return [('id', 'in', holidays.employee_id.ids)]
def _compute_allocation_display(self):
self._compute_from_employee('allocation_display')
def action_time_off_dashboard(self):
self.ensure_one()
if self.is_user:
return self.employee_id.action_time_off_dashboard()
def action_open_time_off_calendar(self):
"""Open the time off calendar filtered on this employee."""
self.ensure_one()
action = self.env.ref('hr_holidays.action_my_days_off_dashboard_calendar').sudo().read()[0]
action['domain'] = [('employee_id', '=', self.id)]
ctx = ({
'active_employee_id': self.id,
'search_default_employee_id': [self.id],
'search_default_my_leaves': 0,
'search_default_team': 0,
'search_default_current_year': 1,
'hide_employee_name': 1,
})
action['context'] = ctx
return action

View file

@ -1,28 +1,67 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from calendar import monthrange
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from odoo.addons.hr_holidays.models.hr_leave_accrual_plan_level import _get_selection_days
class AccrualPlan(models.Model):
_name = "hr.leave.accrual.plan"
class HrLeaveAccrualPlan(models.Model):
_name = 'hr.leave.accrual.plan'
_description = "Accrual Plan"
active = fields.Boolean(default=True)
name = fields.Char('Name', required=True)
time_off_type_id = fields.Many2one('hr.leave.type', string="Time Off Type",
check_company=True, index='btree_not_null',
help="""Specify if this accrual plan can only be used with this Time Off Type.
Leave empty if this accrual plan can be used with any Time Off Type.""")
employees_count = fields.Integer("Employees", compute='_compute_employee_count')
level_ids = fields.One2many('hr.leave.accrual.level', 'accrual_plan_id', copy=True)
allocation_ids = fields.One2many('hr.leave.allocation', 'accrual_plan_id')
level_ids = fields.One2many('hr.leave.accrual.level', 'accrual_plan_id', copy=True, string="Milestones")
allocation_ids = fields.One2many('hr.leave.allocation', 'accrual_plan_id',
export_string_translation=False)
company_id = fields.Many2one('res.company', string='Company', domain=lambda self: [('id', 'in', self.env.companies.ids)],
compute="_compute_company_id", store="True", readonly=False)
transition_mode = fields.Selection([
('immediately', 'Immediately'),
('end_of_accrual', "After this accrual's period")],
string="Level Transition", default="immediately", required=True,
help="""Immediately: When the date corresponds to the new level, your accrual is automatically computed, granted and you switch to new level
After this accrual's period: When the accrual is complete (a week, a month), and granted, you switch to next level if allocation date corresponds""")
show_transition_mode = fields.Boolean(compute='_compute_show_transition_mode')
export_string_translation=False, default="immediately", required=True)
show_transition_mode = fields.Boolean(compute='_compute_show_transition_mode', export_string_translation=False)
is_based_on_worked_time = fields.Boolean(compute="_compute_is_based_on_worked_time", store=True, readonly=False,
export_string_translation=False,
help="Only excludes requests where the time off type is set as unpaid kind of.")
accrued_gain_time = fields.Selection([
("start", "At the start of the accrual period"),
("end", "At the end of the accrual period")],
export_string_translation=False,
default="end", required=True)
can_be_carryover = fields.Boolean(export_string_translation=False)
carryover_date = fields.Selection([
("year_start", "At the start of the year"),
("allocation", "At the allocation date"),
("other", "Custom date")],
export_string_translation=False,
default="year_start", required=True, string="Carry-Over Time")
carryover_day = fields.Selection(
_get_selection_days, compute='_compute_carryover_day',
export_string_translation=False, store=True, readonly=False, default='1')
carryover_month = fields.Selection([
("1", "January"),
("2", "February"),
("3", "March"),
("4", "April"),
("5", "May"),
("6", "June"),
("7", "July"),
("8", "August"),
("9", "September"),
("10", "October"),
("11", "November"),
("12", "December")
], export_string_translation=False, default=lambda self: str((fields.Date.today()).month))
added_value_type = fields.Selection([('day', 'Days'), ('hour', 'Hours')],
export_string_translation=False, default="day", store=True)
@api.depends('level_ids')
def _compute_show_transition_mode(self):
@ -35,10 +74,10 @@ class AccrualPlan(models.Model):
def _compute_level_count(self):
level_read_group = self.env['hr.leave.accrual.level']._read_group(
[('accrual_plan_id', 'in', self.ids)],
fields=['accrual_plan_id'],
groupby=['accrual_plan_id'],
aggregates=['__count'],
)
mapped_count = {group['accrual_plan_id'][0]: group['accrual_plan_id_count'] for group in level_read_group}
mapped_count = {accrual_plan.id: count for accrual_plan, count in level_read_group}
for plan in self:
plan.level_count = mapped_count.get(plan.id, 0)
@ -46,29 +85,76 @@ class AccrualPlan(models.Model):
def _compute_employee_count(self):
allocations_read_group = self.env['hr.leave.allocation']._read_group(
[('accrual_plan_id', 'in', self.ids)],
['accrual_plan_id', 'employee_count:count_distinct(employee_id)'],
['accrual_plan_id'],
['employee_id:count_distinct'],
)
allocations_dict = {res['accrual_plan_id'][0]: res['employee_count'] for res in allocations_read_group}
allocations_dict = {accrual_plan.id: count for accrual_plan, count in allocations_read_group}
for plan in self:
plan.employees_count = allocations_dict.get(plan.id, 0)
@api.depends('time_off_type_id.company_id')
def _compute_company_id(self):
for accrual_plan in self:
if accrual_plan.time_off_type_id:
accrual_plan.company_id = accrual_plan.time_off_type_id.company_id
else:
accrual_plan.company_id = self.env.company
@api.depends("accrued_gain_time")
def _compute_is_based_on_worked_time(self):
for plan in self:
if plan.accrued_gain_time == "start":
plan.is_based_on_worked_time = False
@api.depends("carryover_month")
def _compute_carryover_day(self):
for plan in self:
# 2020 is a leap year, so monthrange(2020, february) will return [2, 29]
plan.carryover_day = str(min(monthrange(2020, int(plan.carryover_month))[1], int(plan.carryover_day)))
def action_open_accrual_plan_employees(self):
self.ensure_one()
return {
'name': _("Accrual Plan's Employees"),
'type': 'ir.actions.act_window',
'view_mode': 'kanban,tree,form',
'view_mode': 'kanban,list,form',
'res_model': 'hr.employee',
'domain': [('id', 'in', self.allocation_ids.employee_id.ids)],
}
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
default = dict(default or {},
name=_("%s (copy)", self.name))
return super().copy(default=default)
def action_create_accrual_plan_level(self):
return {
'name': self.env._('New Milestone'),
'type': 'ir.actions.act_window',
'res_model': 'hr.leave.accrual.level',
'view_mode': 'form',
'views': [[False, 'form']],
'view_id': self.env.ref('hr_holidays.hr_accrual_level_view_form').id,
'target': 'new',
'context': dict(
self.env.context,
new=True,
default_can_be_carryover=self.can_be_carryover,
default_accrued_gain_time=self.accrued_gain_time,
default_can_modify_value_type=not self.time_off_type_id and not self.level_ids,
default_added_value_type=self.added_value_type,
),
}
def action_open_accrual_plan_level(self, level_id):
return {
'name': self.env._('Milestone Edition'),
'type': 'ir.actions.act_window',
'res_model': 'hr.leave.accrual.level',
'view_mode': 'form',
'views': [[False, 'form']],
'target': 'new',
'res_id': level_id,
}
def copy_data(self, default=None):
vals_list = super().copy_data(default=default)
return [dict(vals, name=self.env._("%s (copy)", plan.name)) for plan, vals in zip(self, vals_list)]
@api.ondelete(at_uninstall=False)
def _prevent_used_plan_unlink(self):
@ -81,3 +167,10 @@ class AccrualPlan(models.Model):
raise ValidationError(_(
"Some of the accrual plans you're trying to delete are linked to an existing allocation. Delete or cancel them first."
))
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("name", False):
vals['name'] = self.env._("Unnamed Plan")
return super().create(vals_list)

View file

@ -1,54 +1,49 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
import calendar
from calendar import monthrange
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.tools.date_utils import get_timedelta
from odoo.exceptions import ValidationError, UserError
DAYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
# Used for displaying the days and reversing selection -> integer
DAY_SELECT_VALUES = [str(i) for i in range(1, 29)] + ['last']
DAY_SELECT_SELECTION_NO_LAST = tuple(zip(DAY_SELECT_VALUES, (str(i) for i in range(1, 29))))
def _get_selection_days(self):
return DAY_SELECT_SELECTION_NO_LAST + (("last", _("last day")),)
return [(str(i), str(i)) for i in range(1, 32)]
class AccrualPlanLevel(models.Model):
_name = "hr.leave.accrual.level"
class HrLeaveAccrualLevel(models.Model):
_name = 'hr.leave.accrual.level'
_description = "Accrual Plan Level"
_order = 'sequence asc'
sequence = fields.Integer(
string='sequence', compute='_compute_sequence', store=True,
help='Sequence is generated automatically by start time delta.')
accrual_plan_id = fields.Many2one('hr.leave.accrual.plan', "Accrual Plan", required=True)
start_count = fields.Integer(
"Start after",
help="The accrual starts after a defined period from the allocation start date. This field defines the number of days, months or years after which accrual is used.", default="1")
accrual_plan_id = fields.Many2one('hr.leave.accrual.plan', "Accrual Plan", required=True, index=True, ondelete="cascade", default=lambda self: self.env.context.get("active_id", None))
accrued_gain_time = fields.Selection(related='accrual_plan_id.accrued_gain_time', export_string_translation=False)
start_count = fields.Integer(export_string_translation=False,
help="The accrual starts after a defined period from the allocation start date. This field defines the number of days, months or years after which accrual is used.")
start_type = fields.Selection(
[('day', 'day(s)'),
('month', 'month(s)'),
('year', 'year(s)')],
default='day', string=" ", required=True,
[('day', 'Days'),
('month', 'Months'),
('year', 'Years')],
default='day', required=True, export_string_translation=False,
help="This field defines the unit of time after which the accrual starts.")
is_based_on_worked_time = fields.Boolean("Based on worked time",
help="If checked, the rate will be prorated on time off type where type is set on Working Time in the configuration.")
milestone_date = fields.Selection(
[('creation', 'At allocation creation'),
('after', 'After')],
compute='_compute_milestone_date', inverse='_inverse_milestone_date', readonly=False,
store=True, export_string_translation=False,
default='creation', required=True
)
# Accrue of
added_value = fields.Float(
"Rate", digits=(16, 5), required=True,
help="The number of hours/days that will be incremented in the specified Time Off Type for every period")
added_value_type = fields.Selection(
[('days', 'Days'),
('hours', 'Hours')],
default='days', required=True)
added_value = fields.Float(digits=(16, 5), required=True, default=1, export_string_translation=False)
added_value_type = fields.Selection([
('day', 'Day(s)'),
('hour', 'Hour(s)')
], compute="_compute_added_value_type", inverse="_inverse_added_value_type", precompute=True, store=True, required=True,
readonly=False, export_string_translation=False)
frequency = fields.Selection([
('hourly', 'Hourly'),
('daily', 'Daily'),
('weekly', 'Weekly'),
('bimonthly', 'Twice a month'),
@ -57,85 +52,136 @@ class AccrualPlanLevel(models.Model):
('yearly', 'Yearly'),
], default='daily', required=True, string="Frequency")
week_day = fields.Selection([
('mon', 'Monday'),
('tue', 'Tuesday'),
('wed', 'Wednesday'),
('thu', 'Thursday'),
('fri', 'Friday'),
('sat', 'Saturday'),
('sun', 'Sunday'),
], default='mon', required=True, string="Allocation on")
first_day = fields.Integer(default=1)
first_day_display = fields.Selection(
_get_selection_days, compute='_compute_days_display', inverse='_inverse_first_day_display')
second_day = fields.Integer(default=15)
second_day_display = fields.Selection(
_get_selection_days, compute='_compute_days_display', inverse='_inverse_second_day_display')
first_month_day = fields.Integer(default=1)
first_month_day_display = fields.Selection(
_get_selection_days, compute='_compute_days_display', inverse='_inverse_first_month_day_display')
('0', 'Monday'),
('1', 'Tuesday'),
('2', 'Wednesday'),
('3', 'Thursday'),
('4', 'Friday'),
('5', 'Saturday'),
('6', 'Sunday'),
], default='0', required=True, string="Allocation on")
first_day = fields.Selection(_get_selection_days, default='1', export_string_translation=False)
second_day = fields.Selection(_get_selection_days, default='15', export_string_translation=False)
first_month_day = fields.Selection(
_get_selection_days, compute='_compute_first_month_day', store=True, readonly=False, default='1',
export_string_translation=False)
first_month = fields.Selection([
('jan', 'January'),
('feb', 'February'),
('mar', 'March'),
('apr', 'April'),
('may', 'May'),
('jun', 'June'),
], default="jan")
second_month_day = fields.Integer(default=1)
second_month_day_display = fields.Selection(
_get_selection_days, compute='_compute_days_display', inverse='_inverse_second_month_day_display')
('1', 'January'),
('2', 'February'),
('3', 'March'),
('4', 'April'),
('5', 'May'),
('6', 'June'),
], default="1", export_string_translation=False)
second_month_day = fields.Selection(
_get_selection_days, compute='_compute_second_month_day', store=True, readonly=False, default='1',
export_string_translation=False)
second_month = fields.Selection([
('jul', 'July'),
('aug', 'August'),
('sep', 'September'),
('oct', 'October'),
('nov', 'November'),
('dec', 'December')
], default="jul")
('7', 'July'),
('8', 'August'),
('9', 'September'),
('10', 'October'),
('11', 'November'),
('12', 'December')
], default="7", export_string_translation=False)
yearly_month = fields.Selection([
('jan', 'January'),
('feb', 'February'),
('mar', 'March'),
('apr', 'April'),
('may', 'May'),
('jun', 'June'),
('jul', 'July'),
('aug', 'August'),
('sep', 'September'),
('oct', 'October'),
('nov', 'November'),
('dec', 'December')
], default="jan")
yearly_day = fields.Integer(default=1)
yearly_day_display = fields.Selection(
_get_selection_days, compute='_compute_days_display', inverse='_inverse_yearly_day_display')
('1', 'January'),
('2', 'February'),
('3', 'March'),
('4', 'April'),
('5', 'May'),
('6', 'June'),
('7', 'July'),
('8', 'August'),
('9', 'September'),
('10', 'October'),
('11', 'November'),
('12', 'December')
], default="1", export_string_translation=False)
yearly_day = fields.Selection(
_get_selection_days, compute='_compute_yearly_day', store=True, readonly=False, default='1',
export_string_translation=False)
cap_accrued_time = fields.Boolean(export_string_translation=False,
help="When the field is checked the balance of an allocation using this accrual plan will never exceed the specified amount.")
maximum_leave = fields.Float(
'Limit to', required=False, default=100,
help="Choose a cap for this accrual. 0 means no cap.")
parent_id = fields.Many2one(
'hr.leave.accrual.level', string="Previous Level",
help="If this field is empty, this level is the first one.")
digits=(16, 2), compute="_compute_maximum_leave", default=0, readonly=False, store=True,
help="Choose a cap for this accrual.", export_string_translation=False)
cap_accrued_time_yearly = fields.Boolean(export_string_translation=False,
store=True, readonly=False,
help="When the field is checked the total amount accrued each year will be capped at the specified amount")
maximum_leave_yearly = fields.Float(digits=(16, 2), export_string_translation=False)
can_be_carryover = fields.Boolean(related='accrual_plan_id.can_be_carryover', readonly=True,
export_string_translation=False)
action_with_unused_accruals = fields.Selection(
[('postponed', 'Transferred to the next year'),
('lost', 'Lost')],
string="At the end of the calendar year, unused accruals will be",
default='postponed', required='True')
postpone_max_days = fields.Integer("Maximum amount of accruals to transfer",
help="Set a maximum of days an allocation keeps at the end of the year. 0 for no limit.")
[('lost', 'Lost'),
('all', 'Carried over')],
compute="_compute_action_with_unused_accruals",
store=True,
export_string_translation=False,
default='lost', required=True,
help="When the Carry-Over Time is reached, according to Plan's setting, select what you want "
"to happen with the unused time off: Lost (time will be reset to zero), Carried over (accrued time carried over to "
"the next period.)")
carryover_options = fields.Selection(
[('unlimited', 'Unlimited'),
('limited', 'Up to')],
store=True, readonly=False,
export_string_translation=False,
compute="_compute_carryover_options",
default='unlimited', required=True,
help="You can limit the accrued time carried over for the next period."
)
postpone_max_days = fields.Integer(export_string_translation=False,
help="Set a maximum of accruals an allocation keeps at the end of the year.")
can_modify_value_type = fields.Boolean(compute="_compute_can_modify_value_type", default=False,
export_string_translation=False)
accrual_validity = fields.Boolean(export_string_translation=False, compute="_compute_accrual_validity", store=True, readonly=False)
accrual_validity_count = fields.Integer(
export_string_translation=False,
help="You can define a period of time where the days carried over will be available", default="1")
accrual_validity_type = fields.Selection(
[('day', 'Days'),
('month', 'Months')],
default='day', export_string_translation=False, required=True,
help="This field defines the unit of time after which the accrual ends.")
_sql_constraints = [
('check_dates',
"CHECK( (frequency = 'daily') or"
"(week_day IS NOT NULL AND frequency = 'weekly') or "
"(first_day > 0 AND second_day > first_day AND first_day <= 31 AND second_day <= 31 AND frequency = 'bimonthly') or "
"(first_day > 0 AND first_day <= 31 AND frequency = 'monthly')or "
"(first_month_day > 0 AND first_month_day <= 31 AND second_month_day > 0 AND second_month_day <= 31 AND frequency = 'biyearly') or "
"(yearly_day > 0 AND yearly_day <= 31 AND frequency = 'yearly'))",
"The dates you've set up aren't correct. Please check them."),
('start_count_check', "CHECK( start_count >= 0 )", "You can not start an accrual in the past."),
('added_value_greater_than_zero', 'CHECK(added_value > 0)', 'You must give a rate greater than 0 in accrual plan levels.')
]
_start_count_check = models.Constraint(
"CHECK((start_count > 0 AND milestone_date = 'after') OR (start_count = 0 AND milestone_date = 'creation'))",
'You can not start an accrual in the past.',
)
_added_value_greater_than_zero = models.Constraint(
'CHECK(added_value > 0)',
'You must give a rate greater than 0 in accrual plan levels.',
)
_valid_postpone_max_days_value = models.Constraint(
"CHECK(action_with_unused_accruals <> 'all' OR carryover_options <> 'limited' OR COALESCE(postpone_max_days, 0) > 0)",
'You cannot have a maximum quantity to carryover set to 0.',
)
_valid_accrual_validity_value = models.Constraint(
'CHECK(accrual_validity IS NOT TRUE OR COALESCE(accrual_validity_count, 0) > 0)',
'You cannot have an accrual validity time set to 0.',
)
_valid_yearly_cap_value = models.Constraint(
'CHECK(cap_accrued_time_yearly IS NOT TRUE OR COALESCE(maximum_leave_yearly, 0) > 0)',
'You cannot have a cap on yearly accrued time without setting a maximum amount.',
)
@api.constrains('first_day', 'second_day', 'week_day', 'frequency')
def _check_dates(self):
error_message = ''
for level in self:
if level.frequency == 'weekly' and not level.week_day:
error_message = _("Weekday must be selected to use the frequency weekly")
elif level.frequency == 'bimonthly' and int(level.first_day) >= int(level.second_day):
error_message = _("The first day must be lower than the second day.")
if error_message:
raise ValidationError(error_message)
@api.constrains('cap_accrued_time', 'maximum_leave')
def _check_maximum_leaves(self):
for level in self:
if level.cap_accrued_time and level.maximum_leave <= 0:
raise UserError(self.env._("You cannot have a balance cap on accrued time set to 0."))
@api.depends('start_count', 'start_type')
def _compute_sequence(self):
@ -148,97 +194,124 @@ class AccrualPlanLevel(models.Model):
for level in self:
level.sequence = level.start_count * start_type_multipliers[level.start_type]
@api.depends('first_day', 'second_day', 'first_month_day', 'second_month_day', 'yearly_day')
def _compute_days_display(self):
days_select = _get_selection_days(self)
@api.depends('accrual_plan_id', 'accrual_plan_id.level_ids', 'accrual_plan_id.time_off_type_id')
def _compute_can_modify_value_type(self):
for level in self:
level.first_day_display = days_select[min(level.first_day - 1, 28)][0]
level.second_day_display = days_select[min(level.second_day - 1, 28)][0]
level.first_month_day_display = days_select[min(level.first_month_day - 1, 28)][0]
level.second_month_day_display = days_select[min(level.second_month_day - 1, 28)][0]
level.yearly_day_display = days_select[min(level.yearly_day - 1, 28)][0]
level.can_modify_value_type = not level.accrual_plan_id.time_off_type_id and level.accrual_plan_id.level_ids and level.accrual_plan_id.level_ids[0] == level
def _inverse_first_day_display(self):
def _inverse_added_value_type(self):
for level in self:
if level.first_day_display == 'last':
level.first_day = 31
else:
level.first_day = DAY_SELECT_VALUES.index(level.first_day_display) + 1
if level.accrual_plan_id.level_ids[0] == level:
level.accrual_plan_id.added_value_type = level.added_value_type
def _inverse_second_day_display(self):
@api.depends('accrual_plan_id', 'accrual_plan_id.level_ids', 'accrual_plan_id.added_value_type', 'accrual_plan_id.time_off_type_id')
def _compute_added_value_type(self):
for level in self:
if level.second_day_display == 'last':
level.second_day = 31
else:
level.second_day = DAY_SELECT_VALUES.index(level.second_day_display) + 1
if level.accrual_plan_id.time_off_type_id:
level.added_value_type = "day" if level.accrual_plan_id.time_off_type_id.request_unit in ["day", "half_day"] else "hour"
elif level.accrual_plan_id.level_ids and level.accrual_plan_id.level_ids[0] != level:
level.added_value_type = level.accrual_plan_id.level_ids[0].added_value_type
elif not level.added_value_type:
level.added_value_type = "day" # default value
def _inverse_first_month_day_display(self):
def _set_day(self, day_field, month_field):
for level in self:
if level.first_month_day_display == 'last':
level.first_month_day = 31
else:
level.first_month_day = DAY_SELECT_VALUES.index(level.first_month_day_display) + 1
# 2020 is a leap year, so monthrange(2020, february) will return [2, 29]
level[day_field] = str(min(monthrange(2020, int(level[month_field]))[1], int(level[day_field])))
def _inverse_second_month_day_display(self):
for level in self:
if level.second_month_day_display == 'last':
level.second_month_day = 31
else:
level.second_month_day = DAY_SELECT_VALUES.index(level.second_month_day_display) + 1
@api.depends("first_month")
def _compute_first_month_day(self):
self._set_day("first_month_day", "first_month")
def _inverse_yearly_day_display(self):
@api.depends("second_month")
def _compute_second_month_day(self):
self._set_day("second_month_day", "second_month")
@api.depends("yearly_month")
def _compute_yearly_day(self):
self._set_day("yearly_day", "yearly_month")
@api.depends('cap_accrued_time')
def _compute_maximum_leave(self):
for level in self:
if level.yearly_day_display == 'last':
level.yearly_day = 31
else:
level.yearly_day = DAY_SELECT_VALUES.index(level.yearly_day_display) + 1
if not level.cap_accrued_time:
level.maximum_leave = 0
@api.depends('can_be_carryover')
def _compute_action_with_unused_accruals(self):
for level in self:
if not level.can_be_carryover:
level.action_with_unused_accruals = 'lost'
@api.depends('action_with_unused_accruals')
def _compute_carryover_options(self):
for level in self:
if level.action_with_unused_accruals == 'lost':
level.carryover_options = 'unlimited'
@api.depends('action_with_unused_accruals')
def _compute_accrual_validity(self):
for level in self:
if level.action_with_unused_accruals == 'lost':
level.accrual_validity = False
@api.depends('start_count', 'milestone_date')
def _compute_milestone_date(self):
for level in self:
if level.start_count == 0:
level.milestone_date = 'creation'
def _inverse_milestone_date(self):
for level in self:
if level.milestone_date == 'creation':
level.start_count = 0
def _get_hourly_frequencies(self):
return ['hourly']
def _get_next_date(self, last_call):
"""
Returns the next date with the given last call
"""
self.ensure_one()
if self.frequency == 'daily':
if self.frequency in self._get_hourly_frequencies() + ['daily']:
return last_call + relativedelta(days=1)
elif self.frequency == 'weekly':
daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
weekday = daynames.index(self.week_day)
return last_call + relativedelta(days=1, weekday=weekday)
elif self.frequency == 'bimonthly':
first_date = last_call + relativedelta(day=self.first_day)
second_date = last_call + relativedelta(day=self.second_day)
if self.frequency == 'weekly':
return last_call + relativedelta(days=1, weekday=int(self.week_day))
if self.frequency == 'bimonthly':
first_date = last_call + relativedelta(day=int(self.first_day))
second_date = last_call + relativedelta(day=int(self.second_day))
if last_call < first_date:
return first_date
elif last_call < second_date:
if last_call < second_date:
return second_date
else:
return last_call + relativedelta(months=1, day=self.first_day)
elif self.frequency == 'monthly':
date = last_call + relativedelta(day=self.first_day)
return last_call + relativedelta(day=int(self.first_day), months=1)
if self.frequency == 'monthly':
date = last_call + relativedelta(day=int(self.first_day))
if last_call < date:
return date
else:
return last_call + relativedelta(months=1, day=self.first_day)
elif self.frequency == 'biyearly':
first_month = MONTHS.index(self.first_month) + 1
second_month = MONTHS.index(self.second_month) + 1
first_date = last_call + relativedelta(month=first_month, day=self.first_month_day)
second_date = last_call + relativedelta(month=second_month, day=self.second_month_day)
return last_call + relativedelta(day=int(self.first_day), months=1)
if self.frequency == 'biyearly':
first_date = last_call + relativedelta(month=int(self.first_month), day=int(self.first_month_day))
second_date = last_call + relativedelta(month=int(self.second_month), day=int(self.second_month_day))
if last_call < first_date:
return first_date
elif last_call < second_date:
if last_call < second_date:
return second_date
else:
return last_call + relativedelta(years=1, month=first_month, day=self.first_month_day)
elif self.frequency == 'yearly':
month = MONTHS.index(self.yearly_month) + 1
date = last_call + relativedelta(month=month, day=self.yearly_day)
return last_call + relativedelta(month=int(self.first_month), day=int(self.first_month_day), years=1)
if self.frequency == 'yearly':
date = last_call + relativedelta(month=int(self.yearly_month), day=int(self.yearly_day))
if last_call < date:
return date
else:
return last_call + relativedelta(years=1, month=month, day=self.yearly_day)
else:
return False
return last_call + relativedelta(month=int(self.yearly_month), day=int(self.yearly_day), years=1)
raise ValidationError(_("Your frequency selection is not correct: please choose a frequency between theses options:"
"Hourly, Daily, Weekly, Twice a month, Monthly, Twice a year and Yearly."))
def _get_previous_date(self, last_call):
"""
@ -247,44 +320,52 @@ class AccrualPlanLevel(models.Model):
Contrary to `_get_next_date` this function will return the 01/02 if that date is given
"""
self.ensure_one()
if self.frequency == 'daily':
if self.frequency in self._get_hourly_frequencies() + ['daily']:
return last_call
elif self.frequency == 'weekly':
daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
weekday = daynames.index(self.week_day)
return last_call + relativedelta(days=-6, weekday=weekday)
elif self.frequency == 'bimonthly':
second_date = last_call + relativedelta(day=self.second_day)
first_date = last_call + relativedelta(day=self.first_day)
if self.frequency == 'weekly':
return last_call + relativedelta(days=-6, weekday=int(self.week_day))
if self.frequency == 'bimonthly':
first_date = last_call + relativedelta(day=int(self.first_day))
second_date = last_call + relativedelta(day=int(self.second_day))
if last_call >= second_date:
return second_date
elif last_call >= first_date:
if last_call >= first_date:
return first_date
else:
return last_call + relativedelta(months=-1, day=self.second_day)
elif self.frequency == 'monthly':
date = last_call + relativedelta(day=self.first_day)
return last_call + relativedelta(day=int(self.second_day), months=-1)
if self.frequency == 'monthly':
date = last_call + relativedelta(day=int(self.first_day))
if last_call >= date:
return date
else:
return last_call + relativedelta(months=-1, day=self.first_day)
elif self.frequency == 'biyearly':
first_month = MONTHS.index(self.first_month) + 1
second_month = MONTHS.index(self.second_month) + 1
first_date = last_call + relativedelta(month=first_month, day=self.first_month_day)
second_date = last_call + relativedelta(month=second_month, day=self.second_month_day)
return last_call + relativedelta(day=int(self.first_day), months=-1, days=1)
if self.frequency == 'biyearly':
first_date = last_call + relativedelta(month=int(self.first_month), day=int(self.first_month_day))
second_date = last_call + relativedelta(month=int(self.second_month), day=int(self.second_month_day))
if last_call >= second_date:
return second_date
elif last_call >= first_date:
if last_call >= first_date:
return first_date
else:
return last_call + relativedelta(years=-1, month=second_month, day=self.second_month_day)
elif self.frequency == 'yearly':
month = MONTHS.index(self.yearly_month) + 1
year_date = last_call + relativedelta(month=month, day=self.yearly_day)
return last_call + relativedelta(month=int(self.second_month), day=int(self.second_month_day), years=-1)
if self.frequency == 'yearly':
year_date = last_call + relativedelta(month=int(self.yearly_month), day=int(self.yearly_day))
if last_call >= year_date:
return year_date
else:
return last_call + relativedelta(years=-1, month=month, day=self.yearly_day)
else:
return False
return last_call + relativedelta(month=int(self.yearly_month), day=int(self.yearly_day), years=-1)
raise ValidationError(_("Your frequency selection is not correct: please choose a frequency between theses options:"
"Hourly, Daily, Weekly, Twice a month, Monthly, Twice a year and Yearly."))
def _get_level_transition_date(self, allocation_start):
if self.start_type == 'day':
return allocation_start + relativedelta(days=self.start_count)
if self.start_type == 'month':
return allocation_start + relativedelta(months=self.start_count)
if self.start_type == 'year':
return allocation_start + relativedelta(years=self.start_count)
def action_save_new(self):
return self.accrual_plan_id.action_create_accrual_plan_level()

View file

@ -1,12 +1,12 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from random import randint
from odoo import fields, models
from odoo import api, fields, models
class StressDay(models.Model):
_name = 'hr.leave.stress.day'
_description = 'Stress Day'
class HrLeaveMandatoryDay(models.Model):
_name = 'hr.leave.mandatory.day'
_description = 'Mandatory Day'
_order = 'start_date desc, end_date desc'
name = fields.Char(required=True)
@ -18,7 +18,9 @@ class StressDay(models.Model):
'resource.calendar', 'Working Hours',
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
department_ids = fields.Many2many('hr.department', string="Departments")
job_ids = fields.Many2many('hr.job', string="Job Position")
_sql_constraints = [
('date_from_after_day_to', 'CHECK(start_date <= end_date)', 'The start date must be anterior than the end date.')
]
_date_from_after_day_to = models.Constraint(
'CHECK(start_date <= end_date)',
'The start date must be anterior than the end date.',
)

Some files were not shown because too many files have changed in this diff Show more