Merge branch 'Tresorerie' into 'master'

Tresorerie

Many modifications linked to the issue #23

See merge request !48
This commit is contained in:
Skia 2017-03-12 23:05:44 +01:00
commit 3fd4d4b04b
10 changed files with 104 additions and 23 deletions

View File

@ -45,6 +45,32 @@ class Company(models.Model):
class Meta: class Meta:
verbose_name = _("company") 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 == settings.SITH_CLUB_ROLES_ID['Treasurer']:
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 >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
return True
return False
def get_absolute_url(self): def get_absolute_url(self):
return reverse('accounting:co_edit', kwargs={'co_id': self.id}) return reverse('accounting:co_edit', kwargs={'co_id': self.id})
@ -71,7 +97,7 @@ class BankAccount(models.Model):
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
m = self.club.get_membership_for(user) 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 True
return False return False
@ -103,7 +129,7 @@ class ClubAccount(models.Model):
Method to see if that object can be edited by the given user Method to see if that object can be edited by the given user
""" """
m = self.club.get_membership_for(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 True
return False return False
@ -112,7 +138,7 @@ class ClubAccount(models.Model):
Method to see if that object can be viewed by the given user Method to see if that object can be viewed by the given user
""" """
m = self.club.get_membership_for(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 True
return False return False
@ -161,6 +187,16 @@ class GeneralJournal(models.Model):
return True return True
return False 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): def can_be_viewed_by(self, user):
return self.club_account.can_be_edited_by(user) return self.club_account.can_be_edited_by(user)
@ -192,7 +228,7 @@ class Operation(models.Model):
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal")) journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal"))
amount = CurrencyField(_('amount')) amount = CurrencyField(_('amount'))
date = models.DateField(_('date')) date = models.DateField(_('date'))
remark = models.CharField(_('comment'), max_length=128) 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) 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) 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) invoice = models.ForeignKey(SithFile, related_name='operations', verbose_name=_("invoice"), null=True, blank=True)
@ -265,7 +301,7 @@ class Operation(models.Model):
if self.journal.closed: if self.journal.closed:
return False return False
m = self.journal.club_account.club.get_membership_for(user) 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 True
return False return False
@ -273,7 +309,12 @@ class Operation(models.Model):
""" """
Method to see if that object can be edited by the given user 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 True
return False return False

View File

@ -11,7 +11,7 @@
</p> </p>
<hr> <hr>
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2> <h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
{% 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() %}
<a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
<h4>{% trans %}Infos{% endtrans %}</h4> <h4>{% trans %}Infos{% endtrans %}</h4>
@ -24,6 +24,9 @@
{% for c in object.club_accounts.all() %} {% for c in object.club_accounts.all() %}
<li><a href="{{ url('accounting:club_details', c_account_id=c.id) }}">{{ c }}</a> <li><a href="{{ url('accounting:club_details', c_account_id=c.id) }}">{{ c }}</a>
- <a href="{{ url('accounting:club_edit', c_account_id=c.id) }}">{% trans %}Edit{% endtrans %}</a> - <a href="{{ url('accounting:club_edit', c_account_id=c.id) }}">{% trans %}Edit{% endtrans %}</a>
{% if c.journals.count() == 0 %}
- <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@ -15,7 +15,9 @@
{% if user.is_root and not object.journals.exists() %} {% if user.is_root and not object.journals.exists() %}
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p> <p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
{% endif %}
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p> <p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
{% if not object.has_open_journal() %} {% if not object.has_open_journal() %}
<p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p> <p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p>
@ -52,7 +54,11 @@
<td>{% trans %}No{% endtrans %}</td> <td>{% trans %}No{% endtrans %}</td>
{% endif %} {% endif %}
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a> <td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a>
<a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a> </td> <a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a>
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %}
<a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -5,7 +5,9 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %}
<p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p> <p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
{% endif %}
</br> </br>
<table> <table>

View File

