diff --git a/finances/forms.py b/finances/forms.py index 2384042cfb311f6005a440dad13bb5c267ee9df3..75a320fd0872e776e89c03f3005288f7695583cf 100644 --- a/finances/forms.py +++ b/finances/forms.py @@ -10,6 +10,8 @@ from django.utils import timezone from ajax_select.fields import AutoCompleteSelectField +from scipost.fields import UserModelChoiceField + from .models import Subsidy, WorkLog today = timezone.now().date() @@ -45,8 +47,15 @@ class WorkLogForm(forms.ModelForm): } -class LogsMonthlyActiveFilter(forms.Form): - month = forms.ChoiceField(choices=[(k, v) for k, v in MONTHS.items()]) +class LogsActiveFilter(forms.Form): + """ + Filter work logs given the requested date range and users. + """ + + employee = UserModelChoiceField( + queryset=get_user_model().objects.filter(work_logs__isnull=False), required=False) + month = forms.ChoiceField( + choices=[(None, 9 * '-')] + [(k, v) for k, v in MONTHS.items()], required=False) year = forms.ChoiceField(choices=[(y, y) for y in reversed(range(today.year-6, today.year+1))]) def __init__(self, *args, **kwargs): @@ -63,22 +72,29 @@ class LogsMonthlyActiveFilter(forms.Form): } super().__init__(*args, **kwargs) - def get_totals(self): - # Make accessible without need to explicitly check validity of form. - self.is_valid() - - users = get_user_model().objects.filter( - work_logs__work_date__month=self.cleaned_data['month'], - work_logs__work_date__year=self.cleaned_data['year']).distinct() + def filter(self): + """Filter work logs and return in output-convenient format.""" output = [] - for user in users: - logs = user.work_logs.filter( - work_date__month=self.cleaned_data['month'], - work_date__year=self.cleaned_data['year']) - output.append({ - 'logs': logs, - 'duration': logs.aggregate(total=Sum('duration')), - 'user': user - }) - + if self.is_valid(): + user_qs = get_user_model().objects.filter( + work_logs__isnull=False, work_logs__work_date__year=self.cleaned_data['year']) + if self.cleaned_data['employee']: + # Get as a queryset instead of single instead. + user_qs = user_qs.filter(id=self.cleaned_data['employee'].id) + user_qs = user_qs.distinct() + + output = [] + for user in user_qs: + logs = user.work_logs.filter(work_date__year=self.cleaned_data['year']) + if self.cleaned_data['month']: + logs = logs.filter(work_date__month=self.cleaned_data['month']) + logs = logs.distinct() + + if logs: + # If logs exists for given filters + output.append({ + 'logs': logs, + 'duration': logs.aggregate(total=Sum('duration')), + 'user': user, + }) return output diff --git a/finances/templates/finances/timesheets.html b/finances/templates/finances/timesheets.html index f32ae41dfa46ac45e19d96ffca47e1e1e01e030f..1c616cd18cdba9ca089c299c18ca08455a747955 100644 --- a/finances/templates/finances/timesheets.html +++ b/finances/templates/finances/timesheets.html @@ -25,8 +25,8 @@ <div class="row"> <div class="col-12"> <h2 class="mb-2 mt-4">Team Timesheets</h2> - {% for total in totals %} - <h3 class="mb-1">{{ total.user.first_name }} {{ total.user.last_name }}</h3> + {% for user_log in user_logs %} + <h4 class="mb-1">{{ user_log.user.first_name }} {{ user_log.user.last_name }}</h4> <table class="table"> <thead class="thead-default"> <tr> @@ -38,7 +38,7 @@ </tr> </thead> <tbody> - {% for log in total.logs %} + {% for log in user_log.logs %} <tr> <td>{{ log.work_date }}</td> <td>{{ log.content }}</td> @@ -48,13 +48,13 @@ </tr> {% endfor %} <tr> - <td colspan="4"></td> - <td><strong>{{ total.duration.total }}</strong></td> + <td colspan="4" class="text-right">Total:</td> + <td><strong>{{ user_log.duration.total|duration }}</strong></td> </tr> </tbody> </table> {% empty %} - <h3>Timesheet is empty for this month.</h3> + <p>No logs found.</p> {% endfor %} </div> </div> diff --git a/finances/views.py b/finances/views.py index 8ad451bc6aeb0e1a1cf301067cace3571b5f6535..25945357a5dc41e4a00871d0f6aa4ac4ae9ab6ae 100644 --- a/finances/views.py +++ b/finances/views.py @@ -12,7 +12,7 @@ from django.views.generic.detail import DetailView from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.views.generic.list import ListView -from .forms import SubsidyForm, LogsMonthlyActiveFilter +from .forms import SubsidyForm, LogsActiveFilter from .models import Subsidy, WorkLog from .utils import slug_to_id @@ -87,13 +87,13 @@ def timesheets(request): """ See an overview per month of all timesheets. """ - form = LogsMonthlyActiveFilter(request.GET or None) + form = LogsActiveFilter(request.GET or None) context = { 'form': form, } # if form.is_valid(): - context['totals'] = form.get_totals() + context['user_logs'] = form.filter() return render(request, 'finances/timesheets.html', context) diff --git a/production/forms.py b/production/forms.py index c84b25a10e413a23ab19cce20bf7797492e467ed..afb832597a34012dcbea5fce9f476a6fd81c7e71 100644 --- a/production/forms.py +++ b/production/forms.py @@ -7,6 +7,8 @@ import datetime from django import forms from django.contrib.auth import get_user_model +from scipost.fields import UserModelChoiceField + from . import constants from .models import ProductionUser, ProductionStream, ProductionEvent, Proofs,\ ProductionEventAttachment @@ -127,11 +129,6 @@ class StreamStatusForm(forms.ModelForm): return stream -class UserModelChoiceField(forms.ModelChoiceField): - def label_from_instance(self, obj): - return '{}, {} ({})'.format(obj.last_name, obj.first_name, obj.email) - - class UserToOfficerForm(forms.ModelForm): user = UserModelChoiceField(queryset=get_user_model().objects.filter( production_user__isnull=True).order_by('last_name')) diff --git a/scipost/fields.py b/scipost/fields.py index abdfa395a8a47347006ac3099365e1d87e5e781b..e002c69defb4d747009e9ec280a95e54fcca689d 100644 --- a/scipost/fields.py +++ b/scipost/fields.py @@ -87,3 +87,8 @@ class ReCaptchaField(forms.CharField): self.error_messages['captcha_invalid'] ) return values[0] + + +class UserModelChoiceField(forms.ModelChoiceField): + def label_from_instance(self, obj): + return '{}, {} ({})'.format(obj.last_name, obj.first_name, obj.email)