mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-10 03:49:24 +00:00
Migrate accounting
This commit is contained in:
@ -7,6 +7,7 @@ admin.site.register(BankAccount)
|
||||
admin.site.register(ClubAccount)
|
||||
admin.site.register(GeneralJournal)
|
||||
admin.site.register(AccountingType)
|
||||
admin.site.register(SimplifiedAccountingType)
|
||||
admin.site.register(Operation)
|
||||
|
||||
|
||||
|
104
accounting/migrations/0003_auto_20160824_1732.py
Normal file
104
accounting/migrations/0003_auto_20160824_1732.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounting', '0002_auto_20160814_1634'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SimplifiedAccountingType',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
||||
('label', models.CharField(max_length=128, verbose_name='label')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'simplified type',
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='operation',
|
||||
name='label',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='linked_operation',
|
||||
field=models.OneToOneField(to='accounting.Operation', default=None, null=True, blank=True, verbose_name='linked operation', related_name='operation_linked_to'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accountingtype',
|
||||
name='code',
|
||||
field=models.CharField(max_length=16, verbose_name='code', validators=[django.core.validators.RegexValidator('^[0-9]*$', 'An accounting type code contains only numbers')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accountingtype',
|
||||
name='label',
|
||||
field=models.CharField(max_length=128, verbose_name='label'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accountingtype',
|
||||
name='movement_type',
|
||||
field=models.CharField(max_length=12, verbose_name='movement type', choices=[('CREDIT', 'Credit'), ('DEBIT', 'Debit'), ('NEUTRAL', 'Neutral')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bankaccount',
|
||||
name='club',
|
||||
field=models.ForeignKey(related_name='bank_accounts', verbose_name='club', to='club.Club'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='clubaccount',
|
||||
name='bank_account',
|
||||
field=models.ForeignKey(related_name='club_accounts', verbose_name='bank account', to='accounting.BankAccount'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='clubaccount',
|
||||
name='club',
|
||||
field=models.ForeignKey(related_name='club_account', verbose_name='club', to='club.Club'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='generaljournal',
|
||||
name='club_account',
|
||||
field=models.ForeignKey(related_name='journals', verbose_name='club account', to='accounting.ClubAccount'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='generaljournal',
|
||||
name='name',
|
||||
field=models.CharField(max_length=40, verbose_name='name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operation',
|
||||
name='accounting_type',
|
||||
field=models.ForeignKey(related_name='operations', null=True, blank=True, verbose_name='accounting type', to='accounting.AccountingType'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operation',
|
||||
name='cheque_number',
|
||||
field=models.CharField(verbose_name='cheque number', null=True, max_length=32, blank=True, default=''),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operation',
|
||||
name='journal',
|
||||
field=models.ForeignKey(related_name='operations', verbose_name='journal', to='accounting.GeneralJournal'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operation',
|
||||
name='remark',
|
||||
field=models.CharField(max_length=128, verbose_name='comment'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='simplifiedaccountingtype',
|
||||
name='accounting_type',
|
||||
field=models.ForeignKey(related_name='simplified_types', verbose_name='simplified accounting types', to='accounting.AccountingType'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='simpleaccounting_type',
|
||||
field=models.ForeignKey(related_name='operations', null=True, blank=True, verbose_name='simple type', to='accounting.SimplifiedAccountingType'),
|
||||
),
|
||||
]
|
@ -1,5 +1,6 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core import validators
|
||||
from django.db.models import Count
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
@ -45,7 +46,7 @@ class BankAccount(models.Model):
|
||||
name = models.CharField(_('name'), max_length=30)
|
||||
iban = models.CharField(_('iban'), max_length=255, blank=True)
|
||||
number = models.CharField(_('account number'), max_length=255, blank=True)
|
||||
club = models.ForeignKey(Club, related_name="bank_accounts")
|
||||
club = models.ForeignKey(Club, related_name="bank_accounts", verbose_name=_("club"))
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
@ -66,8 +67,8 @@ class BankAccount(models.Model):
|
||||
|
||||
class ClubAccount(models.Model):
|
||||
name = models.CharField(_('name'), max_length=30)
|
||||
club = models.OneToOneField(Club, related_name="club_account")
|
||||
bank_account = models.ForeignKey(BankAccount, related_name="club_accounts")
|
||||
club = models.ForeignKey(Club, related_name="club_account", verbose_name=_("club"))
|
||||
bank_account = models.ForeignKey(BankAccount, related_name="club_accounts", verbose_name=_("bank account"))
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
@ -92,6 +93,9 @@ class ClubAccount(models.Model):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_open_journal(self):
|
||||
return self.journals.filter(closed=False).first()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('accounting:club_details', kwargs={'c_account_id': self.id})
|
||||
|
||||
@ -108,9 +112,9 @@ class GeneralJournal(models.Model):
|
||||
"""
|
||||
start_date = models.DateField(_('start date'))
|
||||
end_date = models.DateField(_('end date'), null=True, blank=True, default=None)
|
||||
name = models.CharField(_('name'), max_length=30)
|
||||
name = models.CharField(_('name'), max_length=40)
|
||||
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, verbose_name=_("club account"))
|
||||
amount = CurrencyField(_('amount'), default=0)
|
||||
effective_amount = CurrencyField(_('effective_amount'), default=0)
|
||||
|
||||
@ -134,7 +138,7 @@ class GeneralJournal(models.Model):
|
||||
self.amount = 0
|
||||
self.effective_amount = 0
|
||||
for o in self.operations.all():
|
||||
if o.accounting_type.movement_type == "credit":
|
||||
if o.accounting_type.movement_type == "CREDIT":
|
||||
if o.done:
|
||||
self.effective_amount += o.amount
|
||||
self.amount += o.amount
|
||||
@ -149,20 +153,24 @@ class Operation(models.Model):
|
||||
An operation is a line in the journal, a debit or a credit
|
||||
"""
|
||||
number = models.IntegerField(_('number'))
|
||||
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False)
|
||||
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal"))
|
||||
amount = CurrencyField(_('amount'))
|
||||
date = models.DateField(_('date'))
|
||||
label = models.CharField(_('label'), max_length=50)
|
||||
remark = models.TextField(_('remark'), max_length=255)
|
||||
remark = models.CharField(_('comment'), max_length=128)
|
||||
mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD)
|
||||
cheque_number = models.IntegerField(_('cheque number'), default=-1)
|
||||
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)
|
||||
done = models.BooleanField(_('is done'), default=False)
|
||||
accounting_type = models.ForeignKey('AccountingType', related_name="operations", verbose_name=_("accounting type"))
|
||||
simpleaccounting_type = models.ForeignKey('SimplifiedAccountingType', related_name="operations",
|
||||
verbose_name=_("simple type"), null=True, blank=True)
|
||||
accounting_type = models.ForeignKey('AccountingType', related_name="operations",
|
||||
verbose_name=_("accounting type"), null=True, blank=True)
|
||||
target_type = models.CharField(_('target type'), max_length=10,
|
||||
choices=[('USER', _('User')), ('CLUB', _('Club')), ('ACCOUNT', _('Account')), ('COMPANY', _('Company')), ('OTHER', _('Other'))])
|
||||
target_id = models.IntegerField(_('target id'), null=True, blank=True)
|
||||
target_label = models.CharField(_('target label'), max_length=32, default="", blank=True)
|
||||
linked_operation = models.OneToOneField('self', related_name='operation_linked_to', verbose_name=_("linked operation"),
|
||||
null=True, blank=True, default=None)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('number', 'journal')
|
||||
@ -183,6 +191,14 @@ class Operation(models.Model):
|
||||
raise ValidationError(_("Target does not exists"))
|
||||
if self.target_type == "OTHER" and self.target_label == "":
|
||||
raise ValidationError(_("Please add a target label if you set no existing target"))
|
||||
if not self.accounting_type and not self.simpleaccounting_type:
|
||||
raise ValidationError(_("You need to provide ether a simplified accounting type or a standard accounting type"))
|
||||
if self.simpleaccounting_type:
|
||||
self.accounting_type = self.simpleaccounting_type.accounting_type
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
return self.get_target()
|
||||
|
||||
def get_target(self):
|
||||
tar = None
|
||||
@ -237,9 +253,13 @@ class AccountingType(models.Model):
|
||||
|
||||
Thoses are numbers used in accounting to classify operations
|
||||
"""
|
||||
code = models.CharField(_('code'), max_length=16) # TODO: add number validator
|
||||
label = models.CharField(_('label'), max_length=60)
|
||||
movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12)
|
||||
code = models.CharField(_('code'), max_length=16,
|
||||
validators=[
|
||||
validators.RegexValidator(r'^[0-9]*$', _('An accounting type code contains only numbers')),
|
||||
],
|
||||
)
|
||||
label = models.CharField(_('label'), max_length=128)
|
||||
movement_type = models.CharField(_('movement type'), choices=[('CREDIT', 'Credit'), ('DEBIT', 'Debit'), ('NEUTRAL', 'Neutral')], max_length=12)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("accounting type")
|
||||
@ -256,4 +276,29 @@ class AccountingType(models.Model):
|
||||
return reverse('accounting:type_list')
|
||||
|
||||
def __str__(self):
|
||||
return self.movement_type+" - "+self.code+" - "+self.label
|
||||
return self.code+" - "+self.movement_type+" - "+self.label
|
||||
|
||||
class SimplifiedAccountingType(models.Model):
|
||||
"""
|
||||
Class describing the simplified accounting types.
|
||||
"""
|
||||
label = models.CharField(_('label'), max_length=128)
|
||||
accounting_type = models.ForeignKey(AccountingType, related_name="simplified_types",
|
||||
verbose_name=_("simplified accounting types"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("simplified type")
|
||||
|
||||
@property
|
||||
def movement_type(self):
|
||||
return self.accounting_type.movement_type
|
||||
|
||||
def get_movement_type_display(self):
|
||||
return self.accounting_type.get_movement_type_display()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('accounting:simple_type_list')
|
||||
|
||||
def __str__(self):
|
||||
return self.label+" - "+self.accounting_type.code+" - "+self.get_movement_type_display()
|
||||
|
||||
|
@ -5,6 +5,11 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Accounting types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:type_new') }}">{% trans %}New accounting type{% endtrans %}</a></p>
|
||||
{% if accountingtype_list %}
|
||||
<h3>{% trans %}Accounting type list{% endtrans %}</h3>
|
||||
|
@ -1,10 +1,15 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Bank account: {% endtrans %}{{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
|
||||
<h4>{% trans %}Infos{% endtrans %}</h4>
|
||||
<ul>
|
||||
@ -14,9 +19,12 @@
|
||||
<p><a href="{{ url('accounting:club_new') }}?parent={{ object.id }}">{% trans %}New club account{% endtrans %}</a></p>
|
||||
<ul>
|
||||
{% for c in object.club_accounts.all() %}
|
||||
<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_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a></li>
|
||||
<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>
|
||||
{% if user.is_root %}
|
||||
- <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -5,15 +5,24 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h4>
|
||||
{% trans %}Accounting{% endtrans %}
|
||||
</h4>
|
||||
{% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) %}
|
||||
<p><a href="{{ url('accounting:simple_type_list') }}">{% trans %}Manage simplified types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if bankaccount_list %}
|
||||
<h3>{% trans %}Bank account list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in bankaccount_list %}
|
||||
<li><a href="{{ url('accounting:bank_details', b_account_id=a.id) }}">{{ a }}</a> -
|
||||
<a href="{{ url('accounting:bank_edit', b_account_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> -
|
||||
<a href="{{ url('accounting:bank_delete', b_account_id=a.id) }}">{% trans %}Delete{% endtrans %}</a></li>
|
||||
{% for a in object_list %}
|
||||
<li><a href="{{ url('accounting:bank_details', b_account_id=a.id) }}">{{ a }}</a>
|
||||
- <a href="{{ url('accounting:bank_edit', b_account_id=a.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% if user.is_root %}
|
||||
- <a href="{{ url('accounting:bank_delete', b_account_id=a.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
|
@ -1,10 +1,16 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Club account:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
|
||||
{{ object }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Club account:{% endtrans %} {{ object.name }}</h2>
|
||||
{% if not object.has_open_journal() %}
|
||||
<p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p>
|
||||
|
@ -1,5 +1,9 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
@ -7,6 +11,8 @@
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}General journal:{% endtrans %} {{ object.name }}</h2>
|
||||
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }} € -
|
||||
<strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }} €</p>
|
||||
{% if object.closed %}
|
||||
@ -19,7 +25,6 @@
|
||||
<tr>
|
||||
<td>{% trans %}Nb{% endtrans %}</td>
|
||||
<td>{% trans %}Date{% endtrans %}</td>
|
||||
<td>{% trans %}Label{% endtrans %}</td>
|
||||
<td>{% trans %}Amount{% endtrans %}</td>
|
||||
<td>{% trans %}Payment mode{% endtrans %}</td>
|
||||
<td>{% trans %}Target{% endtrans %}</td>
|
||||
@ -36,7 +41,6 @@
|
||||
<tr>
|
||||
<td>{{ o.number }}</td>
|
||||
<td>{{ o.date }}</td>
|
||||
<td>{{ o.label }}</td>
|
||||
<td>{{ o.amount }} €</td>
|
||||
<td>{{ o.get_mode_display() }}</td>
|
||||
{% if o.target_type == "OTHER" %}
|
||||
|
55
accounting/templates/accounting/operation_edit.jinja
Normal file
55
accounting/templates/accounting/operation_edit.jinja
Normal file
@ -0,0 +1,55 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Edit operation{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Edit operation{% endtrans %}</h2>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.journal }}
|
||||
{{ form.target_id }}
|
||||
<p>{{ form.amount.errors }}<label for="{{ form.amount.name }}">{{ form.amount.label }}</label> {{ form.amount }}</p>
|
||||
<p>{{ form.remark.errors }}<label for="{{ form.remark.name }}">{{ form.remark.label }}</label> {{ form.remark }}</p>
|
||||
<p>{{ form.target_type.errors }}<label for="{{ form.target_type.name }}">{{ form.target_type.label }}</label> </p>
|
||||
{% for choice in form.target_type %}
|
||||
{% if choice.choice_value != "" %}
|
||||
{{ choice }}
|
||||
{% if choice.choice_value == "USER" %}
|
||||
{{ form.user }}
|
||||
{% elif choice.choice_value == "CLUB" %}
|
||||
{{ form.club }}
|
||||
{% elif choice.choice_value == "ACCOUNT" %}
|
||||
{{ form.club_account }}
|
||||
{% elif choice.choice_value == "COMPANY" %}
|
||||
{{ form.company }}
|
||||
{% elif choice.choice_value == "OTHER" %}
|
||||
{{ form.target_label }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<p>{{ form.date.errors }}<label for="{{ form.date.name }}">{{ form.date.label }}</label> {{ form.date }}</p>
|
||||
<p>{{ form.mode.errors }}<label for="{{ form.mode.name }}">{{ form.mode.label }}</label> {{ form.mode }}</p>
|
||||
<p>{{ form.cheque_number.errors }}<label for="{{ form.cheque_number.name }}">{{ form.cheque_number.label }}</label> {{
|
||||
form.cheque_number }}</p>
|
||||
<p>{{ form.invoice.errors }}<label for="{{ form.invoice.name }}">{{ form.invoice.label }}</label> {{ form.invoice }}</p>
|
||||
<p>{{ form.simpleaccounting_type.errors }}<label for="{{ form.simpleaccounting_type.name }}">{{
|
||||
form.simpleaccounting_type.label }}</label> {{ form.simpleaccounting_type }}</p>
|
||||
<p>{{ form.accounting_type.errors }}<label for="{{ form.accounting_type.name }}">{{ form.accounting_type.label }}</label> {{
|
||||
form.accounting_type }}</p>
|
||||
<p>{{ form.done.errors }}<label for="{{ form.done.name }}">{{ form.done.label }}</label> {{ form.done }}</p>
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
$( function() {
|
||||
} );
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Simplified type list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Simplified types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:simple_type_new') }}">{% trans %}New simplified type{% endtrans %}</a></p>
|
||||
{% if simplifiedaccountingtype_list %}
|
||||
<h3>{% trans %}Simplified type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in simplifiedaccountingtype_list %}
|
||||
<li><a href="{{ url('accounting:simple_type_edit', type_id=a.id) }}">{{ a }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -3,6 +3,10 @@ from django.conf.urls import url, include
|
||||
from accounting.views import *
|
||||
|
||||
urlpatterns = [
|
||||
# Accounting types
|
||||
url(r'^simple_type$', SimplifiedAccountingTypeListView.as_view(), name='simple_type_list'),
|
||||
url(r'^simple_type/create$', SimplifiedAccountingTypeCreateView.as_view(), name='simple_type_new'),
|
||||
url(r'^simple_type/(?P<type_id>[0-9]+)/edit$', SimplifiedAccountingTypeEditView.as_view(), name='simple_type_edit'),
|
||||
# Accounting types
|
||||
url(r'^type$', AccountingTypeListView.as_view(), name='type_list'),
|
||||
url(r'^type/create$', AccountingTypeCreateView.as_view(), name='type_new'),
|
||||
|
@ -4,10 +4,49 @@ from django.shortcuts import render
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.forms.models import modelform_factory
|
||||
from django.forms import HiddenInput
|
||||
from django import forms
|
||||
|
||||
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
|
||||
|
||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
|
||||
from core.views.forms import SelectFile, SelectDate
|
||||
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company
|
||||
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company, SimplifiedAccountingType
|
||||
|
||||
# Main accounting view
|
||||
|
||||
class BankAccountListView(CanViewMixin, ListView):
|
||||
"""
|
||||
A list view for the admins
|
||||
"""
|
||||
model = BankAccount
|
||||
template_name = 'accounting/bank_account_list.jinja'
|
||||
ordering = ['name']
|
||||
|
||||
# Simplified accounting types
|
||||
|
||||
class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
|
||||
"""
|
||||
A list view for the admins
|
||||
"""
|
||||
model = SimplifiedAccountingType
|
||||
template_name = 'accounting/simplifiedaccountingtype_list.jinja'
|
||||
|
||||
class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
|
||||
"""
|
||||
An edit view for the admins
|
||||
"""
|
||||
model = SimplifiedAccountingType
|
||||
pk_url_kwarg = "type_id"
|
||||
fields = ['label', 'accounting_type']
|
||||
template_name = 'core/edit.jinja'
|
||||
|
||||
class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
|
||||
"""
|
||||
Create an accounting type (for the admins)
|
||||
"""
|
||||
model = SimplifiedAccountingType
|
||||
fields = ['label', 'accounting_type']
|
||||
template_name = 'core/create.jinja'
|
||||
|
||||
# Accounting types
|
||||
|
||||
@ -37,20 +76,13 @@ class AccountingTypeCreateView(CanCreateMixin, CreateView):
|
||||
|
||||
# BankAccount views
|
||||
|
||||
class BankAccountListView(CanViewMixin, ListView):
|
||||
"""
|
||||
A list view for the admins
|
||||
"""
|
||||
model = BankAccount
|
||||
template_name = 'accounting/bank_account_list.jinja'
|
||||
|
||||
class BankAccountEditView(CanViewMixin, UpdateView):
|
||||
"""
|
||||
An edit view for the admins
|
||||
"""
|
||||
model = BankAccount
|
||||
pk_url_kwarg = "b_account_id"
|
||||
fields = ['name', 'iban', 'number']
|
||||
fields = ['name', 'iban', 'number', 'club']
|
||||
template_name = 'core/edit.jinja'
|
||||
|
||||
class BankAccountDetailView(CanViewMixin, DetailView):
|
||||
@ -129,7 +161,8 @@ class JournalCreateView(CanCreateMixin, CreateView):
|
||||
Create a general journal
|
||||
"""
|
||||
model = GeneralJournal
|
||||
fields = ['name', 'start_date', 'club_account']
|
||||
form_class = modelform_factory(GeneralJournal, fields=['name', 'start_date', 'club_account'],
|
||||
widgets={ 'start_date': SelectDate, })
|
||||
template_name = 'core/create.jinja'
|
||||
|
||||
def get_initial(self):
|
||||
@ -159,16 +192,82 @@ class JournalEditView(CanEditMixin, UpdateView):
|
||||
|
||||
# Operation views
|
||||
|
||||
class OperationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Operation
|
||||
fields = ['amount', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode',
|
||||
'cheque_number', 'invoice', 'simpleaccounting_type', 'accounting_type', 'done']
|
||||
widgets = {
|
||||
'journal': HiddenInput,
|
||||
'target_id': HiddenInput,
|
||||
'date': SelectDate,
|
||||
'invoice': SelectFile,
|
||||
'target_type': forms.RadioSelect,
|
||||
}
|
||||
user = AutoCompleteSelectField('users', help_text=None, required=False)
|
||||
club_account = AutoCompleteSelectField('club_accounts', help_text=None, required=False)
|
||||
club = AutoCompleteSelectField('clubs', help_text=None, required=False)
|
||||
company = AutoCompleteSelectField('companies', help_text=None, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(OperationForm, self).__init__(*args, **kwargs)
|
||||
if self.instance.target_type == "USER":
|
||||
self.fields['user'].initial = self.instance.target_id
|
||||
elif self.instance.target_type == "ACCOUNT":
|
||||
self.fields['club_account'].initial = self.instance.target_id
|
||||
elif self.instance.target_type == "CLUB":
|
||||
self.fields['club'].initial = self.instance.target_id
|
||||
elif self.instance.target_type == "COMPANY":
|
||||
self.fields['company'].initial = self.instance.target_id
|
||||
|
||||
def clean(self):
|
||||
self.cleaned_data = super(OperationForm, self).clean()
|
||||
print(self.errors)
|
||||
if self.cleaned_data['target_type'] == "USER":
|
||||
self.cleaned_data['target_id'] = self.cleaned_data['user'].id
|
||||
elif self.cleaned_data['target_type'] == "ACCOUNT":
|
||||
self.cleaned_data['target_id'] = self.cleaned_data['club_account'].id
|
||||
elif self.cleaned_data['target_type'] == "CLUB":
|
||||
self.cleaned_data['target_id'] = self.cleaned_data['club'].id
|
||||
elif self.cleaned_data['target_type'] == "COMPANY":
|
||||
self.cleaned_data['target_id'] = self.cleaned_data['company'].id
|
||||
return self.cleaned_data
|
||||
|
||||
def save(self):
|
||||
ret = super(OperationForm, self).save()
|
||||
if self.instance.target_type == "ACCOUNT" and not self.instance.linked_operation and self.instance.target.has_open_journal():
|
||||
inst = self.instance
|
||||
club_account = inst.target
|
||||
acc_type = AccountingType.objects.exclude(movement_type="NEUTRAL").exclude(
|
||||
movement_type=inst.accounting_type.movement_type).first() # Select a random opposite accounting type
|
||||
op = Operation(
|
||||
journal=club_account.get_open_journal(),
|
||||
amount=inst.amount,
|
||||
date=inst.date,
|
||||
remark=inst.remark,
|
||||
mode=inst.mode,
|
||||
cheque_number=inst.cheque_number,
|
||||
invoice=inst.invoice,
|
||||
done=False, # Has to be checked by hand
|
||||
simpleaccounting_type=None,
|
||||
accounting_type=acc_type,
|
||||
target_type="ACCOUNT",
|
||||
target_id=inst.journal.club_account.id,
|
||||
target_label="",
|
||||
linked_operation=inst,
|
||||
)
|
||||
op.save()
|
||||
self.instance.linked_operation = op
|
||||
self.save()
|
||||
return ret
|
||||
|
||||
class OperationCreateView(CanCreateMixin, CreateView):
|
||||
"""
|
||||
Create an operation
|
||||
"""
|
||||
model = Operation
|
||||
form_class = modelform_factory(Operation,
|
||||
fields=['amount', 'label', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode',
|
||||
'cheque_number', 'invoice', 'accounting_type', 'done'],
|
||||
widgets={'journal': HiddenInput, 'date': SelectDate, 'invoice': SelectFile})
|
||||
template_name = 'core/create.jinja'
|
||||
form_class = OperationForm
|
||||
template_name = 'accounting/operation_edit.jinja'
|
||||
|
||||
def get_initial(self):
|
||||
ret = super(OperationCreateView, self).get_initial()
|
||||
@ -184,11 +283,8 @@ class OperationEditView(CanEditMixin, UpdateView):
|
||||
"""
|
||||
model = Operation
|
||||
pk_url_kwarg = "op_id"
|
||||
form_class = modelform_factory(Operation,
|
||||
fields = ['amount', 'label', 'remark', 'target_type', 'target_id', 'target_label', 'date', 'mode', 'cheque_number',
|
||||
'invoice', 'accounting_type', 'done'],
|
||||
widgets={'date': SelectDate, 'invoice': SelectFile})
|
||||
template_name = 'core/edit.jinja'
|
||||
form_class = OperationForm
|
||||
template_name = 'accounting/operation_edit.jinja'
|
||||
|
||||
# Company views
|
||||
|
||||
|
Reference in New Issue
Block a user