Improve right handling for accounting

This commit is contained in:
Skia 2016-05-09 11:49:01 +02:00
parent 39661b8de7
commit 27805640a1
11 changed files with 240 additions and 60 deletions

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('club', '0001_initial'),
('accounting', '0002_auto_20160502_0952'),
]
operations = [
migrations.AddField(
model_name='bankaccount',
name='club',
field=models.OneToOneField(to='club.Club', related_name='bank_accounts', default=1),
preserve_default=False,
),
migrations.AddField(
model_name='product',
name='club',
field=models.OneToOneField(to='club.Club', related_name='products', default=1),
preserve_default=False,
),
migrations.AlterField(
model_name='clubaccount',
name='club',
field=models.OneToOneField(related_name='club_account', to='club.Club'),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounting', '0003_auto_20160509_0712'),
]
operations = [
migrations.AlterField(
model_name='product',
name='club',
field=models.ForeignKey(related_name='products', to='club.Club'),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounting', '0004_auto_20160509_0715'),
]
operations = [
migrations.AlterField(
model_name='bankaccount',
name='club',
field=models.ForeignKey(related_name='bank_accounts', to='club.Club'),
),
]

View File

@ -39,19 +39,7 @@ class Customer(models.Model):
def __str__(self):
return self.user.username
class AccountingMixin():
"""
Mixin providing the rights managment for all accounting classes
"""
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_GROUPS['accounting-admin']['name']):
return True
return False
class ProductType(models.Model, AccountingMixin):
class ProductType(models.Model):
"""
This describes a product type
Useful only for categorizing, changes are made at the product level for now
@ -60,10 +48,18 @@ class ProductType(models.Model, AccountingMixin):
description = models.TextField(_('description'), null=True, blank=True)
icon = models.ImageField(upload_to='products', null=True, blank=True)
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_GROUPS['accounting-admin']['name']):
return True
return False
def __str__(self):
return self.name
class Product(models.Model, AccountingMixin):
class Product(models.Model):
"""
This describes a product, with all its related informations
"""
@ -75,14 +71,35 @@ class Product(models.Model, AccountingMixin):
selling_price = CurrencyField(_('selling price'))
special_selling_price = CurrencyField(_('special selling price'))
icon = models.ImageField(upload_to='products', null=True, blank=True)
club = models.ForeignKey(Club, related_name="products")
def is_owned_by(self, user): # TODO do this for all models
"""
Method to see if that object can be edited by the given user
"""
if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']):
return True
return False
def __str__(self):
return self.name
class BankAccount(models.Model, AccountingMixin):
class BankAccount(models.Model):
name = models.CharField(_('name'), max_length=30)
rib = models.CharField(_('rib'), max_length=255, blank=True)
number = models.CharField(_('account number'), max_length=255, blank=True)
club = models.ForeignKey(Club, related_name="bank_accounts")
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_GROUPS['accounting-admin']['name']):
return True
m = self.club.get_membership_for(user)
if m is not None and m.role >= 7:
return True
return False
def get_absolute_url(self):
return reverse('accounting:bank_details', kwargs={'b_account_id': self.id})
@ -90,18 +107,35 @@ class BankAccount(models.Model, AccountingMixin):
def __str__(self):
return self.name
class ClubAccount(models.Model, AccountingMixin):
class ClubAccount(models.Model):
name = models.CharField(_('name'), max_length=30)
club = models.OneToOneField(Club, related_name="club_accounts")
club = models.OneToOneField(Club, related_name="club_account")
bank_account = models.ForeignKey(BankAccount, related_name="club_accounts")
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_GROUPS['accounting-admin']['name']):
return True
return False
def can_be_edited_by(self, user):
"""
Method to see if that object can be edited by the given user
"""
m = self.club.get_membership_for(user)
if m is not None and m.role >= 7:
return True
return False
def get_absolute_url(self):
return reverse('accounting:club_details', kwargs={'c_account_id': self.id})
def __str__(self):
return self.name
class GeneralJournal(models.Model, AccountingMixin):
class GeneralJournal(models.Model):
"""
Class storing all the operations for a period of time
"""
@ -111,13 +145,29 @@ class GeneralJournal(models.Model, AccountingMixin):
closed = models.BooleanField(_('is closed'), default=False)
club_account = models.ForeignKey(ClubAccount, related_name="journals", null=False)
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_GROUPS['accounting-admin']['name']):
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 self.club_account.can_be_edited_by(user):
return True
return False
def get_absolute_url(self):
return reverse('accounting:journal_details', kwargs={'j_id': self.id})
def __str__(self):
return self.name
class AccountingType(models.Model, AccountingMixin):
class AccountingType(models.Model):
"""
Class describing the accounting types.
@ -127,13 +177,21 @@ class AccountingType(models.Model, AccountingMixin):
label = models.CharField(_('label'), max_length=60)
movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12)
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_GROUPS['accounting-admin']['name']):
return True
return False
def get_absolute_url(self):
return reverse('accounting:type_list')
def __str__(self):
return self.movement_type+" - "+self.code+" - "+self.label
class Operation(models.Model, AccountingMixin):
class Operation(models.Model):
"""
An operation is a line in the journal, a debit or a credit
"""
@ -146,6 +204,26 @@ class Operation(models.Model, AccountingMixin):
done = models.BooleanField(_('is done'), default=False)
type = models.ForeignKey(AccountingType, related_name="operations")
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_GROUPS['accounting-admin']['name']):
return True
m = self.journal.club_account.get_membership_for(user)
if m is not None and m.role >= 7:
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 self.journal.can_be_edited_by(user):
return True
return False
def get_absolute_url(self):
return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id})

