""" Views for HR app. """ from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from django.views.generic import ListView, CreateView, DetailView, UpdateView, TemplateView from django.utils.translation import gettext_lazy as _ from django.contrib import messages from django.utils import timezone from datetime import datetime, timedelta from core.mixins import TenantFilterMixin from .models import Attendance, Schedule, Holiday from .forms import AttendanceForm, ScheduleForm, HolidayForm # ============================================================================ # Attendance Views # ============================================================================ class AttendanceListView(LoginRequiredMixin, TenantFilterMixin, ListView): """List all attendance records.""" model = Attendance template_name = 'hr/attendance_list.html' context_object_name = 'attendances' paginate_by = 20 def get_queryset(self): queryset = super().get_queryset().filter( tenant=self.request.user.tenant ).select_related('employee') # Filter by employee if provided employee_id = self.request.GET.get('employee') if employee_id: queryset = queryset.filter(employee_id=employee_id) # Filter by status if provided status = self.request.GET.get('status') if status: queryset = queryset.filter(status=status) # Filter by date range if provided date_from = self.request.GET.get('date_from') date_to = self.request.GET.get('date_to') if date_from: queryset = queryset.filter(date__gte=date_from) if date_to: queryset = queryset.filter(date__lte=date_to) return queryset.order_by('-date', 'employee') class AttendanceCreateView(LoginRequiredMixin, TenantFilterMixin, CreateView): """Create a new attendance record.""" model = Attendance form_class = AttendanceForm template_name = 'hr/attendance_form.html' success_url = reverse_lazy('hr:attendance-list') def form_valid(self, form): form.instance.tenant = self.request.user.tenant messages.success(self.request, _('Attendance record created successfully.')) return super().form_valid(form) class AttendanceDetailView(LoginRequiredMixin, TenantFilterMixin, DetailView): """View attendance record details.""" model = Attendance template_name = 'hr/attendance_detail.html' context_object_name = 'attendance' def get_queryset(self): return super().get_queryset().filter( tenant=self.request.user.tenant ).select_related('employee') class AttendanceUpdateView(LoginRequiredMixin, TenantFilterMixin, UpdateView): """Update an attendance record.""" model = Attendance form_class = AttendanceForm template_name = 'hr/attendance_form.html' def get_queryset(self): return super().get_queryset().filter(tenant=self.request.user.tenant) def get_success_url(self): return reverse_lazy('hr:attendance-detail', kwargs={'pk': self.object.pk}) def form_valid(self, form): messages.success(self.request, _('Attendance record updated successfully.')) return super().form_valid(form) class AttendanceKioskView(LoginRequiredMixin, TemplateView): """Kiosk view for quick clock in/out.""" template_name = 'hr/attendance_kiosk.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) today = timezone.now().date() # Get today's attendance for current user try: attendance = Attendance.objects.get( employee=self.request.user, date=today, tenant=self.request.user.tenant ) context['attendance'] = attendance except Attendance.DoesNotExist: context['attendance'] = None return context def post(self, request, *args, **kwargs): """Handle clock in/out.""" today = timezone.now().date() # Get current time in Riyadh timezone now = timezone.localtime(timezone.now()).time() attendance, created = Attendance.objects.get_or_create( employee=request.user, date=today, tenant=request.user.tenant, defaults={'check_in': now, 'status': Attendance.Status.PRESENT} ) if not created and not attendance.check_out: # Clock out attendance.check_out = now attendance.save() messages.success(request, _('Clocked out successfully.')) elif created: messages.success(request, _('Clocked in successfully.')) else: messages.warning(request, _('You have already clocked out for today.')) return self.get(request, *args, **kwargs) # ============================================================================ # Schedule Views # ============================================================================ class ScheduleListView(LoginRequiredMixin, TenantFilterMixin, ListView): """List all schedules.""" model = Schedule template_name = 'hr/schedule_list.html' context_object_name = 'schedules' paginate_by = 50 def get_queryset(self): queryset = super().get_queryset().filter( tenant=self.request.user.tenant ).select_related('employee') # Filter by employee if provided employee_id = self.request.GET.get('employee') if employee_id: queryset = queryset.filter(employee_id=employee_id) # Filter by day if provided day = self.request.GET.get('day') if day: queryset = queryset.filter(day_of_week=day) # Filter by active status is_active = self.request.GET.get('is_active') if is_active: queryset = queryset.filter(is_active=is_active == 'true') return queryset.order_by('employee', 'day_of_week') class ScheduleCreateView(LoginRequiredMixin, TenantFilterMixin, CreateView): """Create a new schedule.""" model = Schedule form_class = ScheduleForm template_name = 'hr/schedule_form.html' success_url = reverse_lazy('hr:schedule-list') def form_valid(self, form): form.instance.tenant = self.request.user.tenant messages.success(self.request, _('Schedule created successfully.')) return super().form_valid(form) class ScheduleDetailView(LoginRequiredMixin, TenantFilterMixin, DetailView): """View schedule details.""" model = Schedule template_name = 'hr/schedule_detail.html' context_object_name = 'schedule' def get_queryset(self): return super().get_queryset().filter( tenant=self.request.user.tenant ).select_related('employee') class ScheduleUpdateView(LoginRequiredMixin, TenantFilterMixin, UpdateView): """Update a schedule.""" model = Schedule form_class = ScheduleForm template_name = 'hr/schedule_form.html' def get_queryset(self): return super().get_queryset().filter(tenant=self.request.user.tenant) def get_success_url(self): return reverse_lazy('hr:schedule-detail', kwargs={'pk': self.object.pk}) def form_valid(self, form): messages.success(self.request, _('Schedule updated successfully.')) return super().form_valid(form) class ScheduleGridView(LoginRequiredMixin, TenantFilterMixin, TemplateView): """Grid view of all schedules.""" template_name = 'hr/schedule_grid.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Get all active schedules schedules = Schedule.objects.filter( tenant=self.request.user.tenant, is_active=True ).select_related('employee').order_by('employee', 'day_of_week') # Organize by employee and day schedule_grid = {} for schedule in schedules: employee_name = schedule.employee.get_full_name() if employee_name not in schedule_grid: schedule_grid[employee_name] = {} schedule_grid[employee_name][schedule.day_of_week] = schedule context['schedule_grid'] = schedule_grid context['days'] = Schedule.DayOfWeek.choices return context # ============================================================================ # Holiday Views # ============================================================================ class HolidayListView(LoginRequiredMixin, TenantFilterMixin, ListView): """List all holidays.""" model = Holiday template_name = 'hr/holiday_list.html' context_object_name = 'holidays' paginate_by = 20 def get_queryset(self): queryset = super().get_queryset().filter( tenant=self.request.user.tenant ) # Filter by recurring status is_recurring = self.request.GET.get('is_recurring') if is_recurring: queryset = queryset.filter(is_recurring=is_recurring == 'true') # Filter by year year = self.request.GET.get('year') if year: queryset = queryset.filter(date__year=year) return queryset.order_by('date') class HolidayCreateView(LoginRequiredMixin, TenantFilterMixin, CreateView): """Create a new holiday.""" model = Holiday form_class = HolidayForm template_name = 'hr/holiday_form.html' success_url = reverse_lazy('hr:holiday-list') def form_valid(self, form): form.instance.tenant = self.request.user.tenant messages.success(self.request, _('Holiday created successfully.')) return super().form_valid(form) class HolidayDetailView(LoginRequiredMixin, TenantFilterMixin, DetailView): """View holiday details.""" model = Holiday template_name = 'hr/holiday_detail.html' context_object_name = 'holiday' def get_queryset(self): return super().get_queryset().filter(tenant=self.request.user.tenant) class HolidayUpdateView(LoginRequiredMixin, TenantFilterMixin, UpdateView): """Update a holiday.""" model = Holiday form_class = HolidayForm template_name = 'hr/holiday_form.html' def get_queryset(self): return super().get_queryset().filter(tenant=self.request.user.tenant) def get_success_url(self): return reverse_lazy('hr:holiday-detail', kwargs={'pk': self.object.pk}) def form_valid(self, form): messages.success(self.request, _('Holiday updated successfully.')) return super().form_valid(form)