Migrate accounting

This commit is contained in:
Skia 2016-08-24 19:50:22 +02:00
parent a4df1ae9a5
commit 078b63d970
22 changed files with 904 additions and 200 deletions

View File

@ -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)

View 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'),
),
]

View File

@ -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()

View File

@ -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>

View File

@ -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>

View File

@ -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 %}

View File

@ -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>

View File

@ -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" %}

View 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 %}

View File

@ -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 %}

View File

@ -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'),

View File

@ -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

View File

@ -8,7 +8,7 @@
<li><a href="{{ url('club:club_view', club_id=club.id) }}">{{ club.name }}</a>
{%- if club.children.all()|length != 0 %}
<ul>
{%- for c in club.children.all() %}
{%- for c in club.children.order_by('name') %}
{{ display_club(c) }}
{%- endfor %}
</ul>
@ -23,7 +23,7 @@
{% if club_list %}
<h3>{% trans %}Club list{% endtrans %}</h3>
<ul>
{%- for c in club_list if c.parent is none %}
{%- for c in club_list.order_by('name') if c.parent is none %}
{{ display_club(c) }}
{%- endfor %}
</ul>

View File

@ -3,11 +3,11 @@
{% block content %}
<h3>{% trans %}Club tools{% endtrans %}</h3>
<p><a href="{{ url('club:club_view', club_id=object.id) }}">Back to club</a></p>
<ul>
{% if object.counters.all()|count > 0 %}
<div>
{% if object.counters.filter(type="OFFICE")|count > 0 %}
<h4>{% trans %}Counters:{% endtrans %}</h4>
<ul>
{% for c in object.counters.all() %}
{% for c in object.counters.filter(type="OFFICE") %}
<li>{{ c }}:
<a href="{{ url('counter:details', counter_id=c.id) }}">View</a>
<a href="{{ url('counter:admin', counter_id=c.id) }}">Edit</a>
@ -15,13 +15,18 @@
{% endfor %}
</ul>
{% endif %}
{% if object.club_account %}
<li>Accouting: <a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object }}</a></li>
{% if object.club_account.exists() %}
<h4>{% trans %}Accouting: {% endtrans %}</h4>
<ul>
{% for ca in object.club_account.all() %}
<li><a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %}
<li><a href="{{ url('launderette:launderette_list') }}">{% trans %}Manage launderettes{% endtrans %}</a></li>
{% endif %}
</ul>
</div>
{% endblock %}

View File

@ -4,6 +4,7 @@ from core.views.site import search_user
from core.models import User, Group
from club.models import Club
from counter.models import Product, Counter
from accounting.models import ClubAccount, Company
@register('users')
class UsersLookup(LookupChannel):
@ -63,3 +64,23 @@ class ProductsLookup(LookupChannel):
def format_item_display(self, item):
return item.name
@register('club_accounts')
class ClubAccountLookup(LookupChannel):
model = ClubAccount
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)[:50]
def format_item_display(self, item):
return item.name
@register('companies')
class CompaniesLookup(LookupChannel):
model = Company
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)[:50]
def format_item_display(self, item):
return item.name

View File

@ -36,6 +36,11 @@ header form {
margin: 0px auto;
padding: 0.3em 1%;
}
#language_chooser {
position: absolute;
left: 5px;
top: 5px;
}
/*---------------------------------NAV---------------------------------*/
nav {

View File

@ -41,16 +41,17 @@
{% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) or user.is_root %}
<li><a href="{{ url('accounting:bank_list') }}">{% trans %}General accounting{% endtrans %}</a></li>
{% endif %}
{% for m in user.membership.filter(end_date=None).filter(role__gte=7).all() %}
{% for b in m.club.bank_accounts.all() %}
{% for m in user.membership.filter(end_date=None).filter(role__gte=7).all() -%}
{%- for b in m.club.bank_accounts.all() %}
<li><strong>{% trans %}Bank account: {% endtrans %}</strong>
<a href="{{ url('accounting:bank_details', b_account_id=b.id) }}">{{ b.club }}</a></li>
{% endfor %}
{% if m.club.club_account %}
<li><strong>{% trans %}Club account: {% endtrans %}</strong>
<a href="{{ url('accounting:club_details', c_account_id=m.club.club_account.id) }}">{{ m.club.club_account }}</a></li>
{% endif %}
{% endfor %}
<a href="{{ url('accounting:bank_details', b_account_id=b.id) }}">{{ b }}</a></li>
{%- endfor %}
{% if m.club.club_account.exists() -%}
{% for ca in m.club.club_account.all() %}
<li><strong>{% trans %}Club account: {% endtrans %}</strong> <a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca }}</a></li>
{%- endfor %}
{%- endif -%}
{%- endfor %}
</ul>
<hr>

