vkk.workhours.accounting.projects.project.views

  1from django.utils.translation import gettext_lazy as _
  2from django.core.exceptions import ValidationError
  3from django.forms import modelform_factory, Form
  4from django.urls import reverse
  5from django.shortcuts import get_object_or_404
  6from django.views.generic import RedirectView, FormView, TemplateView
  7from vkk.generic.forms import CustomDateInput
  8from vkk.generic.mixins import OnSuccessMixin
  9from vkk.generic.views import CustomSuccessView
 10from vkk.users.models import User
 11from vkk.workhours.models import ProjectManager, ProjectAssignment, Project, Period, PeriodClosure, WorkHours, WorkHoursCorrection
 12from vkk.workhours.mixins import PeriodSelectorMixin
 13from vkk.workhours.forms import WorkhourSheetForm, PeriodSelectForm
 14from vkk.workhours.accounting.mixins import AccountantRequiredMixin
 15from vkk.workhours.accounting.views import AccountingDetailView, AccountingFilterView, AccountingCreateView, AccountingUpdateView, AccountingDeleteView
 16from vkk.workhours.accounting.projects.project.forms import ContributorDeleteForm
 17
 18
 19class AccountingProjectOverView(AccountingDetailView):
 20    model = Project
 21    slug_field = 'invoice_number'
 22    slug_url_kwarg = 'invoice_number'
 23    template_name = 'vkk/workhours/accounting/projects/project/details.html'
 24    fields = ['name', 'invoice_number',
 25              'department', 'contractor', 'start', 'end']
 26
 27    def get_context_data(self, **kwargs):
 28        context = super().get_context_data(**kwargs)
 29        context["managers"] = ProjectManager.objects.filter(
 30            project__invoice_number=self.kwargs['invoice_number']
 31        ).prefetch_related('manager').order_by('manager__last_name', 'manager__first_name')
 32        context["contributors"] = ProjectAssignment.objects.filter(
 33            project__invoice_number=self.kwargs['invoice_number']
 34        ).prefetch_related('contributor').order_by('contributor__last_name', 'contributor__first_name')
 35        return context
 36
 37
 38class AccountingProjectUserFilterView(AccountingFilterView):
 39    model = User
 40    fields = ['last_name', 'first_name', 'email']
 41    action_options = None
 42    to_exclude = None
 43
 44    def get(self, request, *args, invoice_number=None, **kwargs):
 45        return super().get(request, *args, **kwargs)
 46
 47    def get_queryset(self):
 48        kwarg = {self.to_exclude: self.kwargs['invoice_number']}
 49        return super().get_queryset().exclude(**kwarg)
 50
 51
 52class AccountingProjectUpdateView(AccountingUpdateView):
 53    model = Project
 54    form_class = modelform_factory(
 55        model=Project,
 56        fields=['invoice_number', 'name', 'department',
 57                'contractor', 'start', 'end'],
 58        widgets={'start': CustomDateInput, 'end': CustomDateInput}
 59    )
 60    drop_key = None
 61    slug_field = 'invoice_number'
 62    slug_url_kwarg = 'invoice_number'
 63
 64    def form_valid(self, form):
 65        self.kwarg_override = {'invoice_number': form.instance.invoice_number}
 66        return super().form_valid(form)
 67
 68
 69class AccountingManagerCreateView(AccountingCreateView):
 70    model = ProjectManager
 71    form_class = modelform_factory(
 72        model=ProjectManager,
 73        fields=['start', 'end', 'is_proxy'],
 74        widgets={'start': CustomDateInput, 'end': CustomDateInput}
 75    )
 76    on_success = 'add_manager_success'
 77    drop_key = 'pk'
 78
 79    def form_valid(self, form):
 80        form.instance.manager = User.objects.get(pk=self.kwargs['pk'])
 81        form.instance.project = Project.objects.get(
 82            invoice_number=self.kwargs['invoice_number'])
 83        try:
 84            form.instance.full_clean()
 85        except ValidationError as err:
 86            form.add_error(None, err)
 87            return self.form_invalid(form)
 88        return super().form_valid(form)
 89
 90
 91class AccountingContributorCreateView(AccountingCreateView):
 92    model = ProjectAssignment
 93    fields = ['salary_level']
 94    on_success = 'add_contributor_success'
 95    drop_key = 'pk'
 96
 97    def form_valid(self, form):
 98        form.instance.contributor = User.objects.get(pk=self.kwargs['pk'])
 99        form.instance.project = Project.objects.get(
100            invoice_number=self.kwargs['invoice_number'])
101        try:
102            form.instance.full_clean()
103        except ValidationError as err:
104            form.add_error(None, err)
105            return self.form_invalid(form)
106        return super().form_valid(form)
107
108
109class AccountingContributorDeleteView(AccountingDeleteView):
110    model = ProjectAssignment
111    form_class = ContributorDeleteForm
112    on_success = 'delete_contributor_success'
113    drop_key = 'pk'
114
115
116class AccountingManagerDeleteView(AccountingDeleteView):
117    model = ProjectManager
118    on_success = 'delete_manager_success'
119    drop_key = 'pk'
120
121
122class AccountingWorkhourSheetSelectionView(AccountantRequiredMixin, PeriodSelectorMixin, RedirectView):
123    def get_redirect_url(self, *args, **kwargs):
124        # Catches Period Selection from GET
125        if 'period' in self.request.GET:
126            query_set = Period.objects.all()
127            form = PeriodSelectForm(query_set, data=self.request.GET)
128            if form.is_valid():
129                period = form.cleaned_data.get("period")
130            else:
131                raise Http404()
132        # Catches Period no given
133        elif 'period_pk' not in kwargs:
134            period = Period.objects.latest(create=True)
135        # Looks up Period
136        else:
137            period = get_object_or_404(Period, pk=kwargs['period_pk'])
138
139        return reverse(
140            'vkk:workhours:accounting:projects:project:workhours_sheet',
141            args=[kwargs['invoice_number'], period.pk]
142        )
143
144
145class AccountingWorkhourSheetView(AccountantRequiredMixin, PeriodSelectorMixin, FormView):
146    form_class = WorkhourSheetForm
147    template_name = 'vkk/workhours/accounting/projects/project/workhours_sheet.html'
148    period_select_namespace = 'vkk:workhours:accounting:projects:project:workhours_sheet_selection'
149
150    def get_form_kwargs(self):
151        kwargs = super().get_form_kwargs()
152        self.assignments = ProjectAssignment.objects.filter(
153            project__invoice_number=self.kwargs['invoice_number']
154        ).order_by('contributor__last_name', 'contributor__first_name')
155        kwargs.update({
156            'period_pk': self.kwargs['period_pk'],
157            'assignments': self.assignments,
158            'closure_lock': False,
159            'invoice_number': self.kwargs['invoice_number'],
160        })
161        return kwargs
162
163    def get_success_url(self):
164        return reverse(
165            'vkk:workhours:accounting:projects:project:workhours_sheet_success',
166            args=[
167                self.kwargs['invoice_number'],
168                self.kwargs['period_pk']
169            ]
170        )
171
172    def get_context_data(self, **kwargs):
173        context = super().get_context_data(**kwargs)
174        manager_closed_count = self.assignments.filter(
175            periodclosure__period=self.kwargs['period_pk'],
176            periodclosure__is_closed_manager=True
177        ).count()
178        assignment_count = self.assignments.count()
179        if manager_closed_count == assignment_count:
180            context['closed'] = True
181        else:
182            context['closed'] = False
183        context['saveable'] = True
184
185        context['project'] = get_object_or_404(
186            Project, invoice_number=self.kwargs['invoice_number'])
187        return context
188
189    def form_valid(self, form):
190        form.save()
191        return super().form_valid(form)
192
193
194class AccountingPeriodClosureView(AccountantRequiredMixin, OnSuccessMixin, FormView):
195    template_name = 'vkk/workhours/contributor/closure.html'
196    form_class = Form
197    on_success = 'period_closure_success'
198
199    def post(self, request, *args, **kwargs):
200        form = self.get_form()
201        if form.is_valid():
202            self.close_period()
203            return self.form_valid(form)
204        else:
205            return self.form_invalid(form)
206
207    def close_period(self):
208        assignments = ProjectAssignment.objects.filter(
209            project__invoice_number=self.kwargs['invoice_number'],
210        )
211        period = get_object_or_404(Period, pk=self.kwargs['period_pk'])
212        closing = [
213            PeriodClosure(
214                period=period,
215                project_assignment=assignment,
216                is_closed_contributor=True,
217                is_closed_manager=True
218            ) for assignment in assignments
219        ]
220        PeriodClosure.objects.bulk_create(
221            closing,
222            update_conflicts=True,
223            update_fields=['is_closed_contributor', 'is_closed_manager'],
224            unique_fields=['project_assignment', 'period']
225        )
226
227
228class AccountingPeriodClosureSuccessView(AccountantRequiredMixin, CustomSuccessView):
229    template_name = 'vkk/workhours/contributor/closure_success.html'
230    model = PeriodClosure
231    on_success = 'workhours_sheet'
232
233
234# Export
235
236class AccountingExportView(AccountantRequiredMixin, FormView):
237    template_name = 'vkk/workhours/accounting/projects/project/export.html'
class AccountingProjectOverView(vkk.workhours.accounting.views.AccountingDetailView):
20class AccountingProjectOverView(AccountingDetailView):
21    model = Project
22    slug_field = 'invoice_number'
23    slug_url_kwarg = 'invoice_number'
24    template_name = 'vkk/workhours/accounting/projects/project/details.html'
25    fields = ['name', 'invoice_number',
26              'department', 'contractor', 'start', 'end']
27
28    def get_context_data(self, **kwargs):
29        context = super().get_context_data(**kwargs)
30        context["managers"] = ProjectManager.objects.filter(
31            project__invoice_number=self.kwargs['invoice_number']
32        ).prefetch_related('manager').order_by('manager__last_name', 'manager__first_name')
33        context["contributors"] = ProjectAssignment.objects.filter(
34            project__invoice_number=self.kwargs['invoice_number']
35        ).prefetch_related('contributor').order_by('contributor__last_name', 'contributor__first_name')
36        return context

