vkk.workhours.accounting.projects.project.export.receipts.views

  1import json
  2import csv
  3import datetime
  4from django.utils.translation import gettext_lazy as _
  5from django.http import JsonResponse, HttpResponse
  6from django.views.generic import FormView
  7from django.shortcuts import get_object_or_404
  8from vkk.workhours.accounting.mixins import AccountantRequiredMixin
  9from vkk.workhours.accounting.views import (
 10    AccountingListView, AccountingCreateView
 11)
 12from vkk.workhours.models import Receipt, Project
 13from .forms import ReceiptForm, ReceiptTemplateSelectForm
 14
 15
 16class ReceiptListView(AccountingListView):
 17    model = Receipt
 18    fields = ['create_time', 'start', 'end']
 19    ordering = ['create_time']
 20    action_options = {
 21        'details': _('Details'),
 22        'delete': _('Delete'),
 23        'receipt_download': _('Download'),
 24    }
 25
 26    def get_queryset(self):
 27        return super().get_queryset().filter(
 28            project__invoice_number=self.kwargs['invoice_number'],
 29        )
 30
 31
 32class ReceiptCreateView(AccountingCreateView):
 33    model = Receipt
 34    form_class = ReceiptForm
 35
 36    def post(self, request, *args, **kwargs):
 37        if request.content_type == 'application/json':
 38            return self.post_json(request, *args, **kwargs)
 39        else:
 40            return super().post(request, *args, **kwargs)
 41
 42    def post_json(self, request, *args, **kwargs):
 43        kwargs = self.get_form_kwargs()
 44        kwargs.update({
 45            "data": json.loads(request.body),
 46        })
 47        form = self.get_form_class()(**kwargs)
 48
 49        if form.is_valid():
 50            return JsonResponse(form.to_data_dict())
 51        else:
 52            return JsonResponse(
 53                {'errors': form.errors}
 54            )
 55
 56    def get_form_kwargs(self):
 57        kwargs = super().get_form_kwargs()
 58        project = Project.objects.get(
 59            invoice_number=self.kwargs['invoice_number']
 60        )
 61        kwargs.update({
 62            "project": project,
 63        })
 64        return kwargs
 65
 66
 67class ReceiptTemplateSelectionView(FormView, AccountantRequiredMixin):
 68    form_class = ReceiptTemplateSelectForm
 69    template_name = "vkk/workhours/accounting/projects/project/export/receipt_select.html"
 70
 71    def form_valid(self, form):
 72        receipt_template = form.cleaned_data.get("receipt_template")
 73        receipt = get_object_or_404(Receipt, pk=self.kwargs["pk"])
 74        return self.csv_response(receipt, receipt_template)
 75
 76    def csv_response(self, receipt, receipt_template):
 77        response = HttpResponse(
 78            content_type='text/csv',
 79            headers={
 80                'Content-Disposition': f'attachment; filename="{ receipt.id }.csv"'},
 81        )
 82
 83        # init writer for creating csv
 84        writer = csv.writer(response, delimiter=';')
 85
 86        # retrieving data for creating the receipt in csv format
 87        template_data = receipt_template.data
 88        data = json.loads(receipt.data)
 89
 90        # retrieving keys and writing header row
 91        keys = [list(column.keys())[0] for column in template_data]
 92        writer.writerow([str(key) for key in keys])
 93
 94        # getting columns and reorganize them to rows
 95        table_template = zip(*(column.get(key)
 96                             for column, key in zip(template_data, keys)))
 97
 98        # here be conversion
 99        table = [
100            [
101                _data_cell_calculation(cell, receipt, data) for cell in row
102            ] for row in table_template
103        ]
104
105        # writing data to csv
106        writer.writerows(table)
107
108        return response
109
110
111def _data_cell_calculation(template, receipt, data):
112    """This functions retrieves the required data point according to the template"""
113    method = template.get("method")
114    if method is None:
115        return ""
116    elif method == "FIXED":
117        return template.get("value")
118    elif method == "GENERATED":
119        value = template.get("value")
120        args = value.split(" ")
121        out = []
122        for arg in args:
123            lookup = None
124            parts = arg.split(".")
125            if parts[0] == "data":
126                lookup = data
127            elif hasattr(receipt, parts[0]):
128                lookup = getattr(receipt, parts[0])
129            if lookup is not None:
130                for part in parts[1:]:
131                    if isinstance(lookup, dict):
132                        lookup = lookup.get(part)
133                    elif hasattr(lookup, part):
134                        lookup = getattr(lookup, part)
135                    if lookup is None:
136                        break
137                if lookup is not None:
138                    out.append(str(_format(lookup)))
139            else:
140                out.append(str(arg))
141        return " ".join(out)
142    else:
143        return ""
144
145
146def _format(value):
147    if isinstance(value, datetime.date):
148        return value.strftime("%d.%m.%Y")
149    elif isinstance(value, str):
150        return 0 if value == "0.00" else value
151    elif isinstance(value, bool):
152        return _("Ja") if value else _("Nein")
153    else:
154        return value
class ReceiptListView(vkk.workhours.accounting.views.AccountingListView):
17class ReceiptListView(AccountingListView):
18    model = Receipt
19    fields = ['create_time', 'start', 'end']
20    ordering = ['create_time']
21    action_options = {
22        'details': _('Details'),
23        'delete': _('Delete'),
24        'receipt_download': _('Download'),
25    }
26
27    def get_queryset(self):
28        return super().get_queryset().filter(
29            project__invoice_number=self.kwargs['invoice_number'],
30        )

Verify that the current user has accountant rights.

