# -*- coding: utf-8 -*- """ Employee Reports ================ - Employee Directory (Payroll Item List) - Time Off Report """ from odoo import api, fields, models, _ class PayrollReportEmployeeDirectory(models.AbstractModel): """ Employee Directory / Payroll Item List Report Shows employees with their pay rates and status. """ _name = 'payroll.report.employee.directory' _inherit = 'payroll.report' _description = 'Employee Directory Report' report_name = 'Payroll Item List' report_code = 'employee_directory' filter_date_range = False # Not date-dependent filter_employee = False def _get_columns(self): return [ {'name': _('Name'), 'field': 'name', 'type': 'char', 'sortable': True}, {'name': _('Salary'), 'field': 'salary', 'type': 'monetary', 'sortable': True}, {'name': _('Regular Pay'), 'field': 'regular_pay', 'type': 'char', 'sortable': False}, {'name': _('Hourly 2'), 'field': 'hourly_2', 'type': 'char', 'sortable': False}, {'name': _('Overtime Pay'), 'field': 'overtime_pay', 'type': 'char', 'sortable': False}, {'name': _('Double Overtime Pay'), 'field': 'double_overtime', 'type': 'char', 'sortable': False}, {'name': _('Stat Holiday Pay'), 'field': 'stat_holiday', 'type': 'char', 'sortable': False}, {'name': _('Bonus'), 'field': 'bonus', 'type': 'char', 'sortable': False}, {'name': _('Status'), 'field': 'status', 'type': 'char', 'sortable': True}, ] def _get_lines(self, options): # Get all employees employees = self.env['hr.employee'].search([ ('company_id', '=', self.env.company.id), ], order='name') lines = [] for emp in employees: # Get pay info directly from employee (Fusion Payroll fields) salary = '' regular_pay = '' # Use Fusion Payroll fields if available pay_type = getattr(emp, 'pay_type', None) if pay_type == 'salary': salary_amount = getattr(emp, 'salary_amount', 0) or 0 if salary_amount: salary = f"${salary_amount * 12:,.2f}/year" elif pay_type == 'hourly': hourly_rate = getattr(emp, 'hourly_rate', 0) or 0 if hourly_rate: regular_pay = f"${hourly_rate:,.2f}/hr" else: # Fallback to hourly_cost if available hourly_cost = getattr(emp, 'hourly_cost', 0) or 0 if hourly_cost: regular_pay = f"${hourly_cost:,.2f}/hr" status = 'Active' if hasattr(emp, 'employment_status') and 'employment_status' in emp._fields: if hasattr(emp._fields['employment_status'], 'selection'): status = dict(emp._fields['employment_status'].selection).get( emp.employment_status, 'Active' ) # Calculate salary value for sorting salary_value = 0 if pay_type == 'salary': salary_value = (getattr(emp, 'salary_amount', 0) or 0) * 12 lines.append({ 'id': f'emp_{emp.id}', 'name': emp.name, 'values': { 'name': emp.name, 'salary': salary_value if salary_value else '', 'regular_pay': regular_pay, 'hourly_2': '', 'overtime_pay': '', 'double_overtime': '', 'stat_holiday': '', 'bonus': '', 'status': status, }, 'level': 0, 'model': 'hr.employee', 'res_id': emp.id, }) return lines class PayrollReportTimeOff(models.AbstractModel): """ Time Off Report Shows vacation/leave balances by employee. """ _name = 'payroll.report.time.off' _inherit = 'payroll.report' _description = 'Time Off Report' report_name = 'Time Off' report_code = 'time_off' filter_date_range = False def _get_columns(self): return [ {'name': _('Employee'), 'field': 'employee', 'type': 'char', 'sortable': True}, {'name': _('Vacation'), 'field': 'vacation', 'type': 'char', 'sortable': False}, {'name': _('Balance'), 'field': 'balance', 'type': 'float', 'sortable': True}, {'name': _('YTD Used'), 'field': 'ytd_used', 'type': 'float', 'sortable': True}, {'name': _('Amount Available'), 'field': 'amount_available', 'type': 'monetary', 'sortable': True}, {'name': _('YTD Amount Used'), 'field': 'ytd_amount_used', 'type': 'monetary', 'sortable': True}, ] def _get_lines(self, options): # Get employees with vacation policy domain = [('company_id', '=', self.env.company.id)] if 'employment_status' in self.env['hr.employee']._fields: domain.append(('employment_status', '=', 'active')) employees = self.env['hr.employee'].search(domain, order='name') lines = [] for emp in employees: # Try to get leave allocation info if hr_holidays is installed balance = 0 ytd_used = 0 try: # Check for vacation allocations allocations = self.env['hr.leave.allocation'].search([ ('employee_id', '=', emp.id), ('state', '=', 'validate'), ('holiday_status_id.name', 'ilike', 'vacation'), ]) balance = sum(allocations.mapped('number_of_days')) # Get used days this year year_start = fields.Date.today().replace(month=1, day=1) leaves = self.env['hr.leave'].search([ ('employee_id', '=', emp.id), ('state', '=', 'validate'), ('holiday_status_id.name', 'ilike', 'vacation'), ('date_from', '>=', year_start), ]) ytd_used = sum(leaves.mapped('number_of_days')) except: pass # hr_holidays may not be installed or different structure # Get vacation pay rate from employee vacation_rate = getattr(emp, 'vacation_pay_rate', 4.0) vacation_policy = f"{vacation_rate}% Paid out each pay period" lines.append({ 'id': f'time_{emp.id}', 'name': emp.name, 'values': { 'employee': emp.name, 'vacation': vacation_policy, 'balance': balance - ytd_used, 'ytd_used': ytd_used, 'amount_available': 0, # Would need to calculate 'ytd_amount_used': 0, }, 'level': 0, 'model': 'hr.employee', 'res_id': emp.id, }) return lines