View File

@ -24,7 +24,7 @@ class AccountingTypeEditView(CanViewMixin, UpdateView):
fields = ['code', 'label', 'movement_type']
template_name = 'accounting/account_edit.jinja'
class AccountingTypeCreateView(CanEditMixin, CreateView):
class AccountingTypeCreateView(CanEditPropMixin, CreateView):
"""
Create an accounting type (for the admins)
"""
@ -58,7 +58,7 @@ class BankAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "b_account_id"
template_name = 'accounting/bank_account_details.jinja'
class BankAccountCreateView(CanEditMixin, CreateView):
class BankAccountCreateView(CanEditPropMixin, CreateView):
"""
Create a bank account (for the admins)
"""
@ -66,7 +66,7 @@ class BankAccountCreateView(CanEditMixin, CreateView):
fields = ['name', 'rib', 'number']
template_name = 'accounting/account_edit.jinja'
class BankAccountDeleteView(CanEditMixin, DeleteView): # TODO change Delete to Close
class BankAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
"""
Delete a bank account (for the admins)
"""
@ -94,7 +94,7 @@ class ClubAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "c_account_id"
template_name = 'accounting/club_account_details.jinja'
class ClubAccountCreateView(CanEditMixin, CreateView):
class ClubAccountCreateView(CanEditPropMixin, CreateView):
"""
Create a club account (for the admins)
"""
@ -102,7 +102,7 @@ class ClubAccountCreateView(CanEditMixin, CreateView):
fields = ['name', 'club', 'bank_account']
template_name = 'accounting/account_edit.jinja'
class ClubAccountDeleteView(CanEditMixin, DeleteView): # TODO change Delete to Close
class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
"""
Delete a club account (for the admins)
"""

View File

@ -0,0 +1,12 @@
{% extends "core/base.jinja" %}
{% block content %}
<h3>Club tools</h3>
<p><a href="{{ url('club:club_view', club_id=object.id) }}">Back to club</a></p>
<ul>
<li><a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object }}</a></li>
</ul>
{% endblock %}

View File

