Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADD][14.0] New module hr_holidays_validator_list #91

Closed
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
2 changes: 2 additions & 0 deletions hr_holidays_validator_list/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
19 changes: 19 additions & 0 deletions hr_holidays_validator_list/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

{
"name": "HR Holidays validator list",
"summary": "Allow to add several leave validators",
"author": "Victor Vermot, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/hr-holidays",
"category": "Human Resources",
"version": "14.0.1.0.0",
"license": "AGPL-3",
"depends": ["hr_holidays"],
"data": [
"views/hr_views.xml",
"views/hr_leave_allocation_views.xml",
"views/hr_leave_views.xml",
],
"installable": True,
}
62 changes: 62 additions & 0 deletions hr_holidays_validator_list/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_holidays_validator_list
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-07 10:12+0000\n"
"PO-Revision-Date: 2023-11-07 10:12+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: hr_holidays_validator_list
#: model:ir.model,name:hr_holidays_validator_list.model_hr_employee_base
msgid "Basic Employee"
msgstr "Employé basique"

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__display_name
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation__display_name
msgid "Display Name"
msgstr "Nom affiché"

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__id
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation__id
msgid "ID"
msgstr "ID"

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base____last_update
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"

#. module: hr_holidays_validator_list
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee__leave_manager_ids
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee_base__leave_manager_ids
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee_public__leave_manager_ids
msgid ""
"Select the users responsible for approving \"Time Off\" of this employee.\n"
"If empty, the approval is done by an Administrator or Approver (determined in settings/users)."
msgstr ""
"Sélectionne le user responsable for approuvé les congés de l'employé.\n"
"Si vide, la validation est faite par un adiministrateur ou approuveur (comme configuré dans paramètres/utilisateurs)"

#. module: hr_holidays_validator_list
#: model:ir.model,name:hr_holidays_validator_list.model_hr_leave_allocation
msgid "Time Off Allocation"
msgstr "Allocation de congés"

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee__leave_manager_ids
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__leave_manager_ids
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_public__leave_manager_ids
msgid "Time Off Managers"
msgstr "Managers de congés"
60 changes: 60 additions & 0 deletions hr_holidays_validator_list/i18n/hr_holidays_validator_list.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_holidays_validator_list
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-07 10:12+0000\n"
"PO-Revision-Date: 2023-11-07 10:12+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: hr_holidays_validator_list
#: model:ir.model,name:hr_holidays_validator_list.model_hr_employee_base
msgid "Basic Employee"
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__display_name
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation__display_name
msgid "Display Name"
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__id
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation__id
msgid "ID"
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base____last_update
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_leave_allocation____last_update
msgid "Last Modified on"
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee__leave_manager_ids
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee_base__leave_manager_ids
#: model:ir.model.fields,help:hr_holidays_validator_list.field_hr_employee_public__leave_manager_ids
msgid ""
"Select the users responsible for approving \"Time Off\" of this employee.\n"
"If empty, the approval is done by an Administrator or Approver (determined in settings/users)."
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model,name:hr_holidays_validator_list.model_hr_leave_allocation
msgid "Time Off Allocation"
msgstr ""

#. module: hr_holidays_validator_list
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee__leave_manager_ids
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_base__leave_manager_ids
#: model:ir.model.fields,field_description:hr_holidays_validator_list.field_hr_employee_public__leave_manager_ids
msgid "Time Off Managers"
msgstr ""
2 changes: 2 additions & 0 deletions hr_holidays_validator_list/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import hr_employee
from . import hr_leave_allocation
47 changes: 47 additions & 0 deletions hr_holidays_validator_list/models/hr_employee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class HrEmployeeBase(models.AbstractModel):
_inherit = "hr.employee.base"

leave_manager_ids = fields.Many2many(
"res.users",
string="Time Off Managers",
store=True,
readonly=False,
help="""Select the users responsible for approving 'Time Off' of this employee.\n
victorvermot marked this conversation as resolved.
Show resolved Hide resolved
If empty, the approval is done by an Administrator
or Approver (determined in settings/users).""",
)

