hr_efficiency_report.py 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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. # Efficiency rates
  23. efficiency_rate = fields.Float('Efficiency Rate (%)', readonly=True)
  24. billable_efficiency_rate = fields.Float('Billable Efficiency Rate (%)', readonly=True)
  25. # Computed fields for analysis
  26. utilization_rate = fields.Float('Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned")
  27. billable_utilization_rate = fields.Float('Billable Utilization Rate (%)', readonly=True, help="Percentage of available hours that were planned on billable projects")
  28. @property
  29. def _table_query(self):
  30. return """
  31. SELECT
  32. e.id,
  33. e.month_year,
  34. e.employee_id,
  35. e.company_id,
  36. emp.department_id,
  37. emp.job_title,
  38. e.available_hours,
  39. e.planned_hours,
  40. e.planned_billable_hours,
  41. e.planned_non_billable_hours,
  42. e.actual_billable_hours,
  43. e.actual_non_billable_hours,
  44. e.total_actual_hours,
  45. e.efficiency_rate,
  46. e.billable_efficiency_rate,
  47. CASE
  48. WHEN e.available_hours > 0 THEN (e.planned_hours / e.available_hours) * 100
  49. ELSE 0
  50. END AS utilization_rate,
  51. CASE
  52. WHEN e.available_hours > 0 THEN (e.planned_billable_hours / e.available_hours) * 100
  53. ELSE 0
  54. END AS billable_utilization_rate
  55. FROM hr_efficiency e
  56. LEFT JOIN hr_employee emp ON e.employee_id = emp.id
  57. """
  58. @api.model
  59. def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
  60. """
  61. Override read_group to handle computed fields
  62. """
  63. res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
  64. # Recalculate computed fields for grouped data
  65. for group in res:
  66. if '__domain' in group:
  67. records = self.search(group['__domain'])
  68. if records:
  69. # Calculate averages for efficiency rates
  70. if 'efficiency_rate' in fields:
  71. group['efficiency_rate'] = sum(r.efficiency_rate for r in records) / len(records)
  72. if 'billable_efficiency_rate' in fields:
  73. group['billable_efficiency_rate'] = sum(r.billable_efficiency_rate for r in records) / len(records)
  74. if 'utilization_rate' in fields:
  75. group['utilization_rate'] = sum(r.utilization_rate for r in records) / len(records)
  76. if 'billable_utilization_rate' in fields:
  77. group['billable_utilization_rate'] = sum(r.billable_utilization_rate for r in records) / len(records)
  78. return res