@ -9,9 +9,6 @@ urlpatterns = [
url(r'^(?P<club_id>[0-9]+)/edit$', ClubEditView.as_view(), name='club_edit'),
url(r'^(?P<club_id>[0-9]+)/members$', ClubMembersView.as_view(), name='club_members'),
url(r'^(?P<club_id>[0-9]+)/prop$', ClubEditPropView.as_view(), name='club_prop'),
#url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='club_tools'),
## API
#url(r'^api/markdown$', render_markdown, name='api_markdown'),
url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'),
]

View File

@ -25,6 +25,14 @@ class ClubView(CanViewMixin, DetailView):
pk_url_kwarg = "club_id"
template_name = 'club/club_detail.jinja'
class ClubToolsView(CanViewMixin, DetailView):
"""
Tools page of a Club
"""
model = Club
pk_url_kwarg = "club_id"
template_name = 'club/club_tools.jinja'
class ClubMemberForm(forms.ModelForm):
"""
Form handling the members of a club

View File

@ -5,7 +5,7 @@ from django.conf import settings
from core.models import Group, User, Page, PageRev
from accounting.models import Customer, GeneralJournal, ProductType, Product, BankAccount, ClubAccount, Operation
from accounting.models import Customer, GeneralJournal, ProductType, Product, BankAccount, ClubAccount, Operation, AccountingType
from club.models import Club, Membership
from subscription.models import Subscription, Subscriber
@ -41,13 +41,13 @@ Welcome to the wiki page!
# Here we add a lot of test datas, that are not necessary for the Sith, but that provide a basic development environment
if not options['prod']:
# Adding user Skia
s = User(username='skia', last_name="Kia", first_name="S'",
skia = User(username='skia', last_name="Kia", first_name="S'",
email="skia@git.an",
date_of_birth="1942-06-12")
s.set_password("plop")
s.save()
s.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
s.save()
skia.set_password("plop")
skia.save()
skia.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
skia.save()
# Adding user public
public = User(username='public', last_name="Not subscribed", first_name="Public",
email="public@git.an",
@ -66,6 +66,16 @@ Welcome to the wiki page!
subscriber.save()
subscriber.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
subscriber.save()
# Adding user Comptable
comptable = User(username='comptable', last_name="Able", first_name="Compte",
email="compta@git.an",
date_of_birth="1942-06-12",
is_superuser=False, is_staff=False)
comptable.set_password("plop")
comptable.save()
comptable.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
comptable.groups=[Group.objects.filter(name=settings.SITH_GROUPS['accounting-admin']['name']).first().id]
comptable.save()
# Adding user Guy
u = User(username='guy', last_name="Carlier", first_name="Guy",
email="guy@git.an",
@ -86,21 +96,24 @@ Welcome to the wiki page!
# Adding syntax help page
p = Page(name='Aide_sur_la_syntaxe')
p.save()
PageRev(page=p, title="Aide sur la syntaxe", author=s, content="""
PageRev(page=p, title="Aide sur la syntaxe", author=skia, content="""
Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
""").save()
# Adding README
p = Page(name='README')
p.save()
p.view_groups=[settings.SITH_GROUPS['public']['id']]
p.set_lock(s)
p.set_lock(skia)
p.save()
with open(os.path.join(root_path)+'/README.md', 'r') as rm:
PageRev(page=p, title="REAMDE", author=s, content=rm.read()).save()
PageRev(page=p, title="REAMDE", author=skia, content=rm.read()).save()
# Subscription
## Skia
Subscription(member=Subscriber.objects.filter(pk=s.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
Subscription(member=Subscriber.objects.filter(pk=skia.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0]).save()
## Comptable
Subscription(member=Subscriber.objects.filter(pk=comptable.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0]).save()
## Richard
Subscription(member=Subscriber.objects.filter(pk=r.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
@ -119,28 +132,29 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
address="Woenzel", parent=guyut).save()
Club(name="BdF", unix_name="bdf",
address="Guyéuéyuéyuyé").save()
Membership(user=s, club=ae, role=3, description="").save()
Membership(user=skia, club=ae, role=3, description="").save()
troll = Club(name="Troll Penché", unix_name="troll",
address="Terre Du Milieu", parent=ae)
troll.save()
# Accounting test values:
Customer(user=s, account_id="6568j").save()
Customer(user=skia, account_id="6568j").save()
p = ProductType(name="Bières bouteilles")
p.save()
Product(name="Barbar", code="BARB", product_type=p, purchase_price="1.50", selling_price="1.7",
special_selling_price="1.6").save()
special_selling_price="1.6", club=ae).save()
Product(name="Chimay", code="CBLE", product_type=p, purchase_price="1.50", selling_price="1.7",
special_selling_price="1.6").save()
special_selling_price="1.6", club=ae).save()
Product(name="Corsendonk", code="CORS", product_type=p, purchase_price="1.50", selling_price="1.7",
special_selling_price="1.6").save()
special_selling_price="1.6", club=ae).save()
Product(name="Carolus", code="CARO", product_type=p, purchase_price="1.50", selling_price="1.7",
special_selling_price="1.6").save()
BankAccount(name="AE TG").save()
BankAccount(name="Carte AE").save()
ba = BankAccount(name="AE TI")
special_selling_price="1.6", club=ae).save()
BankAccount(name="AE TG", club=ae).save()
BankAccount(name="Carte AE", club=ae).save()
ba = BankAccount(name="AE TI", club=ae)
ba.save()
ca = ClubAccount(name="Troll Penché", bank_account=ba, club=troll)
ca.save()
AccountingType(code=666, label="Guy credit", movement_type='credit').save()
AccountingType(code=4000, label="Guy debit", movement_type='debit').save()