def _set_leave_manager_id_from_leave_manager_ids(self, values):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should have used a stored readable only computed method on leave_manager_id with a depends on leave_manager_ids to propagate any change.

Copy link
Author

@victorvermot victorvermot Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right I am going to check that

Copy link
Member

@yvaucher yvaucher Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StephaneMangin The field leave_manager_ids is already a computed stored field. Question is can we insert nicely the set of the values from the M2M nicely or not. We might want to keep leave_manager_ids value to it's current natural computation.

@victorvermot

What we could probably do to improve the code is:

Override https://github.com/odoo/odoo/blob/17.0/addons/hr_holidays/models/hr_employee.py#L152-L159
this way:

    @api.depends('parent_id', 'leave_manager_ids')
    def _compute_leave_manager(self):
            
        for employee in self:
            if self.leave_manager_ids:
               self.leave_manager_id = leave_manager_ids[0]     
           else:
                super()._compute_leave_manager()

if "leave_manager_ids" in values:
if not len(values["leave_manager_ids"][0][-1]):
values["leave_manager_id"] = None
elif "leave_manager_ids" in values.keys():
values["leave_manager_id"] = values["leave_manager_ids"][0][-1][-1]
return values

def _add_leave_manager_ids_in_group(self, values):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An onchange would have suffice to affect groups on managers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, we are on hr_employee, an onchange should only affect the values of the current form. Groups won't be available from here.

if "leave_manager_ids" in values:
approver_group = self.env.ref(
"hr_holidays.group_hr_holidays_responsible", raise_if_not_found=False
)
for manager_id in values["leave_manager_ids"][0][-1]:
if approver_group:
approver_group.sudo().write({"users": [(4, manager_id)]})

def create(self, values):
values = self._set_leave_manager_id_from_leave_manager_ids(values)
res = super().create(values)
self._add_leave_manager_ids_in_group(values)
return res

def write(self, values):
values = self._set_leave_manager_id_from_leave_manager_ids(values)
res = super().write(values)
self._add_leave_manager_ids_in_group(values)
return res
32 changes: 32 additions & 0 deletions hr_holidays_validator_list/models/hr_leave_allocation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import models


class HolidaysAllocation(models.Model):
"""Allocation Requests Access specifications: similar to leave requests"""

_inherit = "hr.leave.allocation"

def activity_update(self):
"""uUpdates activity for all leave_manager_ids"""
victorvermot marked this conversation as resolved.
Show resolved Hide resolved
res = super().activity_update()
for manager in self.employee_id.leave_manager_ids:
old_manager = self.employee_id.leave_manager_id
self.employee_id.leave_manager_id = manager
super().activity_update()
self.employee_id.leave_manager_id = old_manager
return res

def _check_approval_update(self, state):
"""Checks that the leave manager is in leave_manager_ids"""
res = super()._check_approval_update(state)
for manager in self.employee_id.leave_manager_ids:
if manager == self.env.user:
old_manager = self.employee_id.leave_manager_id
self.employee_id.leave_manager_id = manager
super()._check_approval_update(state)
self.employee_id.leave_manager_id = old_manager
break
return res
1 change: 1 addition & 0 deletions hr_holidays_validator_list/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Victor Vermot-Petit-Outhenin <[email protected]>
1 change: 1 addition & 0 deletions hr_holidays_validator_list/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This module allows for an employee to have several leave validators.
10 changes: 10 additions & 0 deletions hr_holidays_validator_list/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
For adding multiple :

#. Go to the menu *Employee > Field leave_manager_ids*.
#. Add managers in the new many2many field.
#. The validation type of the hr.leave should be "manager".

Other changes:

#. The "People I manage" filter in hr.leave and hr.leave.allocation have been
updated accordingly
1 change: 1 addition & 0 deletions hr_holidays_validator_list/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_hr_leave
66 changes: 66 additions & 0 deletions hr_holidays_validator_list/tests/test_hr_leave.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from datetime import datetime

import odoo.tests.common as common
from odoo.exceptions import UserError


