Commit 27805640 authored by Skia's avatar Skia
Browse files

Improve right handling for accounting

parent 39661b8d
Pipeline #26 failed with stage
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
...@@ -39,11 +39,16 @@ class Customer(models.Model): ...@@ -39,11 +39,16 @@ class Customer(models.Model):
def __str__(self): def __str__(self):
return self.user.username return self.user.username
class AccountingMixin(): class ProductType(models.Model):
""" """
Mixin providing the rights managment for all accounting classes This describes a product type
Useful only for categorizing, changes are made at the product level for now
""" """
def can_be_edited_by(self, user): name = models.CharField(_('name'), max_length=30)
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 Method to see if that object can be edited by the given user
""" """
...@@ -51,19 +56,10 @@ class AccountingMixin(): ...@@ -51,19 +56,10 @@ class AccountingMixin():
return True return True
return False return False
class ProductType(models.Model, AccountingMixin):
"""
This describes a product type
Useful only for categorizing, changes are made at the product level for now
"""
name = models.CharField(_('name'), max_length=30)
description = models.TextField(_('description'), null=True, blank=True)
icon = models.ImageField(upload_to='products', null=True, blank=True)
def __str__(self): def __str__(self):
return self.name return self.name
class Product(models.Model, AccountingMixin): class Product(models.Model):
""" """
This describes a product, with all its related informations This describes a product, with all its related informations
""" """
...@@ -75,14 +71,35 @@ class Product(models.Model, AccountingMixin): ...@@ -75,14 +71,35 @@ class Product(models.Model, AccountingMixin):
selling_price = CurrencyField(_('selling price')) selling_price = CurrencyField(_('selling price'))
special_selling_price = CurrencyField(_('special selling price')) special_selling_price = CurrencyField(_('special selling price'))
icon = models.ImageField(upload_to='products', null=True, blank=True) 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): def __str__(self):
return self.name return self.name
class BankAccount(models.Model, AccountingMixin): class BankAccount(models.Model):
name = models.CharField(_('name'), max_length=30) name = models.CharField(_('name'), max_length=30)
rib = models.CharField(_('rib'), max_length=255, blank=True) rib = models.CharField(_('rib'), max_length=255, blank=True)
number = models.CharField(_('account number'), 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): def get_absolute_url(self):
return reverse('accounting:bank_details', kwargs={'b_account_id': self.id}) return reverse('accounting:bank_details', kwargs={'b_account_id': self.id})
...@@ -90,18 +107,35 @@ class BankAccount(models.Model, AccountingMixin): ...@@ -90,18 +107,35 @@ class BankAccount(models.Model, AccountingMixin):
def __str__(self): def __str__(self):
return self.name return self.name
class ClubAccount(models.Model, AccountingMixin): class ClubAccount(models.Model):
name = models.CharField(_('name'), max_length=30) 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") 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): def get_absolute_url(self):
return reverse('accounting:club_details', kwargs={'c_account_id': self.id}) return reverse('accounting:club_details', kwargs={'c_account_id': self.id})
def __str__(self): def __str__(self):
return self.name return self.name
class GeneralJournal(models.Model, AccountingMixin): class GeneralJournal(models.Model):
""" """
Class storing all the operations for a period of time Class storing all the operations for a period of time
""" """
...@@ -111,13 +145,29 @@ class GeneralJournal(models.Model, AccountingMixin): ...@@ -111,13 +145,29 @@ class GeneralJournal(models.Model, AccountingMixin):
closed = models.BooleanField(_('is closed'), default=False) closed = models.BooleanField(_('is closed'), default=False)
club_account = models.ForeignKey(ClubAccount, related_name="journals", null=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): def get_absolute_url(self):
return reverse('accounting:journal_details', kwargs={'j_id': self.id}) return reverse('accounting:journal_details', kwargs={'j_id': self.id})
def __str__(self): def __str__(self):
return self.name return self.name
class AccountingType(models.Model, AccountingMixin): class AccountingType(models.Model):
""" """
Class describing the accounting types. Class describing the accounting types.
...@@ -127,13 +177,21 @@ class AccountingType(models.Model, AccountingMixin): ...@@ -127,13 +177,21 @@ class AccountingType(models.Model, AccountingMixin):
label = models.CharField(_('label'), max_length=60) label = models.CharField(_('label'), max_length=60)
movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12) 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): def get_absolute_url(self):
return reverse('accounting:type_list') return reverse('accounting:type_list')
def __str__(self): def __str__(self):
return self.movement_type+" - "+self.code+" - "+self.label 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 An operation is a line in the journal, a debit or a credit
""" """
...@@ -146,6 +204,26 @@ class Operation(models.Model, AccountingMixin): ...@@ -146,6 +204,26 @@ class Operation(models.Model, AccountingMixin):
done = models.BooleanField(_('is done'), default=False) done = models.BooleanField(_('is done'), default=False)
type = models.ForeignKey(AccountingType, related_name="operations") 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): def get_absolute_url(self):
return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id}) return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id})
......
...@@ -24,7 +24,7 @@ class AccountingTypeEditView(CanViewMixin, UpdateView): ...@@ -24,7 +24,7 @@ class AccountingTypeEditView(CanViewMixin, UpdateView):
fields = ['code', 'label', 'movement_type'] fields = ['code', 'label', 'movement_type']
template_name = 'accounting/account_edit.jinja' template_name = 'accounting/account_edit.jinja'
class AccountingTypeCreateView(CanEditMixin, CreateView): class AccountingTypeCreateView(CanEditPropMixin, CreateView):
""" """
Create an accounting type (for the admins) Create an accounting type (for the admins)
""" """
...@@ -58,7 +58,7 @@ class BankAccountDetailView(CanViewMixin, DetailView): ...@@ -58,7 +58,7 @@ class BankAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "b_account_id" pk_url_kwarg = "b_account_id"
template_name = 'accounting/bank_account_details.jinja' template_name = 'accounting/bank_account_details.jinja'
class BankAccountCreateView(CanEditMixin, CreateView): class BankAccountCreateView(CanEditPropMixin, CreateView):
""" """
Create a bank account (for the admins) Create a bank account (for the admins)
""" """
...@@ -66,7 +66,7 @@ class BankAccountCreateView(CanEditMixin, CreateView): ...@@ -66,7 +66,7 @@ class BankAccountCreateView(CanEditMixin, CreateView):
fields = ['name', 'rib', 'number'] fields = ['name', 'rib', 'number']
template_name = 'accounting/account_edit.jinja' 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) Delete a bank account (for the admins)
""" """
...@@ -94,7 +94,7 @@ class ClubAccountDetailView(CanViewMixin, DetailView): ...@@ -94,7 +94,7 @@ class ClubAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "c_account_id" pk_url_kwarg = "c_account_id"
template_name = 'accounting/club_account_details.jinja' template_name = 'accounting/club_account_details.jinja'
class ClubAccountCreateView(CanEditMixin, CreateView): class ClubAccountCreateView(CanEditPropMixin, CreateView):
""" """
Create a club account (for the admins) Create a club account (for the admins)
""" """
...@@ -102,7 +102,7 @@ class ClubAccountCreateView(CanEditMixin, CreateView): ...@@ -102,7 +102,7 @@ class ClubAccountCreateView(CanEditMixin, CreateView):
fields = ['name', 'club', 'bank_account'] fields = ['name', 'club', 'bank_account']
template_name = 'accounting/account_edit.jinja' 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) Delete a club account (for the admins)
""" """
......
{% 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 %}
...@@ -9,9 +9,6 @@ urlpatterns = [ ...@@ -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]+)/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]+)/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]+)/prop$', ClubEditPropView.as_view(), name='club_prop'),
#url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='club_tools'), url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'),
## API
#url(r'^api/markdown$', render_markdown, name='api_markdown'),
] ]
...@@ -25,6 +25,14 @@ class ClubView(CanViewMixin, DetailView): ...@@ -25,6 +25,14 @@ class ClubView(CanViewMixin, DetailView):
pk_url_kwarg = "club_id" pk_url_kwarg = "club_id"
template_name = 'club/club_detail.jinja' 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): class ClubMemberForm(forms.ModelForm):
""" """
Form handling the members of a club Form handling the members of a club
......
...@@ -5,7 +5,7 @@ from django.conf import settings ...@@ -5,7 +5,7 @@ from django.conf import settings
from core.models import Group, User, Page, PageRev 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 club.models import Club, Membership
from subscription.models import Subscription, Subscriber from subscription.models import Subscription, Subscriber
...@@ -41,13 +41,13 @@ Welcome to the wiki page! ...@@ -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 # 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']: if not options['prod']:
# Adding user Skia # 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", email="skia@git.an",
date_of_birth="1942-06-12") date_of_birth="1942-06-12")
s.set_password("plop") skia.set_password("plop")
s.save() skia.save()
s.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id] skia.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
s.save() skia.save()
# Adding user public # Adding user public
public = User(username='public', last_name="Not subscribed", first_name="Public", public = User(username='public', last_name="Not subscribed", first_name="Public",
email="public@git.an", email="public@git.an",
...@@ -66,6 +66,16 @@ Welcome to the wiki page! ...@@ -66,6 +66,16 @@ Welcome to the wiki page!
subscriber.save() subscriber.save()
subscriber.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id] subscriber.view_groups=[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id]
subscriber.save() 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 # Adding user Guy
u = User(username='guy', last_name="Carlier", first_name="Guy", u = User(username='guy', last_name="Carlier", first_name="Guy",
email="guy@git.an", email="guy@git.an",
...@@ -86,21 +96,24 @@ Welcome to the wiki page! ...@@ -86,21 +96,24 @@ Welcome to the wiki page!
# Adding syntax help page # Adding syntax help page
p = Page(name='Aide_sur_la_syntaxe') p = Page(name='Aide_sur_la_syntaxe')
p.save() 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. Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
""").save() """).save()
# Adding README # Adding README
p = Page(name='README') p = Page(name='README')
p.save() p.save()
p.view_groups=[settings.SITH_GROUPS['public']['id']] p.view_groups=[settings.SITH_GROUPS['public']['id']]
p.set_lock(s) p.set_lock(skia)
p.save() p.save()
with open(os.path.join(root_path)+'/README.md', 'r') as rm: 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 # Subscription
## Skia ## 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() payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0]).save()
## Richard ## Richard
Subscription(member=Subscriber.objects.filter(pk=r.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0], 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. ...@@ -119,28 +132,29 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
address="Woenzel", parent=guyut).save() address="Woenzel", parent=guyut).save()
Club(name="BdF", unix_name="bdf", Club(name="BdF", unix_name="bdf",
address="Guyéuéyuéyuyé").save() 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", troll = Club(name="Troll Penché", unix_name="troll",
address="Terre Du Milieu", parent=ae) address="Terre Du Milieu", parent=ae)
troll.save() troll.save()
# Accounting test values: # Accounting test values:
Customer(user=s, account_id="6568j").save() Customer(user=skia, account_id="6568j").save()
p = ProductType(name="Bières bouteilles") p = ProductType(name="Bières bouteilles")
p.save() p.save()
Product(name="Barbar", code="BARB", product_type=p, purchase_price="1.50", selling_price="1.7", 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", 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", 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", Product(name="Carolus", code="CARO", 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()
BankAccount(name="AE TG").save() BankAccount(name="AE TG", club=ae).save()
BankAccount(name="Carte AE").save() BankAccount(name="Carte AE", club=ae).save()
ba = BankAccount(name="AE TI") ba = BankAccount(name="AE TI", club=ae)
ba.save() ba.save()
ca = ClubAccount(name="Troll Penché", bank_account=ba, club=troll) ca = ClubAccount(name="Troll Penché", bank_account=ba, club=troll)
ca.save() ca.save()
AccountingType(code=666, label="Guy credit", movement_type='credit').save()
AccountingType(code=4000, label="Guy debit", movement_type='debit').save()