diff options
| author | Yannick Tivisse <yti@odoo.com> | 2019-08-14 15:26:41 +0000 |
|---|---|---|
| committer | Yannick Tivisse <yti@odoo.com> | 2019-08-16 11:24:04 +0000 |
| commit | abd73d61a20466cc61525557d8750e8d8fcc2aa7 (patch) | |
| tree | 9898f54cafc2ef942a067260c6d88d9f069eb3a4 /addons | |
| parent | c058562d7301298fd71b2618b5386611dfeb81cb (diff) | |
[IMP] hr_holidays: Improve general UX (back2basics)
TaskID: 2053585
closes odoo/odoo#35737
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons')
24 files changed, 130 insertions, 358 deletions
diff --git a/addons/hr/views/res_users.xml b/addons/hr/views/res_users.xml index cab22bb0cf7..dc030c4b420 100644 --- a/addons/hr/views/res_users.xml +++ b/addons/hr/views/res_users.xml @@ -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> diff --git a/addons/hr_holidays/__manifest__.py b/addons/hr_holidays/__manifest__.py index 17e469332be..f41b34cc4cf 100644 --- a/addons/hr_holidays/__manifest__.py +++ b/addons/hr_holidays/__manifest__.py @@ -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', diff --git a/addons/hr_holidays/data/hr_holidays_demo.xml b/addons/hr_holidays/data/hr_holidays_demo.xml index 1199aea6686..7aa5139583e 100644 --- a/addons/hr_holidays/data/hr_holidays_demo.xml +++ b/addons/hr_holidays/data/hr_holidays_demo.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"> diff --git a/addons/hr_holidays/models/__init__.py b/addons/hr_holidays/models/__init__.py index 0697c64a04e..368a7bc4bf1 100644 --- a/addons/hr_holidays/models/__init__.py +++ b/addons/hr_holidays/models/__init__.py @@ -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 diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 067c37909ea..7b95214e71f 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -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: diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index e37a0f6979d..b11cbffe465 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -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) diff --git a/addons/hr_holidays/models/hr_leave_type.py b/addons/hr_holidays/models/hr_leave_type.py index cb3cbe34a0f..46ac9886973 100644 --- a/addons/hr_holidays/models/hr_leave_type.py +++ b/addons/hr_holidays/models/hr_leave_type.py @@ -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) diff --git a/addons/hr_holidays/models/mail_channel.py b/addons/hr_holidays/models/mail_channel.py deleted file mode 100644 index 8342aeb54eb..00000000000 --- a/addons/hr_holidays/models/mail_channel.py +++ /dev/null @@ -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 diff --git a/addons/hr_holidays/report/hr_leave_reports.xml b/addons/hr_holidays/report/hr_leave_reports.xml index 20bc19d8451..9e48b10678d 100644 --- a/addons/hr_holidays/report/hr_leave_reports.xml +++ b/addons/hr_holidays/report/hr_leave_reports.xml @@ -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> diff --git a/addons/hr_holidays/static/src/js/time_off_calendar.js b/addons/hr_holidays/static/src/js/time_off_calendar.js index c4b27814e1e..36dd3f6387e 100644 --- a/addons/hr_holidays/static/src/js/time_off_calendar.js +++ b/addons/hr_holidays/static/src/js/time_off_calendar.js @@ -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 () { diff --git a/addons/hr_holidays/static/src/scss/time_off.scss b/addons/hr_holidays/static/src/scss/time_off.scss index e7efa3e1604..b32aae50df8 100644 --- a/addons/hr_holidays/static/src/scss/time_off.scss +++ b/addons/hr_holidays/static/src/scss/time_off.scss @@ -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 { diff --git a/addons/hr_holidays/static/src/xml/time_off_calendar.xml b/addons/hr_holidays/static/src/xml/time_off_calendar.xml index 24ecac05586..70bba2fd937 100644 --- a/addons/hr_holidays/static/src/xml/time_off_calendar.xml +++ b/addons/hr_holidays/static/src/xml/time_off_calendar.xml @@ -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> diff --git a/addons/hr_holidays/tests/__init__.py b/addons/hr_holidays/tests/__init__.py index 67c8327e999..9510f75b34b 100644 --- a/addons/hr_holidays/tests/__init__.py +++ b/addons/hr_holidays/tests/__init__.py @@ -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 diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py index 205875c5d74..89e19437dcd 100644 --- a/addons/hr_holidays/tests/test_accrual_allocations.py +++ b/addons/hr_holidays/tests/test_accrual_allocations.py @@ -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, diff --git a/addons/hr_holidays/tests/test_holidays_flow.py b/addons/hr_holidays/tests/test_holidays_flow.py index 15cf8f173e8..1a9e06125fc 100644 --- a/addons/hr_holidays/tests/test_holidays_flow.py +++ b/addons/hr_holidays/tests/test_holidays_flow.py @@ -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', diff --git a/addons/hr_holidays/tests/test_leave_requests.py b/addons/hr_holidays/tests/test_leave_requests.py index 495d2317caf..5b781d5f176 100644 --- a/addons/hr_holidays/tests/test_leave_requests.py +++ b/addons/hr_holidays/tests/test_leave_requests.py @@ -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') diff --git a/addons/hr_holidays/tests/test_out_of_office.py b/addons/hr_holidays/tests/test_out_of_office.py deleted file mode 100644 index 70ca001da0e..00000000000 --- a/addons/hr_holidays/tests/test_out_of_office.py +++ /dev/null @@ -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') diff --git a/addons/hr_holidays/views/hr_holidays_views.xml b/addons/hr_holidays/views/hr_holidays_views.xml index 45ea1cf7340..832de6634fc 100644 --- a/addons/hr_holidays/views/hr_holidays_views.xml +++ b/addons/hr_holidays/views/hr_holidays_views.xml @@ -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"/> diff --git a/addons/hr_holidays/views/hr_leave_allocation_views.xml b/addons/hr_holidays/views/hr_leave_allocation_views.xml index 03daeb41873..6df1d9705a4 100644 --- a/addons/hr_holidays/views/hr_leave_allocation_views.xml +++ b/addons/hr_holidays/views/hr_leave_allocation_views.xml @@ -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> diff --git a/addons/hr_holidays/views/hr_leave_type_views.xml b/addons/hr_holidays/views/hr_leave_type_views.xml index eda5a748a14..33ef8e53aeb 100644 --- a/addons/hr_holidays/views/hr_leave_type_views.xml +++ b/addons/hr_holidays/views/hr_leave_type_views.xml @@ -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"> diff --git a/addons/hr_holidays/views/hr_leave_views.xml b/addons/hr_holidays/views/hr_leave_views.xml index aaa881c4f95..59f8f34b992 100644 --- a/addons/hr_holidays/views/hr_leave_views.xml +++ b/addons/hr_holidays/views/hr_leave_views.xml @@ -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,26 +248,26 @@ 'invisible': [('request_unit_half', '=', False)]}"/> </div> <div class="o_row o_row_readonly oe_edit_only"> - <label for="request_unit_half" attrs="{ + <field name="request_unit_half" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], 'invisible': [('leave_type_request_unit', '=', 'day')] }"/> - <field name="request_unit_half" attrs="{ + <label for="request_unit_half" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], 'invisible': [('leave_type_request_unit', '=', 'day')] }"/> - <label for="request_unit_hours" attrs="{ + <field name="request_unit_hours" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], 'invisible': [('leave_type_request_unit', '!=', 'hour')] }"/> - <field name="request_unit_hours" attrs="{ + <label for="request_unit_hours" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], 'invisible': [('leave_type_request_unit', '!=', 'hour')] }"/> - <label for="request_unit_custom" invisible="1" attrs="{ + <field name="request_unit_custom" invisible="1" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], }"/> - <field name="request_unit_custom" invisible="1" attrs="{ + <label for="request_unit_custom" invisible="1" attrs="{ 'readonly': [('state', 'not in', ('draft', 'confirm'))], }"/> </div> @@ -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"> diff --git a/addons/hr_holidays/wizard/__init__.py b/addons/hr_holidays/wizard/__init__.py index e8b5ecf45ac..c69c60bfbfb 100644 --- a/addons/hr_holidays/wizard/__init__.py +++ b/addons/hr_holidays/wizard/__init__.py @@ -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 diff --git a/addons/hr_holidays/wizard/hr_holidays_summary_department.py b/addons/hr_holidays/wizard/hr_holidays_summary_department.py deleted file mode 100644 index 995e9926a18..00000000000 --- a/addons/hr_holidays/wizard/hr_holidays_summary_department.py +++ /dev/null @@ -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) diff --git a/addons/hr_holidays/wizard/hr_holidays_summary_department_views.xml b/addons/hr_holidays/wizard/hr_holidays_summary_department_views.xml deleted file mode 100644 index c5bf3cb4613..00000000000 --- a/addons/hr_holidays/wizard/hr_holidays_summary_department_views.xml +++ /dev/null @@ -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> |
