Skip to content

Commit

Permalink
allow workinghours to be filtered by event type (#1264)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeriox authored Apr 17, 2024
1 parent 19a318d commit d0ae64b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 22 deletions.
10 changes: 4 additions & 6 deletions ephios/core/templates/core/workinghours_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ <h1 class="page-header">
{% translate "Working hours" %}
</h1>
<form class="row row-cols-sm-auto g-3">
<div class="col-12">
{% crispy_field filter_form.start label_class="col mb-0" field_class="col" wrapper_class="row align-items-center" %}
</div>
<div class="col-12">
{% crispy_field filter_form.end label_class="col mb-0" field_class="col" wrapper_class="row align-items-center" %}
</div>
{% crispy_field filter_form.start wrapper_class="col-12 col-lg" show_labels=False %}
<div class="col pt-1"> <p>{% translate "to" %}</p> </div>
{% crispy_field filter_form.end wrapper_class="col-12 col-lg" show_labels=False %}
{% crispy_field filter_form.type wrapper_class="col-12 col-lg" show_labels=False %}
<div class="col-12">
<button type="submit" class="btn btn-primary">{% translate "Filter" %}</button>
</div>
Expand Down
48 changes: 33 additions & 15 deletions ephios/core/views/workinghour.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
from django.utils.functional import cached_property
from django.utils.translation import gettext as _
from django.views.generic import DeleteView, DetailView, FormView, TemplateView, UpdateView
from django_select2.forms import Select2Widget
from guardian.shortcuts import get_objects_for_user

from ephios.core.forms.users import WorkingHourRequestForm
from ephios.core.models import LocalParticipation, UserProfile, WorkingHours
from ephios.core.models import EventType, LocalParticipation, UserProfile, WorkingHours
from ephios.extra.mixins import CustomPermissionRequiredMixin
from ephios.extra.widgets import CustomDateInput

Expand All @@ -42,23 +43,43 @@ def _get_target_user(self):
return get_object_or_404(UserProfile, pk=self.kwargs["pk"])


class DateFilterForm(forms.Form):
class WorkingHourFilterForm(forms.Form):
start = forms.DateField(required=False, label=_("From"), widget=CustomDateInput)
end = forms.DateField(required=False, label=_("To"), widget=CustomDateInput)
type = forms.ModelChoiceField(
label=_("Event type"),
queryset=EventType.objects.all(),
required=False,
widget=Select2Widget(
attrs={
"data-placeholder": _("Event type"),
"classes": "w-auto",
}
),
)


class WorkingHourOverview(CustomPermissionRequiredMixin, TemplateView):
template_name = "core/workinghours_list.html"
permission_required = "core.view_userprofile"

def _get_working_hours_stats(self, start: Optional[date], end: Optional[date]):
participations = (
LocalParticipation.objects.filter(
state=LocalParticipation.States.CONFIRMED,
start_time__date__gte=start,
end_time__date__lte=end,
def _get_working_hours_stats(self, start: date, end: date, eventtype: Optional[EventType]):
participations = LocalParticipation.objects.filter(
state=LocalParticipation.States.CONFIRMED,
start_time__date__gte=start,
end_time__date__lte=end,
)
workinghours = {}
if eventtype is not None:
participations = participations.filter(shift__event__type=eventtype)
else:
workinghours = (
WorkingHours.objects.filter(date__gte=start, date__lte=end)
.annotate(hour_sum=Sum("hours"))
.values_list("user__pk", "user__display_name", "hour_sum")
)
.annotate(
participations = (
participations.annotate(
duration=ExpressionWrapper(
(F("end_time") - F("start_time")),
output_field=DurationField(),
Expand All @@ -67,11 +88,7 @@ def _get_working_hours_stats(self, start: Optional[date], end: Optional[date]):
.annotate(hour_sum=Sum("duration"))
.values_list("user__pk", "user__display_name", "hour_sum")
)
workinghours = (
WorkingHours.objects.filter(date__gte=start, date__lte=end)
.annotate(hour_sum=Sum("hours"))
.values_list("user__pk", "user__display_name", "hour_sum")
)

result = {}
c = Counter()
for user_pk, display_name, hours in chain(participations, workinghours):
Expand All @@ -89,7 +106,7 @@ def _get_working_hours_stats(self, start: Optional[date], end: Optional[date]):
return sorted(result.values(), key=lambda x: x["hours"], reverse=True)

def get_context_data(self, **kwargs):
filter_form = DateFilterForm(
filter_form = WorkingHourFilterForm(
self.request.GET
or {
# intitial data for initial page laod
Expand All @@ -103,6 +120,7 @@ def get_context_data(self, **kwargs):
kwargs["users"] = self._get_working_hours_stats(
start=filter_form.cleaned_data.get("start") or date.min, # start/end are not required
end=filter_form.cleaned_data.get("end") or date.max,
eventtype=filter_form.cleaned_data.get("type"),
)
kwargs["can_grant_for"] = set(
get_objects_for_user(self.request.user, "decide_workinghours_for_group", klass=Group)
Expand Down
26 changes: 25 additions & 1 deletion tests/core/test_workinghours.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.template.defaultfilters import floatformat
from django.urls import reverse

from ephios.core.models import WorkingHours
from ephios.core.models import LocalParticipation, WorkingHours


class TestWorkingHours:
Expand Down Expand Up @@ -93,3 +93,27 @@ def test_workinghours_add_nologin(self, django_app, volunteer):
reverse("core:workinghours_add", kwargs={"pk": volunteer.pk}), status=302
)
assert "/accounts/login" in response.url

def test_workinghours_filter(
self,
django_app,
volunteer,
manager,
event,
service_event_type,
training_event_type,
workinghours,
):
response = django_app.get(reverse("core:workinghours_list"), user=manager)
assert response.html.find(string=floatformat(volunteer.get_workhour_items()[0], arg=2))
participation = LocalParticipation.objects.create(
shift=event.shifts.first(), user=volunteer, state=LocalParticipation.States.CONFIRMED
)
response = django_app.get(
f'{reverse("core:workinghours_list")}?type={training_event_type.pk}', user=manager
)
assert response.html.find(string="No entries")
response = django_app.get(
f'{reverse("core:workinghours_list")}?type={service_event_type.pk}', user=manager
)
assert response.html.find(string=floatformat(participation.hours_value, arg=2))

0 comments on commit d0ae64b

Please sign in to comment.