From fbb7532d5656d62bd4370017ea61b55723cdd8e2 Mon Sep 17 00:00:00 2001 From: raman Date: Thu, 22 May 2025 15:58:50 +0530 Subject: [PATCH] leave balance in dashboard --- .../hr_emp_dashboard/__init__.py | 2 +- .../hr_emp_dashboard/__manifest__.py | 2 +- .../hr_emp_dashboard/controllers/__init__.py | 1 + .../controllers/employee_dashboard.py | 40 +++++++++++ .../static/src/js/profile_component.js | 68 +++++++++++++++++-- .../src/xml/employee_profile_template.xml | 54 +++++++++++++-- 6 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 addons_extensions/hr_emp_dashboard/controllers/__init__.py create mode 100644 addons_extensions/hr_emp_dashboard/controllers/employee_dashboard.py diff --git a/addons_extensions/hr_emp_dashboard/__init__.py b/addons_extensions/hr_emp_dashboard/__init__.py index 24c19d687..19240f4ea 100644 --- a/addons_extensions/hr_emp_dashboard/__init__.py +++ b/addons_extensions/hr_emp_dashboard/__init__.py @@ -1,2 +1,2 @@ - +from . import controllers from . import models \ No newline at end of file diff --git a/addons_extensions/hr_emp_dashboard/__manifest__.py b/addons_extensions/hr_emp_dashboard/__manifest__.py index 49ac99da1..56d6afa82 100644 --- a/addons_extensions/hr_emp_dashboard/__manifest__.py +++ b/addons_extensions/hr_emp_dashboard/__manifest__.py @@ -5,7 +5,7 @@ 'version': '1.0', 'category': 'Human Resources', 'summary': 'Display employee profile using Owl.js', - 'depends': ['base', 'hr', 'web','muk_web_theme'], # Depends on base, hr, and web for Owl.js and hr.employee model + 'depends': ['base', 'hr', 'web'], # Depends on base, hr, and web for Owl.js and hr.employee model 'data': [ 'views/employee_dashboard_views.xml', # Your template ], diff --git a/addons_extensions/hr_emp_dashboard/controllers/__init__.py b/addons_extensions/hr_emp_dashboard/controllers/__init__.py new file mode 100644 index 000000000..323514bb7 --- /dev/null +++ b/addons_extensions/hr_emp_dashboard/controllers/__init__.py @@ -0,0 +1 @@ +from . import employee_dashboard \ No newline at end of file diff --git a/addons_extensions/hr_emp_dashboard/controllers/employee_dashboard.py b/addons_extensions/hr_emp_dashboard/controllers/employee_dashboard.py new file mode 100644 index 000000000..ecc081858 --- /dev/null +++ b/addons_extensions/hr_emp_dashboard/controllers/employee_dashboard.py @@ -0,0 +1,40 @@ +from odoo import http +from odoo.http import request + +class EmployeeDashboard(http.Controller): + + @http.route('/employee/leave/balance', auth='user', type='json') + def get_leave_balance(self): + employee = request.env.user.employee_id + if not employee: + return {'error': 'No employee linked to this user'} + + leave_data = {} + leave_types = request.env['hr.leave.type'].search([ + ]) + if not leave_types: + return [] + + for leave_type in leave_types: + allocations = request.env['hr.leave.allocation'].search([ + ('employee_id', '=', employee.id), + ('holiday_status_id', '=', leave_type.id), + ('state', '=', 'validate'), + ]) + taken_leaves = request.env['hr.leave'].search([ + ('employee_id', '=', employee.id), + ('holiday_status_id', '=', leave_type.id), + ('state', '=', 'validate'), + ]) + + total_allocated = sum(a.number_of_days for a in allocations) + total_taken = sum(l.number_of_days for l in taken_leaves) + remaining = total_allocated - total_taken + + leave_data[leave_type.name] = { + 'allocated': total_allocated, + 'taken': total_taken, + 'remaining': remaining, + } + + return leave_data diff --git a/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js b/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js index 9eab0c9e9..afe51967c 100644 --- a/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js +++ b/addons_extensions/hr_emp_dashboard/static/src/js/profile_component.js @@ -1,5 +1,5 @@ /** @odoo-module **/ - +import { rpc } from "@web/core/network/rpc"; import { Component, useEffect, useState, onMounted, useRef, onWillStart } from "@odoo/owl"; import { registry } from "@web/core/registry"; const actionRegistry = registry.category("actions"); @@ -34,13 +34,31 @@ export class NetflixProfileContainer extends Component { department_id: '' }, attendance_lines: [], - leaves: [] + leaves: [], + leave_allocations:[] }); - onWillStart(() => loadJS(["/web/static/lib/Chart/Chart.js"])); + onWillStart(async () => { + await loadJS("/web/static/lib/Chart/Chart.js"); + const result = await rpc("/employee/leave/balance"); + const LEAVE_NAME_MAP = { + "Sick Time Off": "SL", + "Casual Leave": "CL", + "Privilege Leave": "PL" + }; + const filteredLeaves = {}; + for (const [name, data] of Object.entries(result)) { + const code = LEAVE_NAME_MAP[name]; + if (code) { + filteredLeaves[code] = data; + } + } + this.state.leave_allocations = filteredLeaves; + }); onMounted(async () => { await this.fetchEmployeeData(); + await this.drawChartWhenReady(); // Make sure Chart is loaded and canvas is available await loadJS(["/web/static/lib/Chart/Chart.js"]); @@ -58,7 +76,48 @@ export class NetflixProfileContainer extends Component { }); } + drawChartWhenReady() { + // Wait for data to be loaded before drawing chart + const interval = setInterval(() => { + if (Object.keys(this.state.leave_allocations).length > 0 && window.Chart) { + this.drawChart(); + clearInterval(interval); + } + }, 100); + } +drawChart() { + const ctx = document.getElementById("leaveChart")?.getContext("2d"); + if (!ctx) { + console.warn("leaveChart canvas not found"); + return; + } + const leaves = this.state.leave_allocations; + + const data = { + labels: ['Sick Leave (SL)', 'Casual Leave (CL)', 'Privilege Leave (PL)'], + datasets: [{ + data: [ + leaves.SL?.remaining || 0, + leaves.CL?.remaining || 0, + leaves.PL?.remaining || 0, + ], + backgroundColor: ['#ed8e34', '#4787bf', '#ff0080'], + }] + }; + + new Chart(ctx, { + type: 'doughnut', + data: data, + options: { + responsive: true, + plugins: { + legend: { position: 'bottom' }, + title: { display: true, text: 'Available Leave Balance' } + } + } + }); +} hr_timesheets() { this.action.doAction({ name: "Timesheets", @@ -144,7 +203,8 @@ export class NetflixProfileContainer extends Component { responsive: true, plugins: { legend: { display: true }, - tooltip: { mode: 'index', intersect: false } + tooltip: { mode: 'index', intersect: false }, + title: { display: true, text: 'Attendance' } }, scales: { y: { diff --git a/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml b/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml index b3fbcc562..3fcad56b0 100644 --- a/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml +++ b/addons_extensions/hr_emp_dashboard/static/src/xml/employee_profile_template.xml @@ -130,11 +130,55 @@ -
-
- -
-
+
+ + +
+

📊 Attendance Summary

+ +
+ + +
+

🗓️ Leave Balance

+
+ +
+ +
+ + +
+
    +
  • + Sick Leave (SL): days +
  • +
  • + Casual Leave (CL): days +
  • +
  • + Privilege Leave (PL): days +
  • +
+
+
+
+ +