def get_queryset(self):
27    def get_queryset(self):
28        return super().get_queryset().filter(
29            project__invoice_number=self.kwargs['invoice_number'],
30        )

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.

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.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
get_context_data
class ReceiptCreateView(vkk.workhours.accounting.views.AccountingCreateView):
33class ReceiptCreateView(AccountingCreateView):
34    model = Receipt
35    form_class = ReceiptForm
36
37    def post(self, request, *args, **kwargs):
38        if request.content_type == 'application/json':
39            return self.post_json(request, *args, **kwargs)
40        else:
41            return super().post(request, *args, **kwargs)
42
43    def post_json(self, request, *args, **kwargs):
44        kwargs = self.get_form_kwargs()
45        kwargs.update({
46            "data": json.loads(request.body),
47        })
48        form = self.get_form_class()(**kwargs)
49
50        if form.is_valid():
51            return JsonResponse(form.to_data_dict())
52        else:
53            return JsonResponse(
54                {'errors': form.errors}
55            )
56
57    def get_form_kwargs(self):
58        kwargs = super().get_form_kwargs()
59        project = Project.objects.get(
60            invoice_number=self.kwargs['invoice_number']
61        )
62        kwargs.update({
63            "project": project,
64        })
65        return kwargs

Verify that the current user has accountant rights.

def post(self, request, *args, **kwargs):
37    def post(self, request, *args, **kwargs):
38        if request.content_type == 'application/json':
39            return self.post_json(request, *args, **kwargs)
40        else:
41            return super().post(request, *args, **kwargs)

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

def post_json(self, request, *args, **kwargs):
43    def post_json(self, request, *args, **kwargs):
44        kwargs = self.get_form_kwargs()
45        kwargs.update({
46            "data": json.loads(request.body),
47        })
48        form = self.get_form_class()(**kwargs)
49
50        if form.is_valid():
51            return JsonResponse(form.to_data_dict())
52        else:
53            return JsonResponse(
54                {'errors': form.errors}
55            )
def get_form_kwargs(self):
57    def get_form_kwargs(self):
58        kwargs = super().get_form_kwargs()
59        project = Project.objects.get(
60            invoice_number=self.kwargs['invoice_number']
61        )
62        kwargs.update({
63            "project": project,
64        })
65        return kwargs

Return the keyword arguments for instantiating the form.

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
django.views.generic.edit.ModelFormMixin
get_form_class
form_valid
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 ReceiptTemplateSelectionView(django.views.generic.edit.FormView, vkk.workhours.accounting.mixins.AccountantRequiredMixin):
 68class ReceiptTemplateSelectionView(FormView, AccountantRequiredMixin):
 69    form_class = ReceiptTemplateSelectForm
 70    template_name = "vkk/workhours/accounting/projects/project/export/receipt_select.html"
 71
 72    def form_valid(self, form):
 73        receipt_template = form.cleaned_data.get("receipt_template")
 74        receipt = get_object_or_404(Receipt, pk=self.kwargs["pk"])
 75        return self.csv_response(receipt, receipt_template)
 76
 77    def csv_response(self, receipt, receipt_template):
 78        response = HttpResponse(
 79            content_type='text/csv',
 80            headers={
 81                'Content-Disposition': f'attachment; filename="{ receipt.id }.csv"'},
 82        )
 83
 84        # init writer for creating csv
 85        writer = csv.writer(response, delimiter=';')
 86
 87        # retrieving data for creating the receipt in csv format
 88        template_data = receipt_template.data
 89        data = json.loads(receipt.data)
 90
 91        # retrieving keys and writing header row
 92        keys = [list(column.keys())[0] for column in template_data]
 93        writer.writerow([str(key) for key in keys])
 94
 95        # getting columns and reorganize them to rows
 96        table_template = zip(*(column.get(key)
 97                             for column, key in zip(template_data, keys)))
 98
 99        # here be conversion
100        table = [
101            [
102                _data_cell_calculation(cell, receipt, data) for cell in row
103            ] for row in table_template
104        ]
105
106        # writing data to csv
107        writer.writerows(table)
108
109        return response

A view for displaying a form and rendering a template response.

def form_valid(self, form):
72    def form_valid(self, form):
73        receipt_template = form.cleaned_data.get("receipt_template")
74        receipt = get_object_or_404(Receipt, pk=self.kwargs["pk"])
75        return self.csv_response(receipt, receipt_template)

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

def csv_response(self, receipt, receipt_template):
 77    def csv_response(self, receipt, receipt_template):
 78        response = HttpResponse(
 79            content_type='text/csv',
 80            headers={
 81                'Content-Disposition': f'attachment; filename="{ receipt.id }.csv"'},
 82        )
 83
 84        # init writer for creating csv
 85        writer = csv.writer(response, delimiter=';')
 86
 87        # retrieving data for creating the receipt in csv format
 88        template_data = receipt_template.data
 89        data = json.loads(receipt.data)
 90
 91        # retrieving keys and writing header row
 92        keys = [list(column.keys())[0] for column in template_data]
 93        writer.writerow([str(key) for key in keys])
 94
 95        # getting columns and reorganize them to rows
 96        table_template = zip(*(column.get(key)
 97                             for column, key in zip(template_data, keys)))
 98
 99        # here be conversion
100        table = [
101            [
102                _data_cell_calculation(cell, receipt, data) for cell in row
103            ] for row in table_template
104        ]
105
106        # writing data to csv
107        writer.writerows(table)
108
109        return response
Inherited Members
django.views.generic.base.View
View
view_is_async
as_view
setup
dispatch
http_method_not_allowed
options
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_invalid
get_context_data
django.views.generic.edit.ProcessFormView
get
post
put
django.contrib.auth.mixins.AccessMixin
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission