190 lines
7.2 KiB
Python
190 lines
7.2 KiB
Python
import logging
|
|
|
|
from odoo import api, fields, models
|
|
from datetime import timedelta
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class HrEmployeeStats(models.Model):
|
|
_name = "hr.employee.stats"
|
|
_description = "Employee Stats"
|
|
_order = "date desc"
|
|
_inherit = ["mail.thread", "mail.activity.mixin"]
|
|
|
|
name = fields.Char("Name", compute="_compute_name", store=True)
|
|
dayofweek = fields.Integer("Day of Week", compute="_compute_dayofweek")
|
|
is_public_holiday = fields.Boolean("Public Holiday", compute="_compute_dayofweek")
|
|
employee_id = fields.Many2one("hr.employee", "Employee", required=True)
|
|
department_id = fields.Many2one("hr.department", "Department")
|
|
timesheet_line_ids = fields.One2many(
|
|
"account.analytic.line",
|
|
"employee_id",
|
|
"Timesheet lines",
|
|
compute="_compute_timesheet_line_ids",
|
|
)
|
|
date = fields.Date("Date", required=True)
|
|
company_id = fields.Many2one(
|
|
"res.company",
|
|
"Company",
|
|
default=lambda self: self.env.company,
|
|
required=True,
|
|
)
|
|
sheet_id = fields.Many2one("hr_timesheet.sheet", "Timesheet")
|
|
total_hours = fields.Float("Total Hours", compute="_compute_hours")
|
|
total_planned_hours = fields.Float("Total Planning Hours", compute="_compute_hours")
|
|
total_leave_hours = fields.Float("Total Leave Hours", compute="_compute_hours")
|
|
total_recovery_hours = fields.Float(
|
|
"Total Recovery Hours", compute="_compute_hours"
|
|
)
|
|
gap_hours = fields.Float("Gap Hours", compute="_compute_hours")
|
|
|
|
def _get_holiday_status_id(self):
|
|
recovery_type_id = self.env.company.recovery_type_id
|
|
if recovery_type_id:
|
|
return recovery_type_id.id
|
|
else:
|
|
return False
|
|
|
|
def _compute_timesheet_line_ids(self):
|
|
for stat in self:
|
|
stat.timesheet_line_ids = self.env["account.analytic.line"].search(
|
|
[
|
|
("employee_id", "=", stat.employee_id.id),
|
|
("date", "=", stat.date),
|
|
]
|
|
)
|
|
|
|
def _get_intersects(
|
|
self, datetime1_start, datetime1_end, datetime2_start, datetime2_end
|
|
):
|
|
latest_start = max(datetime1_start, datetime2_start)
|
|
earliest_end = min(datetime1_end, datetime2_end)
|
|
delta = (earliest_end - latest_start).total_seconds() / 3600
|
|
return max(0, delta)
|
|
|
|
def get_total_hours_domain(self):
|
|
return [
|
|
("employee_id", "=", self.employee_id.id),
|
|
("date", "=", self.date),
|
|
]
|
|
|
|
@api.depends("timesheet_line_ids")
|
|
def _get_total_hours(self):
|
|
timesheet_line = self.env["account.analytic.line"]
|
|
for stat in self:
|
|
if stat.date and stat.employee_id:
|
|
timesheet_line_ids = timesheet_line.search(
|
|
stat.get_total_hours_domain()
|
|
)
|
|
total_hours = sum(timesheet_line_ids.mapped("unit_amount"))
|
|
else:
|
|
total_hours = 0
|
|
return total_hours
|
|
|
|
def _get_total_planned_hours(self):
|
|
for stat in self:
|
|
if stat.employee_id and stat.date and not stat.is_public_holiday:
|
|
dayofweek = int(stat.date.strftime("%u")) - 1
|
|
calendar_id = stat.employee_id.resource_calendar_id
|
|
week_number = stat.date.isocalendar()[1] % 2
|
|
if calendar_id.two_weeks_calendar:
|
|
hours = calendar_id.attendance_ids.search(
|
|
[
|
|
("dayofweek", "=", dayofweek),
|
|
("calendar_id", "=", calendar_id.id),
|
|
("week_type", "=", week_number),
|
|
]
|
|
)
|
|
else:
|
|
hours = calendar_id.attendance_ids.search(
|
|
[
|
|
("dayofweek", "=", dayofweek),
|
|
("calendar_id", "=", calendar_id.id),
|
|
]
|
|
)
|
|
total_planned_hours = sum(
|
|
hours.mapped(lambda r: r.hour_to - r.hour_from)
|
|
)
|
|
else:
|
|
total_planned_hours = 0
|
|
return total_planned_hours
|
|
|
|
def _get_total_recovery_hours(self):
|
|
recovery = self.env["hr.leave"]
|
|
for stat in self:
|
|
if stat.date and stat.employee_id and stat._get_holiday_status_id():
|
|
recovery_ids = recovery.search(
|
|
[
|
|
("employee_id", "=", stat.employee_id.id),
|
|
("request_date_from", ">=", stat.date),
|
|
("request_date_from", "<=", stat.date),
|
|
("holiday_status_id", "=", stat._get_holiday_status_id()),
|
|
]
|
|
)
|
|
total_recovery_hours = sum(
|
|
recovery_ids.mapped("number_of_hours_display")
|
|
)
|
|
else:
|
|
total_recovery_hours = 0
|
|
return total_recovery_hours
|
|
|
|
def _get_total_leave_hours(self):
|
|
total_leave_hours = 0
|
|
for stat in self:
|
|
if stat.date and stat.employee_id:
|
|
leave_ids = self.env["hr.leave"].search(
|
|
[
|
|
("employee_id", "=", stat.employee_id.id),
|
|
("holiday_status_id", "!=", stat._get_holiday_status_id()),
|
|
("request_date_from", ">=", stat.date),
|
|
("request_date_to", "<=", stat.date),
|
|
]
|
|
)
|
|
total_leave_hours = sum(leave_ids.mapped("number_of_hours_display"))
|
|
return total_leave_hours
|
|
|
|
@api.depends("employee_id", "date")
|
|
def _compute_name(self):
|
|
for stat in self:
|
|
stat.name = "%s - %s" % (stat.employee_id.name, stat.date)
|
|
|
|
@api.depends("date","employee_id")
|
|
def _compute_dayofweek(self):
|
|
for stat in self:
|
|
if not stat.date:
|
|
stat.dayofweek = None
|
|
stat.is_public_holiday = False
|
|
continue
|
|
stat.dayofweek = int(stat.date.strftime("%u")) - 1
|
|
stat.is_public_holiday = bool(stat.sheet_id.employee_id._get_public_holidays(stat.date, stat.date - timedelta(days=1)))
|
|
|
|
def _get_gap_hours(self, total_hours, total_recovery_hours, total_leave_hours, total_planned_hours):
|
|
self.ensure_one()
|
|
balance = (
|
|
total_hours
|
|
+ total_recovery_hours
|
|
+ total_leave_hours
|
|
- total_planned_hours
|
|
)
|
|
return balance
|
|
|
|
@api.depends(
|
|
"employee_id",
|
|
"date",
|
|
"total_hours",
|
|
"total_planned_hours",
|
|
"timesheet_line_ids",
|
|
)
|
|
def _compute_hours(self):
|
|
for stat in self:
|
|
total_hours = stat._get_total_hours()
|
|
total_recovery_hours = stat._get_total_recovery_hours()
|
|
total_planned_hours = stat._get_total_planned_hours()
|
|
total_leave_hours = stat._get_total_leave_hours()
|
|
stat.total_hours = total_hours
|
|
stat.total_planned_hours = total_planned_hours
|
|
stat.gap_hours = stat._get_gap_hours(total_hours, total_recovery_hours, total_leave_hours, total_planned_hours)
|
|
stat.total_recovery_hours = total_recovery_hours
|
|
stat.total_leave_hours = total_leave_hours
|