Verify that the current user has accountant rights.

def get_context_data(self, **kwargs):
28    def get_context_data(self, **kwargs):
29        context = super().get_context_data(**kwargs)
30        context["managers"] = ProjectManager.objects.filter(
31            project__invoice_number=self.kwargs['invoice_number']
32        ).prefetch_related('manager').order_by('manager__last_name', 'manager__first_name')
33        context["contributors"] = ProjectAssignment.objects.filter(
34            project__invoice_number=self.kwargs['invoice_number']
35        ).prefetch_related('contributor').order_by('contributor__last_name', 'contributor__first_name')
36        return context

Insert the single object into the context dict.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
django.views.generic.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.detail.BaseDetailView
get
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
class AccountingProjectUserFilterView(vkk.workhours.accounting.views.AccountingFilterView):
39class AccountingProjectUserFilterView(AccountingFilterView):
40    model = User
41    fields = ['last_name', 'first_name', 'email']
42    action_options = None
43    to_exclude = None
44
45    def get(self, request, *args, invoice_number=None, **kwargs):
46        return super().get(request, *args, **kwargs)
47
48    def get_queryset(self):
49        kwarg = {self.to_exclude: self.kwargs['invoice_number']}
50        return super().get_queryset().exclude(**kwarg)

Verify that the current user has accountant rights.

