diff --git a/accounting/admin.py b/accounting/admin.py index 12999c6a..65f35fb9 100644 --- a/accounting/admin.py +++ b/accounting/admin.py @@ -9,6 +9,7 @@ admin.site.register(Product) admin.site.register(BankAccount) admin.site.register(ClubAccount) admin.site.register(GeneralJournal) +admin.site.register(AccountingType) admin.site.register(Operation) diff --git a/accounting/migrations/0002_auto_20160502_0952.py b/accounting/migrations/0002_auto_20160502_0952.py new file mode 100644 index 00000000..a7c8f532 --- /dev/null +++ b/accounting/migrations/0002_auto_20160502_0952.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', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='operation', + name='journal', + field=models.ForeignKey(to='accounting.GeneralJournal', related_name='operations'), + ), + ] diff --git a/accounting/models.py b/accounting/models.py index 02a4fdb7..d8a4b785 100644 --- a/accounting/models.py +++ b/accounting/models.py @@ -39,7 +39,19 @@ class Customer(models.Model): def __str__(self): return self.user.username -class ProductType(models.Model): +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): """ This describes a product type Useful only for categorizing, changes are made at the product level for now @@ -51,7 +63,7 @@ class ProductType(models.Model): def __str__(self): return self.name -class Product(models.Model): +class Product(models.Model, AccountingMixin): """ This describes a product, with all its related informations """ @@ -67,7 +79,7 @@ class Product(models.Model): def __str__(self): return self.name -class BankAccount(models.Model): +class BankAccount(models.Model, AccountingMixin): 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) @@ -78,7 +90,7 @@ class BankAccount(models.Model): def __str__(self): return self.name -class ClubAccount(models.Model): +class ClubAccount(models.Model, AccountingMixin): name = models.CharField(_('name'), max_length=30) club = models.OneToOneField(Club, related_name="club_accounts") bank_account = models.ForeignKey(BankAccount, related_name="club_accounts") @@ -89,7 +101,7 @@ class ClubAccount(models.Model): def __str__(self): return self.name -class GeneralJournal(models.Model): +class GeneralJournal(models.Model, AccountingMixin): """ Class storing all the operations for a period of time """ @@ -99,10 +111,13 @@ class GeneralJournal(models.Model): closed = models.BooleanField(_('is closed'), default=False) club_account = models.ForeignKey(ClubAccount, related_name="journals", null=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): +class AccountingType(models.Model, AccountingMixin): """ Class describing the accounting types. @@ -112,11 +127,17 @@ class AccountingType(models.Model): label = models.CharField(_('label'), max_length=60) movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12) -class Operation(models.Model): + 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): """ An operation is a line in the journal, a debit or a credit """ - journal = models.ForeignKey(GeneralJournal, related_name="invoices", null=False) + journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False) date = models.DateField(_('date')) remark = models.TextField(_('remark'), max_length=255) mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD) @@ -125,6 +146,9 @@ class Operation(models.Model): done = models.BooleanField(_('is done'), default=False) type = models.ForeignKey(AccountingType, related_name="operations") - def __str__(self): - return self.journal.name+' - '+self.name + def get_absolute_url(self): + return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id}) + + def __str__(self): + return str(self.id)+" - "+str(self.date) diff --git a/accounting/templates/accounting/accountingtype_list.jinja b/accounting/templates/accounting/accountingtype_list.jinja new file mode 100644 index 00000000..0961289a --- /dev/null +++ b/accounting/templates/accounting/accountingtype_list.jinja @@ -0,0 +1,23 @@ +{% extends "core/base.jinja" %} + +{% block title %} + Accounting type list +{% endblock %} + +{% block content %} +

New accounting type

+ {% if accountingtype_list %} +

Accounting type list

+ + {% else %} + There is no types in this website. + {% endif %} +{% endblock %} + + + + diff --git a/accounting/templates/accounting/bank_account_list.jinja b/accounting/templates/accounting/bank_account_list.jinja index 2be02051..1ef7eadc 100644 --- a/accounting/templates/accounting/bank_account_list.jinja +++ b/accounting/templates/accounting/bank_account_list.jinja @@ -5,6 +5,7 @@ {% endblock %} {% block content %} +

Manage accounting types

New bank account

{% if bankaccount_list %}

Bank account list

diff --git a/accounting/templates/accounting/club_account_details.jinja b/accounting/templates/accounting/club_account_details.jinja index c0eb0a49..3dafe85b 100644 --- a/accounting/templates/accounting/club_account_details.jinja +++ b/accounting/templates/accounting/club_account_details.jinja @@ -9,8 +9,12 @@

New journal

diff --git a/accounting/templates/accounting/journal_details.jinja b/accounting/templates/accounting/journal_details.jinja new file mode 100644 index 00000000..aa719279 --- /dev/null +++ b/accounting/templates/accounting/journal_details.jinja @@ -0,0 +1,22 @@ +{% extends "core/base.jinja" %} + +{% block content %} +

View journal: {{ object.name }}

+ +

New operation