View File

@ -4,6 +4,8 @@ from core.views import *
urlpatterns = [
url(r'^$', index, name='index'),
# Search
url(r'^search/$', search_view, name='search'),
url(r'^search_json/$', search_json, name='search_json'),
url(r'^search_user/$', search_user_json, name='search_user'),

View File

@ -99,6 +99,17 @@ class CanViewMixin(View):
except: pass
raise PermissionDenied
def get_context_data(self, **kwargs):
context = super(CanViewMixin, self).get_context_data(**kwargs)
if hasattr(self, 'object_list'):
ba_list = list(self.object_list)
l = []
for ba in ba_list:
if self.request.user.can_view(ba):
l.append(ba)
context['object_list'] = l
return context
from .user import *
from .page import *
from .files import *

Binary file not shown.

View File

@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-22 18:13+0200\n"
"POT-Creation-Date: 2016-08-24 16:57+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
@ -16,125 +16,146 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: accounting/models.py:33 accounting/models.py:45 accounting/models.py:68
#: accounting/models.py:111 club/models.py:18 counter/models.py:52
#: accounting/models.py:34 accounting/models.py:46 accounting/models.py:69
#: accounting/models.py:115 club/models.py:18 counter/models.py:52
#: counter/models.py:77 counter/models.py:111 launderette/models.py:15
#: launderette/models.py:60 launderette/models.py:85
msgid "name"
msgstr "nom"
#: accounting/models.py:36
#: accounting/models.py:37
msgid "company"
msgstr "entreprise"
#: accounting/models.py:46
#: accounting/models.py:47
msgid "iban"
msgstr "IBAN"
#: accounting/models.py:47
#: accounting/models.py:48
msgid "account number"
msgstr "numero de compte"
#: accounting/models.py:102
#: accounting/models.py:49 accounting/models.py:70 club/models.py:146
#: counter/models.py:86
msgid "club"
msgstr "club"
#: accounting/models.py:71
msgid "bank account"
msgstr "compte en banque"
#: accounting/models.py:106
#, python-format
msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:109 club/models.py:147 counter/models.py:297
#: accounting/models.py:113 club/models.py:147 counter/models.py:297
#: launderette/models.py:122
msgid "start date"
msgstr "date de début"
#: accounting/models.py:110 club/models.py:148 counter/models.py:298
#: accounting/models.py:114 club/models.py:148 counter/models.py:298
msgid "end date"
msgstr "date de fin"
#: accounting/models.py:112
#: accounting/models.py:116
msgid "is closed"
msgstr "est fermé"
#: accounting/models.py:114 accounting/models.py:153 counter/models.py:25
#: accounting/models.py:117
msgid "club account"
msgstr "compte club"
#: accounting/models.py:118 accounting/models.py:157 counter/models.py:25
#: counter/models.py:212
msgid "amount"
msgstr "montant"
#: accounting/models.py:115
#: accounting/models.py:119
msgid "effective_amount"
msgstr "montant effectif"
#: accounting/models.py:151
#: accounting/models.py:155
msgid "number"
msgstr "numéro"
#: accounting/models.py:154 core/models.py:430 core/models.py:706
#: accounting/models.py:156
msgid "journal"
msgstr "classeur"
#: accounting/models.py:158 core/models.py:430 core/models.py:706
#: counter/models.py:215 counter/models.py:261 eboutic/models.py:14
#: eboutic/models.py:47
msgid "date"
msgstr "date"
#: accounting/models.py:155 accounting/models.py:241 counter/models.py:253
msgid "label"
msgstr "intitulé"
#: accounting/models.py:159
msgid "comment"
msgstr "commentaire"
#: accounting/models.py:156
msgid "remark"
msgstr "remarque"
#: accounting/models.py:157 counter/models.py:216 counter/models.py:262
#: accounting/models.py:160 counter/models.py:216 counter/models.py:262
#: subscription/models.py:34
msgid "payment method"
msgstr "méthode de paiement"
#: accounting/models.py:158
#: accounting/models.py:161
msgid "cheque number"
msgstr "numéro de chèque"
#: accounting/models.py:159 eboutic/models.py:115
#: accounting/models.py:162 eboutic/models.py:115
msgid "invoice"
msgstr "facture"
#: accounting/models.py:160
#: accounting/models.py:163
msgid "is done"
msgstr "est fait"
#: accounting/models.py:161 accounting/models.py:245
#: accounting/models.py:165
msgid "simple type"
msgstr "type simplifié"
#: accounting/models.py:167 accounting/models.py:265
msgid "accounting type"
msgstr "type comptable"
#: accounting/models.py:162
#: accounting/models.py:168
msgid "target type"
msgstr "type de cible"
#: accounting/models.py:163
#: accounting/models.py:169
#: launderette/templates/launderette/launderette_admin.jinja:44
msgid "User"
msgstr "Utilisateur"
#: accounting/models.py:163 club/templates/club/club_detail.jinja:4
#: accounting/models.py:169 club/templates/club/club_detail.jinja:4
msgid "Club"
msgstr "Club"
#: accounting/models.py:163 core/templates/core/user_base.jinja:18
#: accounting/models.py:169 core/templates/core/user_base.jinja:18
msgid "Account"
msgstr "Compte"
#: accounting/models.py:163
#: accounting/models.py:169
msgid "Company"
msgstr "Entreprise"
#: accounting/models.py:163 sith/settings.py:284 sith/settings_sample.py:267
#: accounting/models.py:169 sith/settings.py:284 sith/settings_sample.py:267
msgid "Other"
msgstr "Autre"
#: accounting/models.py:164
#: accounting/models.py:170
msgid "target id"
msgstr "id de la cible"
#: accounting/models.py:165
#: accounting/models.py:171
msgid "target label"
msgstr "nom de la cible"
#: accounting/models.py:180
#: accounting/models.py:172
msgid "linked operation"
msgstr "opération liée"
#: accounting/models.py:188
#, python-format
msgid ""
"The date can not be before the start date of the journal, which is\n"
@ -143,69 +164,102 @@ msgstr ""
"La date ne peut pas être avant la date de début du journal, qui est\n"
"%(start_date)s."
#: accounting/models.py:183
#: accounting/models.py:191
msgid "Target does not exists"
msgstr "La cible n'existe pas."
#: accounting/models.py:185
#: accounting/models.py:193
msgid "Please add a target label if you set no existing target"
msgstr ""
"Merci d'ajouter un nom de cible si vous ne spécifiez pas de cible existante"
#: accounting/models.py:240 counter/models.py:81
#: accounting/models.py:195
msgid ""
"You need to provide ether a simplified accounting type or a standard "
"accounting type"
msgstr ""
"Vous devez fournir soit un type comptable simplifié ou un type comptable "
"standard"
#: accounting/models.py:256 counter/models.py:81
msgid "code"
msgstr "code"
#: accounting/models.py:242
#: accounting/models.py:258
msgid "An accounting type code contains only numbers"
msgstr "Un code comptable ne contient que des numéros"
#: accounting/models.py:261 accounting/models.py:285 counter/models.py:253
msgid "label"
msgstr "intitulé"
#: accounting/models.py:262
msgid "movement type"
msgstr "type de mouvement"
#: accounting/models.py:287
msgid "simplified accounting types"
msgstr "type simplifié"
#: accounting/models.py:290
msgid "simplified type"
msgstr "type simplifié"
#: accounting/templates/accounting/accountingtype_list.jinja:4
#: accounting/templates/accounting/accountingtype_list.jinja:10
#: accounting/templates/accounting/accountingtype_list.jinja:15
msgid "Accounting type list"
msgstr "Liste des types comptable"
#: accounting/templates/accounting/accountingtype_list.jinja:8
msgid "New accounting type"
msgstr "Nouveau type comptable"
#: accounting/templates/accounting/accountingtype_list.jinja:17
msgid "There is no types in this website."
msgstr "Il n'y a pas de types comptable dans ce site web."
#: accounting/templates/accounting/bank_account_details.jinja:5
#: accounting/templates/accounting/club_account_details.jinja:5
#: accounting/templates/accounting/journal_details.jinja:5
#: accounting/templates/accounting/accountingtype_list.jinja:9
#: accounting/templates/accounting/bank_account_details.jinja:9
#: accounting/templates/accounting/bank_account_list.jinja:9
#: accounting/templates/accounting/club_account_details.jinja:9
#: accounting/templates/accounting/journal_details.jinja:9
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:9
#: core/templates/core/user_tools.jinja:39
msgid "Accounting"
msgstr "Comptabilité"
#: accounting/templates/accounting/bank_account_details.jinja:8
#: accounting/templates/accounting/accountingtype_list.jinja:10
msgid "Accounting types"
msgstr "Type comptable"
#: accounting/templates/accounting/accountingtype_list.jinja:13
msgid "New accounting type"
msgstr "Nouveau type comptable"
#: accounting/templates/accounting/accountingtype_list.jinja:22
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:22
msgid "There is no types in this website."
msgstr "Il n'y a pas de types comptable dans ce site web."
#: accounting/templates/accounting/bank_account_details.jinja:4
#: accounting/templates/accounting/bank_account_details.jinja:13
#: core/templates/core/user_tools.jinja:46
msgid "Bank account: "
msgstr "Compte en banque : "
#: accounting/templates/accounting/bank_account_details.jinja:9
#: accounting/templates/accounting/bank_account_details.jinja:14
#: core/templates/core/user_base.jinja:7
msgid "Infos"
msgstr "Infos"
#: accounting/templates/accounting/bank_account_details.jinja:11
#: accounting/templates/accounting/bank_account_details.jinja:16
msgid "IBAN: "
msgstr "IBAN : "
#: accounting/templates/accounting/bank_account_details.jinja:12
#: accounting/templates/accounting/bank_account_details.jinja:17
msgid "Number: "
msgstr "Numéro : "
#: accounting/templates/accounting/bank_account_details.jinja:14
#: accounting/templates/accounting/bank_account_details.jinja:19
msgid "New club account"
msgstr "Nouveau compte club"
#: accounting/templates/accounting/bank_account_details.jinja:18
#: accounting/templates/accounting/bank_account_list.jinja:15
#: accounting/templates/accounting/club_account_details.jinja:44
#: accounting/templates/accounting/journal_details.jinja:62
#: accounting/templates/accounting/bank_account_details.jinja:23
#: accounting/templates/accounting/bank_account_list.jinja:21
#: accounting/templates/accounting/club_account_details.jinja:50
#: accounting/templates/accounting/journal_details.jinja:68
#: club/templates/club/club_detail.jinja:7 core/templates/core/file.jinja:38
#: core/templates/core/page.jinja:31 core/templates/core/user_base.jinja:10
#: core/templates/core/user_tools.jinja:33
@ -214,8 +268,8 @@ msgstr "Nouveau compte club"
msgid "Edit"
msgstr "Éditer"
#: accounting/templates/accounting/bank_account_details.jinja:19
#: accounting/templates/accounting/bank_account_list.jinja:16
#: accounting/templates/accounting/bank_account_details.jinja:25
#: accounting/templates/accounting/bank_account_list.jinja:23
#: core/templates/core/file_detail.jinja:43
#: core/templates/core/group_list.jinja:13
#: core/templates/core/user_edit.jinja:18
@ -225,144 +279,184 @@ msgid "Delete"
msgstr "Supprimer"
#: accounting/templates/accounting/bank_account_list.jinja:4
#: accounting/templates/accounting/bank_account_list.jinja:11
#: accounting/templates/accounting/bank_account_list.jinja:17
msgid "Bank account list"
msgstr "Liste des comptes en banque"
#: accounting/templates/accounting/bank_account_list.jinja:8
#: accounting/templates/accounting/bank_account_list.jinja:12
msgid "Manage simplified types"
msgstr "Gérer les types simplifiés"
#: accounting/templates/accounting/bank_account_list.jinja:13
msgid "Manage accounting types"
msgstr "Gérer les types comptable"
#: accounting/templates/accounting/bank_account_list.jinja:9
#: accounting/templates/accounting/bank_account_list.jinja:14
msgid "New bank account"
msgstr "Nouveau compte en banque"
#: accounting/templates/accounting/bank_account_list.jinja:20
#: accounting/templates/accounting/bank_account_list.jinja:29
msgid "There is no accounts in this website."
msgstr "Il n'y a pas de comptes dans ce site web."
#: accounting/templates/accounting/club_account_details.jinja:8
#: accounting/templates/accounting/club_account_details.jinja:4
#: accounting/templates/accounting/club_account_details.jinja:14
msgid "Club account:"
msgstr "Compte club : "
#: accounting/templates/accounting/club_account_details.jinja:10
#: accounting/templates/accounting/club_account_details.jinja:16
msgid "New journal"
msgstr "Nouveau classeur"
#: accounting/templates/accounting/club_account_details.jinja:12
#: accounting/templates/accounting/club_account_details.jinja:18
msgid "You can not create new journal while you still have one opened"
msgstr "Vous ne pouvez pas créer de journal tant qu'il y en a un d'ouvert"
#: accounting/templates/accounting/club_account_details.jinja:17
#: accounting/templates/accounting/club_account_details.jinja:23
#: launderette/templates/launderette/launderette_admin.jinja:43
msgid "Name"
msgstr "Nom"
#: accounting/templates/accounting/club_account_details.jinja:18
#: accounting/templates/accounting/club_account_details.jinja:24
msgid "Start"
msgstr "Début"
#: accounting/templates/accounting/club_account_details.jinja:19
#: accounting/templates/accounting/club_account_details.jinja:25
msgid "End"
msgstr "Fin"
#: accounting/templates/accounting/club_account_details.jinja:20
#: accounting/templates/accounting/journal_details.jinja:23
#: accounting/templates/accounting/club_account_details.jinja:26
#: accounting/templates/accounting/journal_details.jinja:29
#: core/templates/core/user_account.jinja:19
#: core/templates/core/user_account.jinja:78
msgid "Amount"
msgstr "Montant"
#: accounting/templates/accounting/club_account_details.jinja:21
#: accounting/templates/accounting/club_account_details.jinja:27
msgid "Effective amount"
msgstr "Montant effectif"
#: accounting/templates/accounting/club_account_details.jinja:22
#: accounting/templates/accounting/club_account_details.jinja:28
msgid "Closed"
msgstr "Fermé"
#: accounting/templates/accounting/club_account_details.jinja:23
#: accounting/templates/accounting/journal_details.jinja:31
#: accounting/templates/accounting/club_account_details.jinja:29
#: accounting/templates/accounting/journal_details.jinja:37
msgid "Actions"
msgstr "Actions"
#: accounting/templates/accounting/club_account_details.jinja:39
#: accounting/templates/accounting/journal_details.jinja:50
#: accounting/templates/accounting/club_account_details.jinja:45
#: accounting/templates/accounting/journal_details.jinja:56
msgid "Yes"
msgstr "Oui"
#: accounting/templates/accounting/club_account_details.jinja:41
#: accounting/templates/accounting/journal_details.jinja:52
#: accounting/templates/accounting/club_account_details.jinja:47
#: accounting/templates/accounting/journal_details.jinja:58
msgid "No"
msgstr "Non"
#: accounting/templates/accounting/club_account_details.jinja:43
#: accounting/templates/accounting/club_account_details.jinja:49
#: core/templates/core/file.jinja:36 core/templates/core/page.jinja:28
msgid "View"
msgstr "Voir"
#: accounting/templates/accounting/journal_details.jinja:10
#: accounting/templates/accounting/journal_details.jinja:4
#: accounting/templates/accounting/journal_details.jinja:15
msgid "General journal:"
msgstr "Classeur : "
#: accounting/templates/accounting/journal_details.jinja:16
#: core/templates/core/user_account.jinja:10
#: counter/templates/counter/counter_click.jinja:31
msgid "Amount: "
msgstr "Montant: "
#: accounting/templates/accounting/journal_details.jinja:11
#: accounting/templates/accounting/journal_details.jinja:17
msgid "Effective amount: "
msgstr "Montant effectif: "
#: accounting/templates/accounting/journal_details.jinja:13
#: accounting/templates/accounting/journal_details.jinja:19
msgid "Journal is closed, you can not create operation"
msgstr "Le classeur est fermé, vous ne pouvez pas créer d'opération"
#: accounting/templates/accounting/journal_details.jinja:15
#: accounting/templates/accounting/journal_details.jinja:21
msgid "New operation"
msgstr "Nouvelle opération"
#: accounting/templates/accounting/journal_details.jinja:20
#: accounting/templates/accounting/journal_details.jinja:26
msgid "Nb"
msgstr "No"
#: accounting/templates/accounting/journal_details.jinja:21
#: accounting/templates/accounting/journal_details.jinja:27
#: core/templates/core/user_account.jinja:16
#: core/templates/core/user_account.jinja:44
#: core/templates/core/user_account.jinja:76
msgid "Date"
msgstr "Date"
#: accounting/templates/accounting/journal_details.jinja:22
#: accounting/templates/accounting/journal_details.jinja:28
#: core/templates/core/user_account.jinja:47
msgid "Label"
msgstr "Intitulé"
#: accounting/templates/accounting/journal_details.jinja:24
#: accounting/templates/accounting/journal_details.jinja:30
msgid "Payment mode"
msgstr "Méthode de paiement"
#: accounting/templates/accounting/journal_details.jinja:25
#: accounting/templates/accounting/journal_details.jinja:31
msgid "Target"
msgstr "Cible"
#: accounting/templates/accounting/journal_details.jinja:26
#: accounting/templates/accounting/journal_details.jinja:32
msgid "Code"
msgstr "Code"
#: accounting/templates/accounting/journal_details.jinja:27
#: accounting/templates/accounting/journal_details.jinja:33
msgid "Nature"
msgstr "Nature"
#: accounting/templates/accounting/journal_details.jinja:28
#: accounting/templates/accounting/journal_details.jinja:34
msgid "Done"
msgstr "Effectué"
#: accounting/templates/accounting/journal_details.jinja:29
#: accounting/templates/accounting/journal_details.jinja:35
msgid "Comment"
msgstr "Commentaire"
#: accounting/templates/accounting/journal_details.jinja:30
#: accounting/templates/accounting/journal_details.jinja:36
msgid "File"
msgstr "Fichier"
#: accounting/templates/accounting/operation_edit.jinja:4
#: accounting/templates/accounting/operation_edit.jinja:8
msgid "Edit operation"
msgstr "Éditer l'opération"
#: accounting/templates/accounting/operation_edit.jinja:43
#: club/templates/club/club_edit.jinja:8
#: club/templates/club/club_edit_prop.jinja:8
#: core/templates/core/create.jinja:12 core/templates/core/edit.jinja:12
#: core/templates/core/file_edit.jinja:8 core/templates/core/page_prop.jinja:8
#: core/templates/core/pagerev_edit.jinja:24
#: counter/templates/counter/counter_edit.jinja:12
#: counter/templates/counter/counter_edit.jinja:14
#: subscription/templates/subscription/subscription.jinja:22
msgid "Save"
msgstr "Sauver"
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:4
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:15
msgid "Simplified type list"
msgstr "Liste des types simplifiés"
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:10
msgid "Simplified types"
msgstr "Types simplifiés"
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:13
msgid "New simplified type"
msgstr "Nouveau type simplifié"
#: club/models.py:20
msgid "unix name"
msgstr "nom unix"
@ -400,10 +494,6 @@ msgstr "Un club avec ce nom UNIX existe déjà."
msgid "user"
msgstr "nom d'utilisateur"
#: club/models.py:146 counter/models.py:86
msgid "club"
msgstr "club"
#: club/models.py:149 core/models.py:135
msgid "role"
msgstr "rôle"
@ -443,17 +533,6 @@ msgstr "Membres"
msgid "Edit club"
msgstr "Éditer le club"
#: club/templates/club/club_edit.jinja:8
#: club/templates/club/club_edit_prop.jinja:8
#: core/templates/core/create.jinja:12 core/templates/core/edit.jinja:12
#: core/templates/core/file_edit.jinja:8 core/templates/core/page_prop.jinja:8
#: core/templates/core/pagerev_edit.jinja:24
#: counter/templates/counter/counter_edit.jinja:12
#: counter/templates/counter/counter_edit.jinja:14
#: subscription/templates/subscription/subscription.jinja:22
msgid "Save"
msgstr "Sauver"
#: club/templates/club/club_edit_prop.jinja:4
msgid "Edit club properties"
msgstr "Éditer les propriétés du club"
@ -481,7 +560,7 @@ msgid "Add"
msgstr "Ajouter"
#: club/templates/club/club_tools.jinja:4
#: core/templates/core/user_tools.jinja:57
#: core/templates/core/user_tools.jinja:58
msgid "Club tools"
msgstr "Outils club"
@ -489,7 +568,11 @@ msgstr "Outils club"
msgid "Counters:"
msgstr "Comptoirs : "
#: club/templates/club/club_tools.jinja:22
#: club/templates/club/club_tools.jinja:19
msgid "Accouting: "
msgstr "Comptabilité : "
#: club/templates/club/club_tools.jinja:27
msgid "Manage launderettes"
msgstr "Gestion des laveries"
@ -1354,7 +1437,7 @@ msgstr "Profil actuel : "
#: core/templates/core/user_edit.jinja:24
msgid "Take picture"
msgstr ""
msgstr "Prendre une photo"
#: core/templates/core/user_edit.jinja:29
msgid "Current avatar: "
@ -1447,7 +1530,7 @@ msgstr "Gestion des types de produit"
msgid "General accounting"
msgstr "Comptabilité générale"
#: core/templates/core/user_tools.jinja:50
#: core/templates/core/user_tools.jinja:51
msgid "Club account: "
msgstr "Compte club : "
@ -1495,7 +1578,7 @@ msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés"
#: core/views/user.py:178
msgid "User already has a profile picture"
msgstr ""
msgstr "L'utilisateur a déjà une photo de profil"
#: counter/models.py:24
msgid "account id"
@ -2135,8 +2218,5 @@ msgid "You must either choose an existing user or create a new one properly"
msgstr ""
"Vous devez soit choisir un utilisateur existant, ou en créer un proprement."
#~ msgid "Products: "
#~ msgstr "Produits : "
#~ msgid "Club: "
#~ msgstr "Club : "
#~ msgid "remark"
#~ msgstr "remarque"

View File

@ -24,6 +24,7 @@ from club.models import Club, Membership
from counter.models import Customer, Counter, Selling, Refilling, Product, ProductType, Permanency
from subscription.models import Subscription, Subscriber
from eboutic.models import Invoice, InvoiceItem
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company, SimplifiedAccountingType
db = MySQLdb.connect(
host="ae-db",
@ -467,7 +468,6 @@ def migrate_product_pict():
WHERE id_file IS NOT NULL
""")
for r in cur:
print(r['nom_prod'])
try:
prod = Product.objects.filter(id=r['id_produit']).first()
if prod:
@ -602,24 +602,241 @@ def migrate_permanencies():
print("FAIL to migrate permanency: %s" % (repr(e)))
cur.close()
### Accounting
def migrate_bank_accounts():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_cpbancaire
""")
BankAccount.objects.all().delete()
print("Bank accounts deleted")
ae = Club.objects.filter(unix_name='ae').first()
for r in cur:
try:
new = BankAccount(
id=r['id_cptbc'],
club=ae,
name=to_unicode(r['nom_cptbc']),
)
new.save()
except Exception as e:
print("FAIL to migrate bank account: %s" % (repr(e)))
cur.close()
def migrate_club_accounts():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_cpasso
""")
ClubAccount.objects.all().delete()
print("Club accounts deleted")
ae = Club.objects.filter(id=1).first()
for r in cur:
try:
club = Club.objects.filter(id=r['id_asso']).first() or ae
bank_acc = BankAccount.objects.filter(id=r['id_cptbc']).first()
new = ClubAccount(
id=r['id_cptasso'],
club=club,
name=club.name[:30],
bank_account=bank_acc,
)
new.save()
except Exception as e:
print("FAIL to migrate club account: %s" % (repr(e)))
cur.close()
def migrate_journals():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_classeur
""")
GeneralJournal.objects.all().delete()
print("General journals deleted")
for r in cur:
try:
club_acc = ClubAccount.objects.filter(id=r['id_cptasso']).first()
new = GeneralJournal(
id=r['id_classeur'],
club_account=club_acc,
name=to_unicode(r['nom_classeur']),
start_date=r['date_debut_classeur'],
end_date=r['date_fin_classeur'],
closed=bool(r['ferme']),
)
new.save()
except Exception as e:
print("FAIL to migrate general journal: %s" % (repr(e)))
cur.close()
def migrate_accounting_types():
MOVEMENT = {
-1: "DEBIT",
0: "NEUTRAL",
1: "CREDIT",
}
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_op_plcptl
""")
AccountingType.objects.all().delete()
print("Accounting types deleted")
for r in cur:
try:
new = AccountingType(
id=r['id_opstd'],
code=str(r['code_plan']),
label=to_unicode(r['libelle_plan']).capitalize(),
movement_type=MOVEMENT[r['type_mouvement']],
)
new.save()
except Exception as e:
print("FAIL to migrate accounting type: %s" % (repr(e)))
cur.close()
def migrate_simpleaccounting_types():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_op_clb
WHERE id_asso IS NULL
""")
SimplifiedAccountingType.objects.all().delete()
print("Simple accounting types deleted")
for r in cur:
try:
at = AccountingType.objects.filter(id=r['id_opstd']).first()
new = SimplifiedAccountingType(
id=r['id_opclb'],
label=to_unicode(r['libelle_opclb']).capitalize(),
accounting_type=at,
)
new.save()
except Exception as e:
print("FAIL to migrate simple type: %s" % (repr(e)))
cur.close()
def migrate_operations():
MODE = {
1: "CHECK",
2: "CASH",
3: "TRANSFERT",
4: "CARD",
0: "CASH",
None: "CASH",
}
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_operation
""")
Operation.objects.all().delete()
print("Operation deleted")
for r in cur:
try:
simple_type = None
accounting_type = None
if r['id_opclb']:
simple_type = SimplifiedAccountingType.objects.filter(id=r['id_opclb']).first()
if r['id_opstd']:
accounting_type = AccountingType.objects.filter(id=r['id_opstd']).first()
if not accounting_type and simple_type:
accounting_type = simple_type.accounting_type
if not accounting_type:
accounting_type = AccountingType.objects.filter(movement_type="NEUTRAL").first()
journal = GeneralJournal.objects.filter(id=r['id_classeur']).first()
def get_target_type():
if r['id_utilisateur']:
return "USER"
if r['id_asso']:
return "CLUB"
if r['id_ent']:
return "COMPANY"
if r['id_classeur']:
return "ACCOUNT"
def get_target_id():
return int(r['id_utilisateur'] or r['id_asso'] or r['id_ent'] or r['id_classeur']) or None
new = Operation(
id=r['id_op'],
journal=journal,
amount=r['montant_op']/100,
date=r['date_op'] or journal.end_date,
remark=to_unicode(r['commentaire_op']),
mode=MODE[r['mode_op']],
cheque_number=str(r['num_cheque_op']),
done=bool(r['op_effctue']),
simpleaccounting_type=simple_type,
accounting_type=accounting_type,
target_type=get_target_type(),
target_id=get_target_id(),
target_label="-",
)
try:
new.clean()
except:
new.target_id = get_target_id()
new.target_type = "OTHER"
new.save()
except Exception as e:
print("FAIL to migrate operation: %s" % (repr(e)))
cur.close()
def make_operation_links():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
cur.execute("""
SELECT *
FROM cpta_operation
""")
for r in cur:
if r['id_op_liee']:
try:
op1 = Operation.objects.filter(id=r['id_op']).first()
op2 = Operation.objects.filter(id=r['id_op_liee']).first()
op1.linked_operation = op2
op1.save()
op2.linked_operation = op1
op2.save()
except Exception as e:
print("FAIL to link operations: %s" % (repr(e)))
cur.close()
def main():
migrate_users()
migrate_profile_pict()
migrate_clubs()
migrate_club_memberships()
migrate_subscriptions()
update_customer_account()
migrate_counters()
migrate_permanencies()
migrate_typeproducts()
migrate_products()
migrate_product_pict()
migrate_products_to_counter()
start = datetime.datetime.now()
print("Start at %s" % start)
# migrate_users()
# migrate_profile_pict()
# migrate_clubs()
# migrate_club_memberships()
# migrate_subscriptions()
# update_customer_account()
# migrate_counters()
# migrate_permanencies()
# migrate_typeproducts()
# migrate_products()
# migrate_product_pict()
# migrate_products_to_counter()
# reset_customer_amount()
migrate_invoices()
migrate_refillings()
migrate_sellings()
reset_index('core', 'club', 'subscription', 'accounting', 'eboutic', 'launderette', 'counter')
# migrate_invoices()
# migrate_refillings()
# migrate_sellings()
# reset_index('core', 'club', 'subscription', 'accounting', 'eboutic', 'launderette', 'counter')
# migrate_accounting_types()
# migrate_simpleaccounting_types()
# migrate_bank_accounts()
# migrate_club_accounts()
# migrate_journals()
# migrate_operations()
make_operation_links()
end = datetime.datetime.now()
print("End at %s" % end)
print("Running time: %s" % (end-start))
if __name__ == "__main__":
main()