diff --git a/accounting/migrations/0003_auto_20160509_0712.py b/accounting/migrations/0003_auto_20160509_0712.py new file mode 100644 index 00000000..4b6e26a7 --- /dev/null +++ b/accounting/migrations/0003_auto_20160509_0712.py @@ -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'), + ), + ] diff --git a/accounting/migrations/0004_auto_20160509_0715.py b/accounting/migrations/0004_auto_20160509_0715.py new file mode 100644 index 00000000..a73359f2 --- /dev/null +++ b/accounting/migrations/0004_auto_20160509_0715.py @@ -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'), + ), + ] diff --git a/accounting/migrations/0005_auto_20160509_0716.py b/accounting/migrations/0005_auto_20160509_0716.py new file mode 100644 index 00000000..e4ab3be4 --- /dev/null +++ b/accounting/migrations/0005_auto_20160509_0716.py @@ -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'), + ), + ] diff --git a/accounting/models.py b/accounting/models.py index d8a4b785..3508928b 100644 --- a/accounting/models.py +++ b/accounting/models.py @@ -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}) diff --git a/accounting/views.py b/accounting/views.py index e0f576b3..e6e758b4 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -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) """ diff --git a/club/templates/club/club_tools.jinja b/club/templates/club/club_tools.jinja new file mode 100644 index 00000000..9649c8da --- /dev/null +++ b/club/templates/club/club_tools.jinja @@ -0,0 +1,12 @@ +{% extends "core/base.jinja" %} + +{% block content %} +

Club tools

+

Back to club

+ +{% endblock %} + + + diff --git a/club/urls.py b/club/urls.py index 96e7a27b..497c0818 100644 --- a/club/urls.py +++ b/club/urls.py @@ -9,9 +9,6 @@ urlpatterns = [ url(r'^(?P[0-9]+)/edit$', ClubEditView.as_view(), name='club_edit'), url(r'^(?P[0-9]+)/members$', ClubMembersView.as_view(), name='club_members'), url(r'^(?P[0-9]+)/prop$', ClubEditPropView.as_view(), name='club_prop'), - #url(r'^(?P[0-9]+)/tools$', ClubToolsView.as_view(), name='club_tools'), - - ## API - #url(r'^api/markdown$', render_markdown, name='api_markdown'), + url(r'^(?P[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'), ] diff --git a/club/views.py b/club/views.py index 857728bd..cab47673 100644 --- a/club/views.py +++ b/club/views.py @@ -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 diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index d951d1ae..2eec2755 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -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() diff --git a/core/models.py b/core/models.py index 80176eee..72f95af8 100644 --- a/core/models.py +++ b/core/models.py @@ -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): diff --git a/core/templates/core/user_tools.jinja b/core/templates/core/user_tools.jinja index d99474a1..443350fd 100644 --- a/core/templates/core/user_tools.jinja +++ b/core/templates/core/user_tools.jinja @@ -8,6 +8,7 @@

User Tools

Back to profile

+

Sith management

    {% if user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
  • Groups
  • @@ -15,11 +16,17 @@ {% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) %}
  • Accounting
  • {% 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']) %}
  • Subscriptions
  • Counters management
  • {% endif %}
+

Clubs

+
    + {% for m in user.membership.filter(end_date=None).all() %} +
  • {{ m.club }}
  • + {% endfor %} +
{% endblock %}