| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- # -*- coding: utf-8 -*-
- # Part of Odoo. See LICENSE file for full copyright and licensing details.
- from odoo import api, fields, models
- from odoo.tools.sql import drop_view_if_exists, SQL
- class HrEfficiencyReport(models.Model):
- _name = "hr.efficiency.report"
- _description = "HR Efficiency Analysis Report"
- _auto = False
- month_year = fields.Char('Month Year', readonly=True)
- employee_id = fields.Many2one('hr.employee', 'Employee', readonly=True, domain=[('employee_type', '=', 'employee')])
- company_id = fields.Many2one('res.company', 'Company', readonly=True)
- department_id = fields.Many2one('hr.department', 'Department', readonly=True)
- job_title = fields.Char('Job Title', readonly=True)
-
- # Hours
- available_hours = fields.Float('Available Hours', readonly=True)
- planned_hours = fields.Float('Planned Hours', readonly=True)
- planned_billable_hours = fields.Float('Planned Billable Hours', readonly=True)
- planned_non_billable_hours = fields.Float('Planned Non-Billable Hours', readonly=True)
- actual_billable_hours = fields.Float('Actual Billable Hours', readonly=True)
- actual_non_billable_hours = fields.Float('Actual Non-Billable Hours', readonly=True)
- total_actual_hours = fields.Float('Total Actual Hours', readonly=True)
-
- # Financial
- wage_overhead = fields.Float('Wage Overhead', readonly=True, help="Hourly cost multiplied by available hours for the month, including company overhead")
-
- # Efficiency rates
- efficiency_rate = fields.Float('Efficiency Rate (%)', readonly=True)
- billable_efficiency_rate = fields.Float('Billable Efficiency Rate (%)', readonly=True)
-
- # Computed fields for analysis
- utilization_rate = fields.Float('Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned")
- billable_utilization_rate = fields.Float('Billable Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned on billable projects")
- @property
- def _table_query(self):
- return """
- SELECT
- e.id,
- e.month_year,
- e.employee_id,
- e.company_id,
- emp.department_id,
- emp.job_title,
- e.available_hours,
- e.planned_hours,
- e.planned_billable_hours,
- e.planned_non_billable_hours,
- e.actual_billable_hours,
- e.actual_non_billable_hours,
- e.total_actual_hours,
- e.wage_overhead,
- e.efficiency_rate,
- e.billable_efficiency_rate,
- CASE
- WHEN e.available_hours > 0 THEN (e.planned_hours / e.available_hours) * 100
- ELSE 0
- END AS utilization_rate,
- CASE
- WHEN e.available_hours > 0 THEN (e.planned_billable_hours / e.available_hours) * 100
- ELSE 0
- END AS billable_utilization_rate
- FROM hr_efficiency e
- LEFT JOIN hr_employee emp ON e.employee_id = emp.id
- """
- @api.model
- def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
- """
- Override read_group to handle computed fields
- """
- res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
-
- # Recalculate computed fields for grouped data
- for group in res:
- if '__domain' in group:
- records = self.search(group['__domain'])
- if records:
- # Calculate averages for efficiency rates
- if 'efficiency_rate' in fields:
- group['efficiency_rate'] = sum(r.efficiency_rate for r in records) / len(records)
- if 'billable_efficiency_rate' in fields:
- group['billable_efficiency_rate'] = sum(r.billable_efficiency_rate for r in records) / len(records)
- if 'utilization_rate' in fields:
- group['utilization_rate'] = sum(r.utilization_rate for r in records) / len(records)
- if 'billable_utilization_rate' in fields:
- group['billable_utilization_rate'] = sum(r.billable_utilization_rate for r in records) / len(records)
- if 'wage_overhead' in fields:
- group['wage_overhead'] = sum(r.wage_overhead for r in records)
-
- return res
|