class TestHrLeave(common.TransactionCase):
def setUp(self):
super().setUp()
employee = self.env["hr.employee"].search([])[0]
employee.write({"leave_manager_ids": [(6, 0, [6, 2])]})
hr_leave_type = self.env["hr.leave.type"].create(
{
"name": "Leave Test",
"color_name": "red",
"request_unit": "hour",
}
)
self.hr_leave = self.env["hr.leave"].create(
{
"employee_id": employee.id,
"holiday_status_id": hr_leave_type.id,
"holiday_type": "employee",
"date_from": datetime(year=2023, month=10, day=1, hour=8, minute=0),
"date_to": datetime(year=2023, month=10, day=3, hour=8, minute=0),
}
)

self.user1 = self.env["res.users"].create(
{
"name": "User 1",
"login": "user1",
"password": "password1",
"groups_id": [],
}
)

def test_hr_leave_managers_can_validate_leaves(self):
"""Test that checks if all leave managers in field leave_manager_ids can
confirm a hr_leave and hr_leave_allocations"""
self.env.user = self.env["res.users"].browse(6)
self.hr_leave.with_user(self.env.user).action_validate()
self.assertEqual(self.hr_leave.state, "validate")
self.hr_leave.state = "confirm"
self.env.user = self.env["res.users"].browse(2)
self.hr_leave.with_user(self.env.user).action_validate()
self.assertEqual(self.hr_leave.state, "validate")
self.hr_leave.state = "confirm"

# remove user with id 2 from manager groups
approver_group = self.env.ref(
"hr_holidays.group_hr_holidays_manager", raise_if_not_found=False
)
other_group = self.env.ref(
"hr_holidays.group_hr_holidays_user", raise_if_not_found=False
)
if approver_group:
approver_group.sudo().write({"users": [(3, 2)]})
other_group.sudo().write({"users": [(3, 2)]})

# checks that trying to validate leaves with no rights raises an error
with self.assertRaises(UserError):
self.hr_leave.with_user(self.user1)._check_approval_update("validate")
17 changes: 17 additions & 0 deletions hr_holidays_validator_list/views/hr_leave_allocation_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version='1.0' encoding='UTF-8' ?>
<odoo>
<record id="view_hr_leave_allocation_filter_inherited" model="ir.ui.view">
<field name="name">hr.holidays.filter_allocations.inherited</field>
<field name="model">hr.leave.allocation</field>
<field name="inherit_id" ref="hr_holidays.view_hr_leave_allocation_filter" />
<field name="arch" type="xml">
<data>
<xpath expr="//filter[@name='managed_people']" position="attributes">
<attribute
name="domain"
>[('employee_id.leave_manager_ids', 'in', [uid])]</attribute>
</xpath>
</data>
</field>
</record>
</odoo>
17 changes: 17 additions & 0 deletions hr_holidays_validator_list/views/hr_leave_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version='1.0' encoding='UTF-8' ?>
<odoo>
<record id="view_hr_leave_filter_inherited" model="ir.ui.view">
<field name="name">hr.holidays.hr_leave.inherited</field>
<field name="model">hr.leave</field>
<field name="inherit_id" ref="hr_holidays.view_hr_holidays_filter" />
<field name="arch" type="xml">
<data>
<xpath expr="//filter[@name='managed_people']" position="attributes">
<attribute
name="domain"
>[('employee_id.leave_manager_ids', 'in', [uid])]</attribute>
</xpath>
</data>
</field>
</record>
</odoo>
16 changes: 16 additions & 0 deletions hr_holidays_validator_list/views/hr_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version='1.0' encoding='UTF-8' ?>
<odoo>
<record id="view_employee_form_leave_inherit" model="ir.ui.view">
<field name="name">hr.employee.leave.form.inherit</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_holidays.view_employee_form_leave_inherit" />
<field name="arch" type="xml">
<xpath expr="//field[@name='leave_manager_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//group[@name='managers']" position="inside">
<field name="leave_manager_ids" widget="many2many_tags" />
</xpath>
</field>
</record>
</odoo>
6 changes: 6 additions & 0 deletions setup/hr_holidays_validator_list/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)