vkk.workhours.contributor.views

  1from django.views.generic import RedirectView, FormView, ListView, TemplateView
  2from django.utils import timezone
  3from django.db.models import Sum, Q
  4from django.http import Http404
  5from django.urls import reverse
  6from django.shortcuts import get_object_or_404, redirect
  7from django.forms import Form, modelform_factory
  8from vkk.generic.views import CustomSuccessView
  9from vkk.generic.mixins import OnSuccessMixin
 10from vkk.workhours.models import Period, WorkHours, PeriodClosure, ProjectAssignment, WorkHoursCorrection
 11from vkk.workhours.forms import PeriodSelectForm
 12from .forms import WorkhourCalendarForm
 13from .mixins import ContributorRequiredMixin, ContributorPeriodSelectorMixin
 14
 15
 16class PeriodRedirect(ContributorRequiredMixin, RedirectView):
 17    """ Redirects a contributor to a period."""
 18
 19    def get_redirect_url(self, *args, **kwargs):
 20        # Catches Period Selection from GET
 21        if 'period' in self.request.GET:
 22            now = timezone.now()
 23            query_set = Period.objects.filter(
 24                Q(dead_line__gte=now) |
 25                Q(workhours__project_assignment__pk=self.kwargs['assignment_pk']) |
 26                Q(periodclosure__project_assignment__pk=self.kwargs['assignment_pk'])
 27            ).distinct()
 28            form = PeriodSelectForm(query_set, data=self.request.GET)
 29            if form.is_valid():
 30                period = form.cleaned_data.get("period")
 31            else:
 32                raise Http404()
 33        # Catches Period no given
 34        elif 'period_pk' not in kwargs:
 35            period = Period.objects.latest(create=True)
 36        # Looks up Period
 37        else:
 38            period = get_object_or_404(Period, pk=kwargs['period_pk'])
 39
 40        return reverse(
 41            'vkk:workhours:contributor:calendar',
 42            args=[kwargs['assignment_pk'], period.pk]
 43        )
 44
 45
 46class WorkhoursView(ContributorRequiredMixin, ContributorPeriodSelectorMixin, FormView):
 47    """Displays a calendar for entering work hours."""
 48    form_class = WorkhourCalendarForm
 49    template_name = 'vkk/workhours/contributor/workhours.html'
 50
 51    def get_context_data(self, **kwargs):
 52        context = super().get_context_data(**kwargs)
 53        context["project"] = ProjectAssignment.objects.select_related('project').get(
 54            pk=self.kwargs['assignment_pk']
 55        ).project
 56        return context
 57
 58    def dispatch(self, request, *args, **kwargs):
 59        period = Period.objects.filter(
 60            pk=self.kwargs['period_pk'],
 61            dead_line__lt=timezone.now()
 62        )
 63        if period.exists():
 64            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
 65
 66        closure = PeriodClosure.objects.filter(
 67            project_assignment__pk=self.kwargs['assignment_pk'],
 68            period__pk=self.kwargs['period_pk']
 69        )
 70        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
 71            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
 72        return super().dispatch(request, *args, **kwargs)
 73
 74    def get_form_kwargs(self):
 75        kwargs = super().get_form_kwargs()
 76        kwargs.update({
 77            'period_pk': self.kwargs['period_pk'],
 78            'assignment_pk': self.kwargs['assignment_pk'],
 79        })
 80        return kwargs
 81
 82    def get_success_url(self):
 83        return reverse(
 84            'vkk:workhours:contributor:summary',
 85            args=[
 86                self.kwargs['assignment_pk'],
 87                self.kwargs['period_pk']
 88            ]
 89        )
 90
 91    def form_valid(self, form):
 92        form.save()
 93        return super().form_valid(form)
 94
 95
 96class SummaryView(ContributorRequiredMixin, ContributorPeriodSelectorMixin, ListView):
 97    model = WorkHours
 98    template_name = 'vkk/workhours/contributor/summary.html'
 99
