Browse Source

Feb 01 : [ADD] Initial Commit 'hr_leave_dashboard'

pull/267/merge
RisvanaCybro 1 year ago
parent
commit
f6b2b6282d
  1. 51
      hr_leave_dashboard/README.rst
  2. 23
      hr_leave_dashboard/__init__.py
  3. 68
      hr_leave_dashboard/__manifest__.py
  4. 7
      hr_leave_dashboard/doc/RELEASE_NOTES.md
  5. 23
      hr_leave_dashboard/models/__init__.py
  6. 56
      hr_leave_dashboard/models/hr_employee.py
  7. 172
      hr_leave_dashboard/models/hr_leave.py
  8. 22
      hr_leave_dashboard/report/__init__.py
  9. 111
      hr_leave_dashboard/report/hr_leave_report.py
  10. 89
      hr_leave_dashboard/report/hr_leave_report_templates.xml
  11. 11
      hr_leave_dashboard/report/hr_leave_reports.xml
  12. BIN
      hr_leave_dashboard/static/description/assets/icons/check.png
  13. BIN
      hr_leave_dashboard/static/description/assets/icons/chevron.png
  14. BIN
      hr_leave_dashboard/static/description/assets/icons/cogs.png
  15. BIN
      hr_leave_dashboard/static/description/assets/icons/consultation.png
  16. BIN
      hr_leave_dashboard/static/description/assets/icons/ecom-black.png
  17. BIN
      hr_leave_dashboard/static/description/assets/icons/education-black.png
  18. BIN
      hr_leave_dashboard/static/description/assets/icons/hotel-black.png
  19. BIN
      hr_leave_dashboard/static/description/assets/icons/license.png
  20. BIN
      hr_leave_dashboard/static/description/assets/icons/lifebuoy.png
  21. BIN
      hr_leave_dashboard/static/description/assets/icons/manufacturing-black.png
  22. BIN
      hr_leave_dashboard/static/description/assets/icons/pos-black.png
  23. BIN
      hr_leave_dashboard/static/description/assets/icons/puzzle.png
  24. BIN
      hr_leave_dashboard/static/description/assets/icons/restaurant-black.png
  25. BIN
      hr_leave_dashboard/static/description/assets/icons/service-black.png
  26. BIN
      hr_leave_dashboard/static/description/assets/icons/trading-black.png
  27. BIN
      hr_leave_dashboard/static/description/assets/icons/training.png
  28. BIN
      hr_leave_dashboard/static/description/assets/icons/update.png
  29. BIN
      hr_leave_dashboard/static/description/assets/icons/user.png
  30. BIN
      hr_leave_dashboard/static/description/assets/icons/wrench.png
  31. BIN
      hr_leave_dashboard/static/description/assets/misc/categories.png
  32. BIN
      hr_leave_dashboard/static/description/assets/misc/check-box.png
  33. BIN
      hr_leave_dashboard/static/description/assets/misc/compass.png
  34. BIN
      hr_leave_dashboard/static/description/assets/misc/corporate.png
  35. BIN
      hr_leave_dashboard/static/description/assets/misc/customer-support.png
  36. BIN
      hr_leave_dashboard/static/description/assets/misc/cybrosys-logo.png
  37. BIN
      hr_leave_dashboard/static/description/assets/misc/features.png
  38. BIN
      hr_leave_dashboard/static/description/assets/misc/logo.png
  39. BIN
      hr_leave_dashboard/static/description/assets/misc/pictures.png
  40. BIN
      hr_leave_dashboard/static/description/assets/misc/pie-chart.png
  41. BIN
      hr_leave_dashboard/static/description/assets/misc/right-arrow.png
  42. BIN
      hr_leave_dashboard/static/description/assets/misc/star.png
  43. BIN
      hr_leave_dashboard/static/description/assets/misc/support.png
  44. BIN
      hr_leave_dashboard/static/description/assets/misc/whatsapp.png
  45. BIN
      hr_leave_dashboard/static/description/assets/modules/1.png
  46. BIN
      hr_leave_dashboard/static/description/assets/modules/2.png
  47. BIN
      hr_leave_dashboard/static/description/assets/modules/3.png
  48. BIN
      hr_leave_dashboard/static/description/assets/modules/4.png
  49. BIN
      hr_leave_dashboard/static/description/assets/modules/5.png
  50. BIN
      hr_leave_dashboard/static/description/assets/modules/6.png
  51. BIN
      hr_leave_dashboard/static/description/assets/screenshots/hero.gif
  52. BIN
      hr_leave_dashboard/static/description/assets/screenshots/hr_leave_dashboard.png
  53. BIN
      hr_leave_dashboard/static/description/assets/screenshots/hr_leave_report.png
  54. BIN
      hr_leave_dashboard/static/description/banner.png
  55. BIN
      hr_leave_dashboard/static/description/icon.png
  56. 599
      hr_leave_dashboard/static/description/index.html
  57. 90
      hr_leave_dashboard/static/src/css/hr_leave_dashboard.css
  58. 31
      hr_leave_dashboard/static/src/js/calendar_model.js
  59. 16
      hr_leave_dashboard/static/src/js/calendar_year_renderer.js
  60. 133
      hr_leave_dashboard/static/src/js/emp_org_chart.js
  61. 12
      hr_leave_dashboard/static/src/js/hooks.js
  62. 55
      hr_leave_dashboard/static/src/js/time_off_emp_card.js
  63. 86
      hr_leave_dashboard/static/src/js/time_off_emp_dashboard.js
  64. 16
      hr_leave_dashboard/static/src/scss/calendar_renderer.scss
  65. 10
      hr_leave_dashboard/static/src/scss/time_off_dashboard.scss
  66. 70
      hr_leave_dashboard/static/src/xml/approval_status_card_templates.xml
  67. 45
      hr_leave_dashboard/static/src/xml/emp_department_card_templates.xml
  68. 179
      hr_leave_dashboard/static/src/xml/emp_org_chart_templates.xml
  69. 77
      hr_leave_dashboard/static/src/xml/time_off_emp_card_templates.xml
  70. 43
      hr_leave_dashboard/static/src/xml/time_off_emp_dashboard_templates.xml

51
hr_leave_dashboard/README.rst

@ -0,0 +1,51 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Hr Leave Dashboard
==================
This module helps you to brings a multipurpose graphical dashboard for Time Off module and making the relationship management better and easier.
Installation
============
- www.odoo.com/documentation/16.0/setup/install.html
- Install our custom addon
Configuration
=============
* No additional configurations needed.
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits
-------
* Developer: (v16) Rahul Rajeev, Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

23
hr_leave_dashboard/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import models
from . import report

