hr_efficiency_report.py 4.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from odoo import api, fields, models
  4. from odoo.tools.sql import drop_view_if_exists, SQL
  5. class HrEfficiencyReport(models.Model):
  6. _name = "hr.efficiency.report"
  7. _description = "HR Efficiency Analysis Report"
  8. _auto = False
  9. month_year = fields.Char('Month Year', readonly=True)
  10. employee_id = fields.Many2one('hr.employee', 'Employee', readonly=True, domain=[('employee_type', '=', 'employee')])
  11. company_id = fields.Many2one('res.company', 'Company', readonly=True)
  12. department_id = fields.Many2one('hr.department', 'Department', readonly=True)
  13. job_title = fields.Char('Job Title', readonly=True)
  14. # Hours
  15. available_hours = fields.Float('Available Hours', readonly=True)
  16. planned_hours = fields.Float('Planned Hours', readonly=True)
  17. planned_billable_hours = fields.Float('Planned Billable Hours', readonly=True)
  18. planned_non_billable_hours = fields.Float('Planned Non-Billable Hours', readonly=True)
  19. actual_billable_hours = fields.Float('Actual Billable Hours', readonly=True)
  20. actual_non_billable_hours = fields.Float('Actual Non-Billable Hours', readonly=True)
  21. total_actual_hours = fields.Float('Total Actual Hours', readonly=True)
  22. # Financial
  23. wage_overhead = fields.Float('Wage Overhead', readonly=True, help="Hourly cost multiplied by available hours for the month, including company overhead")
  24. # Efficiency rates
  25. efficiency_rate = fields.Float('Efficiency Rate (%)', readonly=True)
  26. billable_efficiency_rate = fields.Float('Billable Efficiency Rate (%)', readonly=True)
  27. # Computed fields for analysis
  28. utilization_rate = fields.Float('Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned")
  29. billable_utilization_rate = fields.Float('Billable Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned on billable projects")
  30. @property
  31. def _table_query(self):
  32. return """
  33. SELECT
  34. e.id,
  35. e.month_year,
  36. e.employee_id,
  37. e.company_id,
  38. emp.department_id,
  39. emp.job_title,
  40. e.available_hours,
  41. e.planned_hours,
  42. e.planned_billable_hours,
  43. e.planned_non_billable_hours,
  44. e.actual_billable_hours,
  45. e.actual_non_billable_hours,
  46. e.total_actual_hours,
  47. e.wage_overhead,
  48. e.efficiency_rate,
  49. e.billable_efficiency_rate,
  50. CASE
  51. WHEN e.available_hours > 0 THEN (e.planned_hours / e.available_hours) * 100
  52. ELSE 0
  53. END AS utilization_rate,
  54. CASE
  55. WHEN e.available_hours > 0 THEN (e.planned_billable_hours / e.available_hours) * 100
  56. ELSE 0
  57. END AS billable_utilization_rate
  58. FROM hr_efficiency e
  59. LEFT JOIN hr_employee emp ON e.employee_id = emp.id
  60. """
  61. @api.model
  62. def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
  63. """
  64. Override read_group to handle computed fields
  65. """
  66. res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
  67. # Recalculate computed fields for grouped data
  68. for group in res:
  69. if '__domain' in group:
  70. records = self.search(group['__domain'])
  71. if records:
  72. # Calculate averages for efficiency rates
  73. if 'efficiency_rate' in fields:
  74. group['efficiency_rate'] = sum(r.efficiency_rate for r in records) / len(records)
  75. if 'billable_efficiency_rate' in fields:
  76. group['billable_efficiency_rate'] = sum(r.billable_efficiency_rate for r in records) / len(records)
  77. if 'utilization_rate' in fields:
  78. group['utilization_rate'] = sum(r.utilization_rate for r in records) / len(records)
  79. if 'billable_utilization_rate' in fields:
  80. group['billable_utilization_rate'] = sum(r.billable_utilization_rate for r in records) / len(records)
  81. if 'wage_overhead' in fields:
  82. group['wage_overhead'] = sum(r.wage_overhead for r in records)
  83. return res