def get(self, request, *args, invoice_number=None, **kwargs):
45    def get(self, request, *args, invoice_number=None, **kwargs):
46        return super().get(request, *args, **kwargs)
def get_queryset(self):
48    def get_queryset(self):
49        kwarg = {self.to_exclude: self.kwargs['invoice_number']}
50        return super().get_queryset().exclude(**kwarg)

Returns a filtered queryset.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.generic.views.CustomFilterView
get_filter_fields
get_filter
get_context_data
django.views.generic.list.MultipleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
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 AccountingProjectUpdateView(vkk.workhours.accounting.views.AccountingUpdateView):
53class AccountingProjectUpdateView(AccountingUpdateView):
54    model = Project
55    form_class = modelform_factory(
56        model=Project,
57        fields=['invoice_number', 'name', 'department',
58                'contractor', 'start', 'end'],
59        widgets={'start': CustomDateInput, 'end': CustomDateInput}
60    )
61    drop_key = None
62    slug_field = 'invoice_number'
63    slug_url_kwarg = 'invoice_number'
64
65    def form_valid(self, form):
66        self.kwarg_override = {'invoice_number': form.instance.invoice_number}
67        return super().form_valid(form)

Verify that the current user has accountant rights.

def form_valid(self, form):
65    def form_valid(self, form):
66        self.kwarg_override = {'invoice_number': form.instance.invoice_number}
67        return super().form_valid(form)

