diff --git a/addons/hr_holidays/data/hr_holidays_data.xml b/addons/hr_holidays/data/hr_holidays_data.xml index 20ae0403cd6..57b2fdb57c5 100644 --- a/addons/hr_holidays/data/hr_holidays_data.xml +++ b/addons/hr_holidays/data/hr_holidays_data.xml @@ -1,11 +1,10 @@ - - + - + fixed black @@ -14,14 +13,16 @@ Sick Leaves - + no red + Compensatory Days - + fixed_allocation + hour lavender @@ -30,8 +31,11 @@ Unpaid + fixed_allocation + both brown + diff --git a/addons/hr_holidays/data/hr_holidays_demo.xml b/addons/hr_holidays/data/hr_holidays_demo.xml index 0ab4e8a574e..29f5ebf723f 100644 --- a/addons/hr_holidays/data/hr_holidays_demo.xml +++ b/addons/hr_holidays/data/hr_holidays_demo.xml @@ -4,7 +4,7 @@ Overtime Compensation - + fixed_allocation blue @@ -13,18 +13,17 @@ Parental Leaves - + fixed brown both - + fixed wheat - diff --git a/addons/hr_holidays/models/hr.py b/addons/hr_holidays/models/hr.py index e593b88b89a..908dc25eadd 100644 --- a/addons/hr_holidays/models/hr.py +++ b/addons/hr_holidays/models/hr.py @@ -104,7 +104,7 @@ class Employee(models.Model): join hr_leave_type s ON (s.id=h.holiday_status_id) WHERE h.state='validate' AND - s.limit=False AND + (s.allocation_type='fixed' OR s.allocation_type='fixed_allocation') AND h.employee_id in %s GROUP BY h.employee_id""", (tuple(self.ids),)) return dict((row['employee_id'], row['days']) for row in self._cr.dictfetchall()) @@ -142,7 +142,6 @@ class Employee(models.Model): def _compute_leaves_count(self): all_leaves = self.env['hr.leave.report'].read_group([ ('employee_id', 'in', self.ids), - ('holiday_status_id.limit', '=', False), ('state', '=', 'validate') ], fields=['number_of_days', 'employee_id'], groupby=['employee_id']) mapping = dict([(leave['employee_id'][0], leave['number_of_days']) for leave in all_leaves]) diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 637e4770e06..e343e5c9406 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -59,17 +59,12 @@ class HolidaysRequest(models.Model): _inherit = ['mail.thread', 'mail.activity.mixin'] _mail_post_access = 'read' - def _default_domain_holiday_status(self): - if self.user_has_groups('hr_holidays.group_hr_holidays_manager'): - return [('valid', '=', True)] - return [('valid', '=', True), ('employee_applicability', 'in', ['leave', 'both'])] - @api.model def default_get(self, fields_list): defaults = super(HolidaysRequest, self).default_get(fields_list) LeaveType = self.env['hr.leave.type'].with_context(employee_id=defaults.get('employee_id'), default_date_from=defaults.get('date_from', fields.Datetime.now())) - lt = LeaveType.search(self._default_domain_holiday_status()) + lt = LeaveType.search([('valid', '=', True)]) defaults['holiday_status_id'] = lt[0].id if len(lt) > 0 else defaults.get('holiday_status_id') return defaults @@ -103,7 +98,7 @@ class HolidaysRequest(models.Model): holiday_status_id = fields.Many2one( "hr.leave.type", string="Leave Type", required=True, readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, - domain=lambda self: self._default_domain_holiday_status()) + domain=[('valid', '=', True)]) leave_type_request_unit = fields.Selection(related='holiday_status_id.request_unit', readonly=True) validation_type = fields.Selection('Validation Type', related='holiday_status_id.validation_type') # HR data @@ -156,13 +151,9 @@ class HolidaysRequest(models.Model): request_date_to_period = fields.Selection([ ('am', 'Morning'), ('pm', 'Afternoon')], string="Date Period End", default='pm') - # request type + duplicate because we cannot hide some entries of a selection field - request_unit_all = fields.Selection([('half', 'Half-day'), - ('day', '1 Day'), - ('period', 'Period')], default='day') - request_unit_day = fields.Selection([('day', '1 Day'), - ('period', 'Period')], default='day') - + # request type + request_unit = fields.Selection([('day', '1 Day'), + ('period', 'Period')], default='day') _sql_constraints = [ ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL) or (holiday_type='department' AND department_id IS NOT NULL) )", "The employee, department or employee category of this request is missing. Please make sure that your user login is linked to an employee."), @@ -170,7 +161,7 @@ class HolidaysRequest(models.Model): ('date_check', "CHECK ( number_of_days_temp >= 0 )", "If you want to change the number of days you should use the 'period' mode"), ] - @api.onchange('request_unit_all', 'request_date_from_period', 'request_date_to_period', + @api.onchange('request_unit', 'request_date_from_period', 'request_date_to_period', 'holiday_status_id', 'request_date_from', 'request_date_to', 'employee_id') def _onchange_request_parameters(self): date_from = False @@ -205,7 +196,7 @@ class HolidaysRequest(models.Model): first_day = fields.Date.from_string(date_from) last_day = fields.Date.from_string(date_to) - if self.request_unit_all in ['day', 'half']: + if self.request_unit in ['day']: last_day = first_day # find first attendance coming after first_day @@ -213,19 +204,11 @@ class HolidaysRequest(models.Model): # find last attendance coming before last_day attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= last_day.weekday()), attendances[-1]) - if self.request_unit_all == 'day' or (self.request_unit_all == 'period' and self.leave_type_request_unit == 'day'): + if self.request_unit == 'day' or (self.request_unit == 'period' and self.leave_type_request_unit == 'day'): hour_from = float_to_time(attendance_from.hour_from) hour_to = float_to_time(attendance_to.hour_to) - elif self.request_unit_all == 'half': - hour_from = float_to_time(attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_to.hour_from) - hour_to = float_to_time(attendance_from.hour_to if self.request_date_from_period == 'am' else attendance_to.hour_to) - - elif self.request_unit_all == 'period' and self.leave_type_request_unit == 'half': - hour_from = float_to_time(attendance_from.hour_from if self.request_date_from_period == 'am' else attendance_from.hour_to) - hour_to = float_to_time(attendance_to.hour_from if self.request_date_to_period == 'am' else attendance_to.hour_to) - - if self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period': + if self.request_unit == 'period' and self.leave_type_request_unit == 'hour': date_from = fields.Datetime.from_string(date_from) date_to = fields.Datetime.from_string(date_to) else: @@ -236,16 +219,12 @@ class HolidaysRequest(models.Model): self.date_from = date_from self.date_to = date_to - if not (self.leave_type_request_unit == 'hour' and self.request_unit_all == 'period'): + if not (self.request_unit == 'period' and self.leave_type_request_unit == 'hour'): date_from = date_from date_to = date_to self.number_of_days_temp = self._get_number_of_days(date_from, date_to, self.employee_id.id) - @api.onchange('request_unit_day') - def _onchange_request_unit_day(self): - self.request_unit_all = self.request_unit_day - @api.onchange('holiday_type') def _onchange_type(self): if self.holiday_type == 'employee' and not self.employee_id: @@ -276,8 +255,7 @@ class HolidaysRequest(models.Model): self.request_date_to = date_to.date() if date_to else False if (date_from and date_to) and (date_from.day < date_to.day): - self.request_unit_all = 'period' - self.request_unit_day = 'period' + self.request_unit = 'period' # Compute and update the number of days if (date_to and date_from) and (date_from <= date_to): @@ -295,8 +273,7 @@ class HolidaysRequest(models.Model): self.request_date_to = date_to.date() if date_to else False if (date_from and date_to) and (date_from.day < date_to.day): - self.request_unit_all = 'period' - self.request_unit_day = 'period' + self.request_unit = 'period' # Compute and update the number of days if (date_to and date_from) and (date_from <= date_to): @@ -362,7 +339,7 @@ class HolidaysRequest(models.Model): @api.constrains('state', 'number_of_days_temp', 'holiday_status_id') def _check_holidays(self): for holiday in self: - if holiday.holiday_type != 'employee' or not holiday.employee_id or holiday.holiday_status_id.limit or holiday.holiday_status_id.negative: + if holiday.holiday_type != 'employee' or not holiday.employee_id or holiday.holiday_status_id.allocation_type == 'no': continue leave_days = holiday.holiday_status_id.get_days(holiday.employee_id.id)[holiday.holiday_status_id.id] if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \ diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 6c94c317813..e288aaf68e0 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -23,17 +23,11 @@ class HolidaysAllocation(models.Model): _inherit = ['mail.thread', 'mail.activity.mixin'] _mail_post_access = 'read' - def _default_domain_holiday_status_id(self): - if self.user_has_groups('hr_holidays.group_hr_holidays_manager'): - return [('valid', '=', True), ('limit', '=', False)] - return [('valid', '=', True), ('employee_applicability', 'in', ['allocation', 'both']), ('limit', '=', False)] - def _default_employee(self): return self.env.context.get('default_employee_id') or self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1) def _default_holiday_status_id(self): - LeaveType = self.env['hr.leave.type'].with_context(employee_id=self._default_employee().id) - lt = LeaveType.search(self._default_domain_holiday_status_id()) + lt = self.env['hr.leave.type'].with_context(employee_id=self._default_employee().id).search([('valid', '=', True)], limit=1) return lt[:1] name = fields.Char('Description') @@ -58,7 +52,7 @@ class HolidaysAllocation(models.Model): holiday_status_id = fields.Many2one( "hr.leave.type", string="Leave Type", required=True, readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, - domain=lambda self: self._default_domain_holiday_status_id(), default=_default_holiday_status_id) + domain=[('valid', '=', True)], default=_default_holiday_status_id) employee_id = fields.Many2one( 'hr.employee', string='Employee', index=True, readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, track_visibility='onchange') @@ -94,7 +88,10 @@ class HolidaysAllocation(models.Model): 'hr.employee.category', string='Employee Tag', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, help='Category of Employee') # accrual configuration - accrual = fields.Boolean("Accrual", related='holiday_status_id.accrual', store=True, readonly=True) + accrual = fields.Boolean( + "Accrual", 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) interval_number = fields.Integer("Number of unit between two intervals", readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=1) unit_per_interval = fields.Selection([ @@ -171,8 +168,8 @@ class HolidaysAllocation(models.Model): values['number_of_days_temp'] = holiday.number_of_days_temp + days_to_give * prorata - if holiday.holiday_status_id.balance_limit > 0: - values['number_of_days_temp'] = min(values['number_of_days_temp'], holiday.holiday_status_id.balance_limit) + if holiday.accrual_limit > 0: + values['number_of_days_temp'] = min(values['number_of_days_temp'], holiday.accrual_limit) values['number_of_hours'] = values['number_of_days_temp'] * holiday.employee_id.resource_calendar_id.hours_per_day or HOURS_PER_DAY @@ -186,8 +183,8 @@ class HolidaysAllocation(models.Model): if holiday.type_request_unit == 'hour': # In this case we need the number of days to reflect the number of hours taken number_of_days = holiday.number_of_hours / holiday.employee_id.resource_calendar_id.hours_per_day or HOURS_PER_DAY - if holiday.holiday_status_id.balance_limit > 0: - number_of_days = min(number_of_days, holiday.holiday_status_id.balance_limit) + if holiday.accrual_limit > 0: + number_of_days = min(number_of_days, holiday.accrual_limit) holiday.number_of_days = number_of_days diff --git a/addons/hr_holidays/models/hr_leave_type.py b/addons/hr_holidays/models/hr_leave_type.py index 48936f1c9e7..83d81af70c6 100644 --- a/addons/hr_holidays/models/hr_leave_type.py +++ b/addons/hr_holidays/models/hr_leave_type.py @@ -3,6 +3,7 @@ # Copyright (c) 2005-2006 Axelor SARL. (http://www.axelor.com) +import datetime import logging from odoo import api, fields, models @@ -42,7 +43,6 @@ class HolidaysType(models.Model): ('wheat', 'Wheat'), ('ivory', 'Ivory')], string='Color in Report', required=True, default='red', help='This color will be used in the leaves summary located in Reporting > Leaves by Department.') - limit = fields.Boolean('Exceed Allocation', help="If you select this check box, the system will allow the employees to ask for leaves without allocating some beforehand") active = fields.Boolean('Active', default=True, help="If the active field is set to false, it will allow you to hide the leave type without removing it.") max_leaves = fields.Float(compute='_compute_leaves', string='Maximum Allowed', @@ -56,17 +56,23 @@ class HolidaysType(models.Model): virtual_remaining_leaves = fields.Float( compute='_compute_leaves', string='Virtual Remaining Leaves', help='Maximum Leaves Allowed - Leaves Already Taken - Leaves Waiting Approval') + group_days_allocation = fields.Float( + compute='_compute_group_days_allocation', string='Days Allocated') + group_days_leave = fields.Float( + compute='_compute_group_days_leave', string='Group Leaves') company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id) validation_type = fields.Selection([ ('hr', 'Human Resource officer'), ('manager', 'Employee Manager'), ('both', 'Double Validation')], default='hr', string='Validation By') - employee_applicability = fields.Selection([ - ('both', 'Both'), - ('leave', 'Can be requested'), - ('allocation', 'Can be allocated')], - default=lambda self: 'leave' if self.limit else 'both', - string='Mode', help='This leave type will be available on Leave / Allocation request based on selected value') + allocation_type = fields.Selection([ + ('fixed', 'Fixed by HR'), + ('fixed_allocation', 'Fixed by HR + allocation request'), + ('no', 'No allocation')], + default='fixed', string='Mode', + help='\tFixed by HR: allocated by HR and cannot be bypassed; users can request leaves;' + '\tFixed by HR + allocation request: allocated by HR and users can request leaves and allocations;' + '\tNo allocation: no allocation by default, users can freely request leaves;') validity_start = fields.Date("Start Date", default=fields.Date.today, help='Adding validity to types of leaves so that it cannot be selected outside this time period') validity_stop = fields.Date("End Date") @@ -74,18 +80,9 @@ class HolidaysType(models.Model): time_type = fields.Selection([('leave', 'Leave'), ('other', 'Other')], default='leave', string="Kind of Leave", help="Whether this should be computed as a holiday or as work time (eg: formation)") request_unit = fields.Selection([ - ('day', 'Day'), ('half', 'Half-day'), ('hour', 'Hours')], + ('day', 'Day'), ('hour', 'Hours')], default='day', string='Take Leaves in', required=True) - accrual = fields.Boolean('Accrual', default=False, - help='This option forces this type of leave to be allocated accrually') unpaid = fields.Boolean('Is Unpaid', default=False) - negative = fields.Boolean('Allow Negative', help="This option allows to take more leaves than allocated") - balance_limit = fields.Float('Max Balance Limit', default=0, help="The maximum quantity of allocated days on this allocation, zero meaning infinite amount") - - _sql_constraints = [ - ('no_negative_balance_limit', "CHECK(balance_limit >= 0)", "The max balance limit cannot be negative"), - ('no_accrual_unpaid', 'CHECK(NOT (accrual AND unpaid))', "A leave type cannot be accrual and considered as unpaid leaves") - ] @api.multi @api.constrains('validity_start', 'validity_stop') @@ -96,29 +93,7 @@ class HolidaysType(models.Model): raise ValidationError(_("End of validity period should be greater than start of validity period")) @api.multi - @api.constrains('balance_limit', 'accrual') - def _check_balance_limit(self): - for leave_type in self: - if not leave_type.accrual and leave_type.balance_limit > 0: - raise ValidationError(_("Max balance limit can only be set for accrual leaves")) - - @api.onchange('limit') - def _onchange_limit(self): - if self.limit: - self.employee_applicability = 'leave' - self.accrual = False - - @api.onchange('accrual') - def _onchange_accrual(self): - if self.accrual: - self.limit = False - self.employee_applicability = 'both' - else: - self.negative = False - self.balance_limit = 0 - - @api.multi - @api.depends('validity_start', 'validity_stop', 'limit') + @api.depends('validity_start', 'validity_stop') def _compute_valid(self): dt = self._context.get('default_date_from') or fields.Datetime.now() @@ -193,6 +168,30 @@ class HolidaysType(models.Model): holiday_status.remaining_leaves = result.get('remaining_leaves', 0) holiday_status.virtual_remaining_leaves = result.get('virtual_remaining_leaves', 0) + @api.multi + def _compute_group_days_allocation(self): + grouped_res = self.env['hr.leave.allocation'].read_group( + [('holiday_status_id', 'in', self.ids), ('holiday_type', '!=', 'employee'), ('state', '=', 'validate'), + ('date_from', '>=', fields.Datetime.to_string(datetime.datetime.now().replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)))], + ['holiday_status_id', 'number_of_days_temp'], + ['holiday_status_id'], + ) + grouped_dict = dict((data['holiday_status_id'][0], data['number_of_days_temp']) for data in grouped_res) + for allocation in self: + allocation.group_days_allocation = grouped_dict.get(allocation.id, 0) + + @api.multi + def _compute_group_days_leave(self): + grouped_res = self.env['hr.leave'].read_group( + [('holiday_status_id', 'in', self.ids), ('holiday_type', '=', 'employee'), ('state', '=', 'validate'), + ('date_from', '>=', fields.Datetime.to_string(datetime.datetime.now().replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)))], + ['holiday_status_id'], + ['holiday_status_id'], + ) + grouped_dict = dict((data['holiday_status_id'][0], data['holiday_status_id_count']) for data in grouped_res) + for allocation in self: + allocation.group_days_leave = grouped_dict.get(allocation.id, 0) + @api.multi def name_get(self): if not self._context.get('employee_id'): @@ -201,7 +200,7 @@ class HolidaysType(models.Model): res = [] for record in self: name = record.name - if not record.limit: + if record.allocation_type != 'no': name = "%(name)s (%(count)s)" % { 'name': name, 'count': _('%g remaining out of %g') % (float_round(record.virtual_remaining_leaves, precision_digits=2) or 0.0, float_round(record.max_leaves, precision_digits=2) or 0.0) @@ -214,7 +213,7 @@ class HolidaysType(models.Model): """ Override _search to order the results, according to some employee. The order is the following - - limit (limited leaves first, such as Legal Leaves) + - allocation fixed first, then allowing allocation, then free allocation - virtual remaining leaves (higher the better, so using reverse on sorted) This override is necessary because those fields are not stored and depends @@ -225,6 +224,34 @@ class HolidaysType(models.Model): leave_ids = super(HolidaysType, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid) if not count and not order and self._context.get('employee_id'): leaves = self.browse(leave_ids) - sort_key = lambda l: (not l.limit, l.virtual_remaining_leaves) + sort_key = lambda l: (l.allocation_type == 'fixed', l.allocation_type == 'fixed_allocation', l.virtual_remaining_leaves) return leaves.sorted(key=sort_key, reverse=True).ids return leave_ids + + @api.multi + def action_see_days_allocated(self): + self.ensure_one() + action = self.env.ref('hr_holidays.hr_leave_allocation_action_all').read()[0] + action['domain'] = [ + ('holiday_type', '!=', 'employee'), + ('holiday_status_id', '=', self.ids[0]), + ('date_from', '>=', fields.Datetime.to_string(datetime.datetime.now().replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0))) + ] + action['context'] = { + 'default_holiday_type': 'department', + 'default_holiday_status_id': self.ids[0], + } + return action + + @api.multi + def action_see_group_leaves(self): + self.ensure_one() + action = self.env.ref('hr_holidays.hr_leave_action_all').read()[0] + action['domain'] = [ + ('holiday_status_id', '=', self.ids[0]), + ('date_from', '>=', fields.Datetime.to_string(datetime.datetime.now().replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0))) + ] + action['context'] = { + 'default_holiday_status_id': self.ids[0], + } + return action diff --git a/addons/hr_holidays/tests/test_access_rights.py b/addons/hr_holidays/tests/test_access_rights.py index 0631fa10006..997bbf5bbcc 100644 --- a/addons/hr_holidays/tests/test_access_rights.py +++ b/addons/hr_holidays/tests/test_access_rights.py @@ -17,8 +17,8 @@ class TestLeavesRights(TestHrHolidaysBase): super(TestLeavesRights, self).setUp() self.leave_type = self.env['hr.leave.type'].create({ 'name': 'Unlimited', - 'limit': True, 'validation_type': 'hr', + 'allocation_type': 'no', }) self.rd_dept.manager_id = False self.hr_dept.manager_id = False @@ -316,9 +316,9 @@ class TestMultiCompany(TestHrHolidaysBase): }) self.leave_type = self.env['hr.leave.type'].create({ 'name': 'Unlimited - Company New', - 'limit': True, 'company_id': self.new_company.id, 'validation_type': 'hr', + 'allocation_type': 'no', }) self.rd_dept.manager_id = False self.hr_dept.manager_id = False diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py index 8250f88f0a7..06ce87d49be 100644 --- a/addons/hr_holidays/tests/test_accrual_allocations.py +++ b/addons/hr_holidays/tests/test_accrual_allocations.py @@ -19,13 +19,12 @@ class TestAccrualAllocations(TestHrHolidaysBase): self.accrual_type = LeaveType.create({ 'name': 'accrual', - 'limit': False, - 'accrual': True, + 'allocation_type': 'fixed', }) self.unpaid_type = LeaveType.create({ 'name': 'unpaid', - 'limit': True, + 'allocation_type': 'no', 'unpaid': True, }) @@ -45,40 +44,30 @@ class TestAccrualAllocations(TestHrHolidaysBase): """ % (newdate, id)) def test_accrual_base_no_leaves(self): - """ - Test if we can allocate some leaves accrually to an employee - """ - Allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - - alloc_0 = Allocation.create({ + """ Test if we can allocate some leaves accrually to an employee """ + alloc = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True).create({ 'name': 'Accrual allocation for employee', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 1, 'interval_number': 1, 'unit_per_interval': 'days', 'interval_unit': 'weeks', }) + alloc.action_approve() + alloc._update_accrual() - alloc_0.action_approve() - - Allocation._update_accrual() - - self.assertEqual(alloc_0.number_of_days, 1, 'Employee should have been allocated one leave day') + self.assertEqual(alloc.number_of_days, 1, 'Employee should have been allocated one leave day') def test_accrual_base_leaves(self): - """ - Test if the accrual allocation take the unpaid leaves into account - when allocating leaves - """ - Allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - Leave = self.env['hr.leave'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - - alloc_0 = Allocation.create({ + """ Test if the accrual allocation take the unpaid leaves into account when allocating leaves """ + alloc = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True).create({ 'name': 'Accrual allocation for employee with leaves', 'employee_id': self.employee_hruser_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 1, 'interval_number': 1, @@ -86,13 +75,13 @@ class TestAccrualAllocations(TestHrHolidaysBase): 'interval_unit': 'weeks', }) - alloc_0.action_approve() + alloc.action_approve() employee = self.env['hr.employee'].browse(self.employee_hruser_id) # Getting the previous work date df = employee.resource_calendar_id.plan_days(-2, fields.Datetime.now()).date() - leave_0 = Leave.create({ + leave = self.env['hr.leave'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True).create({ 'name': 'Leave for hruser', 'employee_id': self.employee_hruser_id, 'holiday_status_id': self.unpaid_type.id, @@ -101,11 +90,11 @@ class TestAccrualAllocations(TestHrHolidaysBase): 'number_of_days_temp': 1, }) - leave_0.action_approve() + leave.action_approve() - Allocation._update_accrual() + alloc._update_accrual() - self.assertEqual(alloc_0.number_of_days, .8, 'As employee took some unpaid leaves last week, he should be allocated only .8 days') + self.assertEqual(alloc.number_of_days, .8, 'As employee took some unpaid leaves last week, he should be allocated only .8 days') def test_accrual_many(self): """ @@ -117,6 +106,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, 'number_of_days_temp': 0, 'number_per_interval': 1, 'interval_number': 2, @@ -128,6 +118,7 @@ class TestAccrualAllocations(TestHrHolidaysBase): 'name': '4 hours per week', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 4, 'interval_number': 1, @@ -139,6 +130,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, 'number_of_days_temp': 0, 'number_per_interval': 2, 'interval_number': 1, @@ -150,6 +142,7 @@ class TestAccrualAllocations(TestHrHolidaysBase): 'name': '20 days per year', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 20, 'interval_number': 1, @@ -179,6 +172,7 @@ class TestAccrualAllocations(TestHrHolidaysBase): 'name': 'one shot one kill', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 1, 'interval_number': 1, @@ -193,29 +187,23 @@ class TestAccrualAllocations(TestHrHolidaysBase): self.assertEqual(alloc_0.number_of_days, 0, 'Employee is new he should not get any accrual leaves') def test_accrual_multi(self): - """ - Test if the cron does not allocate leaves every time it's called but only - when necessary - """ - Allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - - alloc_0 = Allocation.create({ + """ Test if the cron does not allocate leaves every time it's called but only when necessary """ + alloc = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True).create({ 'name': '2 days per week', 'employee_id': self.employee_emp_id, 'holiday_status_id': self.accrual_type.id, + 'accrual': True, 'number_of_days_temp': 0, 'number_per_interval': 1, 'interval_number': 2, 'unit_per_interval': 'days', 'interval_unit': 'weeks', }) + alloc.action_approve() + alloc._update_accrual() + alloc._update_accrual() - alloc_0.action_approve() - - Allocation._update_accrual() - Allocation._update_accrual() - - self.assertEqual(alloc_0.number_of_days, 1, 'Cron only allocates 1 days every two weeks') + self.assertEqual(alloc.number_of_days, 1, 'Cron only allocates 1 days every two weeks') def test_accrual_validation(self): """ @@ -242,32 +230,20 @@ class TestAccrualAllocations(TestHrHolidaysBase): self.assertEqual(alloc_0.number_of_days, 0, 'Cron validity passed, should not allocate any leave') def test_accrual_balance_limit(self): - """ - Test if accrual allocation does not allocate more than the balance limit - """ - Allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - LeaveType = self.env['hr.leave.type'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - - accrual_max_five = LeaveType.create({ - 'name': 'max 5 days', - 'limit': False, - 'accrual': True, - 'balance_limit': 5, - }) - - allocation = Allocation.create({ + """ Test if accrual allocation does not allocate more than the balance limit""" + allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True).create({ 'name': 'accrual 5 max', 'employee_id': self.employee_emp_id, - 'holiday_status_id': accrual_max_five.id, + 'holiday_status_id': self.accrual_type.id, + 'accrual': True, + 'accrual_limit': 5, 'number_of_days_temp': 0, 'number_per_interval': 6, 'interval_number': 1, 'unit_per_interval': 'days', 'interval_unit': 'weeks', }) - allocation.action_approve() - - Allocation._update_accrual() + allocation._update_accrual() self.assertEqual(allocation.number_of_days, 5, 'Should have allocated only 5 days as balance limit is 5') diff --git a/addons/hr_holidays/tests/test_holidays_flow.py b/addons/hr_holidays/tests/test_holidays_flow.py index 0c3cff00ad9..03cf5b2b7a0 100644 --- a/addons/hr_holidays/tests/test_holidays_flow.py +++ b/addons/hr_holidays/tests/test_holidays_flow.py @@ -33,34 +33,34 @@ class TestHolidaysFlow(TestHrHolidaysBase): with self.assertRaises(AccessError): HolidaysStatus.sudo(self.user_hruser_id).create({ 'name': 'UserCheats', - 'limit': True, + 'allocation_type': 'no', }) # HrManager creates some holiday statuses HolidayStatusManagerGroup = HolidaysStatus.sudo(self.user_hrmanager_id) HolidayStatusManagerGroup.create({ 'name': 'WithMeetingType', - 'limit': True, + 'allocation_type': 'no', 'categ_id': self.env['calendar.event.type'].sudo(self.user_hrmanager_id).create({'name': 'NotLimitedMeetingType'}).id }) self.holidays_status_1 = HolidayStatusManagerGroup.create({ 'name': 'NotLimitedHR', - 'limit': True, + 'allocation_type': 'no', 'validation_type': 'hr', }) self.holidays_status_2 = HolidayStatusManagerGroup.create({ 'name': 'Limited', - 'limit': False, + 'allocation_type': 'fixed', 'validation_type': 'both', }) self.holidays_status_3 = HolidayStatusManagerGroup.create({ 'name': 'NotLimitedManager', - 'limit': True, + 'allocation_type': 'no', 'validation_type': 'manager', }) self.holiday_status_4 = HolidayStatusManagerGroup.create({ 'name': 'TimeNotLimited', - 'limit': True, + 'allocation_type': 'no', 'validation_type': 'manager', 'validity_start': fields.Datetime.from_string('2017-01-01 00:00:00'), 'validity_stop': fields.Datetime.from_string('2017-06-01 00:00:00'), diff --git a/addons/hr_holidays/tests/test_hr_leave_type.py b/addons/hr_holidays/tests/test_hr_leave_type.py index 3232ddc39f0..72fbaa4aee6 100644 --- a/addons/hr_holidays/tests/test_hr_leave_type.py +++ b/addons/hr_holidays/tests/test_hr_leave_type.py @@ -12,8 +12,8 @@ class TestHrLeaveType(TestHrHolidaysBase): def test_time_type(self): leave_type = self.env['hr.leave.type'].create({ 'name': 'Legal Leaves', - 'limit': True, 'time_type': 'leave', + 'allocation_type': 'no', }) leave_1 = self.env['hr.leave'].create({ diff --git a/addons/hr_holidays/views/hr_leave_allocation_views.xml b/addons/hr_holidays/views/hr_leave_allocation_views.xml index 33a9eccad9c..dd167e073c7 100644 --- a/addons/hr_holidays/views/hr_leave_allocation_views.xml +++ b/addons/hr_holidays/views/hr_leave_allocation_views.xml @@ -55,7 +55,6 @@
-
+ +
+

+
- - + - - - + + - - + + - + @@ -48,11 +61,6 @@ - - - - - @@ -88,7 +96,7 @@ - + diff --git a/addons/hr_holidays/views/hr_leave_views.xml b/addons/hr_holidays/views/hr_leave_views.xml index e182fde6329..910ad643279 100644 --- a/addons/hr_holidays/views/hr_leave_views.xml +++ b/addons/hr_holidays/views/hr_leave_views.xml @@ -111,24 +111,23 @@ Hours - - +
- From - - - + From + + + + attrs="{'readonly': [('state', '=', 'validate')], 'invisible': ['|', '|', ('leave_type_request_unit', '=', 'day'), '&', ('leave_type_request_unit', '=', 'half'), ('request_unit', '=', 'day'), '&', ('leave_type_request_unit', '=', 'hour'), ('request_unit', '!=', 'half')]}"/>
- To - - - + To + + + + attrs="{'readonly': [('state', '=', 'validate')], 'invisible': ['|', ('leave_type_request_unit', '!=', 'half'), ('request_unit', '!=', 'period')]}"/>
diff --git a/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py b/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py index a7e484f18d4..a17deae822e 100644 --- a/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py +++ b/addons/project_timesheet_holidays/tests/test_timesheet_holidays.py @@ -16,7 +16,7 @@ class TestTimesheetHolidaysCreate(common.TransactionCase): """Ensure that when a status is created, it fullfills the project and task constrains""" status = self.env['hr.leave.type'].create({ 'name': 'A nice Leave Type', - 'limit': True + 'allocation_type': 'no' }) company = self.env.user.company_id @@ -42,14 +42,14 @@ class TestTimesheetHolidays(TestTimesheet): self.hr_leave_type_with_ts = self.env['hr.leave.type'].create({ 'name': 'Leave Type with timesheet generation', - 'limit': True, + 'allocation_type': 'no', 'timesheet_generate': True, 'timesheet_project_id': self.internal_project.id, 'timesheet_task_id': self.internal_task_leaves.id, }) self.hr_leave_type_no_ts = self.env['hr.leave.type'].create({ 'name': 'Leave Type without timesheet generation', - 'limit': True, + 'allocation_type': 'no', 'timesheet_generate': False, 'timesheet_project_id': False, 'timesheet_task_id': False, diff --git a/addons/project_timesheet_holidays/views/hr_holidays_views.xml b/addons/project_timesheet_holidays/views/hr_holidays_views.xml index 1e010067a57..a74b6aca55a 100644 --- a/addons/project_timesheet_holidays/views/hr_holidays_views.xml +++ b/addons/project_timesheet_holidays/views/hr_holidays_views.xml @@ -6,12 +6,10 @@ hr.leave.type - - - - - - + + + +