All: Apply Black coding rules

This commit is contained in:
2018-10-04 21:29:19 +02:00
parent 0581c667de
commit cb58b00b6e
204 changed files with 13173 additions and 6376 deletions

View File

@ -29,7 +29,14 @@ from datetime import datetime, timedelta
from django.utils import timezone
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, RedirectView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin, BaseFormView
from django.views.generic.edit import (
UpdateView,
CreateView,
DeleteView,
ProcessFormView,
FormMixin,
BaseFormView,
)
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.http import HttpResponseRedirect, HttpResponse
@ -37,7 +44,13 @@ from django.forms.models import modelform_factory
from django.core.urlresolvers import reverse_lazy, reverse
from django.db import transaction, DataError
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
from core.views import (
CanViewMixin,
CanEditMixin,
CanEditPropMixin,
CanCreateMixin,
TabedViewMixin,
)
from counter.views import CounterAdminTabsMixin, CounterTabsMixin
from counter.models import Counter, ProductType
from stock.models import Stock, StockItem, ShoppingList, ShoppingListItem
@ -47,23 +60,26 @@ class StockItemList(CounterAdminTabsMixin, CanCreateMixin, ListView):
"""
The stockitems list view for the counter owner
"""
model = Stock
template_name = 'stock/stock_item_list.jinja'
template_name = "stock/stock_item_list.jinja"
pk_url_kwarg = "stock_id"
current_tab = "stocks"
def get_context_data(self):
ret = super(StockItemList, self).get_context_data()
if 'stock_id' in self.kwargs.keys():
ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first();
if "stock_id" in self.kwargs.keys():
ret["stock"] = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
return ret
class StockListView(CounterAdminTabsMixin, CanViewMixin, ListView):
"""
A list view for the admins
"""
model = Stock
template_name = 'stock/stock_list.jinja'
template_name = "stock/stock_list.jinja"
current_tab = "stocks"
@ -71,9 +87,10 @@ class StockEditForm(forms.ModelForm):
"""
A form to change stock's characteristics
"""
class Meta:
model = Stock
fields = ['name', 'counter']
fields = ["name", "counter"]
def __init__(self, *args, **kwargs):
super(StockEditForm, self).__init__(*args, **kwargs)
@ -86,10 +103,11 @@ class StockEditView(CounterAdminTabsMixin, CanEditPropMixin, UpdateView):
"""
An edit view for the stock
"""
model = Stock
form_class = modelform_factory(Stock, fields=['name', 'counter'])
form_class = modelform_factory(Stock, fields=["name", "counter"])
pk_url_kwarg = "stock_id"
template_name = 'core/edit.jinja'
template_name = "core/edit.jinja"
current_tab = "stocks"
@ -97,10 +115,21 @@ class StockItemEditView(CounterAdminTabsMixin, CanEditPropMixin, UpdateView):
"""
An edit view for a stock item
"""
model = StockItem
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'minimal_quantity', 'type', 'stock_owner'])
form_class = modelform_factory(
StockItem,
fields=[
"name",
"unit_quantity",
"effective_quantity",
"minimal_quantity",
"type",
"stock_owner",
],
)
pk_url_kwarg = "item_id"
template_name = 'core/edit.jinja'
template_name = "core/edit.jinja"
current_tab = "stocks"
@ -108,43 +137,59 @@ class StockCreateView(CounterAdminTabsMixin, CanCreateMixin, CreateView):
"""
A create view for a new Stock
"""
model = Stock
form_class = modelform_factory(Stock, fields=['name', 'counter'])
template_name = 'core/create.jinja'
form_class = modelform_factory(Stock, fields=["name", "counter"])
template_name = "core/create.jinja"
pk_url_kwarg = "counter_id"
current_tab = "stocks"
success_url = reverse_lazy('stock:list')
success_url = reverse_lazy("stock:list")
def get_initial(self):
ret = super(StockCreateView, self).get_initial()
if 'counter_id' in self.kwargs.keys():
ret['counter'] = self.kwargs['counter_id']
if "counter_id" in self.kwargs.keys():
ret["counter"] = self.kwargs["counter_id"]
return ret
class StockItemCreateView(CounterAdminTabsMixin, CanCreateMixin, CreateView):
"""
A create view for a new StockItem
"""
model = StockItem
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'minimal_quantity', 'type', 'stock_owner'])
template_name = 'core/create.jinja'
form_class = modelform_factory(
StockItem,
fields=[
"name",
"unit_quantity",
"effective_quantity",
"minimal_quantity",
"type",
"stock_owner",
],
)
template_name = "core/create.jinja"
pk_url_kwarg = "stock_id"
current_tab = "stocks"
def get_initial(self):
ret = super(StockItemCreateView, self).get_initial()
if 'stock_id' in self.kwargs.keys():
ret['stock_owner'] = self.kwargs['stock_id']
if "stock_id" in self.kwargs.keys():
ret["stock_owner"] = self.kwargs["stock_id"]
return ret
def get_success_url(self):
return reverse_lazy('stock:items_list', kwargs={'stock_id':self.object.stock_owner.id})
return reverse_lazy(
"stock:items_list", kwargs={"stock_id": self.object.stock_owner.id}
)
class StockShoppingListView(CounterAdminTabsMixin, CanViewMixin, ListView):
"""
A list view for the people to know the item to buy
"""
model = Stock
template_name = "stock/stock_shopping_list.jinja"
pk_url_kwarg = "stock_id"
@ -152,8 +197,8 @@ class StockShoppingListView(CounterAdminTabsMixin, CanViewMixin, ListView):
def get_context_data(self):
ret = super(StockShoppingListView, self).get_context_data()
if 'stock_id' in self.kwargs.keys():
ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first();
if "stock_id" in self.kwargs.keys():
ret["stock"] = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
return ret
@ -161,32 +206,45 @@ class StockItemQuantityForm(forms.BaseForm):
def clean(self):
with transaction.atomic():
self.stock = Stock.objects.filter(id=self.stock_id).first()
shopping_list = ShoppingList(name="Courses "+self.stock.counter.name, date=timezone.now(), todo=True)
shopping_list = ShoppingList(
name="Courses " + self.stock.counter.name,
date=timezone.now(),
todo=True,
)
shopping_list.save()
shopping_list.stock_owner = self.stock
shopping_list.save()
for k,t in self.cleaned_data.items():
if k == 'name':
for k, t in self.cleaned_data.items():
if k == "name":
shopping_list.name = t
shopping_list.save()
elif k == "comment":
shopping_list.comment = t
shopping_list.save()
else:
if t > 0 :
if t > 0:
item_id = int(k[5:])
item = StockItem.objects.filter(id=item_id).first()
shoppinglist_item = ShoppingListItem(stockitem_owner=item, name=item.name, type=item.type, tobuy_quantity=t)
shoppinglist_item = ShoppingListItem(
stockitem_owner=item,
name=item.name,
type=item.type,
tobuy_quantity=t,
)
shoppinglist_item.save()
shoppinglist_item.shopping_lists.add(shopping_list)
shoppinglist_item.save()
return self.cleaned_data
class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView):
class StockItemQuantityBaseFormView(
CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView
):
"""
docstring for StockItemOutList
"""
model = StockItem
template_name = "stock/shopping_list_quantity.jinja"
pk_url_kwarg = "stock_id"
@ -195,24 +253,39 @@ class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailV
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
fields['name'] = forms.CharField(max_length=30, required=True, label=_('Shopping list name'))
for t in ProductType.objects.order_by('name').all():
for i in self.stock.items.filter(type=t).order_by('name').all():
fields["name"] = forms.CharField(
max_length=30, required=True, label=_("Shopping list name")
)
for t in ProductType.objects.order_by("name").all():
for i in self.stock.items.filter(type=t).order_by("name").all():
if i.effective_quantity <= i.minimal_quantity:
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.IntegerField(required=True, label=str(i), initial=0,
help_text=_(str(i.effective_quantity)+" left"))
fields['comment'] = forms.CharField(widget=forms.Textarea(attrs={"placeholder":_("Add here, items to buy that are not reference as a stock item (example : sponge, knife, mugs ...)")}),
required=False, label=_("Comments"))
kwargs['stock_id'] = self.stock.id
kwargs['base_fields'] = fields
return type('StockItemQuantityForm', (StockItemQuantityForm,), kwargs)
fields[field_name] = forms.IntegerField(
required=True,
label=str(i),
initial=0,
help_text=_(str(i.effective_quantity) + " left"),
)
fields["comment"] = forms.CharField(
widget=forms.Textarea(
attrs={
"placeholder": _(
"Add here, items to buy that are not reference as a stock item (example : sponge, knife, mugs ...)"
)
}
),
required=False,
label=_("Comments"),
)
kwargs["stock_id"] = self.stock.id
kwargs["base_fields"] = fields
return type("StockItemQuantityForm", (StockItemQuantityForm,), kwargs)
def get(self, request, *args, **kwargs):
"""
Simple get view
"""
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
self.stock = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
return super(StockItemQuantityBaseFormView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
@ -220,7 +293,7 @@ class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailV
Handle the many possibilities of the post request
"""
self.object = self.get_object()
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
self.stock = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
return super(StockItemQuantityBaseFormView, self).post(request, *args, **kwargs)
def form_valid(self, form):
@ -228,17 +301,20 @@ class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailV
def get_context_data(self, **kwargs):
kwargs = super(StockItemQuantityBaseFormView, self).get_context_data(**kwargs)
if 'form' not in kwargs.keys():
kwargs['form'] = self.get_form()
kwargs['stock'] = self.stock
if "form" not in kwargs.keys():
kwargs["form"] = self.get_form()
kwargs["stock"] = self.stock
return kwargs
def get_success_url(self):
return reverse_lazy('stock:shoppinglist_list', args=self.args, kwargs=self.kwargs)
return reverse_lazy(
"stock:shoppinglist_list", args=self.args, kwargs=self.kwargs
)
class StockShoppingListItemListView(CounterAdminTabsMixin, CanViewMixin, ListView):
"""docstring for StockShoppingListItemListView"""
model = ShoppingList
template_name = "stock/shopping_list_items.jinja"
pk_url_kwarg = "shoppinglist_id"
@ -246,27 +322,34 @@ class StockShoppingListItemListView(CounterAdminTabsMixin, CanViewMixin, ListVie
def get_context_data(self):
ret = super(StockShoppingListItemListView, self).get_context_data()
if 'shoppinglist_id' in self.kwargs.keys():
ret['shoppinglist'] = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first();
if "shoppinglist_id" in self.kwargs.keys():
ret["shoppinglist"] = ShoppingList.objects.filter(
id=self.kwargs["shoppinglist_id"]
).first()
return ret
class StockShoppingListDeleteView(CounterAdminTabsMixin, CanEditMixin, DeleteView):
"""
Delete a ShoppingList (for the resonsible account)
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
template_name = 'core/delete_confirm.jinja'
template_name = "core/delete_confirm.jinja"
current_tab = "stocks"
def get_success_url(self):
return reverse_lazy('stock:shoppinglist_list', kwargs={'stock_id':self.object.stock_owner.id})
return reverse_lazy(
"stock:shoppinglist_list", kwargs={"stock_id": self.object.stock_owner.id}
)
class StockShopppingListSetDone(CanEditMixin, DetailView):
"""
Set a ShoppingList as done
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
@ -274,17 +357,30 @@ class StockShopppingListSetDone(CanEditMixin, DetailView):
self.object = self.get_object()
self.object.todo = False
self.object.save()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
return HttpResponseRedirect(
reverse(
"stock:shoppinglist_list",
args=self.args,
kwargs={"stock_id": self.object.stock_owner.id},
)
)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
return HttpResponseRedirect(
reverse(
"stock:shoppinglist_list",
args=self.args,
kwargs={"stock_id": self.object.stock_owner.id},
)
)
class StockShopppingListSetTodo(CanEditMixin, DetailView):
"""
Set a ShoppingList as done
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
@ -292,21 +388,37 @@ class StockShopppingListSetTodo(CanEditMixin, DetailView):
self.object = self.get_object()
self.object.todo = True
self.object.save()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
return HttpResponseRedirect(
reverse(
"stock:shoppinglist_list",
args=self.args,
kwargs={"stock_id": self.object.stock_owner.id},
)
)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
return HttpResponseRedirect(
reverse(
"stock:shoppinglist_list",
args=self.args,
kwargs={"stock_id": self.object.stock_owner.id},
)
)
class StockUpdateAfterShopppingForm(forms.BaseForm):
def clean(self):
with transaction.atomic():
self.shoppinglist = ShoppingList.objects.filter(id=self.shoppinglist_id).first()
for k,t in self.cleaned_data.items():
self.shoppinglist = ShoppingList.objects.filter(
id=self.shoppinglist_id
).first()
for k, t in self.cleaned_data.items():
shoppinglist_item_id = int(k[5:])
if int(t) > 0 :
shoppinglist_item = ShoppingListItem.objects.filter(id=shoppinglist_item_id).first()
if int(t) > 0:
shoppinglist_item = ShoppingListItem.objects.filter(
id=shoppinglist_item_id
).first()
shoppinglist_item.bought_quantity = int(t)
shoppinglist_item.save()
shoppinglist_item.stockitem_owner.effective_quantity += int(t)
@ -315,10 +427,14 @@ class StockUpdateAfterShopppingForm(forms.BaseForm):
self.shoppinglist.save()
return self.cleaned_data
class StockUpdateAfterShopppingBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView):
class StockUpdateAfterShopppingBaseFormView(
CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView
):
"""
docstring for StockUpdateAfterShopppingBaseFormView
"""
model = ShoppingList
template_name = "stock/update_after_shopping.jinja"
pk_url_kwarg = "shoppinglist_id"
@ -327,26 +443,44 @@ class StockUpdateAfterShopppingBaseFormView(CounterAdminTabsMixin, CanEditMixin,
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
for t in ProductType.objects.order_by('name').all():
for i in self.shoppinglist.shopping_items_to_buy.filter(type=t).order_by('name').all():
for t in ProductType.objects.order_by("name").all():
for i in (
self.shoppinglist.shopping_items_to_buy.filter(type=t)
.order_by("name")
.all()
):
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.CharField(max_length=30, required=True, label=str(i),
help_text=_(str(i.tobuy_quantity) + " asked"))
kwargs['shoppinglist_id'] = self.shoppinglist.id
kwargs['base_fields'] = fields
return type('StockUpdateAfterShopppingForm', (StockUpdateAfterShopppingForm,), kwargs)
fields[field_name] = forms.CharField(
max_length=30,
required=True,
label=str(i),
help_text=_(str(i.tobuy_quantity) + " asked"),
)
kwargs["shoppinglist_id"] = self.shoppinglist.id
kwargs["base_fields"] = fields
return type(
"StockUpdateAfterShopppingForm", (StockUpdateAfterShopppingForm,), kwargs
)
def get(self, request, *args, **kwargs):
self.shoppinglist = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first()
return super(StockUpdateAfterShopppingBaseFormView, self).get(request, *args, **kwargs)
self.shoppinglist = ShoppingList.objects.filter(
id=self.kwargs["shoppinglist_id"]
).first()
return super(StockUpdateAfterShopppingBaseFormView, self).get(
request, *args, **kwargs
)
def post(self, request, *args, **kwargs):
"""
Handle the many possibilities of the post request
"""
self.object = self.get_object()
self.shoppinglist = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first()
return super(StockUpdateAfterShopppingBaseFormView, self).post(request, *args, **kwargs)
self.shoppinglist = ShoppingList.objects.filter(
id=self.kwargs["shoppinglist_id"]
).first()
return super(StockUpdateAfterShopppingBaseFormView, self).post(
request, *args, **kwargs
)
def form_valid(self, form):
"""
@ -355,37 +489,45 @@ class StockUpdateAfterShopppingBaseFormView(CounterAdminTabsMixin, CanEditMixin,
return super(StockUpdateAfterShopppingBaseFormView, self).form_valid(form)
def get_context_data(self, **kwargs):
kwargs = super(StockUpdateAfterShopppingBaseFormView, self).get_context_data(**kwargs)
if 'form' not in kwargs.keys():
kwargs['form'] = self.get_form()
kwargs['shoppinglist'] = self.shoppinglist
kwargs['stock'] = self.shoppinglist.stock_owner
kwargs = super(StockUpdateAfterShopppingBaseFormView, self).get_context_data(
**kwargs
)
if "form" not in kwargs.keys():
kwargs["form"] = self.get_form()
kwargs["shoppinglist"] = self.shoppinglist
kwargs["stock"] = self.shoppinglist.stock_owner
return kwargs
def get_success_url(self):
self.kwargs.pop('shoppinglist_id', None)
return reverse_lazy('stock:shoppinglist_list', args=self.args, kwargs=self.kwargs)
self.kwargs.pop("shoppinglist_id", None)
return reverse_lazy(
"stock:shoppinglist_list", args=self.args, kwargs=self.kwargs
)
class StockTakeItemsForm(forms.BaseForm):
"""
docstring for StockTakeItemsFormView
"""
def clean(self):
with transaction.atomic():
for k,t in self.cleaned_data.items():
for k, t in self.cleaned_data.items():
item_id = int(k[5:])
if t > 0 :
if t > 0:
item = StockItem.objects.filter(id=item_id).first()
item.effective_quantity -= t
item.save()
return self.cleaned_data
class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, BaseFormView):
class StockTakeItemsBaseFormView(
CounterTabsMixin, CanEditMixin, DetailView, BaseFormView
):
"""
docstring for StockTakeItemsBaseFormView
"""
model = StockItem
template_name = "stock/stock_take_items.jinja"
pk_url_kwarg = "stock_id"
@ -394,22 +536,31 @@ class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, Bas
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
for t in ProductType.objects.order_by('name').all():
for i in self.stock.items.filter(type=t).order_by('name').all():
for t in ProductType.objects.order_by("name").all():
for i in self.stock.items.filter(type=t).order_by("name").all():
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.IntegerField(required=False, label=str(i), initial=0, min_value=0, max_value=i.effective_quantity,
help_text=_("%(effective_quantity)s left" % {"effective_quantity": str(i.effective_quantity)}))
fields[field_name] = forms.IntegerField(
required=False,
label=str(i),
initial=0,
min_value=0,
max_value=i.effective_quantity,
help_text=_(
"%(effective_quantity)s left"
% {"effective_quantity": str(i.effective_quantity)}
),
)
kwargs[field_name] = i.effective_quantity
kwargs['stock_id'] = self.stock.id
kwargs['counter_id'] = self.stock.counter.id
kwargs['base_fields'] = fields
return type('StockTakeItemsForm', (StockTakeItemsForm,), kwargs)
kwargs["stock_id"] = self.stock.id
kwargs["counter_id"] = self.stock.counter.id
kwargs["base_fields"] = fields
return type("StockTakeItemsForm", (StockTakeItemsForm,), kwargs)
def get(self, request, *args, **kwargs):
"""
Simple get view
"""
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
self.stock = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
return super(StockTakeItemsBaseFormView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
@ -417,11 +568,19 @@ class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, Bas
Handle the many possibilities of the post request
"""
self.object = self.get_object()
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
if self.stock.counter.type == "BAR" and not ('counter_token' in self.request.session.keys() and
self.request.session['counter_token'] == self.stock.counter.token): # Also check the token to avoid the bar to be stolen
return HttpResponseRedirect(reverse_lazy('counter:details', args=self.args,
kwargs={'counter_id': self.stock.counter.id})+'?bad_location')
self.stock = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
if self.stock.counter.type == "BAR" and not (
"counter_token" in self.request.session.keys()
and self.request.session["counter_token"] == self.stock.counter.token
): # Also check the token to avoid the bar to be stolen
return HttpResponseRedirect(
reverse_lazy(
"counter:details",
args=self.args,
kwargs={"counter_id": self.stock.counter.id},
)
+ "?bad_location"
)
return super(StockTakeItemsBaseFormView, self).post(request, *args, **kwargs)
def form_valid(self, form):
@ -429,14 +588,14 @@ class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, Bas
def get_context_data(self, **kwargs):
kwargs = super(StockTakeItemsBaseFormView, self).get_context_data(**kwargs)
if 'form' not in kwargs.keys():
kwargs['form'] = self.get_form()
kwargs['stock'] = self.stock
kwargs['counter'] = self.stock.counter
if "form" not in kwargs.keys():
kwargs["form"] = self.get_form()
kwargs["stock"] = self.stock
kwargs["counter"] = self.stock.counter
return kwargs
def get_success_url(self):
stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
self.kwargs['counter_id'] = stock.counter.id
self.kwargs.pop('stock_id', None)
return reverse_lazy('counter:details', args=self.args, kwargs=self.kwargs)
stock = Stock.objects.filter(id=self.kwargs["stock_id"]).first()
self.kwargs["counter_id"] = stock.counter.id
self.kwargs.pop("stock_id", None)
return reverse_lazy("counter:details", args=self.args, kwargs=self.kwargs)