If the form is valid, save the associated model.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.edit.BaseUpdateView
get
post
django.views.generic.edit.ModelFormMixin
get_form_class
get_form_kwargs
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form
form_invalid
get_context_data
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.edit.ProcessFormView
put
class AccountingManagerCreateView(vkk.workhours.accounting.views.AccountingCreateView):
70class AccountingManagerCreateView(AccountingCreateView):
71    model = ProjectManager
72    form_class = modelform_factory(
73        model=ProjectManager,
74        fields=['start', 'end', 'is_proxy'],
75        widgets={'start': CustomDateInput, 'end': CustomDateInput}
76    )
77    on_success = 'add_manager_success'
78    drop_key = 'pk'
79
80    def form_valid(self, form):
81        form.instance.manager = User.objects.get(pk=self.kwargs['pk'])
82        form.instance.project = Project.objects.get(
83            invoice_number=self.kwargs['invoice_number'])
84        try:
85            form.instance.full_clean()
86        except ValidationError as err:
87            form.add_error(None, err)
88            return self.form_invalid(form)
89        return super().form_valid(form)

Verify that the current user has accountant rights.

def form_valid(self, form):
80    def form_valid(self, form):
81        form.instance.manager = User.objects.get(pk=self.kwargs['pk'])
82        form.instance.project = Project.objects.get(
83            invoice_number=self.kwargs['invoice_number'])
84        try:
85            form.instance.full_clean()
86        except ValidationError as err:
87            form.add_error(None, err)
88            return self.form_invalid(form)
89        return super().form_valid(form)

If the form is valid, save the associated model.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.edit.BaseCreateView
get
post
django.views.generic.edit.ModelFormMixin
get_form_class
get_form_kwargs
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form
form_invalid
get_context_data
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.edit.ProcessFormView
put
class AccountingContributorCreateView(vkk.workhours.accounting.views.AccountingCreateView):
 92class AccountingContributorCreateView(AccountingCreateView):
 93    model = ProjectAssignment
 94    fields = ['salary_level']
 95    on_success = 'add_contributor_success'
 96    drop_key = 'pk'
 97
 98    def form_valid(self, form):
 99        form.instance.contributor = User.objects.get(pk=self.kwargs['pk'])
100        form.instance.project = Project.objects.get(
101            invoice_number=self.kwargs['invoice_number'])
102        try:
103            form.instance.full_clean()
104        except ValidationError as err:
105            form.add_error(None, err)
106            return self.form_invalid(form)
107        return super().form_valid(form)

Verify that the current user has accountant rights.

def form_valid(self, form):
 98    def form_valid(self, form):
 99        form.instance.contributor = User.objects.get(pk=self.kwargs['pk'])
100        form.instance.project = Project.objects.get(
101            invoice_number=self.kwargs['invoice_number'])
102        try:
103            form.instance.full_clean()
104        except ValidationError as err:
105            form.add_error(None, err)
106            return self.form_invalid(form)
107        return super().form_valid(form)

If the form is valid, save the associated model.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.edit.BaseCreateView
get
post
django.views.generic.edit.ModelFormMixin
get_form_class
get_form_kwargs
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form
form_invalid
get_context_data
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.edit.ProcessFormView
put
class AccountingContributorDeleteView(vkk.workhours.accounting.views.AccountingDeleteView):
110class AccountingContributorDeleteView(AccountingDeleteView):
111    model = ProjectAssignment
112    form_class = ContributorDeleteForm
113    on_success = 'delete_contributor_success'
114    drop_key = 'pk'

Verify that the current user has accountant rights.

Inherited Members
django.views.generic.edit.BaseDeleteView
BaseDeleteView
post
form_valid
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.edit.DeletionMixin
delete
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form_class
get_form
get_form_kwargs
form_invalid
get_context_data
django.views.generic.detail.BaseDetailView
get
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.base.View
view_is_async
as_view
setup
http_method_not_allowed
options
class AccountingManagerDeleteView(vkk.workhours.accounting.views.AccountingDeleteView):
117class AccountingManagerDeleteView(AccountingDeleteView):
118    model = ProjectManager
119    on_success = 'delete_manager_success'
120    drop_key = 'pk'

Verify that the current user has accountant rights.