100    def get_queryset(self):
101        query_set = super().get_queryset()
102        query_set = query_set.filter(
103            project_assignment__pk=self.kwargs['assignment_pk'],
104            period__pk=self.kwargs['period_pk']
105        )
106        return query_set.order_by('day')
107
108    def get_context_data(self, **kwargs):
109        context = super().get_context_data(**kwargs)
110        query_set = context["object_list"]
111
112        correction = WorkHoursCorrection.objects.filter(
113            project_assignment__pk=self.kwargs['assignment_pk'],
114            period__pk=self.kwargs['period_pk']
115        )
116        context["correction"] = correction
117
118        context.update(query_set.aggregate(Sum('hours')))
119        if context["hours__sum"] is None:
120            context["hours__sum"] = 0
121        if correction.exists():
122            context["hours__sum"] += correction[0].ammount
123
124        context["fields"] = ['day', 'hours']
125
126        closure = PeriodClosure.objects.filter(
127            project_assignment__pk=self.kwargs['assignment_pk'],
128            period__pk=self.kwargs['period_pk']
129        )
130        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
131            context['closure'] = True
132        else:
133            context['closure'] = False
134
135        context['project'] = ProjectAssignment.objects.select_related('project').get(
136            pk=self.kwargs['assignment_pk']
137        ).project
138
139        return context
140
141
142class ClosureView(ContributorRequiredMixin, OnSuccessMixin, FormView):
143    template_name = 'vkk/workhours/contributor/closure.html'
144    form_class = Form
145    on_success = 'closure_success'
146
147    def post(self, request, *args, **kwargs):
148        form = self.get_form()
149        model_form = modelform_factory(
150            model=PeriodClosure,
151            fields='__all__',
152        )(
153            data={
154                'period': self.kwargs['period_pk'],
155                'project_assignment': self.kwargs['assignment_pk'],
156                'is_closed_contributor': True,
157            },
158        )
159        if form.is_valid and model_form.is_valid:
160            model_form.save()
161            return self.form_valid(form)
162        else:
163            return self.handle_no_permission()
164
165
166class ClosureSuccessView(ContributorRequiredMixin, CustomSuccessView):
167    template_name = 'vkk/workhours/contributor/closure_success.html'
168    model = PeriodClosure
169    on_success = 'summary'
class PeriodRedirect(vkk.workhours.contributor.mixins.ContributorRequiredMixin, django.views.generic.base.RedirectView):
17class PeriodRedirect(ContributorRequiredMixin, RedirectView):
18    """ Redirects a contributor to a period."""
19
20    def get_redirect_url(self, *args, **kwargs):
21        # Catches Period Selection from GET
22        if 'period' in self.request.GET:
23            now = timezone.now()
24            query_set = Period.objects.filter(
25                Q(dead_line__gte=now) |
26                Q(workhours__project_assignment__pk=self.kwargs['assignment_pk']) |
27                Q(periodclosure__project_assignment__pk=self.kwargs['assignment_pk'])
28            ).distinct()
29            form = PeriodSelectForm(query_set, data=self.request.GET)
30            if form.is_valid():
31                period = form.cleaned_data.get("period")
32            else:
33                raise Http404()
34        # Catches Period no given
35        elif 'period_pk' not in kwargs:
36            period = Period.objects.latest(create=True)
37        # Looks up Period
38        else:
39            period = get_object_or_404(Period, pk=kwargs['period_pk'])
40
41        return reverse(
42            'vkk:workhours:contributor:calendar',
43            args=[kwargs['assignment_pk'], period.pk]
44        )

Redirects a contributor to a period.

def get_redirect_url(self, *args, **kwargs):
20    def get_redirect_url(self, *args, **kwargs):
21        # Catches Period Selection from GET
22        if 'period' in self.request.GET:
23            now = timezone.now()
24            query_set = Period.objects.filter(
25                Q(dead_line__gte=now) |
26                Q(workhours__project_assignment__pk=self.kwargs['assignment_pk']) |
27                Q(periodclosure__project_assignment__pk=self.kwargs['assignment_pk'])
28            ).distinct()
29            form = PeriodSelectForm(query_set, data=self.request.GET)
30            if form.is_valid():
31                period = form.cleaned_data.get("period")
32            else:
33                raise Http404()
34        # Catches Period no given
35        elif 'period_pk' not in kwargs:
36            period = Period.objects.latest(create=True)
37        # Looks up Period
38        else:
39            period = get_object_or_404(Period, pk=kwargs['period_pk'])
40
41        return reverse(
42            'vkk:workhours:contributor:calendar',
43            args=[kwargs['assignment_pk'], period.pk]
44        )