View File

@ -207,14 +207,12 @@ class User(AbstractBaseUser, PermissionsMixin):
"""
Determine if the object is owned by the user
"""
if not hasattr(obj, "owner_group"):
return False
if (self.is_superuser or self.is_in_group(obj.owner_group.name) or
self.has_perm(obj.__class__.__module__.split('.')[0]+".change_prop_"+obj.__class__.__name__.lower()) or
self.groups.filter(id=settings.SITH_GROUPS['root']['id']).exists()):
return True
if hasattr(obj, "is_owned_by") and obj.is_owned_by(self):
return True
if hasattr(obj, "owner_group") and self.is_in_group(obj.owner_group.name):
return False
if self.is_superuser or self.is_in_group(settings.SITH_GROUPS['root']['name']):
return True
return False
def can_edit(self, obj):
@ -231,8 +229,6 @@ class User(AbstractBaseUser, PermissionsMixin):
return True
if hasattr(obj, "can_be_edited_by") and obj.can_be_edited_by(self):
return True
if self.has_perm(obj.__class__.__module__.split('.')[0]+".change_"+obj.__class__.__name__.lower()):
return True
return False
def can_view(self, obj):
@ -247,8 +243,6 @@ class User(AbstractBaseUser, PermissionsMixin):
return True
if hasattr(obj, "can_be_viewed_by") and obj.can_be_viewed_by(self):
return True
if self.has_perm(obj.__class__.__module__.split('.')[0]+".view_"+obj.__class__.__name__.lower()):
return True
return False
def can_be_edited_by(self, user):

View File

@ -8,6 +8,7 @@
<h3>User Tools</h3>
<p><a href="{{ url('core:user_profile', user_id=request.user.id) }}">Back to profile</a></p>
<h4>Sith management</h4>
<ul>
{% if user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
<li><a href="{{ url('core:group_list') }}">Groups</a></li>
@ -15,11 +16,17 @@
{% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) %}
<li><a href="{{ url('accounting:bank_list') }}">Accounting</a></li>
{% endif %}
{% if user.is_in_group(settings.SITH_GROUPS['root']['name']) or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) %}
{% if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
<li><a href="{{ url('subscription:subscription') }}">Subscriptions</a></li>
<li><a href="{{ url('counter:admin_list') }}">Counters management</a></li>
{% endif %}
</ul>
<h4>Clubs</h4>
<ul>
{% for m in user.membership.filter(end_date=None).all() %}
<li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
{% endfor %}
</ul>
{% endblock %}