from django.views.generic import ListView, CreateView, UpdateView, TemplateView, DetailView, DeleteView from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from .models import Employee, Department, Attendance, LeaveRequest, JobPosition, BiometricDevice from django.db.models import Count from django.shortcuts import get_object_or_404, redirect from django.contrib import messages import socket from django.utils import timezone class HRDashboardView(LoginRequiredMixin, TemplateView): template_name = 'hr/dashboard.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['total_employees'] = Employee.objects.count() context['active_employees'] = Employee.objects.filter(status='active').count() context['departments_count'] = Department.objects.count() context['pending_leaves'] = LeaveRequest.objects.filter(status='pending').count() return context class EmployeeListView(LoginRequiredMixin, ListView): model = Employee template_name = 'hr/employee_list.html' context_object_name = 'employees' class EmployeeCreateView(LoginRequiredMixin, CreateView): model = Employee fields = '__all__' template_name = 'hr/employee_form.html' success_url = reverse_lazy('hr:employee_list') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = _("Add New Employee") return context class EmployeeUpdateView(LoginRequiredMixin, UpdateView): model = Employee fields = '__all__' template_name = 'hr/employee_form.html' success_url = reverse_lazy('hr:employee_list') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = _("Edit Employee") return context class EmployeeDetailView(LoginRequiredMixin, DetailView): model = Employee template_name = 'hr/employee_detail.html' class DepartmentListView(LoginRequiredMixin, ListView): model = Department template_name = 'hr/department_list.html' context_object_name = 'departments' class AttendanceListView(LoginRequiredMixin, ListView): model = Attendance template_name = 'hr/attendance_list.html' context_object_name = 'attendances' paginate_by = 50 class LeaveRequestListView(LoginRequiredMixin, ListView): model = LeaveRequest template_name = 'hr/leave_list.html' context_object_name = 'leaves' class LeaveRequestCreateView(LoginRequiredMixin, CreateView): model = LeaveRequest fields = ['employee', 'leave_type', 'start_date', 'end_date', 'reason'] template_name = 'hr/leave_form.html' success_url = reverse_lazy('hr:leave_list') class BiometricDeviceListView(LoginRequiredMixin, ListView): model = BiometricDevice template_name = 'hr/biometric_device_list.html' context_object_name = 'devices' class BiometricDeviceCreateView(LoginRequiredMixin, CreateView): model = BiometricDevice fields = ['name', 'ip_address', 'port', 'device_type', 'status'] template_name = 'hr/biometric_device_form.html' success_url = reverse_lazy('hr:device_list') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = _("Add Biometric Device") return context class BiometricDeviceUpdateView(LoginRequiredMixin, UpdateView): model = BiometricDevice fields = ['name', 'ip_address', 'port', 'device_type', 'status'] template_name = 'hr/biometric_device_form.html' success_url = reverse_lazy('hr:device_list') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = _("Edit Biometric Device") return context class BiometricDeviceDeleteView(LoginRequiredMixin, DeleteView): model = BiometricDevice template_name = 'hr/biometric_device_confirm_delete.html' success_url = reverse_lazy('hr:device_list') def test_device_connection(request, pk): device = get_object_or_404(BiometricDevice, pk=pk) try: # Simple socket connect to see if port is open (timeout 3s) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(3) result = sock.connect_ex((device.ip_address, device.port)) sock.close() if result == 0: messages.success(request, _("Connection successful! Device is online.")) device.status = 'active' device.last_sync = timezone.now() device.save() else: # If failed, we still report it but since this is often run in dev/cloud # where the device isn't reachable, we warn. messages.warning(request, _("Connection failed: Port closed or host unreachable. (Error Code: %(code)s)") % {'code': result}) device.status = 'inactive' device.save() except Exception as e: messages.error(request, _("Connection Error: %(error)s") % {'error': str(e)}) return redirect('hr:device_list') def sync_device_logs(request, pk): device = get_object_or_404(BiometricDevice, pk=pk) result = device.sync_data() # This method we added to the model if result.get('error'): messages.error(request, _("Sync Failed: %(error)s") % {'error': result['error']}) else: messages.success(request, _("Sync Successful! Fetched %(total)s records, %(new)s new.") % {'total': result['total'], 'new': result['new']}) return redirect('hr:device_list')