Return the URL redirect to. Keyword arguments from the URL pattern match generating the redirect request are provided as kwargs to this method.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
vkk.workhours.contributor.mixins.ContributorRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
django.views.generic.base.RedirectView
get
head
post
options
delete
put
patch
47class WorkhoursView(ContributorRequiredMixin, ContributorPeriodSelectorMixin, FormView):
48    """Displays a calendar for entering work hours."""
49    form_class = WorkhourCalendarForm
50    template_name = 'vkk/workhours/contributor/workhours.html'
51
52    def get_context_data(self, **kwargs):
53        context = super().get_context_data(**kwargs)
54        context["project"] = ProjectAssignment.objects.select_related('project').get(
55            pk=self.kwargs['assignment_pk']
56        ).project
57        return context
58
59    def dispatch(self, request, *args, **kwargs):
60        period = Period.objects.filter(
61            pk=self.kwargs['period_pk'],
62            dead_line__lt=timezone.now()
63        )
64        if period.exists():
65            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
66
67        closure = PeriodClosure.objects.filter(
68            project_assignment__pk=self.kwargs['assignment_pk'],
69            period__pk=self.kwargs['period_pk']
70        )
71        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
72            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
73        return super().dispatch(request, *args, **kwargs)
74
75    def get_form_kwargs(self):
76        kwargs = super().get_form_kwargs()
77        kwargs.update({
78            'period_pk': self.kwargs['period_pk'],
79            'assignment_pk': self.kwargs['assignment_pk'],
80        })
81        return kwargs
82
83    def get_success_url(self):
84        return reverse(
85            'vkk:workhours:contributor:summary',
86            args=[
87                self.kwargs['assignment_pk'],
88                self.kwargs['period_pk']
89            ]
90        )
91
92    def form_valid(self, form):
93        form.save()
94        return super().form_valid(form)

Displays a calendar for entering work hours.

def get_context_data(self, **kwargs):
52    def get_context_data(self, **kwargs):
53        context = super().get_context_data(**kwargs)
54        context["project"] = ProjectAssignment.objects.select_related('project').get(
55            pk=self.kwargs['assignment_pk']
56        ).project
57        return context

Insert the form into the context dict.

def dispatch(self, request, *args, **kwargs):
59    def dispatch(self, request, *args, **kwargs):
60        period = Period.objects.filter(
61            pk=self.kwargs['period_pk'],
62            dead_line__lt=timezone.now()
63        )
64        if period.exists():
65            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
66
67        closure = PeriodClosure.objects.filter(
68            project_assignment__pk=self.kwargs['assignment_pk'],
69            period__pk=self.kwargs['period_pk']
70        )
71        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
72            return redirect('vkk:workhours:contributor:summary', **self.kwargs)
73        return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
75    def get_form_kwargs(self):
76        kwargs = super().get_form_kwargs()
77        kwargs.update({
78            'period_pk': self.kwargs['period_pk'],
79            'assignment_pk': self.kwargs['assignment_pk'],
80        })
81        return kwargs

Return the keyword arguments for instantiating the form.

def get_success_url(self):
83    def get_success_url(self):
84        return reverse(
85            'vkk:workhours:contributor:summary',
86            args=[
87                self.kwargs['assignment_pk'],
88                self.kwargs['period_pk']
89            ]
90        )

Return the URL to redirect to after processing a valid form.

def form_valid(self, form):
92    def form_valid(self, form):
93        form.save()
94        return super().form_valid(form)

If the form is valid, redirect to the supplied URL.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
django.views.generic.base.TemplateResponseMixin
render_to_response
get_template_names
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form_class
get_form
form_invalid
django.views.generic.edit.ProcessFormView
get
post
put
 97class SummaryView(ContributorRequiredMixin, ContributorPeriodSelectorMixin, ListView):
 98    model = WorkHours
 99    template_name = 'vkk/workhours/contributor/summary.html'
100
101    def get_queryset(self):
102        query_set = super().get_queryset()
103        query_set = query_set.filter(
104            project_assignment__pk=self.kwargs['assignment_pk'],
105            period__pk=self.kwargs['period_pk']
106        )
107        return query_set.order_by('day')
108
109    def get_context_data(self, **kwargs):
110        context = super().get_context_data(**kwargs)
111        query_set = context["object_list"]
112
113        correction = WorkHoursCorrection.objects.filter(
114            project_assignment__pk=self.kwargs['assignment_pk'],
115            period__pk=self.kwargs['period_pk']
116        )
117        context["correction"] = correction
118
119        context.update(query_set.aggregate(Sum('hours')))
120        if context["hours__sum"] is None:
121            context["hours__sum"] = 0
122        if correction.exists():
123            context["hours__sum"] += correction[0].ammount
124
125        context["fields"] = ['day', 'hours']
126
127        closure = PeriodClosure.objects.filter(
128            project_assignment__pk=self.kwargs['assignment_pk'],
129            period__pk=self.kwargs['period_pk']
130        )
131        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
132            context['closure'] = True
133        else:
134            context['closure'] = False
135
136        context['project'] = ProjectAssignment.objects.select_related('project').get(
137            pk=self.kwargs['assignment_pk']
138        ).project
139
140        return context

