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

This submodule contains class based views.

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

A class based ListView providing utilities for listing Receipts.

model = <class 'vkk.workhours.models.Receipt'>
fields = ['create_time', 'start', 'end']
ordering = ['create_time']
action_options = {'details': 'Details', 'delete': 'Löschen', 'receipt_download': 'Herunterladen'}
def get_queryset(self):
34    def get_queryset(self):
35        """
36        Returns a query set of `Receipt`s for a given project.
37        """
38        return super().get_queryset().filter(
39            project__invoice_number=self.kwargs['invoice_number'],
40        )

Returns a query set of Receipts for a given project.

Inherited Members
django.views.generic.base.View
View
http_method_names
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
login_url
permission_denied_message
raise_exception
redirect_field_name
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.generic.views.CustomListView
keys
paginate_by
template_name
django.views.generic.list.MultipleObjectTemplateResponseMixin
template_name_suffix
get_template_names
django.views.generic.base.TemplateResponseMixin
template_engine
response_class
content_type
render_to_response
django.views.generic.list.BaseListView
get
django.views.generic.list.MultipleObjectMixin
allow_empty
queryset
paginate_orphans
context_object_name
paginator_class
page_kwarg
get_ordering
paginate_queryset
get_paginate_by
get_paginator
get_paginate_orphans
get_allow_empty
get_context_object_name
get_context_data
django.views.generic.base.ContextMixin
extra_context
class ReceiptCreateView(vkk.workhours.accounting.views.AccountingCreateView):
43class ReceiptCreateView(AccountingCreateView):
44    """
45    A class based `CreateView` providing utilities for creating `Receipt`s.
46    """
47    model = Receipt
48    form_class = ReceiptForm
49
50    def post(self, request, *args, **kwargs):
51        """
52        Handler for POST requests.
53        """
54        if request.content_type == 'application/json':
55            return self.post_json(request, *args, **kwargs)
56        else:
57            return super().post(request, *args, **kwargs)
58
59    def post_json(self, request, *args, **kwargs):
60        """
61        Handler for POST requests with content type `'application/json'`.
62        """
63        kwargs = self.get_form_kwargs()
64        kwargs.update({
65            "data": json.loads(request.body),
66        })
67        form = self.get_form_class()(**kwargs)
68
69        if form.is_valid():
70            return JsonResponse(form.to_data_dict())
71        else:
72            return JsonResponse(
73                {'errors': form.errors}
74            )
75
76    def get_form_kwargs(self):
77        """
78        Returns a dictionary of keywords for instanciating the associated form.
79        """
80        kwargs = super().get_form_kwargs()
81        project = Project.objects.get(
82            invoice_number=self.kwargs['invoice_number']
83        )
84        kwargs.update({
85            "project": project,
86        })
87        return kwargs

A class based CreateView providing utilities for creating Receipts.

model = <class 'vkk.workhours.models.Receipt'>
def post(self, request, *args, **kwargs):
50    def post(self, request, *args, **kwargs):
51        """
52        Handler for POST requests.
53        """
54        if request.content_type == 'application/json':
55            return self.post_json(request, *args, **kwargs)
56        else:
57            return super().post(request, *args, **kwargs)

Handler for POST requests.

def post_json(self, request, *args, **kwargs):
59    def post_json(self, request, *args, **kwargs):
60        """
61        Handler for POST requests with content type `'application/json'`.
62        """
63        kwargs = self.get_form_kwargs()
64        kwargs.update({
65            "data": json.loads(request.body),
66        })
67        form = self.get_form_class()(**kwargs)
68
69        if form.is_valid():
70            return JsonResponse(form.to_data_dict())
71        else:
72            return JsonResponse(
73                {'errors': form.errors}
74            )

Handler for POST requests with content type 'application/json'.

def get_form_kwargs(self):
76    def get_form_kwargs(self):
77        """
78        Returns a dictionary of keywords for instanciating the associated form.
79        """
80        kwargs = super().get_form_kwargs()
81        project = Project.objects.get(
82            invoice_number=self.kwargs['invoice_number']
83        )
84        kwargs.update({
85            "project": project,
86        })
87        return kwargs

Returns a dictionary of keywords for instanciating the associated form.

