diff --git a/addons/hr_payroll/models/hr_payroll.py b/addons/hr_payroll/models/hr_payroll.py index eaa03177f57..4e85266fa01 100644 --- a/addons/hr_payroll/models/hr_payroll.py +++ b/addons/hr_payroll/models/hr_payroll.py @@ -308,19 +308,25 @@ class HrPayslip(models.Model): @param contract_ids: list of contract id @return: returns a list of dict containing the input that should be applied for the given contract between date_from and date_to """ - def was_on_leave(employee_id, datetime_day): - day = fields.Date.to_string(datetime_day) + + def was_on_leave_interval(employee_id, date_from, date_to): + date_from = fields.Datetime.to_string(date_from) + date_to = fields.Datetime.to_string(date_to) return self.env['hr.holidays'].search([ ('state', '=', 'validate'), ('employee_id', '=', employee_id), ('type', '=', 'remove'), - ('date_from', '<=', day), - ('date_to', '>=', day) - ], limit=1).holiday_status_id.name + ('date_from', '<=', date_from), + ('date_to', '>=', date_to) + ], limit=1) res = [] #fill only if the contract as a working schedule linked + uom_day = self.env.ref('product.product_uom_day', raise_if_not_found=False) for contract in self.env['hr.contract'].browse(contract_ids).filtered(lambda contract: contract.working_hours): + uom_hour = contract.employee_id.resource_id.calendar_id.uom_id or self.env.ref('product.product_uom_hour', raise_if_not_found=False) + interval_data = [] + holidays = self.env['hr.holidays'] attendances = { 'name': _("Normal Working Days paid at 100%"), 'sequence': 1, @@ -333,31 +339,43 @@ class HrPayslip(models.Model): day_from = fields.Datetime.from_string(date_from) day_to = fields.Datetime.from_string(date_to) nb_of_days = (day_to - day_from).days + 1 + + # Gather all intervals and holidays for day in range(0, nb_of_days): - working_hours_on_day = contract.working_hours.working_hours_on_day(day_from + timedelta(days=day)) - if working_hours_on_day: - #the employee had to work - leave_type = was_on_leave(contract.employee_id.id, day_from + timedelta(days=day)) - if leave_type: - #if he was on leave, fill the leaves dict - if leave_type in leaves: - leaves[leave_type]['number_of_days'] += 1.0 - leaves[leave_type]['number_of_hours'] += working_hours_on_day - else: - leaves[leave_type] = { - 'name': leave_type, - 'sequence': 5, - 'code': leave_type, - 'number_of_days': 1.0, - 'number_of_hours': working_hours_on_day, - 'contract_id': contract.id, - } + working_intervals_on_day = contract.working_hours.get_working_intervals_of_day(start_dt=day_from + timedelta(days=day)) + for interval in working_intervals_on_day: + interval_data.append((interval, was_on_leave_interval(contract.employee_id.id, interval[0], interval[1]))) + + # Extract information from previous data. A working interval is considered: + # - as a leave if a hr.holiday completely covers the period + # - as a working period instead + for interval, holiday in interval_data: + holidays |= holiday + hours = (interval[1] - interval[0]).total_seconds() / 3600.0 + if holiday: + #if he was on leave, fill the leaves dict + if holiday.holiday_status_id.name in leaves: + leaves[holiday.holiday_status_id.name]['number_of_hours'] += hours else: - #add the input vals to tmp (increment if existing) - attendances['number_of_days'] += 1.0 - attendances['number_of_hours'] += working_hours_on_day + leaves[holiday.holiday_status_id.name] = { + 'name': holiday.holiday_status_id.name, + 'sequence': 5, + 'code': holiday.holiday_status_id.name, + 'number_of_days': 0.0, + 'number_of_hours': hours, + 'contract_id': contract.id, + } + else: + #add the input vals to tmp (increment if existing) + attendances['number_of_hours'] += hours + + # Clean-up the results leaves = [value for key, value in leaves.items()] - res += [attendances] + leaves + for data in [attendances] + leaves: + data['number_of_days'] = uom_hour._compute_quantity(data['number_of_hours'], uom_day)\ + if uom_day and uom_hour\ + else data['number_of_hours'] / 8.0 + res.append(data) return res # YTI TODO contract_ids should be a browse record