Add signal for period created to auto-clockin Student
This commit is contained in:
parent
b9630092d5
commit
76339dc65a
@ -2,6 +2,7 @@ from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class Department(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
{% elif user.instructor %}
|
||||
<p>{{ user.instructor.department }}</p>
|
||||
{% endif %}
|
||||
{% if periods %}
|
||||
{% if periods and periods.total %}
|
||||
<p>Total clocked hours: <strong>{{ periods.total|timedelta_format }}</strong></p>
|
||||
{% endif %}
|
||||
<p>
|
||||
|
||||
@ -2,6 +2,8 @@ from datetime import datetime
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from accounts.models import Student
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
class Code(models.Model):
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
@ -46,3 +48,10 @@ class Period(models.Model):
|
||||
if self.clocked_out != None:
|
||||
self.duration = self.clocked_out - self.clocked_in
|
||||
super(Period, self).save(*args, **kwargs)
|
||||
|
||||
@receiver(post_save, sender=Period)
|
||||
def auto_clockin_student(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
instance.student.is_clocked_in = True
|
||||
instance.student.current_period_id = instance.pk
|
||||
instance.student.save()
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<input type="submit" value="clock-in/out">
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -93,7 +93,9 @@
|
||||
{% for student in student_list %}
|
||||
<tr>
|
||||
<td>{{ student.user.first_name }} {{ student.user.last_name }}</td>
|
||||
{% if student.total_hours %}
|
||||
<td><strong>{{ student.total_hours|timedelta_format }}</strong></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="2">No periods yet.</td></tr>
|
||||
|
||||
@ -20,7 +20,11 @@
|
||||
</section>
|
||||
<section class="student__attendance attendance">
|
||||
<h2 class="attendance__title">Attendance log</h2>
|
||||
<p class="attendance__total">Total hours for the month: <strong>{{ period_total.total|timedelta_format:2 }}</strong> <small>(Does not include current session.)</small></p>
|
||||
{% if monthly_total.duration %}
|
||||
<p class="attendance__total">Total hours for the month: <strong>{{ monthly_total.duration|timedelta_format }}</strong>
|
||||
<small>(Does not include current session.)</small>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% include 'attendance/_student_periods.html' %}
|
||||
<p>
|
||||
<a class="action-button" href="{% url 'period-list' %}">See previous →</a>
|
||||
|
||||
@ -2,9 +2,13 @@
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<h1>Delete Session</h1>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<p>Are you sure you want to delete "{{ object }}"?</p>
|
||||
<input type="submit" value="Confirm">
|
||||
<input type="submit" value="Confirm"> or
|
||||
<a href="{% url 'period-detail' object.pk %}">Cancel</a>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,26 +1,32 @@
|
||||
{% extends 'application.html' %}
|
||||
{% load timedelta_filter %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Period</h1>
|
||||
|
||||
<section>
|
||||
<header>
|
||||
<section class="period panel">
|
||||
<h1>Session</h1>
|
||||
<header class="period__header">
|
||||
<a href="{% url 'attendance-overview' %}">← Back</a>
|
||||
<div>
|
||||
<a href="{% url 'period-update' period.id %}">Edit</a>
|
||||
<a href="{% url 'period-delete' period.id %}">Delete</a>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
<dl>
|
||||
<dl class="period__data">
|
||||
<dt>Student</dt>
|
||||
<dd>{{ period.student }}</dd>
|
||||
<dt>Clocked in</dt>
|
||||
<dd>{{ period.clocked_in }}</dd>
|
||||
{% if period.clocked_out %}
|
||||
<dt>Clocked out</dt>
|
||||
<dd>{{ period.clocked_out }}</dd>
|
||||
{% else %}
|
||||
<dt>Not clocked out.</dt>
|
||||
{% endif %}
|
||||
{% if period.duration %}
|
||||
<dt>Duration</dt>
|
||||
<dd>{{ period.duration }}</dd>
|
||||
<dd>{{ period.duration|timedelta_format }} hours</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{% block content %}
|
||||
|
||||
<section class="period panel">
|
||||
<h1>Generate Period</h1>
|
||||
<h1>Session</h1>
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
@ -16,19 +16,11 @@ 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_queryset(self):
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['user'] = self.request.user
|
||||
@ -50,13 +42,13 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
||||
student = self.request.user.student
|
||||
|
||||
# sum all duration fields for student
|
||||
context['period_total'] = Period.objects.filter(
|
||||
context['monthly_total'] = Period.objects.filter(
|
||||
student = student
|
||||
).filter(
|
||||
clocked_in__year=timezone.now().year
|
||||
).filter(
|
||||
clocked_in__month=timezone.now().month
|
||||
).aggregate(total=Sum('duration'))
|
||||
).aggregate(duration=Sum('duration'))
|
||||
|
||||
context['period_list'] = Period.objects.filter(
|
||||
student=student
|
||||
@ -74,7 +66,6 @@ class AttendanceUpdateView(LoginRequiredMixin, FormView):
|
||||
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)
|
||||
@ -86,8 +77,8 @@ class AttendanceUpdateView(LoginRequiredMixin, FormView):
|
||||
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
|
||||
period = student.period_set.create(student=student, clocked_in=timezone.now(), station_number=station_number)
|
||||
student.current_period_id = period.pk
|
||||
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.')
|
||||
|
||||
@ -5,18 +5,18 @@
|
||||
<article class="home">
|
||||
<header class="panel">
|
||||
<h1>Welcome to<br>
|
||||
Btech Time Tracker</h1>
|
||||
BTech Time Tracker</h1>
|
||||
<h2>Know exactly how many hours you've clocked, anytime, anywhere.</h2>
|
||||
</header>
|
||||
<section>
|
||||
<section class="home__section">
|
||||
<h3>No more paper</h3>
|
||||
<p>No more reading bad handwriting or putting the wrong date or time.</p>
|
||||
</section>
|
||||
<section>
|
||||
<section class="home__section">
|
||||
<h3>No more questions</h3>
|
||||
<p>No more asking your instructor, or being asked by your student how many hours they have.</p>
|
||||
</section>
|
||||
<section>
|
||||
<section class="home__section">
|
||||
<h3>No more manual entry</h3>
|
||||
<p>We invented computers to do that for us.</p>
|
||||
</section>
|
||||
|
||||
@ -2,4 +2,8 @@
|
||||
h1, h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__section {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
.period {
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,11 @@ class TimezoneMiddleware:
|
||||
|
||||
def __call__(self, request):
|
||||
tzname = request.session.get('django_timezone')
|
||||
if request.user.is_authenticated:
|
||||
if hasattr(request.user, 'instructor'):
|
||||
tzname = request.user.instructor.timezone
|
||||
if hasattr(request.user, 'student'):
|
||||
tzname = request.user.student.timezone
|
||||
if tzname:
|
||||
timezone.activate(pytz.timezone(tzname))
|
||||
else:
|
||||
|
||||
@ -149,4 +149,4 @@ MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = BASE_DIR / 'media'
|
||||
|
||||
|
||||
LOGIN_REDIRECT_URL = '/accounts/timezone/'
|
||||
LOGIN_REDIRECT_URL = '/attendance/'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user