Verify that the current user is a contributor to the given project.

def get_queryset(self):
101    def get_queryset(self):
102        query_set = super().get_queryset()
103        query_set = query_set.filter(
104            project_assignment__pk=self.kwargs['assignment_pk'],
105            period__pk=self.kwargs['period_pk']
106        )
107        return query_set.order_by('day')

Return the list of items for this view.

The return value must be an iterable and may be an instance of QuerySet in which case QuerySet specific behavior will be enabled.

def get_context_data(self, **kwargs):
109    def get_context_data(self, **kwargs):
110        context = super().get_context_data(**kwargs)
111        query_set = context["object_list"]
112
113        correction = WorkHoursCorrection.objects.filter(
114            project_assignment__pk=self.kwargs['assignment_pk'],
115            period__pk=self.kwargs['period_pk']
116        )
117        context["correction"] = correction
118
119        context.update(query_set.aggregate(Sum('hours')))
120        if context["hours__sum"] is None:
121            context["hours__sum"] = 0
122        if correction.exists():
123            context["hours__sum"] += correction[0].ammount
124
125        context["fields"] = ['day', 'hours']
126
127        closure = PeriodClosure.objects.filter(
128            project_assignment__pk=self.kwargs['assignment_pk'],
129            period__pk=self.kwargs['period_pk']
130        )
131        if closure.exists() and (closure[0].is_closed_contributor or closure[0].is_closed_manager):
132            context['closure'] = True
133        else:
134            context['closure'] = False
135
136        context['project'] = ProjectAssignment.objects.select_related('project').get(
137            pk=self.kwargs['assignment_pk']
138        ).project
139
140        return context

Get the context for this view.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.contributor.mixins.ContributorRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
django.views.generic.list.MultipleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.list.BaseListView
get
django.views.generic.list.MultipleObjectMixin
get_ordering
paginate_queryset
get_paginate_by
get_paginator
get_paginate_orphans
get_allow_empty
get_context_object_name
class ClosureView(vkk.workhours.contributor.mixins.ContributorRequiredMixin, vkk.generic.mixins.OnSuccessMixin, django.views.generic.edit.FormView):
143class ClosureView(ContributorRequiredMixin, OnSuccessMixin, FormView):
144    template_name = 'vkk/workhours/contributor/closure.html'
145    form_class = Form
146    on_success = 'closure_success'
147
148    def post(self, request, *args, **kwargs):
149        form = self.get_form()
150        model_form = modelform_factory(
151            model=PeriodClosure,
152            fields='__all__',
153        )(
154            data={
155                'period': self.kwargs['period_pk'],
156                'project_assignment': self.kwargs['assignment_pk'],
157                'is_closed_contributor': True,
158            },
159        )
160        if form.is_valid and model_form.is_valid:
161            model_form.save()
162            return self.form_valid(form)
163        else:
164            return self.handle_no_permission()

Verify that the current user is a contributor to the given project.

def post(self, request, *args, **kwargs):
148    def post(self, request, *args, **kwargs):
149        form = self.get_form()
150        model_form = modelform_factory(
151            model=PeriodClosure,
152            fields='__all__',
153        )(
154            data={
155                'period': self.kwargs['period_pk'],
156                'project_assignment': self.kwargs['assignment_pk'],
157                'is_closed_contributor': True,
158            },
159        )
160        if form.is_valid and model_form.is_valid:
161            model_form.save()
162            return self.form_valid(form)
163        else:
164            return self.handle_no_permission()

Handle POST requests: instantiate a form instance with the passed POST variables and then check if it's valid.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.contributor.mixins.ContributorRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.generic.mixins.OnSuccessMixin
get_success_url
django.views.generic.base.TemplateResponseMixin
render_to_response
get_template_names
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form_class
get_form
get_form_kwargs
form_valid
form_invalid
get_context_data
django.views.generic.edit.ProcessFormView
get
put
167class ClosureSuccessView(ContributorRequiredMixin, CustomSuccessView):
168    template_name = 'vkk/workhours/contributor/closure_success.html'
169    model = PeriodClosure
170    on_success = 'summary'

Verify that the current user is a contributor to the given project.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.contributor.mixins.ContributorRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.generic.mixins.OnSuccessMixin
get_success_url
django.views.generic.base.TemplateView
get
django.views.generic.base.TemplateResponseMixin
render_to_response
get_template_names
django.views.generic.base.ContextMixin
get_context_data