144 lines
5.6 KiB
Python
144 lines
5.6 KiB
Python
from django.shortcuts import render, reverse
|
|
from django.db.models import Avg, Count, Min, Sum
|
|
from django.urls import reverse_lazy
|
|
from django.views.generic.base import TemplateView
|
|
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
|
|
from django.views.generic.detail import DetailView
|
|
from django.views.generic.list import ListView
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
|
from django.utils import timezone
|
|
from django.contrib import messages
|
|
from django.contrib.auth.models import User
|
|
from accounts.models import Instructor, Student
|
|
from .models import Code, Period
|
|
from .forms import AttendanceUpdateForm, PeriodForm
|
|
|
|
# EXAMPLE PERMISSION MIXIN
|
|
# class MyView(PermissionRequiredMixin, View):
|
|
# permission_required = 'polls.add_choice'
|
|
# # Or multiple of permissions:
|
|
# permission_required = ('polls.view_choice', 'polls.change_choice')
|
|
|
|
# OVERVIEW
|
|
class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
|
template_name = 'attendance/attendance_overview.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['user'] = User.objects.get(pk=self.request.user.id)
|
|
if hasattr(self.request.user, 'instructor'):
|
|
context['student_list'] = Student.objects.filter(department=self.request.user.instructor.department)
|
|
context['period_list'] = Period.objects.order_by('-clocked_in')
|
|
elif hasattr(self.request.user, 'student'):
|
|
# sum all duration fields for student
|
|
periods_duration_sum = Period.objects.filter(
|
|
student = self.request.user.student
|
|
).filter(
|
|
clocked_in__year=timezone.now().year
|
|
).filter(
|
|
clocked_in__month=timezone.now().month
|
|
).aggregate(total_duration=Sum('duration'))
|
|
|
|
hours = 0
|
|
# Convert to hours floating point
|
|
if periods_duration_sum['total_duration'] != None:
|
|
hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
|
|
|
|
context['period_list'] = Period.objects.filter(
|
|
student=self.request.user.student
|
|
).filter(
|
|
clocked_in__year=timezone.now().year
|
|
).filter(
|
|
clocked_in__month=timezone.now().month
|
|
).order_by('-clocked_in')
|
|
context['period_total'] = hours
|
|
context['current_period'] = Period.objects.get(pk=self.request.user.student.current_period_id)
|
|
return context
|
|
|
|
class AttendanceUpdateView(LoginRequiredMixin, FormView):
|
|
template_name = 'attendance/attendance_form.html'
|
|
form_class = AttendanceUpdateForm
|
|
|
|
def form_valid(self, form):
|
|
# update checked in
|
|
student_number = form.cleaned_data['qr_string'].split(':')[0]
|
|
station_number = form.cleaned_data['qr_string'].split(':')[1]
|
|
student = Student.objects.get(student_number=student_number)
|
|
if student.is_clocked_in:
|
|
student.is_clocked_in=False
|
|
period = student.period_set.get(pk=student.current_period_id)
|
|
period.clocked_out=timezone.now()
|
|
student.save()
|
|
period.save()
|
|
messages.add_message(self.request, messages.INFO, f'{student.user.first_name} {student.user.last_name} clocked out.')
|
|
else:
|
|
c_p = student.period_set.create(student=student, clocked_in=timezone.now(), station_number=station_number)
|
|
student.current_period_id = c_p.id
|
|
student.is_clocked_in=True
|
|
student.save()
|
|
messages.add_message(self.request, messages.INFO, f'{student.user.first_name} {student.user.last_name} clocked in.')
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse('attendance-update')
|
|
|
|
|
|
|
|
|
|
# PERIODS
|
|
class PeriodCreateView(LoginRequiredMixin, CreateView):
|
|
model = Period
|
|
form_class = PeriodForm
|
|
template_name = 'attendance/period_form.html'
|
|
|
|
class PeriodDetailView(LoginRequiredMixin, DetailView):
|
|
model = Period
|
|
template_name = 'attendance/period_detail.html'
|
|
|
|
class PeriodUpdateView(LoginRequiredMixin, UpdateView):
|
|
model = Period
|
|
form_class = PeriodForm
|
|
template_name = 'attendance/period_form.html'
|
|
|
|
# When editing a period, check if it matches the current period of the student and clock them out
|
|
def form_valid(self, form):
|
|
student = form.instance.student
|
|
if form.instance.id == student.current_period_id:
|
|
student.is_clocked_in = False
|
|
student.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
pk = self.kwargs["pk"]
|
|
return reverse('period-detail', kwargs={'pk': pk})
|
|
|
|
class PeriodDeleteView(LoginRequiredMixin, DeleteView):
|
|
model = Period
|
|
success_url = '/attendance'
|
|
|
|
|
|
|
|
# CODES
|
|
class CodeCreateView(LoginRequiredMixin, CreateView):
|
|
model = Code
|
|
fields = ['station_number']
|
|
template_name = 'attendance/code_form.html'
|
|
|
|
def form_valid(self, form):
|
|
form.instance.student = self.request.user.student
|
|
return super().form_valid(form)
|
|
|
|
class CodeDetailView(LoginRequiredMixin, DetailView):
|
|
model = Code
|
|
template_name = 'attendance/code_detail.html'
|
|
|
|
class CodeUpdateView(LoginRequiredMixin, UpdateView):
|
|
model = Code
|
|
fields = ['station_number']
|
|
template_name = 'attendance/code_update_form.html'
|
|
|
|
def get_success_url(self):
|
|
pk = self.kwargs["pk"]
|
|
return reverse('code-detail', kwargs={'pk': pk})
|