@ -78,9 +78,11 @@
<td>-</td> <td>-</td>
{% endif %} {% endif %}
<td> <td>
{% if o.journal.club_account.bank_account.name != "AE TI" and journal.club_account.bank_account.name != "TI" or user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
{% if not o.journal.closed %} {% if not o.journal.closed %}
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a> <a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
{% endif %} {% endif %}
{% endif %}
</td> </td>
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td> <td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
</tr> </tr>

View File

@ -12,13 +12,18 @@
</p> </p>
<hr> <hr>
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p> <p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p>
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p> <p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
{% endif %}
{% if object.labels.all() %} {% if object.labels.all() %}
<h3>{% trans %}Label list{% endtrans %}</h3> <h3>{% trans %}Label list{% endtrans %}</h3>
<ul> <ul>
{% for l in object.labels.all() %} {% for l in object.labels.all() %}
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a> - <li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a>
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
-
<a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@ -26,6 +26,7 @@ urlpatterns = [
url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'), url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'),
url(r'^journal/(?P<j_id>[0-9]+)$', JournalDetailView.as_view(), name='journal_details'), url(r'^journal/(?P<j_id>[0-9]+)$', JournalDetailView.as_view(), name='journal_details'),
url(r'^journal/(?P<j_id>[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'), url(r'^journal/(?P<j_id>[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'),
url(r'^journal/(?P<j_id>[0-9]+)/delete$', JournalDeleteView.as_view(), name='journal_delete'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/nature$', JournalNatureStatementView.as_view(), name='journal_nature_statement'), url(r'^journal/(?P<j_id>[0-9]+)/statement/nature$', JournalNatureStatementView.as_view(), name='journal_nature_statement'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/person$', JournalPersonStatementView.as_view(), name='journal_person_statement'), url(r'^journal/(?P<j_id>[0-9]+)/statement/person$', JournalPersonStatementView.as_view(), name='journal_person_statement'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/accounting$', JournalAccountingStatementView.as_view(), name='journal_accounting_statement'), url(r'^journal/(?P<j_id>[0-9]+)/statement/accounting$', JournalAccountingStatementView.as_view(), name='journal_accounting_statement'),

View File

@ -230,6 +230,21 @@ class JournalEditView(CanEditMixin, UpdateView):
fields = ['name', 'start_date', 'end_date', 'club_account', 'closed'] fields = ['name', 'start_date', 'end_date', 'club_account', 'closed']
template_name = 'core/edit.jinja' 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')
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
if self.object.operations.count() == 0:
return super(JournalDeleteView, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
# Operation views # Operation views

View File

@ -4,6 +4,7 @@ from django.shortcuts import render
from django.http import HttpResponseForbidden, HttpResponseNotFound from django.http import HttpResponseForbidden, HttpResponseNotFound
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured
from django.views.generic.base import View from django.views.generic.base import View
from django.db.models import Count
from core.models import Group from core.models import Group
from core.views.forms import LoginForm from core.views.forms import LoginForm
@ -66,7 +67,7 @@ class CanEditPropMixin(View):
except: pass except: pass
# If we get here, it's a ListView # 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)] 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 raise PermissionDenied
self._get_queryset = self.get_queryset self._get_queryset = self.get_queryset
def get_qs(self2): def get_qs(self2):
@ -88,7 +89,7 @@ class CanEditMixin(View):
except: pass except: pass
# If we get here, it's a ListView # If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_edit(o, request.user)] 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 raise PermissionDenied
self._get_queryset = self.get_queryset self._get_queryset = self.get_queryset
def get_qs(self2): def get_qs(self2):
@ -110,7 +111,7 @@ class CanViewMixin(View):
except: pass except: pass
# If we get here, it's a ListView # If we get here, it's a ListView
l_id = [o.id for o in self.get_queryset() if can_view(o, request.user)] 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 raise PermissionDenied
self._get_queryset = self.get_queryset self._get_queryset = self.get_queryset
def get_qs(self2): def get_qs(self2):

View File

@ -426,18 +426,23 @@ SITH_SUBSCRIPTIONS = {
# To be completed.... # To be completed....
} }
SITH_CLUB_ROLES = { SITH_CLUB_ROLES = {}
10: _('President'),
9: _('Vice-President'), SITH_CLUB_ROLES_ID = {
7: _('Treasurer'), 'President': 10,
5: _('Communication supervisor'), 'Vice-President': 9,
4: _('Secretary'), 'Treasurer': 7,
3: _('IT supervisor'), 'Communication supervisor': 5,
2: _('Board member'), 'Secretary': 4,
1: _('Active member'), 'IT supervisor': 3,
0: _('Curious'), '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 # 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 # In this case, SITH_MAXIMUM_FREE_ROLE=1 means that a user can set himself as "Membre actif" or "Curieux", but not higher
SITH_MAXIMUM_FREE_ROLE=1 SITH_MAXIMUM_FREE_ROLE=1