Files
Odoo-Modules/fusion_payroll/models/payroll_report_employee.py
2026-02-22 01:22:18 -05:00

179 lines
7.1 KiB
Python

# -*- 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