+ + +{% endblock %} + + + diff --git a/accounting/urls.py b/accounting/urls.py index b42c2aad..33e62379 100644 --- a/accounting/urls.py +++ b/accounting/urls.py @@ -3,6 +3,10 @@ from django.conf.urls import url, include from accounting.views import * urlpatterns = [ + # Accounting types + url(r'^type$', AccountingTypeListView.as_view(), name='type_list'), + url(r'^type/create$', AccountingTypeCreateView.as_view(), name='type_new'), + url(r'^type/(?P[0-9]+)/edit$', AccountingTypeEditView.as_view(), name='type_edit'), # Bank accounts url(r'^$', BankAccountListView.as_view(), name='bank_list'), url(r'^bank/create$', BankAccountCreateView.as_view(), name='bank_new'), @@ -16,6 +20,11 @@ urlpatterns = [ url(r'^club/(?P[0-9]+)/delete$', ClubAccountDeleteView.as_view(), name='club_delete'), # Journals url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'), + url(r'^journal/(?P[0-9]+)$', JournalDetailView.as_view(), name='journal_details'), + url(r'^journal/(?P[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'), + # Operations + url(r'^operation/create$', OperationCreateView.as_view(), name='op_new'), + url(r'^operation/(?P[0-9]+)$', OperationEditView.as_view(), name='op_edit'), ] diff --git a/accounting/views.py b/accounting/views.py index a59e061e..a8900e60 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -4,7 +4,33 @@ from django.shortcuts import render from django.core.urlresolvers import reverse_lazy from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin -from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation +from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType + +# Accounting types + +class AccountingTypeListView(CanViewMixin, ListView): + """ + A list view for the admins + """ + model = AccountingType + template_name = 'accounting/accountingtype_list.jinja' + +class AccountingTypeEditView(CanViewMixin, UpdateView): + """ + An edit view for the admins + """ + model = AccountingType + pk_url_kwarg = "type_id" + fields = ['code', 'label', 'movement_type'] + template_name = 'accounting/account_edit.jinja' + +class AccountingTypeCreateView(CanEditMixin, CreateView): + """ + Create an accounting type (for the admins) + """ + model = AccountingType + fields = ['code', 'label', 'movement_type'] + template_name = 'accounting/account_edit.jinja' # BankAccount views @@ -92,6 +118,42 @@ class JournalCreateView(CanEditMixin, CreateView): Create a general journal """ model = GeneralJournal - fields = ['name'] + fields = ['name', 'start_date', 'club_account'] + template_name = 'accounting/account_edit.jinja' + +class JournalDetailView(CanViewMixin, DetailView): + """ + A detail view, listing every operation + """ + model = GeneralJournal + pk_url_kwarg = "j_id" + template_name = 'accounting/journal_details.jinja' + +class JournalEditView(CanEditMixin, UpdateView): + """ + Update a general journal + """ + model = GeneralJournal + pk_url_kwarg = "j_id" + fields = ['name', 'start_date', 'club_account'] + template_name = 'accounting/account_edit.jinja' + +# Operation views + +class OperationCreateView(CanEditMixin, CreateView): + """ + Create an operation + """ + model = Operation + fields = ['journal', 'date', 'cheque_number', 'type'] + template_name = 'accounting/account_edit.jinja' + +class OperationEditView(CanViewMixin, UpdateView): + """ + An edit view, working as detail for the moment + """ + model = Operation + pk_url_kwarg = "op_id" + fields = ['journal', 'date', 'cheque_number', 'type'] template_name = 'accounting/account_edit.jinja' diff --git a/core/models.py b/core/models.py index dd14bfdb..80176eee 100644 --- a/core/models.py +++ b/core/models.py @@ -266,7 +266,9 @@ class AnonymousUser(AuthAnonymousUser): return False def can_view(self, obj): - if obj.view_groups.filter(pk=settings.SITH_GROUPS['public']['id']).exists(): + if hasattr(obj, 'view_groups') and obj.view_groups.filter(pk=settings.SITH_GROUPS['public']['id']).exists(): + return True + if hasattr(obj, 'can_be_viewed_by') and obj.can_be_viewed_by(self): return True return False diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index d4dc4711..22ee71fc 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -24,6 +24,7 @@ {% if user.is_authenticated() %}
  • Profile
  • +
  • Tools
  • Users
  • Pages
  • Clubs
  • diff --git a/core/templates/core/user_tools.jinja b/core/templates/core/user_tools.jinja index 28afe295..d99474a1 100644 --- a/core/templates/core/user_tools.jinja +++ b/core/templates/core/user_tools.jinja @@ -12,6 +12,9 @@ {% if user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
  • Groups
  • {% endif %} +{% 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) %}
  • Subscriptions
  • Counters management
  • diff --git a/sith/settings.py b/sith/settings.py index acec74ad..2d3a65db 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -189,9 +189,13 @@ SITH_GROUPS = { 'id': 1, 'name': "root", }, - 'public': { + 'accounting-admin': { 'id': 2, - 'name': "not_registered_users", + 'name': "accounting-admin", + }, + 'public': { + 'id': 3, + 'name': "not-registered-users", }, }