[FIX] hr_holidays: "Everyone" view on calendar_event

Purpose
=======

Avoid to show to much information to leave responsibles.

Specification
=============

- Dynamically add/remove the leave_manager_ids on the group
  group_hr_holidays_responsible, on employee creation/modification
- Retrict the available employees when creating a leave. For
  manager/users : Everyone. For responsibles: The employee for
  who the user is responsible. Otherwise: Only me.
- Don't obfuscate the leave name on employees for who I'm the
  responsible.
- Add a new SQL view for "Everyone" report. To select only the
  information we want to share instead of showing the hr.leave
  model directly.

closes odoo/odoo#47659

closes odoo/odoo#49765

Taskid: 2206862
Related: odoo/enterprise#9239
Related: odoo/enterprise#10021
X-original-commit: 781147dcaf1552b8f2ab687ed73034b8fd1f7352
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Kevin Baptiste
2020-04-20 09:19:48 +00:00
parent 755e00bdcd
commit b8a8ad27de
13 changed files with 197 additions and 33 deletions
+1
View File
@@ -45,6 +45,7 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
'report/hr_holidays_templates.xml',
'report/hr_holidays_reports.xml',
'report/hr_leave_reports.xml',
'report/hr_leave_report_calendar.xml',
'views/hr_views.xml',
'views/hr_leave_template.xml',
+29
View File
@@ -148,8 +148,37 @@ class HrEmployeeBase(models.AbstractModel):
])
return [('id', 'in', holidays.mapped('employee_id').ids)]
@api.model
def create(self, values):
if 'parent_id' in values:
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
values['leave_manager_id'] = values.get('leave_manager_id', manager.id)
if values.get('leave_manager_id', False):
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
if approver_group:
approver_group.sudo().write({'users': [(4, values['leave_manager_id'])]})
return super(HrEmployeeBase, self).create(values)
def write(self, values):
if 'parent_id' in values:
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
if manager:
to_change = self.filtered(lambda e: e.leave_manager_id == e.parent_id.user_id or not e.leave_manager_id)
to_change.write({'leave_manager_id': values.get('leave_manager_id', manager.id)})
old_managers = self.env['res.users']
if 'leave_manager_id' in values:
old_managers = self.mapped('leave_manager_id')
if values['leave_manager_id']:
old_managers -= self.env['res.users'].browse(values['leave_manager_id'])
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
if approver_group:
approver_group.sudo().write({'users': [(4, values['leave_manager_id'])]})
res = super(HrEmployeeBase, self).write(values)
# remove users from the Responsible group if they are no longer leave managers
old_managers._clean_leave_responsible_users()
if 'parent_id' in values or 'department_id' in values:
today_date = fields.Datetime.now()
hr_vals = {}
+2 -1
View File
@@ -128,6 +128,7 @@ class HolidaysRequest(models.Model):
domain=[('valid', '=', True)])
validation_type = fields.Selection(string='Validation Type', related='holiday_status_id.leave_validation_type', readonly=False)
# HR data
employee_id = fields.Many2one(
'hr.employee', string='Employee', index=True, readonly=True, ondelete="restrict",
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, tracking=True)
@@ -829,7 +830,7 @@ class HolidaysRequest(models.Model):
holidays._create_resource_leave()
for holiday in holidays.filtered(lambda l: l.holiday_status_id.create_calendar_meeting):
meeting_values = holiday._prepare_holidays_meeting_values()
meeting = self.env['calendar.event'].with_context(no_mail_to_attendees=True).create(meeting_values)
meeting = self.env['calendar.event'].with_context(no_mail_to_attendees=True, active_model=self._name).create(meeting_values)
holiday.write({'meeting_id': meeting.id})
def _prepare_holidays_meeting_values(self):
+16
View File
@@ -57,3 +57,19 @@ class User(models.Model):
AND res_users.active = 't'
AND date_from <= %%s AND date_to >= %%s''' % field, (now, now))
return [r[0] for r in self.env.cr.fetchall()]
def _clean_leave_responsible_users(self):
# self = old bunch of leave responsibles
# This method compares the current leave managers
# and remove the access rights to those who don't
# need them anymore
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
if not self or not approver_group:
return
res = self.env['hr.employee'].read_group(
[('leave_manager_id', 'in', self.ids)],
['leave_manager_id'],
['leave_manager_id'])
responsibles_to_remove_ids = set(self.ids) - {x['leave_manager_id'][0] for x in res}
approver_group.sudo().write({
'users': [(3, manager_id) for manager_id in responsibles_to_remove_ids]})
+1
View File
@@ -3,3 +3,4 @@
from . import holidays_summary_report
from . import hr_leave_report
from . import hr_leave_report_calendar
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools
from odoo.addons.base.models.res_partner import _tz_get
class LeaveReportCalendar(models.Model):
_name = "hr.leave.report.calendar"
_description = 'Time Off Calendar'
_auto = False
_order = "start_datetime DESC, employee_id"
name = fields.Char(string='Name', readonly=True)
start_datetime = fields.Datetime(string='From', readonly=True)
stop_datetime = fields.Datetime(string='To', readonly=True)
tz = fields.Selection(_tz_get, string="Timezone", readonly=True)
duration = fields.Float(string='Duration', readonly=True)
employee_id = fields.Many2one('hr.employee', readonly=True)
company_id = fields.Many2one('res.company', readonly=True)
def init(self):
tools.drop_view_if_exists(self._cr, 'hr_leave_report_calendar')
self._cr.execute("""CREATE OR REPLACE VIEW hr_leave_report_calendar AS
(SELECT
row_number() OVER() AS id,
ce.name AS name,
ce.start AS start_datetime,
ce.stop AS stop_datetime,
ce.duration AS duration,
hl.employee_id AS employee_id,
em.company_id AS company_id
FROM hr_leave hl
LEFT JOIN calendar_event ce
ON ce.id = hl.meeting_id
LEFT JOIN hr_employee em
ON em.id = hl.employee_id
WHERE
hl.state = 'validate');
""")
@@ -0,0 +1,39 @@
<?xml version='1.0' encoding='UTF-8' ?>
<odoo>
<record id="action_hr_holidays_dashboard" model="ir.actions.act_window">
<field name="name">All Time Off</field>
<field name="res_model">hr.leave.report.calendar</field>
<field name="view_mode">calendar</field>
<!-- YTI : Ecrabouille explicitely those fields, as this is deployed on
a stable release. -->
<field name="view_id"/>
<field name="search_view_id"/>
<field name="domain"/>
<field name="context"/>
</record>
<record id="hr_leave_report_calendar_view" model="ir.ui.view">
<field name="name">hr.leave.report.calendar.view</field>
<field name="model">hr.leave.report.calendar</field>
<field name="arch" type="xml">
<calendar string="Time Off" date_start="start_datetime" date_stop="stop_datetime" mode="month" quick_add="False" color="employee_id" event_open_popup="True">
<field name="name"/>
</calendar>
</field>
</record>
<record id="hr_leave_report_calendar_view_form" model="ir.ui.view">
<field name="name">hr.leave.report.calendar.view.form</field>
<field name="model">hr.leave.report.calendar</field>
<field name="arch" type="xml">
<form string="Time Off">
<group>
<field name="name"/>
<field name="start_datetime"/>
<field name="stop_datetime"/>
<field name="employee_id" />
</group>
</form>
</field>
</record>
</odoo>
@@ -5,10 +5,16 @@
<field name="sequence">10</field>
</record>
<record id="group_hr_holidays_responsible" model="res.groups">
<field name="name">Responsible</field>
<field name="category_id" ref="base.module_category_human_resources_time_off"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
<record id="group_hr_holidays_user" model="res.groups">
<field name="name">All Approver</field>
<field name="category_id" ref="base.module_category_human_resources_time_off"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="implied_ids" eval="[(4, ref('hr_holidays.group_hr_holidays_responsible'))]"/>
</record>
<record id="group_hr_holidays_manager" model="res.groups">
@@ -27,7 +33,7 @@
<record id="hr_leave_rule_employee" model="ir.rule">
<field name="name">Time Off base.group_user read</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
@@ -62,6 +68,44 @@
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
</record>
<record id="hr_leave_rule_responsible_read" model="ir.rule">
<field name="name">Time Off Responsible read</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="domain_force">[
('employee_id.leave_manager_id', '=', user.id),
]</field>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_responsible'))]"/>
</record>
<record id="hr_leave_rule_responsible_update" model="ir.rule">
<field name="name">Time Off Responsible create/write</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="domain_force">[
('holiday_type', '=', 'employee'),
'|',
'&amp;',
('employee_id.user_id', '=', user.id),
('state', '!=', 'validate'),
('employee_id.leave_manager_id', '=', user.id),
]</field>
<field name="perm_read" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_responsible'))]"/>
</record>
<record id="hr_leave_rule_responsible_read" model="ir.rule">
<field name="name">Time Off All Approver read</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
</record>
<record id="hr_leave_rule_officer_update" model="ir.rule">
<field name="name">Time Off All Approver create/write</field>
<field name="model_id" ref="model_hr_leave"/>
@@ -193,5 +237,12 @@
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
<record id="hr_leave_report_calendar_rule_multi_company" model="ir.rule">
<field name="name">Time Off Report Calendar: multi company global rule</field>
<field name="model_id" ref="model_hr_leave_report_calendar"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
</data>
</odoo>
@@ -15,3 +15,4 @@ access_calendar_event_type_manager,calendar.event.type.manager,calendar.model_ca
access_calendar_attendee_hr_user,calendar.attendee.hr.user,calendar.model_calendar_attendee,hr_holidays.group_hr_holidays_user,1,1,1,1
access_mail_activity_type_holidays_manager,mail.activity.type.holidays.manager,mail.model_mail_activity_type,hr_holidays.group_hr_holidays_manager,1,1,1,1
access_hr_holidays_summary_employee,access.hr.holidays.summary.employee,model_hr_holidays_summary_employee,hr_holidays.group_hr_holidays_user,1,1,1,0
access_hr_leave_report_calendar,access_hr_leave_report_calendar,model_hr_leave_report_calendar,base.group_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
15 access_calendar_attendee_hr_user calendar.attendee.hr.user calendar.model_calendar_attendee hr_holidays.group_hr_holidays_user 1 1 1 1
16 access_mail_activity_type_holidays_manager mail.activity.type.holidays.manager mail.model_mail_activity_type hr_holidays.group_hr_holidays_manager 1 1 1 1
17 access_hr_holidays_summary_employee access.hr.holidays.summary.employee model_hr_holidays_summary_employee hr_holidays.group_hr_holidays_user 1 1 1 0
18 access_hr_leave_report_calendar access_hr_leave_report_calendar model_hr_leave_report_calendar base.group_user 1 0 0 0
+7 -12
View File
@@ -528,7 +528,7 @@ class TestAccessRightsRead(TestHrHolidaysAccessRightsCommon):
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_other(self):
""" Users should be able to read other people requests except name field """
""" Users should not be able to read other people requests """
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
'name': 'Test',
'holiday_status_id': self.leave_type.id,
@@ -538,15 +538,12 @@ class TestAccessRightsRead(TestHrHolidaysAccessRightsCommon):
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
res = other_leave.with_user(self.user_employee_id).read(['number_of_days', 'state', 'name'])
self.assertEqual(
res[0]['name'], '*****',
'Private information should have been stripped, received %s instead' % res[0]['name']
)
with self.assertRaises(AccessError), self.cr.savepoint():
res = other_leave.with_user(self.user_employee_id).read(['number_of_days', 'state', 'name'])
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_other_browse(self):
""" Users should be able to browse other people requests except name field """
""" Users should not be able to browse other people requests """
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
'name': 'Test',
'holiday_status_id': self.leave_type.id,
@@ -556,11 +553,9 @@ class TestAccessRightsRead(TestHrHolidaysAccessRightsCommon):
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
other_leave.invalidate_cache(['name'])
self.assertEqual(
other_leave.with_user(self.user_employee_id).name, '*****',
'Private information should have been stripped, received %s instead' % other_leave.with_user(self.user_employee_id).name
)
with self.assertRaises(AccessError), self.cr.savepoint():
other_leave.invalidate_cache(['name'])
name = other_leave.with_user(self.user_employee_id).name
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_own(self):
@@ -50,6 +50,7 @@
id="hr_holidays_menu_manager_approve"
name="To Approve"
parent="menu_hr_holidays_approvals"
groups="hr_holidays.group_hr_holidays_responsible,hr_holidays.group_hr_holidays_user"
sequence="1"/>
<menuitem
@@ -200,7 +200,7 @@
<button string="Approve" name="action_approve" type="object"
icon="fa-check text-success"
states="confirm"
groups="hr_holidays.group_hr_holidays_user"/>
groups="hr_holidays.group_hr_holidays_responsible"/>
<button string="Validate" name="action_validate" type="object"
icon="fa-check text-success"
states="validate1"
@@ -371,8 +371,8 @@
<field name="name">Department Allocation to Approve</field>
<field name="res_model">hr.leave.allocation</field>
<field name="view_mode">tree,form,kanban,activity</field>
<field name="context">{'search_default_managed_people':1, 'search_default_approve':1}</field>
<field name="domain">[]</field>
<field name="context">{'search_default_approve':1}</field>
<field name="domain">[('employee_id.leave_manager_id', '=', uid)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new time off allocation
+2 -15
View File
@@ -501,7 +501,7 @@
<button string="Approve" name="action_approve" type="object"
icon="fa-check text-success"
states="confirm"
groups="hr_holidays.group_hr_holidays_user"/>
groups="hr_holidays.group_hr_holidays_responsible"/>
<button string="Validate" name="action_validate" type="object"
icon="fa-check text-success"
states="validate1"
@@ -546,18 +546,6 @@
</field>
</record>
<record id="action_hr_holidays_dashboard" model="ir.actions.act_window">
<field name="name">All Time Off</field>
<field name="res_model">hr.leave</field>
<field name="view_mode">calendar,tree,form</field>
<field name="context">{
'form_view_ref': 'hr_holidays.hr_leave_view_form_manager',
}</field>
<field name="domain">[('holiday_type','=','employee'), ('state', '!=', 'refuse')]</field>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
<field name="view_id" />
</record>
<record id="hr_leave_action_new_request" model="ir.actions.act_window">
<field name="name">Dashboard</field>
<field name="res_model">hr.leave</field>
@@ -663,11 +651,10 @@
<field name="res_model">hr.leave</field>
<field name="view_mode">tree,kanban,form,calendar,activity</field>
<field name="context">{
'search_default_managed_people':1,
'search_default_my_team_leaves':1,
'search_default_approve':1}
</field>
<field name="domain">[]</field>
<field name="domain">[('employee_id.leave_manager_id', '=', uid)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new time off request