Inherited Members
django.views.generic.base.View
View
http_method_names
view_is_async
as_view
setup
http_method_not_allowed
options
vkk.workhours.accounting.mixins.AccountantRequiredMixin
dispatch
django.contrib.auth.mixins.AccessMixin
login_url
permission_denied_message
raise_exception
redirect_field_name
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission
vkk.generic.views.CustomCreateView
on_success
template_name
vkk.generic.mixins.OnSuccessMixin
drop_key
kwarg_override
get_success_url
django.views.generic.edit.CreateView
template_name_suffix
django.views.generic.detail.SingleObjectTemplateResponseMixin
template_name_field
get_template_names
django.views.generic.base.TemplateResponseMixin
template_engine
response_class
content_type
render_to_response
django.views.generic.edit.BaseCreateView
get
django.views.generic.edit.ModelFormMixin
fields
get_form_class
form_valid
django.views.generic.edit.FormMixin
initial
success_url
prefix
get_initial
get_prefix
get_form
form_invalid
get_context_data
django.views.generic.detail.SingleObjectMixin
queryset
slug_field
context_object_name
slug_url_kwarg
pk_url_kwarg
query_pk_and_slug
get_object
get_queryset
get_slug_field
get_context_object_name
django.views.generic.base.ContextMixin
extra_context
django.views.generic.edit.ProcessFormView
put
class ReceiptTemplateSelectionView(django.views.generic.edit.FormView, vkk.workhours.accounting.mixins.AccountantRequiredMixin):
 90class ReceiptTemplateSelectionView(FormView, AccountantRequiredMixin):
 91    """
 92    A class based `View` providing utilities for selecting a template for a receipt and export
 93    in shape of a `.csv` file.
 94    """
 95    form_class = ReceiptTemplateSelectForm
 96    template_name = "vkk/workhours/accounting/projects/project/export/receipt_select.html"
 97
 98    def form_valid(self, form):
 99        """
100        Returns a CSV-Response based on the given receipt and receipt template from the form.
101        """
102        receipt_template = form.cleaned_data.get("receipt_template")
103        receipt = get_object_or_404(Receipt, pk=self.kwargs["pk"])
104        return self.csv_response(receipt, receipt_template)
105
106    def csv_response(self, receipt, receipt_template):
107        """
108        Returns a CSV-Response based on the given receipt and receipt template.
109        """
110        response = HttpResponse(
111            content_type='text/csv',
112            headers={
113                'Content-Disposition': f'attachment; filename="{ receipt.id }.csv"'},
114        )
115
116        # init writer for creating csv
117        writer = csv.writer(response, delimiter=';')
118
119        # retrieving data for creating the receipt in csv format
120        template_data = receipt_template.data
121        data = json.loads(receipt.data)
122
123        # retrieving keys and writing header row
124        keys = [list(column.keys())[0] for column in template_data]
125        writer.writerow([str(key) for key in keys])
126
127        # getting columns and reorganize them to rows
128        table_template = zip(*(column.get(key)
129                             for column, key in zip(template_data, keys)))
130
131        # here be conversion
132        table = [
133            [
134                _data_cell_calculation(cell, receipt, data) for cell in row
135            ] for row in table_template
136        ]
137
138        # writing data to csv
139        writer.writerows(table)
140
141        return response

A class based View providing utilities for selecting a template for a receipt and export in shape of a .csv file.

template_name = 'vkk/workhours/accounting/projects/project/export/receipt_select.html'
def form_valid(self, form):
 98    def form_valid(self, form):
 99        """
100        Returns a CSV-Response based on the given receipt and receipt template from the form.
101        """
102        receipt_template = form.cleaned_data.get("receipt_template")
103        receipt = get_object_or_404(Receipt, pk=self.kwargs["pk"])
104        return self.csv_response(receipt, receipt_template)

Returns a CSV-Response based on the given receipt and receipt template from the form.

def csv_response(self, receipt, receipt_template):
106    def csv_response(self, receipt, receipt_template):
107        """
108        Returns a CSV-Response based on the given receipt and receipt template.
109        """
110        response = HttpResponse(
111            content_type='text/csv',
112            headers={
113                'Content-Disposition': f'attachment; filename="{ receipt.id }.csv"'},
114        )
115
116        # init writer for creating csv
117        writer = csv.writer(response, delimiter=';')
118
119        # retrieving data for creating the receipt in csv format
120        template_data = receipt_template.data
121        data = json.loads(receipt.data)
122
123        # retrieving keys and writing header row
124        keys = [list(column.keys())[0] for column in template_data]
125        writer.writerow([str(key) for key in keys])
126
127        # getting columns and reorganize them to rows
128        table_template = zip(*(column.get(key)
129                             for column, key in zip(template_data, keys)))
130
131        # here be conversion
132        table = [
133            [
134                _data_cell_calculation(cell, receipt, data) for cell in row
135            ] for row in table_template
136        ]
137
138        # writing data to csv
139        writer.writerows(table)
140
141        return response

Returns a CSV-Response based on the given receipt and receipt template.

Inherited Members
django.views.generic.base.View
View
http_method_names
view_is_async
as_view
setup
dispatch
http_method_not_allowed
options
django.views.generic.base.TemplateResponseMixin
template_engine
response_class
content_type
render_to_response
get_template_names
django.views.generic.edit.FormMixin
initial
success_url
prefix
get_initial
get_prefix
get_form_class
get_form
get_form_kwargs
get_success_url
form_invalid
get_context_data
django.views.generic.base.ContextMixin
extra_context
django.views.generic.edit.ProcessFormView
get
post
put
django.contrib.auth.mixins.AccessMixin
login_url
permission_denied_message
raise_exception
redirect_field_name
get_login_url
get_permission_denied_message
get_redirect_field_name
handle_no_permission