Inherited Members
django.views.generic.edit.BaseDeleteView
BaseDeleteView
post
form_valid
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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.detail.SingleObjectTemplateResponseMixin
get_template_names
django.views.generic.base.TemplateResponseMixin
render_to_response
django.views.generic.edit.DeletionMixin
delete
django.views.generic.edit.FormMixin
get_initial
get_prefix
get_form_class
get_form
get_form_kwargs
form_invalid
get_context_data
django.views.generic.detail.BaseDetailView
get
django.views.generic.detail.SingleObjectMixin
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.base.View
view_is_async
as_view
setup
http_method_not_allowed
options
class AccountingWorkhourSheetSelectionView(vkk.workhours.accounting.mixins.AccountantRequiredMixin, vkk.workhours.mixins.PeriodSelectorMixin, django.views.generic.base.RedirectView):
123class AccountingWorkhourSheetSelectionView(AccountantRequiredMixin, PeriodSelectorMixin, RedirectView):
124    def get_redirect_url(self, *args, **kwargs):
125        # Catches Period Selection from GET
126        if 'period' in self.request.GET:
127            query_set = Period.objects.all()
128            form = PeriodSelectForm(query_set, data=self.request.GET)
129            if form.is_valid():
130                period = form.cleaned_data.get("period")
131            else:
132                raise Http404()
133        # Catches Period no given
134        elif 'period_pk' not in kwargs:
135            period = Period.objects.latest(create=True)
136        # Looks up Period
137        else:
138            period = get_object_or_404(Period, pk=kwargs['period_pk'])
139
140        return reverse(
141            'vkk:workhours:accounting:projects:project:workhours_sheet',
142            args=[kwargs['invoice_number'], period.pk]
143        )

Verify that the current user has accountant rights.

def get_redirect_url(self, *args, **kwargs):
124    def get_redirect_url(self, *args, **kwargs):
125        # Catches Period Selection from GET
126        if 'period' in self.request.GET:
127            query_set = Period.objects.all()
128            form = PeriodSelectForm(query_set, data=self.request.GET)
129            if form.is_valid():
130                period = form.cleaned_data.get("period")
131            else:
132                raise Http404()
133        # Catches Period no given
134        elif 'period_pk' not in kwargs:
135            period = Period.objects.latest(create=True)
136        # Looks up Period
137        else:
138            period = get_object_or_404(Period, pk=kwargs['period_pk'])
139
140        return reverse(
141            'vkk:workhours:accounting:projects:project:workhours_sheet',
142            args=[kwargs['invoice_number'], period.pk]
143        )

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.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.workhours.mixins.PeriodSelectorMixin
get_context_data
get_select_url
django.views.generic.base.RedirectView
get
head
post
options
delete
put
patch
class AccountingWorkhourSheetView(vkk.workhours.accounting.mixins.AccountantRequiredMixin, vkk.workhours.mixins.PeriodSelectorMixin, django.views.generic.edit.FormView):
146class AccountingWorkhourSheetView(AccountantRequiredMixin, PeriodSelectorMixin, FormView):
147    form_class = WorkhourSheetForm
148    template_name = 'vkk/workhours/accounting/projects/project/workhours_sheet.html'
149    period_select_namespace = 'vkk:workhours:accounting:projects:project:workhours_sheet_selection'
150
151    def get_form_kwargs(self):
152        kwargs = super().get_form_kwargs()
153        self.assignments = ProjectAssignment.objects.filter(
154            project__invoice_number=self.kwargs['invoice_number']
155        ).order_by('contributor__last_name', 'contributor__first_name')
156        kwargs.update({
157            'period_pk': self.kwargs['period_pk'],
158            'assignments': self.assignments,
159            'closure_lock': False,
160            'invoice_number': self.kwargs['invoice_number'],
161        })
162        return kwargs
163
164    def get_success_url(self):
165        return reverse(
166            'vkk:workhours:accounting:projects:project:workhours_sheet_success',
167            args=[
168                self.kwargs['invoice_number'],
169                self.kwargs['period_pk']
170            ]
171        )
172
173    def get_context_data(self, **kwargs):
174        context = super().get_context_data(**kwargs)
175        manager_closed_count = self.assignments.filter(
176            periodclosure__period=self.kwargs['period_pk'],
177            periodclosure__is_closed_manager=True
178        ).count()
179        assignment_count = self.assignments.count()
180        if manager_closed_count == assignment_count:
181            context['closed'] = True
182        else:
183            context['closed'] = False
184        context['saveable'] = True
185
186        context['project'] = get_object_or_404(
187            Project, invoice_number=self.kwargs['invoice_number'])
188        return context
189
190    def form_valid(self, form):
191        form.save()
192        return super().form_valid(form)

Verify that the current user has accountant rights.

def get_form_kwargs(self):
151    def get_form_kwargs(self):
152        kwargs = super().get_form_kwargs()
153        self.assignments = ProjectAssignment.objects.filter(
154            project__invoice_number=self.kwargs['invoice_number']
155        ).order_by('contributor__last_name', 'contributor__first_name')
156        kwargs.update({
157            'period_pk': self.kwargs['period_pk'],
158            'assignments': self.assignments,
159            'closure_lock': False,
160            'invoice_number': self.kwargs['invoice_number'],
161        })
162        return kwargs

