[IMP] hr_holidays: send time off cancellation notification to manager

Purpose:

User should be abled to delete him time off (time off that needs to be
validated by both, manager and time off officer), if it has not been validated
by officer yet.

The manager that validated the time off, should be notified
if/when the time off is canceled by the user.

Both manager and user should be notified if officer refused time off,
validated by manager.

This commit also fixes traceback on time off form in development mode.

If there is

<field name="A"/>
<label for="A"/>

we get traceback in dev mode.

Instread it should be

<label for="A"/>
<field name="A"/>

task - 2857233

closes odoo/odoo#94533

Related: odoo/upgrade#3809
Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
sofiagvaladze
2023-01-10 15:43:00 +01:00
parent 65ee6ddacc
commit 262c0ad84f
4 changed files with 53 additions and 6 deletions
+50 -3
View File
@@ -605,7 +605,7 @@ class HolidaysRequest(models.Model):
def _compute_can_cancel(self):
now = fields.Datetime.now()
for leave in self:
leave.can_cancel = leave.id and leave.employee_id.user_id == self.env.user and leave.state == 'validate' and leave.date_from and leave.date_from > now
leave.can_cancel = leave.id and leave.employee_id.user_id == self.env.user and leave.state in ['validate', 'validate1'] and leave.date_from and leave.date_from > now
@api.depends('state')
def _compute_is_hatched(self):
@@ -1037,7 +1037,7 @@ class HolidaysRequest(models.Model):
if not self.user_has_groups('hr_holidays.group_hr_holidays_user'):
for hol in self:
if hol.state not in ['draft', 'confirm']:
if hol.state not in ['draft', 'confirm', 'validate1']:
raise UserError(error_message % state_description_values.get(self[:1].state))
if hol.date_from < now:
raise UserError(_('You cannot delete a time off which is in the past'))
@@ -1219,13 +1219,15 @@ class HolidaysRequest(models.Model):
for holiday in self.filtered(lambda holiday: holiday.employee_id.user_id):
user_tz = timezone(holiday.tz)
utc_tz = pytz.utc.localize(holiday.date_from).astimezone(user_tz)
# Do not notify the employee by mail, in case if the time off still needs Officer's approval
notify_partner_ids = holiday.employee_id.user_id.partner_id.ids if holiday.validation_type != 'both' else []
holiday.message_post(
body=_(
'Your %(leave_type)s planned on %(date)s has been accepted',
leave_type=holiday.holiday_status_id.display_name,
date=utc_tz.replace(tzinfo=None)
),
partner_ids=holiday.employee_id.user_id.partner_id.ids)
partner_ids=notify_partner_ids)
self.filtered(lambda hol: not hol.validation_type == 'both').action_validate()
if not self.env.context.get('leave_fast_create'):
@@ -1363,6 +1365,7 @@ class HolidaysRequest(models.Model):
if any(holiday.state not in ['draft', 'confirm', 'validate', 'validate1'] for holiday in self):
raise UserError(_('Time off request must be confirmed or validated in order to refuse it.'))
self._notify_manager()
validated_holidays = self.filtered(lambda hol: hol.state == 'validate1')
validated_holidays.write({'state': 'refuse', 'first_approver_id': current_employee.id})
(self - validated_holidays).write({'state': 'refuse', 'second_approver_id': current_employee.id})
@@ -1383,6 +1386,24 @@ class HolidaysRequest(models.Model):
self.activity_update()
return True
def _notify_manager(self):
leaves = self.filtered(lambda hol: (hol.validation_type == 'both' and hol.state in ['validate1', 'validate']) or (hol.validation_type == 'manager' and hol.state == 'validate'))
holiday_names = self.name_get()
for holiday in leaves:
responsible = holiday.employee_id.leave_manager_id.partner_id.ids
if responsible:
holiday_name = list(filter(lambda h: holiday.id in h, holiday_names))[0][1]
self.env['mail.thread'].sudo().message_notify(
partner_ids=responsible,
model_description='Time Off',
subject=_('Refused Time Off'),
body=_(
'%(holiday_name)s has been refused.',
holiday_name=holiday_name,
),
email_layout_xmlid='mail.mail_notification_light',
)
def _action_user_cancel(self, reason):
self.ensure_one()
if not self.can_cancel:
@@ -1391,12 +1412,38 @@ class HolidaysRequest(models.Model):
self._force_cancel(reason, 'mail.mt_note')
def _force_cancel(self, reason, msg_subtype='mail.mt_comment'):
leave_names = self.name_get()
for leave in self:
leave.message_post(
body=_('The time off has been canceled: %s', reason),
subtype_xmlid=msg_subtype
)
responsibles = self.env['res.partner']
# manager
if (leave.holiday_status_id.leave_validation_type == 'manager' and leave.state == 'validate') or (leave.holiday_status_id.leave_validation_type == 'both' and leave.state == 'validate1'):
responsibles = leave.employee_id.leave_manager_id.partner_id
# officer
elif leave.holiday_status_id.leave_validation_type == 'hr' and leave.state == 'validate':
responsibles = leave.holiday_status_id.responsible_id.partner_id
# both
elif leave.holiday_status_id.leave_validation_type == 'both' and leave.state == 'validate':
responsibles = leave.employee_id.leave_manager_id.partner_id
responsibles |= leave.holiday_status_id.responsible_id.partner_id
if responsibles:
leave_name = list(filter(lambda h: leave.id in h, leave_names))[0][1]
self.env['mail.thread'].sudo().message_notify(
partner_ids=responsibles.ids,
model_description='Time Off',
subject=_('Canceled Time Off'),
body=_(
"%(leave_name)s has been cancelled with the justification: <br/> %(reason)s.",
leave_name=leave_name,
reason=reason
),
email_layout_xmlid='mail.mail_notification_light',
)
leave_sudo = self.sudo()
leave_sudo.with_context(from_cancel_wizard=True).active = False
leave_sudo.meeting_id.active = False
@@ -61,7 +61,7 @@
<record id="hr_leave_rule_employee_unlink" model="ir.rule">
<field name="name">Time Off base.group_user unlink</field>
<field name="model_id" ref="model_hr_leave"/>
<field name="domain_force">[('employee_id.user_id', '=', user.id), ('state', 'in', ['draft', 'confirm'])]</field>
<field name="domain_force">[('employee_id.user_id', '=', user.id), ('state', 'in', ['draft', 'confirm', 'validate1'])]</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
+1 -1
View File
@@ -262,12 +262,12 @@
<field name="date_to" invisible="1" />
<!-- half day or custom hours: only show one date -->
<label for="request_date_from" attrs="{'invisible': [('request_unit_half', '=', False), ('request_unit_hours', '=', False)]}" string="Date" />
<label for="request_date_from" attrs="{'invisible': ['|', ('request_unit_half', '=', True), ('request_unit_hours', '=', True)]}" string="Dates" />
<div class="o_row" attrs="{'invisible': [('request_unit_half', '=', False), ('request_unit_hours', '=', False)]}">
<field name="request_date_from" class="oe_inline" string="Date" />
<field name="request_date_from_period" attrs="{'invisible': [('request_unit_half', '!=', True)], 'required': [('request_unit_half', '=', True)]}"/>
</div>
<!-- full days: show date start/end with daterange -->
<label for="request_date_from" attrs="{'invisible': ['|', ('request_unit_half', '=', True), ('request_unit_hours', '=', True)]}" string="Dates" />
<div class="o_row" attrs="{'invisible': ['|', ('request_unit_half', '=', True), ('request_unit_hours', '=', True)]}">
<span class="text-muted">From</span>
<field name="request_date_from" class="oe_inline" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))],
@@ -6,7 +6,7 @@
<form string="Cancel Time Off">
<group>
<field name="leave_id" invisible="1" />
<field name="reason" placeholder="Provide a reason for cancellation of an approved time off" />
<field name="reason" placeholder="Provide a reason to delete an approved time off" />
</group>
<footer>
<button name="action_cancel_leave" type="object" class="btn-primary" string="Delete Time Off" />