68
hr_leave_dashboard/__manifest__.py

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
{
'name': "Hr Leave Dashboard",
'version': '16.0.1.0.0',
'category': 'Human Resources',
'summary': """Advanced Leave Dashboard helps to view your and your
subordinate's details""",
'description': """Advanced Leave Dashboard brings a multipurpose graphical
dashboard for Time Off module and making the relationship management better
and easier""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['base', 'hr_holidays', 'hr_org_chart'],
'data': [
'report/hr_leave_reports.xml',
'report/hr_leave_report_templates.xml',
],
'assets': {
'web.assets_backend': [
'hr_leave_dashboard/static/src/js/calendar_model.js',
'hr_leave_dashboard/static/src/js/calendar_year_renderer.js',
'hr_leave_dashboard/static/src/js/hooks.js',
'hr_leave_dashboard/static/src/js/emp_org_chart.js',
'hr_leave_dashboard/static/src/js/time_off_emp_card.js',
'hr_leave_dashboard/static/src/js/time_off_emp_dashboard.js',
'hr_leave_dashboard/static/src/xml/approval_status_card_templates.xml',
'hr_leave_dashboard/static/src/xml/time_off_emp_dashboard_templates.xml',
'hr_leave_dashboard/static/src/xml/emp_org_chart_templates.xml',
'hr_leave_dashboard/static/src/xml/emp_department_card_templates.xml',
'hr_leave_dashboard/static/src/xml/time_off_emp_card_templates.xml',
'hr_leave_dashboard/static/src/css/hr_leave_dashboard.css',
'hr_org_chart/static/src/fields/hr_org_chart.scss',
'hr_leave_dashboard/static/src/scss/time_off_dashboard.scss',
'hr_holidays/static/src/dashboard/time_off_card.scss',
'hr_leave_dashboard/static/src/scss/calendar_renderer.scss'
],
},
'external_dependencies': {
'python': ['pandas'],
},
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

7
hr_leave_dashboard/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <hr_leave_dashboard>
#### 10.01.2024
#### Version 16.0.1.0.0
#### ADD
- Initial Commit Hr Leave Dashboard

23
hr_leave_dashboard/models/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import hr_employee
from . import hr_leave

56
hr_leave_dashboard/models/hr_employee.py

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from odoo import models
class HrEmployee(models.Model):
"""Inherit the model hr.employee to add the functionality for retrieving
public holiday information"""
_inherit = 'hr.employee'
def get_public_holidays(self, start_date, end_date):
"""The function get_public_holidays takes in a start date and end
date as arguments and returns a dictionary with all the public
holidays within that range. It does this by calling the
_get_public_holidays method and then iterating through the results to
add each holiday to the dictionary."""
all_days = {}
user = self or self.env.user.employee_id
public_holidays = user._get_public_holidays(start_date, end_date)
for holiday in public_holidays:
num_days = (holiday.date_to - holiday.date_from).days
for day in range(num_days + 1):
all_days[str(holiday.date_from.date())] = day
return all_days
def _get_public_holidays(self, start_date, end_date):
"""The _get_public_holidays function searches for public holidays
within a given date range, for all companies associated with the
current environment's user. It returns a recordset of
resource.calendar.leaves that match the search criteria."""
public_holidays = self.env['resource.calendar.leaves'].search([
('date_from', '<=', end_date),
('date_to', '>=', start_date),
('resource_id', '=', False),
('company_id', 'in', self.env.companies.ids),
])
return public_holidays

172
hr_leave_dashboard/models/hr_leave.py

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import pytz
from odoo import api, fields, models
class HrLeave(models.Model):
"""Inherit the model hr.leave to introduce supplementary functionality
aimed at incorporating specific employee details."""
_inherit = 'hr.leave'
def _prepare_employee_data(self, employee):
"""Function to prepare employee data for the dashboard"""
return {
'id': employee.id,
'name': employee.name,
'job_id': employee.job_id.name,
'approval_status_count': self.get_approval_status_count(employee.id)
}
@api.model
def get_current_employee(self):
"""This function fetches current employee details in a dictionary"""
current_employee = self.env.user.employee_ids
return {
'id': current_employee.id,
'name': current_employee.name,
'job_id': current_employee.job_id.id,
'image_1920': current_employee.image_1920,
'work_email': current_employee.work_email,
'work_phone': current_employee.work_phone,
'resource_calendar_id': current_employee.resource_calendar_id.name,
'link': '/mail/view?model=%s&res_id=%s' % (
'hr.employee.public', current_employee.id,),
'department_id': current_employee.department_id.name,
'company': current_employee.company_id.name,
'job_position': current_employee.job_id.name,
'parent_id': current_employee.parent_id.ids,
'child_ids': current_employee.child_ids.ids,
'child_all_count': current_employee.child_all_count,
'manager': self._prepare_employee_data(
current_employee.parent_id) if (
current_employee.parent_id) else {},
'manager_all_count': len(current_employee.parent_id.ids),
'children': [self._prepare_employee_data(child) for child in
current_employee.child_ids if
child != current_employee],
}
@api.model
def get_absentees(self):
"""The function retrieves a list of employees who are absent on the
current date by querying the hr_leave table and comparing the
date_from and date_to fields of validated leave requests. It returns
a list of dictionaries containing the employee's name, employee_id,
date_from, and date_to"""
current_employee = self.env.user.employee_ids
children = [self._prepare_employee_data(child) for child in
current_employee.child_ids if
child != current_employee]
child_list = [child.get('id') for child in children]
if len(child_list) > 1:
query = "SELECT employee_id,name,date_from,date_to FROM hr_leave " \
"INNER JOIN hr_employee ON hr_leave.employee_id = " \
"hr_employee.id WHERE state = 'validate' AND " \
"employee_id in %s" % str(tuple(child_list))
self._cr.execute(query)
elif len(child_list) == 1:
query = "SELECT employee_id,name,date_from,date_to FROM hr_leave " \
"INNER JOIN hr_employee ON hr_leave.employee_id = " \
"hr_employee.id WHERE state = 'validate' AND " \
"employee_id = %s" % child_list[0]
self._cr.execute(query)
leave = self._cr.dictfetchall()
absentees = [
leave[leave_date] for leave_date in range(len(leave))
if leave[leave_date].get('date_from') <= fields.datetime.now() <= leave[
leave_date].get('date_to')
]
return absentees
@api.model
def get_current_shift(self):
""" This function fetches current employee's current shift"""
current_employee = self.env.user.employee_ids
employee_tz = current_employee.tz or self.env.context.get('tz')
employee_pytz = pytz.timezone(employee_tz) if employee_tz else pytz.utc
employee_datetime = fields.datetime.now().astimezone(employee_pytz)
hour = employee_datetime.strftime("%H")
minute = employee_datetime.strftime("%M")
day = employee_datetime.strftime("%A")
time = hour + '.' + minute
day_num = '0' if day == 'Monday' else '1' if day == 'Tuesday' \
else '2' if day == 'Wednesday' else '3' if day == 'Thursday' \
else '4' if day == 'Friday' else '5' if day == 'Saturday' else '6'
for shift in current_employee.resource_calendar_id.attendance_ids:
if shift.dayofweek == day_num and shift.hour_from <= float(
time) <= shift.hour_to:
return shift.name
return False
@api.model
def get_upcoming_holidays(self):
""" This function fetches upcoming holidays"""
current_employee = self.env.user.employee_ids
employee_tz = current_employee.tz or self.env.context.get('tz')
employee_pytz = pytz.timezone(employee_tz) if employee_tz else pytz.utc
employee_datetime = fields.datetime.now().astimezone(employee_pytz)
query = "SELECT * FROM public.resource_calendar_leaves WHERE " \
"resource_id is null"
self._cr.execute(query)
holidays = self._cr.dictfetchall()
upcoming_holidays = [holiday for holiday in holidays if
employee_datetime.date() < holiday.get(
'date_to').date()]
return upcoming_holidays
@api.model
def get_approval_status_count(self, current_employee):
""" This function fetches approval status count"""
return {
'validate_count': self.env['hr.leave'].search_count([
('employee_id', '=', current_employee),
('state', '=', 'validate')
]),
'confirm_count': self.env['hr.leave'].search_count([
('employee_id', '=', current_employee),
('state', '=', 'confirm')
]),
'refuse_count': self.env['hr.leave'].search_count([
('employee_id', '=', current_employee),
('state', '=', 'refuse')
])
}
@api.model
def get_all_validated_leaves(self):
""" This function fetches all validated leaves"""
leaves = self.env['hr.leave'].search([('state', '=', 'validate')])
all_validated_leaves = [
{
'id': leave.id,
'employee_id': leave.employee_id.id,
'employee_name': leave.employee_id.name,
'request_date_from': leave.request_date_from,
'request_date_to': leave.request_date_to,
'leave_type_id': leave.holiday_status_id.id,
'leave_type': leave.holiday_status_id.name,
'number_of_days': leave.number_of_days
}
for leave in leaves
]
return all_validated_leaves

22
hr_leave_dashboard/report/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import hr_leave_report

111
hr_leave_dashboard/report/hr_leave_report.py

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import pandas
from datetime import timedelta
from odoo import api, fields, models
from odoo.tools import date_utils
class HrLeaveReport(models.AbstractModel):
"""Model for the dashboard for viewing the employees leave"""
_name = 'report.hr_leave_dashboard.hr_leave_report'
_description = 'HR Leave Report'
@api.model
def _get_report_values(self, docids, data=None):
"""Function for getting the report values"""
if data.get('duration') == 'this_month':
option = pandas.date_range(
date_utils.start_of(fields.Date.today(), 'month'),
date_utils.end_of(fields.Date.today(), 'month') - timedelta(
days=0),
freq='d').strftime(
"%Y-%m-%d").tolist()
elif data.get('duration') == 'this_year':
option = pandas.date_range(
date_utils.start_of(fields.Date.today(), 'year'),
date_utils.end_of(fields.Date.today(), 'year') - timedelta(
days=0),
freq='d').strftime(
"%Y-%m-%d").tolist()
elif data.get('duration') == 'this_week':
option = pandas.date_range(
date_utils.start_of(fields.Date.today(), 'week'),
date_utils.end_of(fields.Date.today(), 'week') - timedelta(
days=0),
freq='d').strftime(
"%Y-%m-%d").tolist()
else:
option = [str(fields.Date.today())]
if not self.env.user.employee_ids.child_ids:
query = """SELECT l.id, lt.id as hr_leave_type_id, e.id as
emp_id, e.name as emp_name, e.department_id as emp_department,
e.parent_id as emp_parent_id, request_date_from, request_date_to,
l.number_of_days, lt.name ::jsonb->> 'en_US' as leave_type,
SUM(al.number_of_days) AS allocated_days, SUM(CASE WHEN l.state =
'validate' THEN l.number_of_days ELSE 0 END) AS taken_days,
SUM(al.number_of_days) - SUM(CASE WHEN l.state = 'validate' THEN
l.number_of_days ELSE 0 END) AS balance_days FROM hr_employee e
inner join hr_leave_allocation al ON al.employee_id = e.id inner
join hr_leave l on l.employee_id = e.id inner join hr_leave_type
lt on l.holiday_status_id = lt.id WHERE l.state = 'validate' AND
e.department_id = '%s' GROUP BY e.id,lt.id,l.id""" % \
self.env.user.employee_ids.department_id.id
else:
query = """SELECT l.id, lt.id as hr_leave_type_id, e.id as
emp_id, e.name as emp_name, e.department_id as emp_department,
e.parent_id as emp_parent_id, request_date_from, request_date_to,
l.number_of_days, lt.name ::jsonb->> 'en_US' as leave_type,
SUM(al.number_of_days) AS allocated_days, SUM(CASE WHEN l.state =
'validate' THEN l.number_of_days ELSE 0 END) AS taken_days,
SUM(al.number_of_days) - SUM(CASE WHEN l.state = 'validate' THEN
l.number_of_days ELSE 0 END) AS balance_days FROM hr_employee e
inner join hr_leave_allocation al ON al.employee_id = e.id inner
join hr_leave l on l.employee_id = e.id inner join hr_leave_type
lt on l.holiday_status_id = lt.id WHERE l.state = 'validate'
GROUP BY e.id,lt.id,l.id"""
self.env.cr.execute(query)
leave_data = self.env.cr.dictfetchall()
filtered_list = []
filtered_tuple = []
for leave in leave_data:
leave_list = pandas.date_range(leave.get('request_date_from'),
leave.get(
'request_date_to') - timedelta(
days=1), freq='d').strftime(
"%Y-%m-%d").tolist()
for date in leave_list:
if date in option:
filtered_list.append(leave)
break
for leave in filtered_list:
if (leave.get('hr_leave_type_id'), leave.get('emp_id')) in \
filtered_tuple:
filtered_list.remove(leave)
else:
filtered_tuple.append(
(leave.get('hr_leave_type_id'), leave.get('emp_id')))
return {
'duration': data.get('duration'),
'filtered_list': filtered_list,
}

89
hr_leave_dashboard/report/hr_leave_report_templates.xml

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Template for the hr leave report -->
<template id="hr_leave_report">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<div class="oe_structure">
<div class="text-center">
<h1>Leave Report</h1>
</div>
<div class="text-center" t-if="duration=='today'">
<h5>Absentees Today</h5>
</div>
<div class="text-center" t-if="duration=='this_week'">
<h5>Absentees this week</h5>
</div>
<div class="text-center" t-if="duration=='this_month'">
<h5>Absentees this month</h5>
</div>
<div class="text-center" t-if="duration=='this_year'">
<h5>Absentees this year</h5>
</div>
<div class="row">
<table class="table">
<thead>
<tr>
<th>
<strong>
Employee ID
</strong>
</th>
<th>
<strong>
Employee Name
</strong>
</th>
<th>
<strong>
Leave Type
</strong>
</th>
<th>
<strong>
Allocated Balance
</strong>
</th>
<th>
<strong>
Taken Leaves
</strong>
</th>
<th>
<strong>
Remaining Balance
</strong>
</th>
</tr>
</thead>
<t t-foreach="filtered_list" t-as="leave_data">
<tr>
<td>
<span t-esc="leave_data['emp_id']"/>
</td>
<td>
<span t-esc="leave_data['emp_name']"/>
</td>
<td>
<span t-esc="leave_data['leave_type']"/>
</td>
<td>
<span t-esc="leave_data['allocated_days']"/>
</td>
<td>
<span t-esc="leave_data['taken_days']"/>
</td>
<td>
<span t-esc="leave_data['balance_days']"/>
</td>
</tr>
</t>
</table>
</div>
</div>
</div>
</t>
</t>
</template>
</odoo>

11
hr_leave_dashboard/report/hr_leave_reports.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Report Action-->
<record id="hr_leave_report_action" model="ir.actions.report">
<field name="name">Leave report</field>
<field name="model">hr.leave.report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">hr_leave_dashboard.hr_leave_report</field>
<field name="report_file">hr_leave_dashboard.hr_leave_report</field>
</record>
</odoo>

BIN
hr_leave_dashboard/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
hr_leave_dashboard/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
hr_leave_dashboard/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
hr_leave_dashboard/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
hr_leave_dashboard/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
hr_leave_dashboard/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
hr_leave_dashboard/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
hr_leave_dashboard/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
hr_leave_dashboard/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
hr_leave_dashboard/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
hr_leave_dashboard/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
hr_leave_dashboard/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
hr_leave_dashboard/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
hr_leave_dashboard/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
hr_leave_dashboard/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
hr_leave_dashboard/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
hr_leave_dashboard/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
hr_leave_dashboard/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
hr_leave_dashboard/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
hr_leave_dashboard/static/description/assets/screenshots/hr_leave_dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
hr_leave_dashboard/static/description/assets/screenshots/hr_leave_report.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
hr_leave_dashboard/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
hr_leave_dashboard/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

599
hr_leave_dashboard/static/description/index.html

@ -0,0 +1,599 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Hr Leave Dashboard</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
This Module Helps You
View Your and Your Subordinate's Details.</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36"
height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36"
height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36"
height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
<div class="col-sm-12 py-4">
This module helps you view your and your subordinate's details and
approval status of your all employees.
With this module, you can print hr leave report on basis of today,
this week, this month and this year
in pdf format.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Hr Leave Dashboard.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">HR Leave PDF Report.</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Available in Odoo 16.0
Community.</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
HR Leave Dashboard
</h3>
<img src="assets/screenshots/hr_leave_dashboard.png"
class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
HR Leave PDF Report
</h3>
<img src="assets/screenshots/hr_leave_report.png"
class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/dashboard_pos/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/crm_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_dynamic_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_payroll_community/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_vacation_mngmt/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/5.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_contract_types/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right" style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png"
class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48"
width="48" style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need
help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52"
width="52" style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on
WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

90
hr_leave_dashboard/static/src/css/hr_leave_dashboard.css

@ -0,0 +1,90 @@
td.fc-day.fc-widget-content.fc-public-holiday{
background-color:red !important;
}
td.fc-day.fc-widget-content.fc-sat{
background-color:red !important;
}
td.fc-day.fc-widget-content.fc-sun{
background-color:red !important;
}
.holidaay{
display :none !important;
}
.o_timeoff_duration{
margin-top:12px !important;
}
.employee_details{
font-size:12px !important;
margin-top: 12px;
margin-bottom: 12px;
}
.o_timeoff_card:not(:last-child) {
font-size: 12px !important;
padding: 12px !important;
position:relative;
}
.o_timeoff_card .o_timeoff_duration{
margin-bottom:12px !important;
}
.o_treeEntry:before, .o_treeEntry:after{
background: #7a539e !important;
}
.duration{
width: 190px;
float: left;
margin: 1px 2px 0px 10px;
height: 29px;
padding: 5px;
margin-bottom: 21px;
}
.time_off_dashboard_table tr th{
background-color: #eaeef3 !important;
font-size: 11px;
}
.employee_image{
border-radius: 50%;
width: 50px;
height: 50px;
overflow: hidden;
position: relative;
}
.employee_name{
font-size: 16px !important;
width: 165px;
/* position: absolute; */
right:62px;
top:24px;
}
.employee_box{
display:flex;
justify-content:center;
align-items:center;
}
.divider-box{
float: left;
margin-bottom: 12px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.box-content{
width: 100%;
margin-right: 2px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
height: 80px;
margin-top: 0px;
border: 1px solid #cebce1;
background-color: #eaedf3;
color: #573674;
}
.divide-leave{
padding:10px;
border: 1px solid #cebce1;
background-color: #eaedf3;
color: #573674;
margin-top:10px;
}

31
hr_leave_dashboard/static/src/js/calendar_model.js

@ -0,0 +1,31 @@
/** @odoo-module */
import { TimeOffCalendarModel } from '@hr_holidays/views/calendar/calendar_model';
import { serializeDate } from "@web/core/l10n/dates";
import { patch } from "@web/core/utils/patch";
//The patch function to modify the TimeOffCalendarModel prototype by adding or
//modifying several methods and properties: setup, updateData,
//fetchPublicHolidays, and a getter for publicHolidays.
patch(TimeOffCalendarModel.prototype, 'hr_holidays.TimeOffCalendarModel',{
setup(params, services) {
this._super(params, services);
this.data.publicHolidays = {};
if (this.env.isSmall) {
this.meta.scale = 'month';
}
},
async updateData(data) {
await this._super(data);
data.publicHolidays = await this.fetchPublicHolidays(data);
},
// Fetches public holidays in a year
async fetchPublicHolidays(data) {
return this.orm.call("hr.employee", "get_public_holidays", [
this.employeeId,
serializeDate(data.range.start, "datetime"),
serializeDate(data.range.end, "datetime"),
]);
},
get publicHolidays() {
return this.data.publicHolidays;
}
});

16
hr_leave_dashboard/static/src/js/calendar_year_renderer.js

@ -0,0 +1,16 @@
/** @odoo-module */
import { patch } from "@web/core/utils/patch";
import { TimeOffCalendarYearRenderer } from "@hr_holidays/views/calendar/year/calendar_year_renderer";
import { usePublicHolidays } from '@hr_leave_dashboard/js/hooks';
//The patch function to modify the TimeOffCalendarYearRenderer prototype
//by adding or modifying two methods: setup and onDayRender.
patch(TimeOffCalendarYearRenderer.prototype, 'hr_leave_dashboard.TimeOffCalendarYearRenderer',{
setup() {
this._super(...arguments);
this.publicHolidays = usePublicHolidays(this.props);
},
onDayRender(info) {
this._super(info);
this.publicHolidays(info);
}
});

133
hr_leave_dashboard/static/src/js/emp_org_chart.js

@ -0,0 +1,133 @@
/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
import { usePopover } from "@web/core/popover/popover_hook";
import { onEmployeeSubRedirect } from "@hr_org_chart/fields/hooks"
const { Component, onWillStart, onWillRender, useState } = owl;
//The useUniquePopover function is a custom hook that enhances the functionality
//of a popover by ensuring that only one popover is visible at a time.
//It utilizes another hook called usePopover to manage the
//popover's state and behavior.
function useUniquePopover() {
const popover = usePopover();
let remove = null;
return Object.assign(Object.create(popover), {
add(target, component, props, options) {
if (remove) {
remove();
}
remove = popover.add(target, component, props, options);
return () => {
remove();
remove = null;
};
},
});
}
//Class TimeOffEmpOrgChartPopover that extends
//the Component class. It is a custom component used for handling
//popovers in an employee organization chart.
class TimeOffEmpOrgChartPopover extends Component {
async setup() {
super.setup();
this.rpc = useService('rpc');
this.orm = useService('orm');
this.actionService = useService("action");
}
/**
* Redirect to the employee form view.
*
* @private
* @param {MouseEvent} event
* @returns {Promise} action loaded
*/
async _onEmployeeRedirect(employeeId) {
const action = await this.orm.call('hr.employee', 'get_formview_action', [employeeId]);
this.actionService.doAction(action);
}
}
TimeOffEmpOrgChartPopover.template = 'hr_leave_dashboard.hr_orgchart_emp_popover';
//Exports a class TimeOffEmpOrgChart that extends the Component class.
//It is a custom component used for displaying an employee organization chart.
export class TimeOffEmpOrgChart extends Component {
async setup() {
super.setup();
this.rpc = useService('rpc');
this.orm = useService('orm');
this.actionService = useService("action");
this.popover = useUniquePopover();
this.jsonStringify = JSON.stringify;
this.state = useState({'employee_id': null});
this._onEmployeeSubRedirect = onEmployeeSubRedirect();
onWillStart(this.handleComponentUpdate.bind(this));
onWillRender(this.handleComponentUpdate.bind(this));
}
/**
* Called on start and on render
*/
async handleComponentUpdate() {
this.employee = this.props.id;
// The widget is either displayed in the context of a hr.employee form or a res.users form
this.state.employee_id = this.props;
const forceReload = this.lastRecord !== this.props.record;
this.lastRecord = this.props.record;
await this.fetchEmployeeData(this.state.employee_id, forceReload);
}
async fetchEmployeeData(employeeId, force = false) {
employeeId = this.props.id
if (!employeeId) {
this.managers = [];
this.children = [];
if (this.view_employee_id) {
this.render(true);
}
this.view_employee_id = null;
} else if (employeeId !== this.view_employee_id || force) {
this.view_employee_id = employeeId;
var orgData = await this.rpc(
'/hr/get_org_chart',
{
employee_id: employeeId,
context: Component.env.session.user_context,
}
);
if (Object.keys(orgData).length === 0) {
orgData = {
managers: [],
children: [],
}
}
this.managers = orgData.managers;
this.children = orgData.children;
this.managers_more = orgData.managers_more;
this.self = orgData.self;
this.render(true);
}
}
_onOpenPopover(event, employee) {
this.popover.add(
event.currentTarget,
this.constructor.components.Popover,
{employee},
{closeOnClickAway: true}
);
}
/**
* Redirect to the employee form view.
*
* @private
* @param {MouseEvent} event
* @returns {Promise} action loaded
*/
async _onEmployeeRedirect(employeeId) {
const action = await this.orm.call('hr.employee', 'get_formview_action', [employeeId]);
this.actionService.doAction(action);
}
async _onEmployeeMoreManager(managerId) {
await this.fetchEmployeeData(managerId);
this.state.employee_id = managerId;
}
}
TimeOffEmpOrgChart.components = {
Popover: TimeOffEmpOrgChartPopover,
};
TimeOffEmpOrgChart.template = 'hr_leave_dashboard.hr_org_chart';

12
hr_leave_dashboard/static/src/js/hooks.js

@ -0,0 +1,12 @@
/** @odoo-module */
//Exports a custom hook usePublicHolidays that takes in props as a parameter.
//This hook is likely intended to be used in a calendar component to mark public holidays.
export function usePublicHolidays(props) {
return (info) => {
const date = luxon.DateTime.fromJSDate(info.date).toISODate();
const publicHolidays = props.model.publicHolidays[date];
if (publicHolidays) {
info.el.classList.add('fc-public-holiday');
}
}
}

55
hr_leave_dashboard/static/src/js/time_off_emp_card.js

@ -0,0 +1,55 @@
/* @odoo-module */
import session from 'web.session';
import { useService } from "@web/core/utils/hooks";
const { Component } = owl;
export class TimeOffEmpCard extends Component {}
TimeOffEmpCard.template = 'hr_leave_dashboard.TimeOffEmpCard';
TimeOffEmpCard.props = ['name', 'id', 'department_id', 'job_position',
'children', 'image_1920', 'work_email', 'work_phone', 'company', 'resource_calendar_id'];
//Exports a class TimeOffEmpOrgChart that extends the Component class.
//It is a custom component used for managing an employee organization
//chart in the context of time off and holidays.
export class TimeOffEmpOrgChart extends Component {
setup() {
this.props;
session.user_has_group('hr_holidays.group_hr_holidays_manager').then(hasGroup => {
this.manager = hasGroup;
});
}
}
TimeOffEmpOrgChart.template = 'hr_leave_dashboard.hr_org_chart';
TimeOffEmpOrgChart.props = ['name', 'id', 'department_id', 'job_position', 'children'];
export class EmpDepartmentCard extends Component {}
EmpDepartmentCard.template = 'hr_leave_dashboard.EmpDepartmentCard';
EmpDepartmentCard.props = ['name', 'id', 'department_id', 'child_all_count',
'children', 'absentees', 'current_shift', 'upcoming_holidays'];
//Exports a class ApprovalStatusCard that extends the Component class.
//It is a custom component used for managing the approval status of
//a card, possibly related to HR leave requests.
export class ApprovalStatusCard extends Component {
setup() {
this.props;
this.rpc = useService('rpc');
this.actionService = useService("action");
session.user_has_group('hr_holidays.group_hr_holidays_manager').then(hasGroup => {
this.manager = hasGroup;
});
}
async printPdfReport() {
const duration = $(this.__owl__.bdom.el.querySelectorAll("#duration")).val();
return this.actionService.doAction({
type: "ir.actions.report",
report_type: "qweb-pdf",
report_name: "hr_leave_dashboard.hr_leave_report",
report_file: "hr_leave_dashboard.hr_leave_report",
data: {
'duration': duration,
'all_validated_leaves': this.props.all_validated_leaves,
}
});
}
}
ApprovalStatusCard.template = 'hr_leave_dashboard.ApprovalStatusCard';
ApprovalStatusCard.props = ['id','name','approval_status_count','child_ids',
'children', 'all_validated_leaves'];

86
hr_leave_dashboard/static/src/js/time_off_emp_dashboard.js

@ -0,0 +1,86 @@
/** @odoo-module */
import { patch } from "@web/core/utils/patch";
import { TimeOffDashboard } from '@hr_holidays/dashboard/time_off_dashboard';
import { TimeOffCard } from '@hr_holidays/dashboard/time_off_card';
import { TimeOffEmpCard } from './time_off_emp_card';
import { TimeOffEmpOrgChart } from './emp_org_chart';
import { EmpDepartmentCard } from './time_off_emp_card';
import { ApprovalStatusCard } from './time_off_emp_card';
import session from 'web.session';
const { Component } = owl;
//The code is a patch that modifies the loadDashboardData method of the TimeOffDashboard class.
patch(TimeOffDashboard.prototype, 'hr_holidays.TimeOffDashboard',{
//It sets the context based on the employee ID provided and checks
//if the logged-in user has a specific user group, setting the manager property accordingly.
async loadDashboardData() {
const context = {};
if (this.props.employeeId !== null) {
context['employee_id'] = this.props.employeeId;
}
session.user_has_group('hr_holidays.group_hr_holidays_manager').then(hasGroup => {
this.manager = hasGroup;
});
this.state.holidays = await this.orm.call(
'hr.leave.type',
'get_days_all_request',
[],
{
context: context
}
);
this.current_employee = await this.orm.call(
'hr.leave',
'get_current_employee',
[],
{
context: context
}
);
this.absentees = await this.orm.call(
'hr.leave',
'get_absentees',
[],
{
context: context
}
);
this.current_shift = await this.orm.call(
'hr.leave',
'get_current_shift',
[],
{
context: context
}
);
this.upcoming_holidays = await this.orm.call(
'hr.leave',
'get_upcoming_holidays',
[],
{
context: context
}
);
this.approval_status_count = await this.orm.call(
'hr.leave',
'get_approval_status_count',
[this.current_employee.id],
{
context: context
}
);
this.all_validated_leaves = await this.orm.call(
'hr.leave',
'get_all_validated_leaves',
[],
{
context: context
}
);
if (this.props.employeeId == null) {
this.props.employeeId = this.current_employee.id;
}
}
});
TimeOffDashboard.components = { TimeOffCard, TimeOffEmpCard ,TimeOffEmpOrgChart, EmpDepartmentCard, ApprovalStatusCard};
TimeOffDashboard.template = 'hr_holidays.TimeOffDashboard';
TimeOffDashboard.props = ['employeeId'];

16
hr_leave_dashboard/static/src/scss/calendar_renderer.scss

@ -0,0 +1,16 @@
.o_timeoff_calendar {
.o_calendar_renderer {
height: unset;
.o_calendar_widget {
@for $size from 1 through length($o-colors) {
.hr_public_holiday_#{$size - 1}:not(.fc-disabled-day) {
background: nth($o-colors, $size) !important;
opacity: 0.4;
}
}
}
.fc-bgevent {
border-radius: 25px;
}
}
}

10
hr_leave_dashboard/static/src/scss/time_off_dashboard.scss

@ -0,0 +1,10 @@
.o_timeoff_dashboard {
display: flex;
justify-content: space-between;
height: auto;
box-shadow: inset 0 -1px 0 $border-color;
position: sticky;
top: 0;
z-index: 100;
background-color: $o-webclient-background-color;
}

70
hr_leave_dashboard/static/src/xml/approval_status_card_templates.xml

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<!-- Component for displaying approval status of employee leave requests. -->
<!-- It includes conditional rendering of approval status based on the -->
<!-- user role and a dropdown menu and button for generating a PDF report.-->
<div t-name="hr_leave_dashboard.ApprovalStatusCard" owl='1'
class="o_timeoff_card approval_status_card py-3 text-odoo"
style="height: 475px;overflow-y: scroll;">
<t t-set="approval_status_count"
t-value="props.approval_status_count"/>
<t t-set="children" t-value="props.children"/>
<t t-if="!manager">
<div class="hr_holiday_user">
<span class="o_timeoff_duration">
<t t-esc="approval_status_count.validate_count"/>
</span>
<div class="text-uppercase">
<span>Approved</span>
</div>
<span class="o_timeoff_duration">
<t t-esc="approval_status_count.confirm_count"/>
</span>
<div class="text-uppercase">
<span>To Approve</span>
</div>
<span class="o_timeoff_duration">
<t t-esc="approval_status_count.refuse_count"/>
</span>
<div class="text-uppercase">
<span>Refused</span>
</div>
</div>
</t>
<t t-else="">
<div class="hr_holiday_manager">
<div class="pdf_report">
<select id="duration" class="duration">
<option value="today">Today</option>
<option value="this_week">This week</option>
<option value="this_month">This month</option>
<option value="this_year">This Year</option>
</select>
<button t-on-click="printPdfReport" type="button"
class="btn btn-primary">Print PDF</button>
</div>
<table class="table table-hover time_off_dashboard_table">
<thead>
<tr>
<th>Name</th>
<th>Approved</th>
<th>To Approve</th>
<th>Refused</th>
</tr>
</thead>
<tbody>
<t t-foreach="children" t-as="child"
t-key="child.id">
<tr>
<td><t t-esc="child.name"/></td>
<td><t t-esc="child.approval_status_count.validate_count"/></td>
<td><t t-esc="child.approval_status_count.confirm_count"/></td>
<td><t t-esc="child.approval_status_count.refuse_count"/></td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</div>
</templates>

45
hr_leave_dashboard/static/src/xml/emp_department_card_templates.xml

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<!-- This template renders a department card that displays the current shift,-->
<!-- upcoming holidays, and a list of employees on leave. -->
<!-- It takes in various props such as department ID, employee count, and absentees.-->
<div t-name="hr_leave_dashboard.EmpDepartmentCard" owl="1"
class="o_timeoff_card py-3 text-odoo" style="width:18%;">
<t t-set="id" t-value="props.id"/>
<t t-set="department_id" t-value="props.department_id"/>
<t t-set="emp_count" t-value="0"/>
<t t-set="child_count" t-value="props.child_all_count"/>
<t t-set="children" t-value="props.children"/>
<t t-set="absentees" t-value="props.absentees"/>
<t t-set="shift" t-value="props.current_shift"/>
<t t-set="upcoming_holidays" t-value="props.upcoming_holidays"/>
<span class="o_timeoff_duration">
<t t-esc="department_id"/>
</span>
<div t-if="shift">
<div class="text-uppercase col-lg-12 divide-leave ">
<t t-if="shift" name="duration_unit">Current Shift: <t
t-esc="shift"/></t>
</div>
</div>
<div t-if="upcoming_holidays.length>0" class="col-lg-12 divide-leave">
<div class="text-success">Upcoming Holidays</div>
<t t-foreach="upcoming_holidays" t-as="holiday" t-key="holiday.id">
<div>
<t t-esc="holiday.name"/>
</div>
<div>
(<t t-esc="holiday.date_from"/>)
</div>
</t>
</div>
<div t-if="absentees.length>0" class="col-lg-12 divide-leave">
<div class="text-danger">On Leave</div>
<t t-foreach="absentees" t-as="child" t-key="child.employee_id">
<div>
<t t-esc="child.name"/>
</div>
</t>
</div>
</div>
</templates>

179
hr_leave_dashboard/static/src/xml/emp_org_chart_templates.xml

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<!-- This template renders the manager count and child count in the dashboard-->
<t t-name="hr_leave_dashboard.hr_org_chart_employee" owl="1">
<t t-set="is_self" t-value="employee.id == view_employee_id"/>
<t t-set="child_count" t-value="props.child_all_count"/>
<t t-set="manager_count" t-value="props.manager_all_count"/>
<section t-if="employee_type == 'self'"
t-attf-class="o_org_chart_entry_self_container #{manager_count &gt; 0 ? 'o_org_chart_has_managers' : ''}">
<div t-attf-class="o_org_chart_entry o_org_chart_entry_#{employee_type} d-flex position-relative py-2 overflow-visible #{manager_count &gt; 0 ? 'o_treeEntry' : ''}">
<t t-call="hr_leave_dashboard.hr_org_chart_employee_content">
<t t-set="is_self" t-value="is_self"/>
</t>
</div>
</section>
<div t-else=""
t-attf-class="o_org_chart_entry o_org_chart_entry_#{employee_type} o_treeEntry d-flex position-relative py-2 overflow-visible">
<t t-call="hr_leave_dashboard.hr_org_chart_employee_content">
<t t-set="is_self" t-value="is_self"/>
</t>
</div>
</t>
<t t-name="hr_leave_dashboard.hr_org_chart_employee_content" owl="1">
<div class="o_media_left position-relative">
<!-- NOTE: Since by the default on not squared images odoo add white borders,
use bg-images to get a clean and centred images -->
<a t-if="! is_self"
class="o_media_object d-block rounded-circle o_employee_redirect"
t-att-style="'background-image:url(\'/web/image/hr.employee.public/' + employee.id + '/avatar_1024/\')'"
t-att-alt="employee.name"
t-att-data-employee-id="employee.id"
t-att-href="employee.link"
t-on-click.prevent="() => this._onEmployeeRedirect(employee.id)"/>
<div t-if="is_self"
class="o_media_object d-block rounded-circle border border-info"
t-att-style="'background-image:url(\'/web/image/hr.employee.public/' + employee.id + '/avatar_1024/\')'"/>
</div>
<div class="d-flex flex-grow-1 align-items-center justify-content-between position-relative px-3">
<a t-if="!is_self" t-att-href="employee.link"
class="o_employee_redirect d-flex flex-column"
t-att-data-employee-id="employee.id"
t-on-click.prevent="() => this._onEmployeeRedirect(employee.id)">
<b class="o_media_heading m-0 fs-6" t-esc="employee.name"/>
<small class="text-muted fw-bold" t-esc="employee.job_title"/>
</a>
<div t-if="is_self" class="d-flex flex-column">
<h5 class="o_media_heading m-0" t-esc="employee.name"/>
<small class="text-muted fw-bold" t-esc="employee.job_title"/>
</div>
<button t-if="employee.indirect_sub_count &gt; 0"
class="btn p-0 fs-3"
tabindex="0"
t-att-data-emp-name="employee.name"
t-att-data-emp-id="employee.id"
t-att-data-emp-dir-subs="employee.direct_sub_count"
t-att-data-emp-ind-subs="employee.indirect_sub_count"
data-bs-trigger="focus"
data-bs-toggle="popover"
t-on-click="(event) => this._onOpenPopover(event, employee)">
<a href="#"
t-attf-class="badge rounded-pill bg-white border {{employee.indirect_sub_count &lt; 10 ? 'px-2' : 'px-1' }}"
t-esc="employee.indirect_sub_count"/>
</button>
</div>
</t>
<t t-name="hr_leave_dashboard.hr_org_chart" owl="1">
<!-- NOTE: Desired behaviour:
The maximum number of people is always 7 (including 'self'). Managers have priority over subordinates
E.g. 1 Manager + 1 self = show just 5 subordinates (if available)
E.g. 0 Manager + 1 self = show 6 subordinates (if available) -->
<t t-set="emp_count" t-value="0"/>
<t t-set="child_count" t-value="props.child_all_count"/>
<t t-set="manager_count" t-value="props.manager_all_count"/>
<div t-if='manager_count &gt; 0'
class="o_org_chart_group_up position-relative">
<t t-foreach="managers" t-as="employee" t-key="employee_index">
<t t-set="emp_count" t-value="emp_count + 1"/>
<t t-call="hr_leave_dashboard.hr_org_chart_employee">
<t t-set="employee_type" t-value="'manager'"/>
</t>
</t>
</div>
<t t-if="child_count || manager_count"
t-call="hr_leave_dashboard.hr_org_chart_employee">
<t t-set="employee_type" t-value="'self'"/>
<t t-set="employee" t-value="self"/>
</t>
<t t-if="!child_count &amp;&amp; !manager_count">
<div class="alert alert-info" role="alert">
<p><b>No hierarchy position.</b></p>
<p>This employee has no manager or subordinate.</p>
<p>In order to get an organism, set a manager and save the record.</p>
</div>
</t>
<div t-if="child_count"
t-attf-class="o_org_chart_group_down position-relative #{manager_count &gt; 0 ? 'o_org_chart_has_managers' : ''}"
style="height: 475px;overflow: scroll;">
<t t-if="props.manager">
<t t-foreach="children" t-as="employee" t-key="employee_index">
<t t-set="emp_count" t-value="emp_count + 1"/>
<t t-if="emp_count &lt; 20">
<t t-call="hr_leave_dashboard.hr_org_chart_employee">
<t t-set="employee_type" t-value="'sub'"/>
</t>
</t>
</t>
<t t-if="(child_count + manager_count) &gt; 19">
<div class="o_org_chart_entry o_org_chart_more d-flex overflow-visible">
<div class="o_media_left position-relative">
<a href="#"
t-att-data-employee-id="self.id"
t-att-data-employee-name="self.name"
class="o_org_chart_show_more o_employee_sub_redirect btn btn-link ps-2"
t-on-click.prevent="_onEmployeeSubRedirect">See All</a>
</div>
</div>
</t>
</t>
<t t-else="">
<t t-foreach="children" t-as="employee" t-key="employee_index">
<t t-if="props.job_id == employee.job_id">
<t t-set="emp_count" t-value="emp_count + 1"/>
<t t-if="emp_count &lt; 20">
<t t-call="hr_leave_dashboard.hr_org_chart_employee">
<t t-set="employee_type" t-value="'sub'"/>
</t>
</t>
</t>
</t>
</t>
</div>
</t>
<t t-name="hr_leave_dashboard.hr_orgchart_emp_popover" owl="1">
<div class="popover o_org_chart_popup" role="tooltip">
<div class="tooltip-arrow">
</div>
<h3 class="popover-header">
<div class="d-flex align-items-center">
<span class="flex-shrink-0"
t-att-style='"background-image:url(\"/web/image/hr.employee.public/" + props.employee.id + "/avatar_1024/\")"'/>
<b class="flew-grow-1"><t t-esc="props.employee.name"/></b>
<a href="#" class="ms-auto o_employee_redirect"
t-att-data-employee-id="props.employee.id"
t-on-click.prevent="() => this._onEmployeeRedirect(props.employee.id)">
<i class="fa fa-external-link" role="img"
aria-label='Redirect' title="Redirect">
</i>
</a>
</div>
</h3>
<div class="popover-body">
<table class="table table-sm table-borderless mb-0">
<tbody>
<tr>
<td class="text-end"><b t-esc="props.employee.direct_sub_count"/></td>
<td>
<b>Direct subordinates</b>
</td>
</tr>
<tr>
<td class="text-end">
<b t-esc="props.employee.indirect_sub_count - props.employee.direct_sub_count"/>
</td>
<td>
Indirect subordinates
</td>
</tr>
<tr>
<td class="text-end"><b t-esc="props.employee.indirect_sub_count"/></td>
<td>
Total
</td>
</tr>
</tbody>
</table>
</div>
</div>
</t>
</templates>

77
hr_leave_dashboard/static/src/xml/time_off_emp_card_templates.xml

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<!-- The template defines a card to display employee information such as name, job position, -->
<!-- working hours, department, and company. -->
<!-- It also includes the employee's image and contact information like email and phone number.-->
<div t-name="hr_leave_dashboard.TimeOffEmpCard" owl="1" style="width:22%;"
class="o_timeoff_card py-3 text-odoo">
<t t-set="id" t-value="props.id"/>
<t t-set="name" t-value="props.name"/>
<t t-set="work_email" t-value="props.work_email"/>
<t t-set="work_phone" t-value="props.work_phone"/>
<t t-set="department_id" t-value="props.department_id"/>
<t t-set="resource_calendar_id" t-value="props.resource_calendar_id"/>
<t t-set="company" t-value="props.company"/>
<t t-set="job_position" t-value="props.job_position"/>
<t t-set="child_ids" t-value="props.child_ids"/>
<t t-set="child_count" t-value="props.child_count"/>
<t t-set="image" t-value="props.image_1920"/>
<div class="w-100 mt-2 mb-2 employee_box">
<div class="employee_image">
<t t-if="image">
<img style="width: 50px; height: 50px;"
t-attf-src="data:image/png;base64,{{image}}"/>
</t>
</div>
<span class="o_timeoff_duration employee_name">
<t t-esc="name"/>
</span>
</div>
<div class="employee_details" style="width:100%;">
<div class="col-lg-6 divider-box"
style="float:left; margin-bottom:12px;">
<div class="text-uppercase box-content">
<t t-if="job_position" name="duration_unit">Job Position: <t
t-esc="job_position"/>
</t>
</div>
</div>
<div class="col-lg-6 divider-box"
style="float:left; margin-bottom:12px;">
<div class="box-content">
<t t-if="resource_calendar_id" name="duration_unit">Working Hours: <t
t-esc="resource_calendar_id"/>
</t>
</div>
</div>
<div class="col-lg-12 divider-box"
style="float:left; margin-bottom:12px;">
<div class="box-content">
<t t-if="work_email" name="duration_unit">EMAIL: <t
t-esc="work_email"/></t>
</div>
</div>
<div class="col-lg-6 divider-box"
style="float:left; margin-bottom:12px;">
<div class="box-content">
<t t-if="work_phone" name="duration_unit">PHONE: <t
t-esc="work_phone"/></t>
</div>
</div>
<div class="col-lg-6 divider-box"
style="float:left; margin-bottom:12px;">
<div class="text-uppercase box-content">
<t t-if="department_id" name="duration_unit">Department: <t
t-esc="department_id"/></t>
</div>
</div>
<div class="col-lg-12 divider-box"
style="float:left; margin-bottom:12px;">
<div class="text-uppercase box-content">
<t t-if="company" name="duration_unit">Company: <t
t-esc="company"/></t>
</div>
</div>
</div>
</div>
</templates>

43
hr_leave_dashboard/static/src/xml/time_off_emp_dashboard_templates.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<!-- This template is an extension of the "hr_holidays.TimeOffDashboard"-->
<!-- template and includes four sub-templates to display information about an -->
<!-- employee's time off, organization chart, department, and approval status. -->
<!-- It uses the "current_employee" object to fetch and display relevant information.-->
<div t-name="hr_leave_dashboard.TimeOffEmpDashboard"
t-inherit="hr_holidays.TimeOffDashboard" t-inherit-mode='extension'
owl="1" class="o_timeoff_dashboard">
<xpath expr="//div[hasclass('o_timeoff_dashboard')]" position="inside">
<TimeOffEmpCard name="current_employee.name"
id="current_employee.id"
work_email="current_employee.work_email"
work_phone="current_employee.work_phone"
image_1920="current_employee.image_1920"
department_id="current_employee.department_id"
resource_calendar_id="current_employee.resource_calendar_id"
company="current_employee.company"
job_position="current_employee.job_position"
children="current_employee.children"/>
<TimeOffEmpOrgChart name="current_employee.name"
id="current_employee.id"
job_id="current_employee.job_id"
manager="manager"
manager_all_count="current_employee.manager_all_count"
child_all_count="current_employee.child_all_count"/>
<EmpDepartmentCard name="current_employee.name"
id="current_employee.id"
child_all_count="current_employee.child_all_count"
children="current_employee.children"
department_id="current_employee.department_id"
absentees="absentees"
current_shift="current_shift"
upcoming_holidays="upcoming_holidays"/>
<ApprovalStatusCard id="current_employee.id"
name="current_employee.name"
child_ids="current_employee.child_ids"
children="current_employee.children"
all_validated_leaves="all_validated_leaves"
approval_status_count="approval_status_count"/>
</xpath>
</div>
</templates>
Loading…
Cancel
Save