[IMP] hr_holidays: Improve general UX (back2basics)
TaskID: 2053585 closes odoo/odoo#35737 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
<field name="signature" position="replace" />
|
||||
<xpath expr="//group[@name='preference_contact']" position="before">
|
||||
<group>
|
||||
<field name="out_of_office_message"/>
|
||||
<field name="signature" />
|
||||
</group>
|
||||
</xpath>
|
||||
|
||||
@@ -39,7 +39,6 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
|
||||
'views/hr_leave_allocation_views.xml',
|
||||
'views/mail_activity_views.xml',
|
||||
|
||||
'wizard/hr_holidays_summary_department_views.xml',
|
||||
'wizard/hr_holidays_summary_employees_views.xml',
|
||||
|
||||
'report/hr_holidays_templates.xml',
|
||||
|
||||
@@ -12,15 +12,6 @@
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
</record>
|
||||
|
||||
<!-- Home working -->
|
||||
<record id="holiday_status_hw" model="hr.leave.type">
|
||||
<field name="name">Home Workings</field>
|
||||
<field name="color_name">lightgreen</field>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave_home_working')"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="validity_start" eval="False"/>
|
||||
</record>
|
||||
|
||||
<!-- ++++++++++++++++++++++ Mitchell Admin ++++++++++++++++++++++ -->
|
||||
|
||||
<record id="hr_holidays_allocation_cl" model="hr.leave.allocation">
|
||||
@@ -293,14 +284,6 @@
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_int_tour_fpi" model="hr.leave.allocation">
|
||||
<field name="name">International Tour</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_hw"/>
|
||||
<field name="number_of_days">8</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_fpi" model="hr.leave.allocation">
|
||||
<field name="name">Summer Vacation</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_unpaid"/>
|
||||
@@ -308,34 +291,6 @@
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_int_tour_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- leave request -->
|
||||
<record id="hr_holidays_sl_fpi" model="hr.leave">
|
||||
<field name="name">Home working</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_hw"/>
|
||||
<field eval="(datetime.now()+relativedelta(months=-1)).strftime('%Y-%m-10 1:0:0')" name="date_from"/>
|
||||
<field eval="(datetime.now()+relativedelta(months=-1)).strftime('%Y-%m-17 23:0:0')" name="date_to"/>
|
||||
<field eval="(datetime.now()+relativedelta(months=-1)).strftime('%Y-%m-10 1:0:0')" name="request_date_from"/>
|
||||
<field eval="(datetime.now()+relativedelta(months=-1)).strftime('%Y-%m-17 23:0:0')" name="request_date_to"/>
|
||||
<field name="number_of_days">8</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
</record>
|
||||
|
||||
<!-- approve the leave request -->
|
||||
<function model="hr.leave" name="action_approve">
|
||||
<value model="hr.leave" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_sl_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- ++++++++++++++++++++++ Olivia ++++++++++++++++++++++ -->
|
||||
|
||||
<record id="hr_holidays_allocation_cl_vad" model="hr.leave.allocation">
|
||||
|
||||
@@ -7,7 +7,6 @@ from . import hr_department
|
||||
from . import hr_leave
|
||||
from . import hr_leave_allocation
|
||||
from . import hr_leave_type
|
||||
from . import mail_channel
|
||||
from . import mail_message_subtype
|
||||
from . import res_partner
|
||||
from . import res_users
|
||||
|
||||
@@ -126,7 +126,6 @@ class HolidaysRequest(models.Model):
|
||||
'hr.department', string='Department', readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
notes = fields.Text('Reasons', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
out_of_office_message = fields.Char(string='Chat Status')
|
||||
# duration
|
||||
date_from = fields.Datetime(
|
||||
'Start Date', readonly=True, index=True, copy=False, required=True,
|
||||
@@ -263,11 +262,6 @@ class HolidaysRequest(models.Model):
|
||||
self.request_unit_custom = False
|
||||
self.state = 'confirm' if self.validation_type != 'no_validation' else 'draft'
|
||||
|
||||
@api.onchange('user_id')
|
||||
def _onchange_user_id(self):
|
||||
if not self.out_of_office_message:
|
||||
self.out_of_office_message = self.user_id.out_of_office_message
|
||||
|
||||
@api.onchange('request_date_from_period', 'request_hour_from', 'request_hour_to',
|
||||
'request_date_from', 'request_date_to',
|
||||
'employee_id')
|
||||
@@ -630,9 +624,6 @@ class HolidaysRequest(models.Model):
|
||||
pass
|
||||
|
||||
def write(self, values):
|
||||
# Allow an employee to always write his own out of office message
|
||||
if len(self) == 1 and values.keys() == {'out_of_office_message'} and self.employee_id.user_id == self.env.user:
|
||||
return super(HolidaysRequest, self.sudo()).write(values)
|
||||
is_officer = self.env.user.has_group('hr_holidays.group_hr_holidays_user')
|
||||
|
||||
if not is_officer:
|
||||
|
||||
@@ -111,8 +111,11 @@ class HolidaysAllocation(models.Model):
|
||||
'hr.employee.category', string='Employee Tag', readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
# accrual configuration
|
||||
accrual = fields.Boolean(
|
||||
"Accrual", readonly=True,
|
||||
allocation_type = fields.Selection(
|
||||
[
|
||||
('regular', 'Regular Allocation'),
|
||||
('accrual', 'Accrual Allocation')
|
||||
], string="Allocation Type", default="regular", required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
accrual_limit = fields.Integer('Balance limit', default=0, help="Maximum of allocation for accrual; 0 means no maximum.")
|
||||
number_per_interval = fields.Float("Number of unit per interval", readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=1)
|
||||
@@ -150,7 +153,7 @@ class HolidaysAllocation(models.Model):
|
||||
"""
|
||||
today = fields.Date.from_string(fields.Date.today())
|
||||
|
||||
holidays = self.search([('accrual', '=', True), ('state', '=', 'validate'), ('holiday_type', '=', 'employee'),
|
||||
holidays = self.search([('allocation_type', '=', 'accrual'), ('state', '=', 'validate'), ('holiday_type', '=', 'employee'),
|
||||
'|', ('date_to', '=', False), ('date_to', '>', fields.Datetime.now()),
|
||||
'|', ('nextcall', '=', False), ('nextcall', '<=', today)])
|
||||
|
||||
@@ -298,7 +301,7 @@ class HolidaysAllocation(models.Model):
|
||||
if new_date_to < self.date_to:
|
||||
self.date_to = new_date_to
|
||||
|
||||
if self.accrual:
|
||||
if self.allocation_type == 'accrual':
|
||||
self.number_of_days = 0
|
||||
|
||||
if self.holiday_status_id.request_unit == 'hour':
|
||||
@@ -357,7 +360,7 @@ class HolidaysAllocation(models.Model):
|
||||
@api.model
|
||||
def create(self, values):
|
||||
""" Override to avoid automatic logging of creation """
|
||||
if values.get('accrual', False):
|
||||
if values.get('allocation_type', 'regular') == 'accrual':
|
||||
values['date_from'] = fields.Datetime.now()
|
||||
employee_id = values.get('employee_id', False)
|
||||
if not values.get('department_id'):
|
||||
@@ -407,7 +410,7 @@ class HolidaysAllocation(models.Model):
|
||||
'number_of_days': self.number_of_days,
|
||||
'parent_id': self.id,
|
||||
'employee_id': employee.id,
|
||||
'accrual': self.accrual,
|
||||
'allocation_type': self.allocation_type,
|
||||
'date_to': self.date_to,
|
||||
'interval_unit': self.interval_unit,
|
||||
'interval_number': self.interval_number,
|
||||
@@ -450,7 +453,6 @@ class HolidaysAllocation(models.Model):
|
||||
self.filtered(lambda hol: hol.validation_type == 'both').write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
self.filtered(lambda hol: not hol.validation_type == 'both').action_validate()
|
||||
self.activity_update()
|
||||
return True
|
||||
|
||||
def action_validate(self):
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
|
||||
@@ -61,7 +61,7 @@ class HolidaysType(models.Model):
|
||||
compute='_compute_leaves', string='Remaining Time Off',
|
||||
help='Maximum Time Off Allowed - Time Off Already Taken')
|
||||
virtual_remaining_leaves = fields.Float(
|
||||
compute='_compute_leaves', string='Virtual Remaining Time Off',
|
||||
compute='_compute_leaves', search='_search_virtual_remaining_leaves' ,string='Virtual Remaining Time Off',
|
||||
help='Maximum Time Off Allowed - Time Off Already Taken - Time Off Waiting Approval')
|
||||
group_days_allocation = fields.Float(
|
||||
compute='_compute_group_days_allocation', string='Days Allocated')
|
||||
@@ -154,6 +154,30 @@ class HolidaysType(models.Model):
|
||||
|
||||
return [('id', 'in', valid_leave)]
|
||||
|
||||
def _search_virtual_remaining_leaves(self, operator, value):
|
||||
value = float(value)
|
||||
leave_types = self.env['hr.leave.type'].search([])
|
||||
valid_leave_types = self.env['hr.leave.type']
|
||||
|
||||
for leave_type in leave_types:
|
||||
if leave_type.allocation_type != 'no':
|
||||
if operator == '>' and leave_type.virtual_remaining_leaves > value:
|
||||
valid_leave_types |= leave_type
|
||||
elif operator == '<' and leave_type.virtual_remaining_leaves < value:
|
||||
valid_leave_types |= leave_type
|
||||
elif operator == '>=' and leave_type.virtual_remaining_leaves >= value:
|
||||
valid_leave_types |= leave_type
|
||||
elif operator == '<=' and leave_type.virtual_remaining_leaves <= value:
|
||||
valid_leave_types |= leave_type
|
||||
elif operator == '=' and leave_type.virtual_remaining_leaves == value:
|
||||
valid_leave_types |= leave_type
|
||||
elif operator == '!=' and leave_type.virtual_remaining_leaves != value:
|
||||
valid_leave_types |= leave_type
|
||||
else:
|
||||
valid_leave_types |= leave_type
|
||||
|
||||
return [('id', 'in', valid_leave_types.ids)]
|
||||
|
||||
def get_days(self, employee_id):
|
||||
# need to use `dict` constructor to create a dict per id
|
||||
result = dict((id, dict(max_leaves=0, leaves_taken=0, remaining_leaves=0, virtual_remaining_leaves=0)) for id in self.ids)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class Channel(models.Model):
|
||||
_inherit = 'mail.channel'
|
||||
|
||||
def partner_info(self, all_partners, direct_partners):
|
||||
partner_infos = super(Channel, self).partner_info(all_partners, direct_partners)
|
||||
# only search for leave out_of_office_message if im_status is on leave
|
||||
partners_on_leave = [partner_id for partner_id in direct_partners.ids if 'leave' in partner_infos[partner_id]['im_status']]
|
||||
if partners_on_leave:
|
||||
now = fields.Datetime.now()
|
||||
self.env.cr.execute('''SELECT res_users.partner_id as partner_id, hr_leave.out_of_office_message as out_of_office_message, hr_leave.date_to as date_to
|
||||
FROM res_users
|
||||
JOIN hr_leave ON hr_leave.user_id = res_users.id
|
||||
AND hr_leave.state not in ('cancel', 'refuse')
|
||||
AND res_users.active = 't'
|
||||
AND hr_leave.date_from <= %s
|
||||
AND hr_leave.date_to >= %s
|
||||
AND res_users.partner_id in %s''', (now, now, tuple(partners_on_leave)))
|
||||
out_of_office_infos = dict(((res['partner_id'], res) for res in self.env.cr.dictfetchall()))
|
||||
for partner_id, out_of_office_info in out_of_office_infos.items():
|
||||
partner_infos[partner_id]['out_of_office_date_end'] = out_of_office_info['date_to']
|
||||
partner_infos[partner_id]['out_of_office_message'] = out_of_office_info['out_of_office_message']
|
||||
return partner_infos
|
||||
@@ -111,11 +111,11 @@
|
||||
</record>
|
||||
|
||||
<record id="act_hr_employee_holiday_request" model="ir.actions.act_window">
|
||||
<field name="name">Time off</field>
|
||||
<field name="name">Time off Analysis</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">hr.leave.report</field>
|
||||
<field name="binding_model_id" ref="hr.model_hr_employee"/>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,form,pivot</field>
|
||||
<field name="context">{
|
||||
'search_default_group_type': 1,
|
||||
'search_default_year': 1}</field>
|
||||
|
||||
@@ -72,7 +72,9 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'hr.leave.allocation',
|
||||
name: 'New Allocation Request',
|
||||
views: [[false,'form']],
|
||||
context: {'form_view_ref': 'hr_holidays.hr_leave_allocation_view_form_dashboard'},
|
||||
target: 'new',
|
||||
}, {
|
||||
on_close: function () {
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
.o_timeoff_card {
|
||||
border-right: #adb5bd solid 2px;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
margin-top: 4px;
|
||||
div {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.o_timeoff_card_last {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<t t-set="cl" t-value="'o_timeoff_green'"/>
|
||||
</t>
|
||||
|
||||
<div>
|
||||
<div class="mt-2">
|
||||
<t t-if="need_allocation">
|
||||
<span t-esc="timeoff[1]['leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> / <span t-esc="timeoff[1]['max_leaves']"/> Days
|
||||
</t>
|
||||
@@ -20,9 +20,9 @@
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<span t-esc="timeoff[0]" class="o_timeoff_name"/>
|
||||
<b><span t-esc="timeoff[0]" class="o_timeoff_name"/></b>
|
||||
|
||||
<span t-if="need_allocation"><span t-attf-class="mr-1 font-weight-bold {{ cl }}" t-esc="timeoff[1]['remaining_leaves']"/><span class="text-muted">remaining</span></span>
|
||||
<span class="mb-4" t-if="need_allocation"><span t-attf-class="mr-1 font-weight-bold {{ cl }}" t-esc="timeoff[1]['remaining_leaves']"/><span>remaining</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -7,4 +7,3 @@ from . import test_hr_leave_type
|
||||
from . import test_accrual_allocations
|
||||
from . import test_change_department
|
||||
from . import test_leave_requests
|
||||
from . import test_out_of_office
|
||||
|
||||
@@ -51,7 +51,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': 'Accrual allocation for employee',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 1,
|
||||
'interval_number': 1,
|
||||
@@ -69,7 +69,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': 'Accrual allocation for employee with leaves',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 1,
|
||||
'interval_number': 1,
|
||||
@@ -108,7 +108,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': '1 day per 2 weeks',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 1,
|
||||
'interval_number': 2,
|
||||
@@ -120,7 +120,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': '4 hours per week',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 4,
|
||||
'interval_number': 1,
|
||||
@@ -132,7 +132,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': '2 day per 1 month',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 2,
|
||||
'interval_number': 1,
|
||||
@@ -144,7 +144,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': '20 days per year',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 20,
|
||||
'interval_number': 1,
|
||||
@@ -174,7 +174,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': 'one shot one kill',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 1,
|
||||
'interval_number': 1,
|
||||
@@ -194,7 +194,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': '2 days per week',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 1,
|
||||
'interval_number': 2,
|
||||
@@ -237,7 +237,7 @@ class TestAccrualAllocations(TestHrHolidaysBase):
|
||||
'name': 'accrual 5 max',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.accrual_type.id,
|
||||
'accrual': True,
|
||||
'allocation_type': 'accrual',
|
||||
'accrual_limit': 5,
|
||||
'number_of_days': 0,
|
||||
'number_per_interval': 6,
|
||||
|
||||
@@ -195,18 +195,6 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
_check_holidays_status(hol3_status, 20.0, 1.0, 19.0, 19.0)
|
||||
|
||||
def test_10_leave_summary_reports(self):
|
||||
# Print the HR Holidays(Summary Department) Report through the wizard
|
||||
ctx = {
|
||||
'model': 'hr.department',
|
||||
'active_ids': [self.ref('hr.employee_admin'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')]
|
||||
}
|
||||
data_dict = {
|
||||
'date_from': datetime.today().strftime('%Y-%m-01'),
|
||||
'depts': [(6, 0, [self.ref('hr.dep_sales')])],
|
||||
'holiday_type': 'Approved'
|
||||
}
|
||||
test_reports.try_report_action(self.env.cr, self.env.uid, 'action_hr_holidays_summary_dept', wiz_data=data_dict, context=ctx, our_module='hr_holidays')
|
||||
|
||||
# Print the HR Holidays(Summary Employee) Report through the wizard
|
||||
ctx = {
|
||||
'model': 'hr.employee',
|
||||
|
||||
@@ -174,6 +174,7 @@ class TestLeaveRequests(TestHrHolidaysBase):
|
||||
# employee should be set to current user
|
||||
allocation_form = Form(self.env['hr.leave.allocation'].with_user(self.user_employee))
|
||||
allocation_form.holiday_status_id = self.holidays_type_1
|
||||
allocation_form.name = 'New Allocation Request'
|
||||
allocation = allocation_form.save()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.tests.common import tagged, users, warmup, Form
|
||||
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase
|
||||
|
||||
|
||||
@tagged('out_of_office')
|
||||
class TestOutOfOffice(TestHrHolidaysBase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
'name': 'Legal Leaves',
|
||||
'time_type': 'leave',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
def test_leave_ooo(self):
|
||||
self.assertNotEqual(self.employee_hruser.user_id.im_status, 'leave_offline', 'user should not be on leave')
|
||||
self.assertNotEqual(self.employee_hruser.user_id.partner_id.im_status, 'leave_offline', 'user should not be on leave')
|
||||
leave_date_end = (datetime.today() + relativedelta(days=3))
|
||||
leave = self.env['hr.leave'].create({
|
||||
'name': 'Christmas',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'date_from': (datetime.today() - relativedelta(days=1)),
|
||||
'date_to': leave_date_end,
|
||||
'out_of_office_message': 'contact tde in case of problems',
|
||||
'number_of_days': 4,
|
||||
})
|
||||
leave.action_approve()
|
||||
self.assertEqual(self.employee_hruser.user_id.im_status, 'leave_offline', 'user should be out (leave_offline)')
|
||||
self.assertEqual(self.employee_hruser.user_id.partner_id.im_status, 'leave_offline', 'user should be out (leave_offline)')
|
||||
|
||||
partner = self.employee_hruser.user_id.partner_id
|
||||
partner2 = self.user_employee.partner_id
|
||||
|
||||
channel = self.env['mail.channel'].with_context({
|
||||
'mail_create_nolog': True,
|
||||
'mail_create_nosubscribe': True,
|
||||
'mail_channel_noautofollow': True,
|
||||
}).create({
|
||||
'channel_partner_ids': [(4, partner.id), (4, partner2.id)],
|
||||
'public': 'private',
|
||||
'channel_type': 'chat',
|
||||
'email_send': False,
|
||||
'name': 'test'
|
||||
})
|
||||
infos = channel.with_user(self.user_employee).channel_info()
|
||||
self.assertEqual(infos[0]['direct_partner'][0]['out_of_office_date_end'], leave_date_end)
|
||||
self.assertEqual(infos[0]['direct_partner'][0]['out_of_office_message'], 'contact tde in case of problems')
|
||||
|
||||
def test_leave_ooo_use_default(self):
|
||||
""" Out of office message from Preferences should be used as default value """
|
||||
self.user_hruser.out_of_office_message = 'contact xdo in case of problems'
|
||||
|
||||
leave_form = Form(self.env['hr.leave'].with_user(self.user_hruser), view='hr_holidays.hr_leave_view_form')
|
||||
leave_form.date_from = datetime.today() - relativedelta(days=1)
|
||||
leave_form.date_to = datetime.today()
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave = leave_form.save()
|
||||
self.assertEqual(leave.out_of_office_message, 'contact xdo in case of problems')
|
||||
|
||||
def test_leave_ooo_overwrite_default(self):
|
||||
""" Out of office message default value should be overwrittable """
|
||||
self.user_hruser.out_of_office_message = 'contact xdo in case of problems'
|
||||
|
||||
leave_form = Form(self.env['hr.leave'].with_user(self.user_hruser), view='hr_holidays.hr_leave_view_form')
|
||||
leave_form.date_from = datetime.today() - relativedelta(days=1)
|
||||
leave_form.date_to = datetime.today()
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.out_of_office_message = 'contact tde in case of problems'
|
||||
leave = leave_form.save()
|
||||
self.assertEqual(leave.out_of_office_message, 'contact tde in case of problems')
|
||||
|
||||
|
||||
@tagged('out_of_office')
|
||||
class TestOutOfOfficePerformance(TestHrHolidaysBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOutOfOfficePerformance, self).setUp()
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
'name': 'Legal Leaves',
|
||||
'time_type': 'leave',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
self.leave_date_end = (datetime.today() + relativedelta(days=3))
|
||||
self.leave = self.env['hr.leave'].create({
|
||||
'name': 'Christmas',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'date_from': (datetime.today() - relativedelta(days=1)),
|
||||
'date_to': (datetime.today() + relativedelta(days=3)),
|
||||
'out_of_office_message': 'contact tde in case of problems',
|
||||
'number_of_days': 4,
|
||||
})
|
||||
|
||||
self.hr_user = self.employee_hruser.user_id
|
||||
self.hr_partner = self.employee_hruser.user_id.partner_id
|
||||
self.employer_partner = self.user_employee.partner_id
|
||||
|
||||
@users('__system__', 'demo')
|
||||
@warmup
|
||||
def test_leave_im_status_performance_partner_offline(self):
|
||||
with self.assertQueryCount(__system__=2, demo=2):
|
||||
self.assertEqual(self.employer_partner.im_status, 'offline')
|
||||
|
||||
@users('__system__', 'demo')
|
||||
@warmup
|
||||
def test_leave_im_status_performance_user_leave_offline(self):
|
||||
with self.assertQueryCount(__system__=2, demo=2):
|
||||
self.assertEqual(self.hr_user.im_status, 'leave_offline')
|
||||
|
||||
@users('__system__', 'demo')
|
||||
@warmup
|
||||
def test_leave_im_status_performance_partner_leave_offline(self):
|
||||
with self.assertQueryCount(__system__=2, demo=2):
|
||||
self.assertEqual(self.hr_partner.im_status, 'leave_offline')
|
||||
@@ -113,21 +113,14 @@
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_available_holidays_report_tree"
|
||||
name="Time Off Analysis"
|
||||
name="by Employee"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="action_hr_available_holidays_report"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_summary_dept"
|
||||
name="Report by Department"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="action_hr_holidays_summary_dept"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_summary_all"
|
||||
name="Time Off Summary"
|
||||
name="by Type"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="act_hr_employee_holiday_request"
|
||||
sequence="3"/>
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
<search string="Search allocations">
|
||||
<field name="employee_id"/>
|
||||
<field name="name"/>
|
||||
<field name="accrual"/>
|
||||
<field name="allocation_type"/>
|
||||
<filter domain="[('state','in',('confirm', 'validate1'))]" string="To Approve" name="approve"/>
|
||||
<filter string="Approved Allocations" domain="[('state', '=', 'validate')]" name="validated"/>
|
||||
<filter string="Accrual Allocations" domain="[('accrual', '=', True)]" name="accrual_allocation"/>
|
||||
<filter string="Accrual Allocations" domain="[('allocation_type', '=', 'accrual')]" name="accrual_allocation"/>
|
||||
<separator/>
|
||||
<filter name="active_types" string="Active Types" domain="[('holiday_status_id.active', '=', True)]" help="Filters only on allocations that belong to an time off type that is 'active' (active field is True)"/>
|
||||
<separator/>
|
||||
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="My Department Time Off" name="department" domain="[('department_id.member_ids.user_id', '=', uid)]" help="My Department Time Off"/>
|
||||
<filter string="People I Manage" name="managed_people" domain="[('employee_id.leave_manager_id', '=', uid)]" help="Time off of people you are manager of"/>
|
||||
<filter string="My Team Time Off" name="my_team_leaves" domain="[('employee_id.parent_id.user_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_manager" help="Time Off of Your Team Member"/>
|
||||
<separator/>
|
||||
<filter name="year" string="Current Year"
|
||||
@@ -35,8 +35,6 @@
|
||||
<filter invisible="1" string="Future Activities" name="activities_upcoming_all"
|
||||
domain="[('activity_ids.date_deadline', '>', context_today().strftime('%Y-%m-%d'))
|
||||
]"/>
|
||||
<filter string="Exception Activities" name="activities_exception"
|
||||
domain="[('activity_exception_decoration', '!=', False)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_name" string="Description" context="{'group_by':'name'}"/>
|
||||
<filter name="group_employee" string="Employee" context="{'group_by':'employee_id'}"/>
|
||||
@@ -87,12 +85,14 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="type_request_unit" invisible="1"/>
|
||||
<field name="name" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}"/>
|
||||
<field name="name" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}" required="1"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id}"/>
|
||||
|
||||
<field name="allocation_type" invisible="1" widget="radio"/>
|
||||
|
||||
<field name="number_of_days" invisible="1"/>
|
||||
<label for="number_of_days" string="Duration"/>
|
||||
<div>
|
||||
<label for="number_of_days" string="Duration" attrs="{'invisible': [('allocation_type', '=', 'accrual')]}"/>
|
||||
<div attrs="{'invisible': [('allocation_type', '=', 'accrual')]}">
|
||||
<field name="number_of_days_display" class="oe_inline" nolabel="1"
|
||||
attrs="{'readonly': ['|', ('type_request_unit', '=', 'hour'), ('state', 'not in', ('draft', 'confirm'))], 'invisible': [('type_request_unit', '=', 'hour')]}"/>
|
||||
<field name="number_of_hours_display" class="oe_inline" nolabel="1"
|
||||
@@ -100,8 +100,6 @@
|
||||
<span class="ml8" attrs="{'invisible': [('type_request_unit', '=', 'hour')]}">Days</span>
|
||||
<span class="ml8" attrs="{'invisible': [('type_request_unit', '!=', 'hour')]}">Hours</span>
|
||||
</div>
|
||||
|
||||
<field name="accrual" invisible="1"/>
|
||||
</group>
|
||||
<group name="alloc_right_col">
|
||||
<field name="employee_id" invisible="1" groups="hr_holidays.group_hr_holidays_user"/>
|
||||
@@ -148,33 +146,33 @@
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='department_id']" position="replace">
|
||||
<field name="department_id" groups="hr_holidays.group_hr_holidays_user"
|
||||
attrs="{'required': [('holiday_type', '=', 'department')], 'invisible': [('holiday_type', 'not in', ('department', 'category'))]}"/>
|
||||
attrs="{'required': [('holiday_type', '=', 'department')], 'invisible': [('holiday_type', '!=', 'department')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='department_id']" position="after">
|
||||
<field name="mode_company_id" groups="hr_holidays.group_hr_holidays_user"
|
||||
attrs="{'required': [('holiday_type', '=', 'company')], 'invisible': [('holiday_type', '!=', 'company')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='accrual']" position="attributes">
|
||||
<xpath expr="//field[@name='allocation_type']" position="attributes">
|
||||
<attribute name="invisible">0</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='accrual']" position="after">
|
||||
<xpath expr="//field[@name='allocation_type']" position="after">
|
||||
<label for="date_to" string=""
|
||||
attrs="{'invisible': [('accrual', '=', False)]}"/>
|
||||
<div attrs="{'invisible': [('accrual', '=', False)]}">
|
||||
attrs="{'invisible': [('allocation_type', '=', 'regular')]}"/>
|
||||
<div attrs="{'invisible': [('allocation_type', '=', 'regular')]}">
|
||||
<div class="o_row">
|
||||
Run until <field name="date_to" string="Run Until" help="If no value set, runs indefinitely"/>
|
||||
Run until <field name="date_to" string="Run Until" help="If no value set, runs indefinitely" class="ml-2" widget="date"/>
|
||||
</div>
|
||||
<div class="o_row">
|
||||
<span>Add</span>
|
||||
<field name="number_per_interval" class="ml8"
|
||||
attrs="{'required': [('accrual', '=', True)]}"/>
|
||||
attrs="{'required': [('allocation_type', '=', 'accrual')]}"/>
|
||||
<field name="unit_per_interval"
|
||||
attrs="{'required': [('accrual', '=', True)]}"/>
|
||||
attrs="{'required': [('allocation_type', '=', 'accrual')]}"/>
|
||||
<span class="ml8">of time off every</span>
|
||||
<field name="interval_number" class="ml8"
|
||||
attrs="{'required': [('accrual', '=', True)]}"/>
|
||||
attrs="{'required': [('allocation_type', '=', 'accrual')]}"/>
|
||||
<field name="interval_unit"
|
||||
attrs="{'required': [('accrual', '=', True)]}"/>
|
||||
attrs="{'required': [('allocation_type', '=', 'accrual')]}"/>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
@@ -189,7 +187,7 @@
|
||||
<tree decoration-danger="state == 'refuse'" decoration-info="state == 'draft'" string="Allocation Requests"
|
||||
decoration-bf="message_needaction == True">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" optional="hide"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<field name="name"/>
|
||||
<field name="duration_display"/>
|
||||
@@ -370,7 +368,7 @@
|
||||
<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_department':1, 'search_default_approve':1}</field>
|
||||
<field name="context">{'search_default_managed_people':1, 'search_default_approve':1}</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
@@ -382,4 +380,29 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_actions_server_approve_allocations" model="ir.actions.server">
|
||||
<field name="name">Approve Allocations</field>
|
||||
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||
<field name="binding_model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = records.action_approve()</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_view_form_dashboard" model="ir.ui.view">
|
||||
<field name="name">hr.leave.view.form.dashboard</field>
|
||||
<field name="model">hr.leave.allocation</field>
|
||||
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="priority">100</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<div name="button_box" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<group>
|
||||
<group name="description" string="Options">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="code"/>
|
||||
<field name="code" string="Payroll Code"/>
|
||||
<field name="request_unit" widget="radio"/>
|
||||
</group>
|
||||
<group name="validation" string="Validation">
|
||||
|
||||
@@ -58,10 +58,6 @@
|
||||
<filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
|
||||
<filter string="Approved Time Off" domain="[('state', '=', 'validate')]" name="validated"/>
|
||||
<separator/>
|
||||
<filter name="active_types" string="Active Types" domain="[('holiday_status_id.active', '=', True)]" help="Filters only on requests that belong to an time off type that is 'active' (active field is True)"/>
|
||||
<separator/>
|
||||
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="My Department Time Off" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department Time Off"/>
|
||||
<filter string="People I Manage" name="managed_people" domain="[('employee_id.leave_manager_id', '=', uid)]" help="Time off of people you are manager of"/>
|
||||
<filter string="My Time Off" name="my_leaves" domain="[('employee_id.user_id', '=', uid)]"/>
|
||||
@@ -70,7 +66,7 @@
|
||||
<separator/>
|
||||
<filter string="To Do" name="todo" domain="[('payslip_status', '=', False), ('holiday_status_id.active', '=', True)]"/>
|
||||
<separator/>
|
||||
<filter name="year" string="Current Year"
|
||||
<filter name="year" string="Active Time Off"
|
||||
domain="[('holiday_status_id.active', '=', True)]" help="Active Time Off"/>
|
||||
<filter invisible="1" string="Late Activities" name="activities_overdue"
|
||||
domain="[('activity_ids.date_deadline', '<', context_today().strftime('%Y-%m-%d'))]"
|
||||
@@ -219,10 +215,13 @@
|
||||
<field name="display_name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col-2" for="holiday_status_id"/>
|
||||
<!-- RLI FIXME: we should avoid redefining the domain in the view when there already is a domain on the model -->
|
||||
<field name="holiday_status_id" domain="['&', ('virtual_remaining_leaves', '>', 0), '|', ('allocation_type', 'in', ['fixed_allocation', 'no']),'&',('allocation_type', '=', 'fixed'), ('max_leaves', '>', '0')]" context="{'employee_id':employee_id, 'default_date_from':date_from}" options="{'no_create': True, 'no_open': True}" class="col-9" nolabel="1"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<!-- RLI FIXME: we should avoid redefining the domain in the view when there already is a domain on the model -->
|
||||
<field name="holiday_status_id" domain="['|',('allocation_type', 'in', ['fixed_allocation', 'no']),'&',('allocation_type', '=', 'fixed'), ('max_leaves', '>', '0')]" context="{'employee_id':employee_id, 'default_date_from':date_from}" options="{'no_create': True, 'no_open': True}"/>
|
||||
|
||||
<label for="request_date_from" string="From"/>
|
||||
<div>
|
||||
@@ -249,28 +248,28 @@
|
||||
'invisible': [('request_unit_half', '=', False)]}"/>
|
||||
</div>
|
||||
<div class="o_row o_row_readonly oe_edit_only">
|
||||
<label for="request_unit_half" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
'invisible': [('leave_type_request_unit', '=', 'day')]
|
||||
}"/>
|
||||
<field name="request_unit_half" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
'invisible': [('leave_type_request_unit', '=', 'day')]
|
||||
}"/>
|
||||
<label for="request_unit_hours" attrs="{
|
||||
<label for="request_unit_half" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
'invisible': [('leave_type_request_unit', '!=', 'hour')]
|
||||
'invisible': [('leave_type_request_unit', '=', 'day')]
|
||||
}"/>
|
||||
<field name="request_unit_hours" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
'invisible': [('leave_type_request_unit', '!=', 'hour')]
|
||||
}"/>
|
||||
<label for="request_unit_custom" invisible="1" attrs="{
|
||||
<label for="request_unit_hours" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
'invisible': [('leave_type_request_unit', '!=', 'hour')]
|
||||
}"/>
|
||||
<field name="request_unit_custom" invisible="1" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
}"/>
|
||||
<label for="request_unit_custom" invisible="1" attrs="{
|
||||
'readonly': [('state', 'not in', ('draft', 'confirm'))],
|
||||
}"/>
|
||||
</div>
|
||||
<div class="o_row o_row_readonly">
|
||||
<label for="request_hour_from" string="From"
|
||||
@@ -292,8 +291,8 @@
|
||||
|
||||
<!-- When the user is leave manager, he should always see `number_of_days` to allow
|
||||
him to edit the value. `number_of_hours_display` is only an informative field -->
|
||||
<label for="number_of_days" string="Duration"/>
|
||||
<div>
|
||||
<label for="number_of_days" string="Duration" attrs="{'invisible': ['|', ('request_unit_half', '=', True), ('request_unit_hours', '=', True)]}"/>
|
||||
<div attrs="{'invisible': ['|', ('request_unit_half', '=', True), ('request_unit_hours', '=', True)]}">
|
||||
<div groups="!hr_holidays.group_hr_holidays_manager" attrs="{'invisible': [('leave_type_request_unit', '=', 'hour')]}">
|
||||
<field name="number_of_days_display" nolabel="1" readonly="1" class="oe_inline"/>
|
||||
<span class="ml8">Days</span>
|
||||
@@ -308,15 +307,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<field name="name" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="out_of_office_message"/>
|
||||
</group>
|
||||
<group name="col_right">
|
||||
<field name="employee_id" invisible="1"/>
|
||||
<field name="department_id" groups="hr_holidays.group_hr_holidays_user" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<div class="row">
|
||||
<label class="col-2" for="name"/>
|
||||
<field name="name" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}" class="col-9" nolabel="1"/>
|
||||
</div>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
@@ -467,6 +468,12 @@
|
||||
<xpath expr="//field[@name='employee_id']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='department_id']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='holiday_type']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='payslip_status']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
@@ -498,6 +505,7 @@
|
||||
<field name="res_model">hr.leave</field>
|
||||
<field name="view_mode">calendar,tree,form,activity</field>
|
||||
<field name="domain">[('user_id', '=', uid)]</field>
|
||||
<field name="context">{'short_name': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new time off request
|
||||
@@ -676,7 +684,7 @@
|
||||
<field name="name">Time Off Analysis</field>
|
||||
<field name="res_model">hr.leave</field>
|
||||
<field name="view_mode">graph,pivot,calendar,form</field>
|
||||
<field name="context">{'search_default_leaves':1}</field>
|
||||
<field name="context">{'search_default_year': 1, 'search_default_group_employee': 1, 'search_default_group_type': 1}</field>
|
||||
</record>
|
||||
|
||||
<record id="action_window_leave_graph" model="ir.actions.act_window.view">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import hr_holidays_summary_department
|
||||
from . import hr_holidays_summary_employees
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import time
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class HolidaysSummaryDept(models.TransientModel):
|
||||
|
||||
_name = 'hr.holidays.summary.dept'
|
||||
_description = 'HR Time Off Summary Report By Department'
|
||||
|
||||
date_from = fields.Date(string='From', required=True, default=lambda *a: time.strftime('%Y-%m-01'))
|
||||
depts = fields.Many2many('hr.department', 'summary_dept_rel', 'sum_id', 'dept_id', string='Department(s)')
|
||||
holiday_type = fields.Selection([
|
||||
('Approved', 'Approved'),
|
||||
('Confirmed', 'Confirmed'),
|
||||
('both', 'Both Approved and Confirmed')
|
||||
], string='Time Off Type', required=True, default='Approved')
|
||||
|
||||
def print_report(self):
|
||||
self.ensure_one()
|
||||
[data] = self.read()
|
||||
if not data.get('depts'):
|
||||
raise UserError(_('You have to select at least one department.'))
|
||||
departments = self.env['hr.department'].browse(data['depts'])
|
||||
datas = {
|
||||
'ids': [],
|
||||
'model': 'hr.department',
|
||||
'form': data
|
||||
}
|
||||
return self.env.ref('hr_holidays.action_report_holidayssummary').with_context(from_transient_model=True).report_action(departments, data=datas)
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_hr_holidays_summary_dept" model="ir.ui.view">
|
||||
<field name="name">hr.holidays.summary.dept.form</field>
|
||||
<field name="model">hr.holidays.summary.dept</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Time Off by Department">
|
||||
<group>
|
||||
<field name="date_from" />
|
||||
<field name="holiday_type"/>
|
||||
<field name="depts"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="print_report" string="Print" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" special="cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_holidays_summary_dept" model="ir.actions.act_window">
|
||||
<field name="name">Time Off by Department</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">hr.holidays.summary.dept</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user