Return the keyword arguments for instantiating the form.

def get_success_url(self):
164    def get_success_url(self):
165        return reverse(
166            'vkk:workhours:accounting:projects:project:workhours_sheet_success',
167            args=[
168                self.kwargs['invoice_number'],
169                self.kwargs['period_pk']
170            ]
171        )

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

def get_context_data(self, **kwargs):
173    def get_context_data(self, **kwargs):
174        context = super().get_context_data(**kwargs)
175        manager_closed_count = self.assignments.filter(
176            periodclosure__period=self.kwargs['period_pk'],
177            periodclosure__is_closed_manager=True
178        ).count()
179        assignment_count = self.assignments.count()
180        if manager_closed_count == assignment_count:
181            context['closed'] = True
182        else:
183            context['closed'] = False
184        context['saveable'] = True
185
186        context['project'] = get_object_or_404(
187            Project, invoice_number=self.kwargs['invoice_number'])
188        return context

Adds the form for selecting Period instances to the context and returns it.

def form_valid(self, form):
190    def form_valid(self, form):
191        form.save()
192        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
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.workhours.mixins.PeriodSelectorMixin
get_select_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
form_invalid
django.views.generic.edit.ProcessFormView
get
post
put
class AccountingPeriodClosureView(vkk.workhours.accounting.mixins.AccountantRequiredMixin, vkk.generic.mixins.OnSuccessMixin, django.views.generic.edit.FormView):
195class AccountingPeriodClosureView(AccountantRequiredMixin, OnSuccessMixin, FormView):
196    template_name = 'vkk/workhours/contributor/closure.html'
197    form_class = Form
198    on_success = 'period_closure_success'
199
200    def post(self, request, *args, **kwargs):
201        form = self.get_form()
202        if form.is_valid():
203            self.close_period()
204            return self.form_valid(form)
205        else:
206            return self.form_invalid(form)
207
208    def close_period(self):
209        assignments = ProjectAssignment.objects.filter(
210            project__invoice_number=self.kwargs['invoice_number'],
211        )
212        period = get_object_or_404(Period, pk=self.kwargs['period_pk'])
213        closing = [
214            PeriodClosure(
215                period=period,
216                project_assignment=assignment,
217                is_closed_contributor=True,
218                is_closed_manager=True
219            ) for assignment in assignments
220        ]
221        PeriodClosure.objects.bulk_create(
222            closing,
223            update_conflicts=True,
224            update_fields=['is_closed_contributor', 'is_closed_manager'],
225            unique_fields=['project_assignment', 'period']
226        )

Verify that the current user has accountant rights.

def post(self, request, *args, **kwargs):
200    def post(self, request, *args, **kwargs):
201        form = self.get_form()
202        if form.is_valid():
203            self.close_period()
204            return self.form_valid(form)
205        else:
206            return self.form_invalid(form)

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

def close_period(self):
208    def close_period(self):
209        assignments = ProjectAssignment.objects.filter(
210            project__invoice_number=self.kwargs['invoice_number'],
211        )
212        period = get_object_or_404(Period, pk=self.kwargs['period_pk'])
213        closing = [
214            PeriodClosure(
215                period=period,
216                project_assignment=assignment,
217                is_closed_contributor=True,
218                is_closed_manager=True
219            ) for assignment in assignments
220        ]
221        PeriodClosure.objects.bulk_create(
222            closing,
223            update_conflicts=True,
224            update_fields=['is_closed_contributor', 'is_closed_manager'],
225            unique_fields=['project_assignment', 'period']
226        )
Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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
229class AccountingPeriodClosureSuccessView(AccountantRequiredMixin, CustomSuccessView):
230    template_name = 'vkk/workhours/contributor/closure_success.html'
231    model = PeriodClosure
232    on_success = 'workhours_sheet'

Verify that the current user has accountant rights.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
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
class AccountingExportView(vkk.workhours.accounting.mixins.AccountantRequiredMixin, django.views.generic.edit.FormView):
237class AccountingExportView(AccountantRequiredMixin, FormView):
238    template_name = 'vkk/workhours/accounting/projects/project/export.html'

Verify that the current user has accountant rights.

Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
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
get_form_kwargs
get_success_url
form_valid
form_invalid
get_context_data
django.views.generic.edit.ProcessFormView
get
post
put