Files
enterprise-addons/planning_attendance/report/planning_attendance_analysis_report.py
T

99 lines
4.6 KiB
Python

# 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 PlanningAttendanceAnalysisReport(models.Model):
_name = 'planning.attendance.analysis.report'
_description = "Planning / Attendance Analysis"
_auto = False
_rec_name = "entry_date"
_order = "entry_date desc"
entry_date = fields.Date(readonly=True)
employee_id = fields.Many2one("hr.employee", string="Employee", readonly=True)
department_id = fields.Many2one("hr.department", string="Department", readonly=True)
company_id = fields.Many2one("res.company", string="Company", readonly=True)
effective_hours = fields.Float("Attendance Time", readonly=True)
planned_hours = fields.Float("Planned Time", readonly=True)
time_difference = fields.Float("Time Difference", readonly=True)
effective_costs = fields.Float("Attendance Cost", readonly=True)
planned_costs = fields.Float("Planned Cost", readonly=True)
cost_difference = fields.Float("Cost Difference", readonly=True)
def init(self):
query = """
SELECT MAX(id) AS id,
t.entry_date,
t.employee_id,
t.department_id,
t.company_id,
COALESCE(SUM(t.worked_hours), 0) AS effective_hours,
COALESCE(SUM(t.allocated_hours), 0) AS planned_hours,
COALESCE(SUM(t.worked_hours), 0) - COALESCE(SUM(t.allocated_hours), 0) AS time_difference,
NULLIF(COALESCE(SUM(t.worked_hours), 0) * t.hourly_cost, 0) AS effective_costs,
NULLIF(COALESCE(SUM(t.allocated_hours), 0) * t.hourly_cost, 0) AS planned_costs,
NULLIF((COALESCE(SUM(t.worked_hours), 0) - COALESCE(sum(t.allocated_hours), 0)) * t.hourly_cost, 0) AS cost_difference
FROM (
SELECT -A.id AS id,
A.check_in::date AS entry_date,
A.employee_id AS employee_id,
V.department_id AS department_id,
E.company_id AS company_id,
E.hourly_cost AS hourly_cost,
A.worked_hours AS worked_hours,
0.0 AS allocated_hours
FROM hr_attendance A
LEFT JOIN hr_employee E ON E.id = A.employee_id
LEFT JOIN (
SELECT DISTINCT ON (employee_id) *
FROM hr_version
ORDER BY employee_id, date_version DESC
) V ON V.employee_id = E.id
UNION ALL
SELECT S.id AS id,
d::date AS entry_date,
S.employee_id AS employee_id,
V.department_id AS department_id,
S.company_id AS company_id,
E.hourly_cost AS hourly_cost,
0.0 AS worked_hours,
(S.allocated_hours / NULLIF((S.end_datetime::date - S.start_datetime::date + 1), 0)) AS allocated_hours
FROM generate_series(
(SELECT min(start_datetime) FROM planning_slot)::date,
CURRENT_DATE,
'1 day'::interval
) d
LEFT JOIN planning_slot S
ON d::date >= S.start_datetime::date
AND d::date <= S.end_datetime::date
LEFT JOIN hr_employee E ON E.id = S.employee_id
LEFT JOIN (
SELECT DISTINCT ON (employee_id) *
FROM hr_version
ORDER BY employee_id, date_version DESC
) V ON V.employee_id = E.id
) AS t
WHERE t.employee_id IS NOT NULL
AND entry_date <= CURRENT_DATE
GROUP BY t.entry_date, t.employee_id, t.department_id, t.company_id, t.hourly_cost
ORDER BY t.entry_date, t.employee_id
"""
drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute(
SQL(
"""CREATE OR REPLACE VIEW %s AS (%s)""",
SQL.identifier(self._table),
SQL(query),
)
)
@api.model
def formatted_read_group(self, domain, groupby=(), aggregates=(), having=(), offset=0, limit=None, order=None) -> list[dict]:
if not order and groupby:
order = ', '.join(f"{spec} DESC" if spec.startswith('date:') else spec for spec in groupby)
return super().formatted_read_group(domain, groupby, aggregates, having=having, offset=offset, limit=limit, order=order)