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 .
+```
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 %}
{% trans %}Create new company{% endtrans %}
+{% endif %}
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')
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)