From 39b102d8aaeff0f1c587935ce242e6dc18bac58a Mon Sep 17 00:00:00 2001
From: Skia
Date: Mon, 27 Feb 2017 15:40:48 +0100
Subject: [PATCH 01/10] README: add counting lines of code
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index e3770b20..d1cbea94 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,12 @@ Finally, when building a class based view, which is highly advised, you just hav
CanEditMixin, or CanViewMixin, which are located in core.views. Your view will then be protected using either the
appropriate group fields, or the right method to check user permissions.
+#### Counting the number of line of code
+
+```
+# apt install cloc
+$ cloc --exclude-dir=doc,env .
+```
From 158a140aa4b07a16335fbf3612d41990fa450913 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Wed, 1 Mar 2017 10:21:57 +0100
Subject: [PATCH 02/10] No negative values for cash summary
---
counter/views.py | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/counter/views.py b/counter/views.py
index 6962e2f3..ed97a84e 100644
--- a/counter/views.py
+++ b/counter/views.py
@@ -688,26 +688,26 @@ class CashRegisterSummaryForm(forms.Form):
"""
Provide the cash summary form
"""
- ten_cents = forms.IntegerField(label=_("10 cents"), required=False)
- twenty_cents = forms.IntegerField(label=_("20 cents"), required=False)
- fifty_cents = forms.IntegerField(label=_("50 cents"), required=False)
- one_euro = forms.IntegerField(label=_("1 euro"), required=False)
- two_euros = forms.IntegerField(label=_("2 euros"), required=False)
- five_euros = forms.IntegerField(label=_("5 euros"), required=False)
- ten_euros = forms.IntegerField(label=_("10 euros"), required=False)
- twenty_euros = forms.IntegerField(label=_("20 euros"), required=False)
- fifty_euros = forms.IntegerField(label=_("50 euros"), required=False)
- hundred_euros = forms.IntegerField(label=_("100 euros"), required=False)
- check_1_value = forms.DecimalField(label=_("Check amount"), required=False)
- check_1_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
- check_2_value = forms.DecimalField(label=_("Check amount"), required=False)
- check_2_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
- check_3_value = forms.DecimalField(label=_("Check amount"), required=False)
- check_3_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
- check_4_value = forms.DecimalField(label=_("Check amount"), required=False)
- check_4_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
- check_5_value = forms.DecimalField(label=_("Check amount"), required=False)
- check_5_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
+ ten_cents = forms.IntegerField(label=_("10 cents"), required=False, min_value=0)
+ twenty_cents = forms.IntegerField(label=_("20 cents"), required=False, min_value=0)
+ fifty_cents = forms.IntegerField(label=_("50 cents"), required=False, min_value=0)
+ one_euro = forms.IntegerField(label=_("1 euro"), required=False, min_value=0)
+ two_euros = forms.IntegerField(label=_("2 euros"), required=False, min_value=0)
+ five_euros = forms.IntegerField(label=_("5 euros"), required=False, min_value=0)
+ ten_euros = forms.IntegerField(label=_("10 euros"), required=False, min_value=0)
+ twenty_euros = forms.IntegerField(label=_("20 euros"), required=False, min_value=0)
+ fifty_euros = forms.IntegerField(label=_("50 euros"), required=False, min_value=0)
+ hundred_euros = forms.IntegerField(label=_("100 euros"), required=False, min_value=0)
+ check_1_value = forms.DecimalField(label=_("Check amount"), required=False, min_value=0)
+ check_1_quantity = forms.IntegerField(label=_("Check quantity"), required=False, min_value=0)
+ check_2_value = forms.DecimalField(label=_("Check amount"), required=False, min_value=0)
+ check_2_quantity = forms.IntegerField(label=_("Check quantity"), required=False, min_value=0)
+ check_3_value = forms.DecimalField(label=_("Check amount"), required=False, min_value=0)
+ check_3_quantity = forms.IntegerField(label=_("Check quantity"), required=False, min_value=0)
+ check_4_value = forms.DecimalField(label=_("Check amount"), required=False, min_value=0)
+ check_4_quantity = forms.IntegerField(label=_("Check quantity"), required=False, min_value=0)
+ check_5_value = forms.DecimalField(label=_("Check amount"), required=False, min_value=0)
+ check_5_quantity = forms.IntegerField(label=_("Check quantity"), required=False, min_value=0)
comment = forms.CharField(label=_("Comment"), required=False)
emptied = forms.BooleanField(label=_("Emptied"), required=False)
From 95f984824aeef332f42f91b012827e5c475e6f83 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Wed, 8 Mar 2017 13:25:23 +0100
Subject: [PATCH 03/10] Fix accents in wiki page name and allow to delete a
page
---
core/models.py | 22 ++++++++++++++++++++--
core/templates/core/pagerev_edit.jinja | 1 +
core/urls.py | 1 +
core/views/page.py | 11 ++++++++++-
4 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/core/models.py b/core/models.py
index 92e65a85..c1ff10ee 100644
--- a/core/models.py
+++ b/core/models.py
@@ -736,9 +736,9 @@ class Page(models.Model):
name = models.CharField(_('page unix name'), max_length=30,
validators=[
validators.RegexValidator(
- r'^[\w.+-]+$',
+ r'^[A-z.+-]+$',
_('Enter a valid page name. This value may contain only '
- 'letters, numbers ' 'and ./+/-/_ characters.')
+ 'unaccented letters, numbers ' 'and ./+/-/_ characters.')
),
],
blank=False)
@@ -846,6 +846,14 @@ class Page(models.Model):
p.set_lock_recursive(user)
self.set_lock(user)
+ def unset_lock_recursive(self):
+ """
+ Unlocks recursively all the child pages
+ """
+ for p in self.children.all():
+ p.unset_lock_recursive()
+ self.unset_lock()
+
def unset_lock(self):
"""Always try to unlock, even if there is no lock"""
self.lock_user = None
@@ -886,6 +894,16 @@ class Page(models.Model):
except:
return self.name
+ def delete(self):
+ self.unset_lock_recursive()
+ self.set_lock_recursive(User.objects.get(id=0))
+ for child in self.children.all():
+ child.parent = self.parent
+ child.save()
+ child.unset_lock_recursive()
+ super(Page, self).delete()
+
+
class PageRev(models.Model):
"""
This is the true content of the page.
diff --git a/core/templates/core/pagerev_edit.jinja b/core/templates/core/pagerev_edit.jinja
index ca9b41df..52f90edb 100644
--- a/core/templates/core/pagerev_edit.jinja
+++ b/core/templates/core/pagerev_edit.jinja
@@ -23,6 +23,7 @@ function make_preview() {
+{% trans %}Delete{% endtrans %}
{% endblock %}
diff --git a/core/urls.py b/core/urls.py
index 2f471195..e8e2d4d0 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -61,6 +61,7 @@ urlpatterns = [
# Page views
url(r'^page/$', PageListView.as_view(), name='page_list'),
url(r'^page/create$', PageCreateView.as_view(), name='page_new'),
+ url(r'^page/(?P[0-9]*)/delete$', PageDeleteView.as_view(), name='page_delete'),
url(r'^page/(?P[a-z0-9/-_]*)/edit$', PageEditView.as_view(), name='page_edit'),
url(r'^page/(?P[a-z0-9/-_]*)/prop$', PagePropView.as_view(), name='page_prop'),
url(r'^page/(?P[a-z0-9/-_]*)/hist$', PageHistView.as_view(), name='page_hist'),
diff --git a/core/views/page.py b/core/views/page.py
index e7a48d97..a130753f 100644
--- a/core/views/page.py
+++ b/core/views/page.py
@@ -1,7 +1,8 @@
# This file contains all the views that concern the page model
from django.shortcuts import render, redirect, get_object_or_404
+from django.core.urlresolvers import reverse_lazy
from django.views.generic import ListView, DetailView
-from django.views.generic.edit import UpdateView, CreateView
+from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.decorators import method_decorator
from django.forms.models import modelform_factory
@@ -159,3 +160,11 @@ class PageEditView(CanEditMixin, UpdateView):
form.instance = new_rev
return super(PageEditView, self).form_valid(form)
+
+class PageDeleteView(CanEditPropMixin, DeleteView):
+ model = Page
+ template_name = 'core/delete_confirm.jinja'
+ pk_url_kwarg = 'page_id'
+
+ def get_success_url(self, **kwargs):
+ return reverse_lazy('core:page_list')
From 554929b4ec0cbc37fe4f90675e74b90f3644d8d9 Mon Sep 17 00:00:00 2001
From: Krophil
Date: Sun, 5 Feb 2017 15:22:52 +0100
Subject: [PATCH 04/10] small fix in canViewList
---
core/views/__init__.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/core/views/__init__.py b/core/views/__init__.py
index eaa08760..12c45c11 100644
--- a/core/views/__init__.py
+++ b/core/views/__init__.py
@@ -4,6 +4,7 @@ from django.shortcuts import render
from django.http import HttpResponseForbidden, HttpResponseNotFound
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured
from django.views.generic.base import View
+from django.db.models import Count
from core.models import Group
from core.views.forms import LoginForm
@@ -110,7 +111,7 @@ class CanViewMixin(View):
except: pass
# If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_view(o, request.user)]
- if not l_id:
+ if ((not l_id) and self.get_queryset().count() != 0):
raise PermissionDenied
self._get_queryset = self.get_queryset
def get_qs(self2):
From 8133db804ef9fc678d74e1b5937b34071c55c4c2 Mon Sep 17 00:00:00 2001
From: Krophil
Date: Sun, 5 Feb 2017 15:50:42 +0100
Subject: [PATCH 05/10] fix permission for companies
---
accounting/models.py | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/accounting/models.py b/accounting/models.py
index 7338e907..8b0be338 100644
--- a/accounting/models.py
+++ b/accounting/models.py
@@ -45,6 +45,32 @@ class Company(models.Model):
class Meta:
verbose_name = _("company")
+ def is_owned_by(self, user):
+ """
+ Method to see if that object can be edited by the given user
+ """
+ if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
+ return True
+ return False
+
+ def can_be_edited_by(self, user):
+ """
+ Method to see if that object can be edited by the given user
+ """
+ for club in user.memberships.filter(end_date=None).all():
+ if club and club.role == 7:
+ return True
+ return False
+
+ def can_be_viewed_by(self, user):
+ """
+ Method to see if that object can be viewed by the given user
+ """
+ for club in user.memberships.filter(end_date=None).all():
+ if club and club.role >= 7:
+ return True
+ return False
+
def get_absolute_url(self):
return reverse('accounting:co_edit', kwargs={'co_id': self.id})
From 1acac17d7ec7c8e7dabf9adc2ad75a42c4beccee Mon Sep 17 00:00:00 2001
From: Krophil
Date: Sun, 5 Feb 2017 17:26:04 +0100
Subject: [PATCH 06/10] Several modifications in accounting
---
accounting/models.py | 2 +-
.../templates/accounting/bank_account_details.jinja | 3 ++-
.../templates/accounting/club_account_details.jinja | 8 +++++++-
accounting/templates/accounting/journal_details.jinja | 2 ++
accounting/templates/accounting/label_list.jinja | 7 ++++++-
accounting/urls.py | 1 +
accounting/views.py | 9 +++++++++
7 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/accounting/models.py b/accounting/models.py
index 8b0be338..6dbf56d8 100644
--- a/accounting/models.py
+++ b/accounting/models.py
@@ -218,7 +218,7 @@ class Operation(models.Model):
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal"))
amount = CurrencyField(_('amount'))
date = models.DateField(_('date'))
- remark = models.CharField(_('comment'), max_length=128)
+ remark = models.CharField(_('comment'), max_length=128, default="", null=True, blank=True)
mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD)
cheque_number = models.CharField(_('cheque number'), max_length=32, default="", null=True, blank=True)
invoice = models.ForeignKey(SithFile, related_name='operations', verbose_name=_("invoice"), null=True, blank=True)
diff --git a/accounting/templates/accounting/bank_account_details.jinja b/accounting/templates/accounting/bank_account_details.jinja
index 076d2753..95981b1b 100644
--- a/accounting/templates/accounting/bank_account_details.jinja
+++ b/accounting/templates/accounting/bank_account_details.jinja
@@ -11,7 +11,7 @@
{% trans %}Bank account: {% endtrans %}{{ object.name }}
- {% if user.is_root and not object.club_accounts.exists() %}
+ {% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %}
{% trans %}Delete{% endtrans %}
{% endif %}
{% trans %}Infos{% endtrans %}
@@ -24,6 +24,7 @@
{% for c in object.club_accounts.all() %}
diff --git a/accounting/urls.py b/accounting/urls.py
index 3255cb9d..2a3727fa 100644
--- a/accounting/urls.py
+++ b/accounting/urls.py
@@ -26,6 +26,7 @@ urlpatterns = [
url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'),
url(r'^journal/(?P[0-9]+)$', JournalDetailView.as_view(), name='journal_details'),
url(r'^journal/(?P[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'),
+ url(r'^journal/(?P[0-9]+)/delete$', JournalDeleteView.as_view(), name='journal_delete'),
url(r'^journal/(?P[0-9]+)/statement/nature$', JournalNatureStatementView.as_view(), name='journal_nature_statement'),
url(r'^journal/(?P[0-9]+)/statement/person$', JournalPersonStatementView.as_view(), name='journal_person_statement'),
url(r'^journal/(?P[0-9]+)/statement/accounting$', JournalAccountingStatementView.as_view(), name='journal_accounting_statement'),
diff --git a/accounting/views.py b/accounting/views.py
index c50b1f6b..8ea2c3c1 100644
--- a/accounting/views.py
+++ b/accounting/views.py
@@ -230,6 +230,15 @@ class JournalEditView(CanEditMixin, UpdateView):
fields = ['name', 'start_date', 'end_date', 'club_account', 'closed']
template_name = 'core/edit.jinja'
+class JournalDeleteView(CanEditPropMixin, DeleteView):
+ """
+ Delete a club account (for the admins)
+ """
+ model = GeneralJournal
+ pk_url_kwarg = "j_id"
+ template_name = 'core/delete_confirm.jinja'
+ success_url = reverse_lazy('accounting:club_details')
+
# Operation views
From 6c8671c160360863eac073db9463bfe54aa448bc Mon Sep 17 00:00:00 2001
From: klmp200
Date: Mon, 6 Feb 2017 16:50:11 +0100
Subject: [PATCH 07/10] Better club roles in settings
---
sith/settings.py | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/sith/settings.py b/sith/settings.py
index 24b0ea62..472e464a 100644
--- a/sith/settings.py
+++ b/sith/settings.py
@@ -423,17 +423,22 @@ SITH_SUBSCRIPTIONS = {
# To be completed....
}
-SITH_CLUB_ROLES = {
- 10: _('President'),
- 9: _('Vice-President'),
- 7: _('Treasurer'),
- 5: _('Communication supervisor'),
- 4: _('Secretary'),
- 3: _('IT supervisor'),
- 2: _('Board member'),
- 1: _('Active member'),
- 0: _('Curious'),
- }
+SITH_CLUB_ROLES = {}
+
+SITH_CLUB_ROLES_ID = {
+ 'President': 10,
+ 'Vice-President': 9,
+ 'Treasurer': 7,
+ 'Communication supervisor': 5,
+ 'Secretary': 4,
+ 'IT supervisor': 3,
+ 'Board member': 2,
+ 'Active member': 1,
+ 'Curious': 0,
+}
+
+for role in SITH_CLUB_ROLES_ID:
+ SITH_CLUB_ROLES[SITH_CLUB_ROLES_ID[role]] = _(role)
# This corresponds to the maximum role a user can freely subscribe to
# In this case, SITH_MAXIMUM_FREE_ROLE=1 means that a user can set himself as "Membre actif" or "Curieux", but not higher
From 95775d3b9bef34f1046ecb1dea0b09b8ad766b9c Mon Sep 17 00:00:00 2001
From: Krophil
Date: Mon, 6 Feb 2017 22:18:44 +0100
Subject: [PATCH 08/10] adaptations for settings and deletion checked
---
accounting/models.py | 12 ++++++------
.../templates/accounting/bank_account_details.jinja | 2 ++
.../templates/accounting/club_account_details.jinja | 2 +-
core/views/__init__.py | 6 +++---
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/accounting/models.py b/accounting/models.py
index 6dbf56d8..7371bff0 100644
--- a/accounting/models.py
+++ b/accounting/models.py
@@ -58,7 +58,7 @@ class Company(models.Model):
Method to see if that object can be edited by the given user
"""
for club in user.memberships.filter(end_date=None).all():
- if club and club.role == 7:
+ if club and club.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -67,7 +67,7 @@ class Company(models.Model):
Method to see if that object can be viewed by the given user
"""
for club in user.memberships.filter(end_date=None).all():
- if club and club.role >= 7:
+ if club and club.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -97,7 +97,7 @@ class BankAccount(models.Model):
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True
m = self.club.get_membership_for(user)
- if m is not None and m.role >= 7:
+ if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -129,7 +129,7 @@ class ClubAccount(models.Model):
Method to see if that object can be edited by the given user
"""
m = self.club.get_membership_for(user)
- if m and m.role == 7:
+ if m and m.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -138,7 +138,7 @@ class ClubAccount(models.Model):
Method to see if that object can be viewed by the given user
"""
m = self.club.get_membership_for(user)
- if m and m.role >= 7:
+ if m and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -218,7 +218,7 @@ class Operation(models.Model):
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal"))
amount = CurrencyField(_('amount'))
date = models.DateField(_('date'))
- remark = models.CharField(_('comment'), max_length=128, default="", null=True, blank=True)
+ remark = models.CharField(_('comment'), max_length=128, null=True, blank=True)
mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD)
cheque_number = models.CharField(_('cheque number'), max_length=32, default="", null=True, blank=True)
invoice = models.ForeignKey(SithFile, related_name='operations', verbose_name=_("invoice"), null=True, blank=True)
diff --git a/accounting/templates/accounting/bank_account_details.jinja b/accounting/templates/accounting/bank_account_details.jinja
index 95981b1b..cd968322 100644
--- a/accounting/templates/accounting/bank_account_details.jinja
+++ b/accounting/templates/accounting/bank_account_details.jinja
@@ -24,7 +24,9 @@
{% for c in object.club_accounts.all() %}
diff --git a/core/views/__init__.py b/core/views/__init__.py
index 12c45c11..c0a613bc 100644
--- a/core/views/__init__.py
+++ b/core/views/__init__.py
@@ -67,7 +67,7 @@ class CanEditPropMixin(View):
except: pass
# If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_edit_prop(o, request.user)]
- if not l_id:
+ if not l_id and self.get_queryset().count() != 0:
raise PermissionDenied
self._get_queryset = self.get_queryset
def get_qs(self2):
@@ -89,7 +89,7 @@ class CanEditMixin(View):
except: pass
# If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_edit(o, request.user)]
- if not l_id:
+ if not l_id and self.get_queryset().count() != 0:
raise PermissionDenied
self._get_queryset = self.get_queryset
def get_qs(self2):
@@ -111,7 +111,7 @@ class CanViewMixin(View):
except: pass
# If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_view(o, request.user)]
- if ((not l_id) and self.get_queryset().count() != 0):
+ if not l_id and self.get_queryset().count() != 0:
raise PermissionDenied
self._get_queryset = self.get_queryset
def get_qs(self2):
From 8329a19cc26a10359e5902caf398d906483e2891 Mon Sep 17 00:00:00 2001
From: Krophil
Date: Mon, 27 Feb 2017 01:09:50 +0100
Subject: [PATCH 09/10] fix permissions
---
accounting/models.py | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/accounting/models.py b/accounting/models.py
index 7371bff0..f4ea5c73 100644
--- a/accounting/models.py
+++ b/accounting/models.py
@@ -187,6 +187,16 @@ class GeneralJournal(models.Model):
return True
return False
+ def can_be_edited_by(self, user):
+ """
+ Method to see if that object can be edited by the given user
+ """
+ if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
+ return True
+ if self.club_account.can_be_edited_by(user):
+ return True
+ return False
+
def can_be_viewed_by(self, user):
return self.club_account.can_be_edited_by(user)
@@ -291,7 +301,7 @@ class Operation(models.Model):
if self.journal.closed:
return False
m = self.journal.club_account.club.get_membership_for(user)
- if m is not None and m.role >= 7:
+ if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
@@ -299,7 +309,12 @@ class Operation(models.Model):
"""
Method to see if that object can be edited by the given user
"""
- if self.is_owned_by(user):
+ if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
+ return True
+ if self.journal.closed:
+ return False
+ m = self.journal.club_account.club.get_membership_for(user)
+ if m is not None and m.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
From 0bf457de50f47782d0adccea4019b731f10ecc29 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sat, 11 Mar 2017 11:57:20 +0100
Subject: [PATCH 10/10] Hiding some already forbidden stuff
---
accounting/templates/accounting/co_list.jinja | 2 ++
1 file changed, 2 insertions(+)
diff --git a/accounting/templates/accounting/co_list.jinja b/accounting/templates/accounting/co_list.jinja
index 0cfbca70..e40ee2d8 100644
--- a/accounting/templates/accounting/co_list.jinja
+++ b/accounting/templates/accounting/co_list.jinja
@@ -5,7 +5,9 @@
{% endblock %}
{% block content %}
+{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %}