Format accounting

This commit is contained in:
Pierre Brunet 2017-06-12 08:49:03 +02:00
parent 38026025af
commit 544ff630a5
5 changed files with 236 additions and 205 deletions

View File

@ -35,5 +35,3 @@ admin.site.register(SimplifiedAccountingType)
admin.site.register(Operation) admin.site.register(Operation)
admin.site.register(Label) admin.site.register(Label)
admin.site.register(Company) admin.site.register(Company)

View File

@ -25,7 +25,6 @@
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core import validators from django.core import validators
from django.db.models import Count
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -37,6 +36,7 @@ from decimal import Decimal
from core.models import User, SithFile from core.models import User, SithFile
from club.models import Club from club.models import Club
class CurrencyField(models.DecimalField): class CurrencyField(models.DecimalField):
""" """
This is a custom database field used for currency This is a custom database field used for currency
@ -50,12 +50,13 @@ class CurrencyField(models.DecimalField):
def to_python(self, value): def to_python(self, value):
try: try:
return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
except AttributeError: except AttributeError:
return None return None
# Accounting classes # Accounting classes
class Company(models.Model): class Company(models.Model):
name = models.CharField(_('name'), max_length=60) name = models.CharField(_('name'), max_length=60)
street = models.CharField(_('street'), max_length=60, blank=True) street = models.CharField(_('street'), max_length=60, blank=True)
@ -104,6 +105,7 @@ class Company(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
class BankAccount(models.Model): class BankAccount(models.Model):
name = models.CharField(_('name'), max_length=30) name = models.CharField(_('name'), max_length=30)
iban = models.CharField(_('iban'), max_length=255, blank=True) iban = models.CharField(_('iban'), max_length=255, blank=True)
@ -131,6 +133,7 @@ class BankAccount(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
class ClubAccount(models.Model): class ClubAccount(models.Model):
name = models.CharField(_('name'), max_length=30) name = models.CharField(_('name'), max_length=30)
club = models.ForeignKey(Club, related_name="club_account", verbose_name=_("club")) club = models.ForeignKey(Club, related_name="club_account", verbose_name=_("club"))
@ -244,6 +247,7 @@ class GeneralJournal(models.Model):
self.amount -= o.amount self.amount -= o.amount
self.save() self.save()
class Operation(models.Model): class Operation(models.Model):
""" """
An operation is a line in the journal, a debit or a credit An operation is a line in the journal, a debit or a credit
@ -258,17 +262,17 @@ class Operation(models.Model):
invoice = models.ForeignKey(SithFile, related_name='operations', verbose_name=_("invoice"), 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) done = models.BooleanField(_('is done'), default=False)
simpleaccounting_type = models.ForeignKey('SimplifiedAccountingType', related_name="operations", simpleaccounting_type = models.ForeignKey('SimplifiedAccountingType', related_name="operations",
verbose_name=_("simple type"), null=True, blank=True) verbose_name=_("simple type"), null=True, blank=True)
accounting_type = models.ForeignKey('AccountingType', related_name="operations", accounting_type = models.ForeignKey('AccountingType', related_name="operations",
verbose_name=_("accounting type"), null=True, blank=True) verbose_name=_("accounting type"), null=True, blank=True)
label = models.ForeignKey('Label', related_name="operations", label = models.ForeignKey('Label', related_name="operations",
verbose_name=_("label"), null=True, blank=True, on_delete=models.SET_NULL) verbose_name=_("label"), null=True, blank=True, on_delete=models.SET_NULL)
target_type = models.CharField(_('target type'), max_length=10, target_type = models.CharField(_('target type'), max_length=10,
choices=[('USER', _('User')), ('CLUB', _('Club')), ('ACCOUNT', _('Account')), ('COMPANY', _('Company')), ('OTHER', _('Other'))]) choices=[('USER', _('User')), ('CLUB', _('Club')), ('ACCOUNT', _('Account')), ('COMPANY', _('Company')), ('OTHER', _('Other'))])
target_id = models.IntegerField(_('target id'), null=True, blank=True) target_id = models.IntegerField(_('target id'), null=True, blank=True)
target_label = models.CharField(_('target label'), max_length=32, default="", 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"), linked_operation = models.OneToOneField('self', related_name='operation_linked_to', verbose_name=_("linked operation"),
null=True, blank=True, default=None) null=True, blank=True, default=None)
class Meta: class Meta:
unique_together = ('number', 'journal') unique_together = ('number', 'journal')
@ -349,8 +353,9 @@ class Operation(models.Model):
def __str__(self): def __str__(self):
return "%d € | %s | %s | %s" % ( return "%d € | %s | %s | %s" % (
self.amount, self.date, self.accounting_type, self.done, self.amount, self.date, self.accounting_type, self.done,
) )
class AccountingType(models.Model): class AccountingType(models.Model):
""" """
@ -359,13 +364,13 @@ class AccountingType(models.Model):
Thoses are numbers used in accounting to classify operations Thoses are numbers used in accounting to classify operations
""" """
code = models.CharField(_('code'), max_length=16, code = models.CharField(_('code'), max_length=16,
validators=[ validators=[
validators.RegexValidator(r'^[0-9]*$', _('An accounting type code contains only numbers')), validators.RegexValidator(r'^[0-9]*$', _('An accounting type code contains only numbers')),
], ],
) )
label = models.CharField(_('label'), max_length=128) label = models.CharField(_('label'), max_length=128)
movement_type = models.CharField(_('movement type'), choices=[('CREDIT', _('Credit')), ('DEBIT', _('Debit')), movement_type = models.CharField(_('movement type'), choices=[('CREDIT', _('Credit')), ('DEBIT', _('Debit')),
('NEUTRAL', _('Neutral'))], max_length=12) ('NEUTRAL', _('Neutral'))], max_length=12)
class Meta: class Meta:
verbose_name = _("accounting type") verbose_name = _("accounting type")
@ -383,7 +388,8 @@ class AccountingType(models.Model):
return reverse('accounting:type_list') return reverse('accounting:type_list')
def __str__(self): def __str__(self):
return self.code+" - "+self.get_movement_type_display()+" - "+self.label return self.code + " - " + self.get_movement_type_display() + " - " + self.label
class SimplifiedAccountingType(models.Model): class SimplifiedAccountingType(models.Model):
""" """
@ -391,7 +397,7 @@ class SimplifiedAccountingType(models.Model):
""" """
label = models.CharField(_('label'), max_length=128) label = models.CharField(_('label'), max_length=128)
accounting_type = models.ForeignKey(AccountingType, related_name="simplified_types", accounting_type = models.ForeignKey(AccountingType, related_name="simplified_types",
verbose_name=_("simplified accounting types")) verbose_name=_("simplified accounting types"))
class Meta: class Meta:
verbose_name = _("simplified type") verbose_name = _("simplified type")
@ -408,7 +414,8 @@ class SimplifiedAccountingType(models.Model):
return reverse('accounting:simple_type_list') return reverse('accounting:simple_type_list')
def __str__(self): def __str__(self):
return self.get_movement_type_display()+" - "+self.accounting_type.code+" - "+self.label return self.get_movement_type_display() + " - " + self.accounting_type.code + " - " + self.label
class Label(models.Model): class Label(models.Model):
"""Label allow a club to sort its operations""" """Label allow a club to sort its operations"""
@ -432,4 +439,3 @@ class Label(models.Model):
def can_be_viewed_by(self, user): def can_be_viewed_by(self, user):
return self.club_account.can_be_viewed_by(user) return self.club_account.can_be_viewed_by(user)

View File

@ -22,15 +22,12 @@
# #
# #
from django.test import Client, TestCase from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import Group
from django.core.management import call_command from django.core.management import call_command
from django.conf import settings from datetime import date
from datetime import date, datetime
from core.models import User from core.models import User
from counter.models import Counter
from accounting.models import GeneralJournal, Operation, Label, AccountingType, SimplifiedAccountingType from accounting.models import GeneralJournal, Operation, Label, AccountingType, SimplifiedAccountingType
@ -72,10 +69,11 @@ class RefoundAccountTest(TestCase):
self.assertFalse(response_post.status_code == 403) self.assertFalse(response_post.status_code == 403)
self.assertTrue(self.skia.customer.amount == 0) self.assertTrue(self.skia.customer.amount == 0)
class JournalTest(TestCase): class JournalTest(TestCase):
def setUp(self): def setUp(self):
call_command("populate") call_command("populate")
self.journal = GeneralJournal.objects.filter(id = 1).first() self.journal = GeneralJournal.objects.filter(id=1).first()
def test_permission_granted(self): def test_permission_granted(self):
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
@ -91,115 +89,116 @@ class JournalTest(TestCase):
self.assertTrue(response_get.status_code == 403) self.assertTrue(response_get.status_code == 403)
self.assertFalse('<td>M\xc3\xa9thode de paiement</td>' in str(response_get.content)) self.assertFalse('<td>M\xc3\xa9thode de paiement</td>' in str(response_get.content))
class OperationTest(TestCase): class OperationTest(TestCase):
def setUp(self): def setUp(self):
call_command("populate") call_command("populate")
self.journal = GeneralJournal.objects.filter(id = 1).first() self.journal = GeneralJournal.objects.filter(id=1).first()
self.skia = User.objects.filter(username='skia').first() self.skia = User.objects.filter(username='skia').first()
at = AccountingType(code='443', label="Ce code n'existe pas", movement_type='CREDIT') at = AccountingType(code='443', label="Ce code n'existe pas", movement_type='CREDIT')
at.save() at.save()
l = Label(club_account= self.journal.club_account, name='bob') l = Label(club_account=self.journal.club_account, name='bob')
l.save() l.save()
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
self.op1 = Operation(journal=self.journal, date=date.today(), amount=1, self.op1 = Operation(journal=self.journal, date=date.today(), amount=1,
remark="Test bilan", mode='CASH', done=True, label=l, remark="Test bilan", mode='CASH', done=True, label=l,
accounting_type=at, target_type='USER', target_id=self.skia.id) accounting_type=at, target_type='USER', target_id=self.skia.id)
self.op1.save() self.op1.save()
self.op2 = Operation(journal=self.journal, date=date.today(), amount=2, self.op2 = Operation(journal=self.journal, date=date.today(), amount=2,
remark="Test bilan", mode='CASH', done=True, label=l, remark="Test bilan", mode='CASH', done=True, label=l,
accounting_type=at, target_type='USER', target_id=self.skia.id) accounting_type=at, target_type='USER', target_id=self.skia.id)
self.op2.save() self.op2.save()
def test_new_operation(self): def test_new_operation(self):
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
at = AccountingType.objects.filter(code = '604').first() at = AccountingType.objects.filter(code='604').first()
response = self.client.post(reverse('accounting:op_new', response = self.client.post(reverse('accounting:op_new',
args=[self.journal.id]), args=[self.journal.id]),
{'amount': 30, {'amount': 30,
'remark' : "Un gros test", 'remark': "Un gros test",
'journal' : self.journal.id, 'journal': self.journal.id,
'target_type' : 'OTHER', 'target_type': 'OTHER',
'target_id' : '', 'target_id': '',
'target_label' : "Le fantome de la nuit", 'target_label': "Le fantome de la nuit",
'date' : '04/12/2020', 'date': '04/12/2020',
'mode' : 'CASH', 'mode': 'CASH',
'cheque_number' : '', 'cheque_number': '',
'invoice' : '', 'invoice': '',
'simpleaccounting_type' : '', 'simpleaccounting_type': '',
'accounting_type': at.id, 'accounting_type': at.id,
'label' : '', 'label': '',
'done' : False, 'done': False,
}) })
self.assertFalse(response.status_code == 403) self.assertFalse(response.status_code == 403)
self.assertTrue(self.journal.operations.filter(target_label = "Le fantome de la nuit").exists()) self.assertTrue(self.journal.operations.filter(target_label="Le fantome de la nuit").exists())
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id])) response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
self.assertTrue('<td>Le fantome de la nuit</td>' in str(response_get.content)) self.assertTrue('<td>Le fantome de la nuit</td>' in str(response_get.content))
def test_bad_new_operation(self): def test_bad_new_operation(self):
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
at = AccountingType.objects.filter(code = '604').first() AccountingType.objects.filter(code='604').first()
response = self.client.post(reverse('accounting:op_new', response = self.client.post(reverse('accounting:op_new',
args=[self.journal.id]), args=[self.journal.id]),
{'amount': 30, {'amount': 30,
'remark' : "Un gros test", 'remark': "Un gros test",
'journal' : self.journal.id, 'journal': self.journal.id,
'target_type' : 'OTHER', 'target_type': 'OTHER',
'target_id' : '', 'target_id': '',
'target_label' : "Le fantome de la nuit", 'target_label': "Le fantome de la nuit",
'date' : '04/12/2020', 'date': '04/12/2020',
'mode' : 'CASH', 'mode': 'CASH',
'cheque_number' : '', 'cheque_number': '',
'invoice' : '', 'invoice': '',
'simpleaccounting_type' : '', 'simpleaccounting_type': '',
'accounting_type': '', 'accounting_type': '',
'label' : '', 'label': '',
'done' : False, 'done': False,
}) })
self.assertTrue('Vous devez fournir soit un type comptable simplifi\\xc3\\xa9 ou un type comptable standard' in str(response.content)) self.assertTrue('Vous devez fournir soit un type comptable simplifi\\xc3\\xa9 ou un type comptable standard' in str(response.content))
def test_new_operation_not_authorized(self): def test_new_operation_not_authorized(self):
self.client.login(username='skia', password='plop') self.client.login(username='skia', password='plop')
at = AccountingType.objects.filter(code = '604').first() at = AccountingType.objects.filter(code='604').first()
response = self.client.post(reverse('accounting:op_new', response = self.client.post(reverse('accounting:op_new',
args=[self.journal.id]), args=[self.journal.id]),
{'amount': 30, {'amount': 30,
'remark' : "Un gros test", 'remark': "Un gros test",
'journal' : self.journal.id, 'journal': self.journal.id,
'target_type' : 'OTHER', 'target_type': 'OTHER',
'target_id' : '', 'target_id': '',
'target_label' : "Le fantome du jour", 'target_label': "Le fantome du jour",
'date' : '04/12/2020', 'date': '04/12/2020',
'mode' : 'CASH', 'mode': 'CASH',
'cheque_number' : '', 'cheque_number': '',
'invoice' : '', 'invoice': '',
'simpleaccounting_type' : '', 'simpleaccounting_type': '',
'accounting_type': at.id, 'accounting_type': at.id,
'label' : '', 'label': '',
'done' : False, 'done': False,
}) })
self.assertTrue(response.status_code == 403) self.assertTrue(response.status_code == 403)
self.assertFalse(self.journal.operations.filter(target_label = "Le fantome du jour").exists()) self.assertFalse(self.journal.operations.filter(target_label="Le fantome du jour").exists())
def test__operation_simple_accounting(self): def test__operation_simple_accounting(self):
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
sat = SimplifiedAccountingType.objects.all().first() sat = SimplifiedAccountingType.objects.all().first()
response = self.client.post(reverse('accounting:op_new', response = self.client.post(reverse('accounting:op_new',
args=[self.journal.id]), args=[self.journal.id]),
{'amount': 23, {'amount': 23,
'remark' : "Un gros test", 'remark': "Un gros test",
'journal' : self.journal.id, 'journal': self.journal.id,
'target_type' : 'OTHER', 'target_type': 'OTHER',
'target_id' : '', 'target_id': '',
'target_label' : "Le fantome de l'aurore", 'target_label': "Le fantome de l'aurore",
'date' : '04/12/2020', 'date': '04/12/2020',
'mode' : 'CASH', 'mode': 'CASH',
'cheque_number' : '', 'cheque_number': '',
'invoice' : '', 'invoice': '',
'simpleaccounting_type' : sat.id, 'simpleaccounting_type': sat.id,
'accounting_type': '', 'accounting_type': '',
'label' : '', 'label': '',
'done' : False, 'done': False,
}) })
self.assertFalse(response.status_code == 403) self.assertFalse(response.status_code == 403)
self.assertTrue(self.journal.operations.filter(amount=23).exists()) self.assertTrue(self.journal.operations.filter(amount=23).exists())
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id])) response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
@ -216,8 +215,7 @@ class OperationTest(TestCase):
response_get = self.client.get(reverse("accounting:journal_person_statement", args=[self.journal.id])) response_get = self.client.get(reverse("accounting:journal_person_statement", args=[self.journal.id]))
self.assertTrue("S&#39; Kia</a></td>\\n \\n <td>3.00</td>" in str(response_get.content)) self.assertTrue("S&#39; Kia</a></td>\\n \\n <td>3.00</td>" in str(response_get.content))
def test_accounting_statement(self): def test_accounting_statement(self):
self.client.login(username='comptable', password='plop') self.client.login(username='comptable', password='plop')
response_get = self.client.get(reverse("accounting:journal_accounting_statement", args=[self.journal.id])) response_get = self.client.get(reverse("accounting:journal_accounting_statement", args=[self.journal.id]))
self.assertTrue("<td>443 - Cr\\xc3\\xa9dit - Ce code n&#39;existe pas</td>\\n <td>3.00</td>" in str(response_get.content)) self.assertTrue("<td>443 - Cr\\xc3\\xa9dit - Ce code n&#39;existe pas</td>\\n <td>3.00</td>" in str(response_get.content))

View File

@ -22,7 +22,7 @@
# #
# #
from django.conf.urls import url, include from django.conf.urls import url
from accounting.views import * from accounting.views import *
@ -71,5 +71,3 @@ urlpatterns = [
# User account # User account
url(r'^refound/account$', RefoundAccountView.as_view(), name='refound_account'), url(r'^refound/account$', RefoundAccountView.as_view(), name='refound_account'),
] ]

View File

@ -22,25 +22,21 @@
# #
# #
from django.views.generic import ListView, DetailView, RedirectView from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView
from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from django.forms import HiddenInput, TextInput from django.forms import HiddenInput
from django.db import transaction from django.db import transaction
from django.db.models import Sum from django.db.models import Sum
from django.conf import settings from django.conf import settings
from django import forms from django import forms
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.conf import settings
import collections import collections
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField from ajax_select.fields import AutoCompleteSelectField
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
from core.views.forms import SelectFile, SelectDate from core.views.forms import SelectFile, SelectDate
@ -49,6 +45,7 @@ from counter.models import Counter, Selling, Product
# Main accounting view # Main accounting view
class BankAccountListView(CanViewMixin, ListView): class BankAccountListView(CanViewMixin, ListView):
""" """
A list view for the admins A list view for the admins
@ -57,6 +54,7 @@ class BankAccountListView(CanViewMixin, ListView):
template_name = 'accounting/bank_account_list.jinja' template_name = 'accounting/bank_account_list.jinja'
ordering = ['name'] ordering = ['name']
# Simplified accounting types # Simplified accounting types
class SimplifiedAccountingTypeListView(CanViewMixin, ListView): class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
@ -66,6 +64,7 @@ class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
model = SimplifiedAccountingType model = SimplifiedAccountingType
template_name = 'accounting/simplifiedaccountingtype_list.jinja' template_name = 'accounting/simplifiedaccountingtype_list.jinja'
class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView): class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
""" """
An edit view for the admins An edit view for the admins
@ -75,6 +74,7 @@ class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
fields = ['label', 'accounting_type'] fields = ['label', 'accounting_type']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView): class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
""" """
Create an accounting type (for the admins) Create an accounting type (for the admins)
@ -83,6 +83,7 @@ class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
fields = ['label', 'accounting_type'] fields = ['label', 'accounting_type']
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
# Accounting types # Accounting types
class AccountingTypeListView(CanViewMixin, ListView): class AccountingTypeListView(CanViewMixin, ListView):
@ -92,6 +93,7 @@ class AccountingTypeListView(CanViewMixin, ListView):
model = AccountingType model = AccountingType
template_name = 'accounting/accountingtype_list.jinja' template_name = 'accounting/accountingtype_list.jinja'
class AccountingTypeEditView(CanViewMixin, UpdateView): class AccountingTypeEditView(CanViewMixin, UpdateView):
""" """
An edit view for the admins An edit view for the admins
@ -101,6 +103,7 @@ class AccountingTypeEditView(CanViewMixin, UpdateView):
fields = ['code', 'label', 'movement_type'] fields = ['code', 'label', 'movement_type']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class AccountingTypeCreateView(CanCreateMixin, CreateView): class AccountingTypeCreateView(CanCreateMixin, CreateView):
""" """
Create an accounting type (for the admins) Create an accounting type (for the admins)
@ -109,6 +112,7 @@ class AccountingTypeCreateView(CanCreateMixin, CreateView):
fields = ['code', 'label', 'movement_type'] fields = ['code', 'label', 'movement_type']
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
# BankAccount views # BankAccount views
class BankAccountEditView(CanViewMixin, UpdateView): class BankAccountEditView(CanViewMixin, UpdateView):
@ -120,6 +124,7 @@ class BankAccountEditView(CanViewMixin, UpdateView):
fields = ['name', 'iban', 'number', 'club'] fields = ['name', 'iban', 'number', 'club']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class BankAccountDetailView(CanViewMixin, DetailView): class BankAccountDetailView(CanViewMixin, DetailView):
""" """
A detail view, listing every club account A detail view, listing every club account
@ -128,6 +133,7 @@ class BankAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "b_account_id" pk_url_kwarg = "b_account_id"
template_name = 'accounting/bank_account_details.jinja' template_name = 'accounting/bank_account_details.jinja'
class BankAccountCreateView(CanCreateMixin, CreateView): class BankAccountCreateView(CanCreateMixin, CreateView):
""" """
Create a bank account (for the admins) Create a bank account (for the admins)
@ -136,7 +142,8 @@ class BankAccountCreateView(CanCreateMixin, CreateView):
fields = ['name', 'club', 'iban', 'number'] fields = ['name', 'club', 'iban', 'number']
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
class BankAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
class BankAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
""" """
Delete a bank account (for the admins) Delete a bank account (for the admins)
""" """
@ -145,6 +152,7 @@ class BankAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete
template_name = 'core/delete_confirm.jinja' template_name = 'core/delete_confirm.jinja'
success_url = reverse_lazy('accounting:bank_list') success_url = reverse_lazy('accounting:bank_list')
# ClubAccount views # ClubAccount views
class ClubAccountEditView(CanViewMixin, UpdateView): class ClubAccountEditView(CanViewMixin, UpdateView):
@ -156,6 +164,7 @@ class ClubAccountEditView(CanViewMixin, UpdateView):
fields = ['name', 'club', 'bank_account'] fields = ['name', 'club', 'bank_account']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class ClubAccountDetailView(CanViewMixin, DetailView): class ClubAccountDetailView(CanViewMixin, DetailView):
""" """
A detail view, listing every journal A detail view, listing every journal
@ -164,6 +173,7 @@ class ClubAccountDetailView(CanViewMixin, DetailView):
pk_url_kwarg = "c_account_id" pk_url_kwarg = "c_account_id"
template_name = 'accounting/club_account_details.jinja' template_name = 'accounting/club_account_details.jinja'
class ClubAccountCreateView(CanCreateMixin, CreateView): class ClubAccountCreateView(CanCreateMixin, CreateView):
""" """
Create a club account (for the admins) Create a club account (for the admins)
@ -180,7 +190,8 @@ class ClubAccountCreateView(CanCreateMixin, CreateView):
ret['bank_account'] = obj.id ret['bank_account'] = obj.id
return ret return ret
class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
""" """
Delete a club account (for the admins) Delete a club account (for the admins)
""" """
@ -189,6 +200,7 @@ class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete
template_name = 'core/delete_confirm.jinja' template_name = 'core/delete_confirm.jinja'
success_url = reverse_lazy('accounting:bank_list') success_url = reverse_lazy('accounting:bank_list')
# Journal views # Journal views
class JournalTabsMixin(TabedViewMixin): class JournalTabsMixin(TabedViewMixin):
@ -198,34 +210,35 @@ class JournalTabsMixin(TabedViewMixin):
def get_list_of_tabs(self): def get_list_of_tabs(self):
tab_list = [] tab_list = []
tab_list.append({ tab_list.append({
'url': reverse('accounting:journal_details', kwargs={'j_id': self.object.id}), 'url': reverse('accounting:journal_details', kwargs={'j_id': self.object.id}),
'slug': 'journal', 'slug': 'journal',
'name': _("Journal"), 'name': _("Journal"),
}) })
tab_list.append({ tab_list.append({
'url': reverse('accounting:journal_nature_statement', kwargs={'j_id': self.object.id}), 'url': reverse('accounting:journal_nature_statement', kwargs={'j_id': self.object.id}),
'slug': 'nature_statement', 'slug': 'nature_statement',
'name': _("Statement by nature"), 'name': _("Statement by nature"),
}) })
tab_list.append({ tab_list.append({
'url': reverse('accounting:journal_person_statement', kwargs={'j_id': self.object.id}), 'url': reverse('accounting:journal_person_statement', kwargs={'j_id': self.object.id}),
'slug': 'person_statement', 'slug': 'person_statement',
'name': _("Statement by person"), 'name': _("Statement by person"),
}) })
tab_list.append({ tab_list.append({
'url': reverse('accounting:journal_accounting_statement', kwargs={'j_id': self.object.id}), 'url': reverse('accounting:journal_accounting_statement', kwargs={'j_id': self.object.id}),
'slug': 'accounting_statement', 'slug': 'accounting_statement',
'name': _("Accounting statement"), 'name': _("Accounting statement"),
}) })
return tab_list return tab_list
class JournalCreateView(CanCreateMixin, CreateView): class JournalCreateView(CanCreateMixin, CreateView):
""" """
Create a general journal Create a general journal
""" """
model = GeneralJournal model = GeneralJournal
form_class = modelform_factory(GeneralJournal, fields=['name', 'start_date', 'club_account'], form_class = modelform_factory(GeneralJournal, fields=['name', 'start_date', 'club_account'],
widgets={ 'start_date': SelectDate, }) widgets={'start_date': SelectDate, })
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
def get_initial(self): def get_initial(self):
@ -236,6 +249,7 @@ class JournalCreateView(CanCreateMixin, CreateView):
ret['club_account'] = obj.id ret['club_account'] = obj.id
return ret return ret
class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView): class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView):
""" """
A detail view, listing every operation A detail view, listing every operation
@ -245,6 +259,7 @@ class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView):
template_name = 'accounting/journal_details.jinja' template_name = 'accounting/journal_details.jinja'
current_tab = 'journal' current_tab = 'journal'
class JournalEditView(CanEditMixin, UpdateView): class JournalEditView(CanEditMixin, UpdateView):
""" """
Update a general journal Update a general journal
@ -254,6 +269,7 @@ class JournalEditView(CanEditMixin, UpdateView):
fields = ['name', 'start_date', 'end_date', 'club_account', 'closed'] fields = ['name', 'start_date', 'end_date', 'club_account', 'closed']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class JournalDeleteView(CanEditPropMixin, DeleteView): class JournalDeleteView(CanEditPropMixin, DeleteView):
""" """
Delete a club account (for the admins) Delete a club account (for the admins)
@ -264,11 +280,12 @@ class JournalDeleteView(CanEditPropMixin, DeleteView):
success_url = reverse_lazy('accounting:club_details') success_url = reverse_lazy('accounting:club_details')
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
if self.object.operations.count() == 0: if self.object.operations.count() == 0:
return super(JournalDeleteView, self).dispatch(request, *args, **kwargs) return super(JournalDeleteView, self).dispatch(request, *args, **kwargs)
else: else:
raise PermissionDenied raise PermissionDenied
# Operation views # Operation views
@ -276,13 +293,13 @@ class OperationForm(forms.ModelForm):
class Meta: class Meta:
model = Operation model = Operation
fields = ['amount', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode', fields = ['amount', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode',
'cheque_number', 'invoice', 'simpleaccounting_type', 'accounting_type', 'label', 'done' ] 'cheque_number', 'invoice', 'simpleaccounting_type', 'accounting_type', 'label', 'done']
widgets = { widgets = {
'journal': HiddenInput, 'journal': HiddenInput,
'target_id': HiddenInput, 'target_id': HiddenInput,
'date': SelectDate, 'date': SelectDate,
'invoice': SelectFile, 'invoice': SelectFile,
} }
user = AutoCompleteSelectField('users', help_text=None, required=False) user = AutoCompleteSelectField('users', help_text=None, required=False)
club_account = AutoCompleteSelectField('club_accounts', help_text=None, required=False) club_account = AutoCompleteSelectField('club_accounts', help_text=None, required=False)
club = AutoCompleteSelectField('clubs', help_text=None, required=False) club = AutoCompleteSelectField('clubs', help_text=None, required=False)
@ -328,28 +345,29 @@ class OperationForm(forms.ModelForm):
inst = self.instance inst = self.instance
club_account = inst.target club_account = inst.target
acc_type = AccountingType.objects.exclude(movement_type="NEUTRAL").exclude( acc_type = AccountingType.objects.exclude(movement_type="NEUTRAL").exclude(
movement_type=inst.accounting_type.movement_type).order_by('code').first() # Select a random opposite accounting type movement_type=inst.accounting_type.movement_type).order_by('code').first() # Select a random opposite accounting type
op = Operation( op = Operation(
journal=club_account.get_open_journal(), journal=club_account.get_open_journal(),
amount=inst.amount, amount=inst.amount,
date=inst.date, date=inst.date,
remark=inst.remark, remark=inst.remark,
mode=inst.mode, mode=inst.mode,
cheque_number=inst.cheque_number, cheque_number=inst.cheque_number,
invoice=inst.invoice, invoice=inst.invoice,
done=False, # Has to be checked by hand done=False, # Has to be checked by hand
simpleaccounting_type=None, simpleaccounting_type=None,
accounting_type=acc_type, accounting_type=acc_type,
target_type="ACCOUNT", target_type="ACCOUNT",
target_id=inst.journal.club_account.id, target_id=inst.journal.club_account.id,
target_label="", target_label="",
linked_operation=inst, linked_operation=inst,
) )
op.save() op.save()
self.instance.linked_operation = op self.instance.linked_operation = op
self.save() self.save()
return ret return ret
class OperationCreateView(CanCreateMixin, CreateView): class OperationCreateView(CanCreateMixin, CreateView):
""" """
Create an operation Create an operation
@ -376,6 +394,7 @@ class OperationCreateView(CanCreateMixin, CreateView):
kwargs['object'] = self.journal kwargs['object'] = self.journal
return kwargs return kwargs
class OperationEditView(CanEditMixin, UpdateView): class OperationEditView(CanEditMixin, UpdateView):
""" """
An edit view, working as detail for the moment An edit view, working as detail for the moment
@ -391,6 +410,7 @@ class OperationEditView(CanEditMixin, UpdateView):
kwargs['object'] = self.object.journal kwargs['object'] = self.object.journal
return kwargs return kwargs
class OperationPDFView(CanViewMixin, DetailView): class OperationPDFView(CanViewMixin, DetailView):
""" """
Display the PDF of a given operation Display the PDF of a given operation
@ -402,11 +422,10 @@ class OperationPDFView(CanViewMixin, DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
from reportlab.pdfgen import canvas from reportlab.pdfgen import canvas
from reportlab.lib.units import cm from reportlab.lib.units import cm
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors from reportlab.lib import colors
from reportlab.lib.pagesizes import letter from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader from reportlab.lib.utils import ImageReader
from reportlab.graphics.shapes import Drawing
from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase import pdfmetrics
@ -419,7 +438,6 @@ class OperationPDFView(CanViewMixin, DetailView):
num = self.object.number num = self.object.number
date = self.object.date date = self.object.date
mode = self.object.mode mode = self.object.mode
cheque_number = self.object.cheque_number
club_name = self.object.journal.club_account.name club_name = self.object.journal.club_account.name
ti = self.object.journal.name ti = self.object.journal.name
op_label = self.object.label op_label = self.object.label
@ -432,7 +450,7 @@ class OperationPDFView(CanViewMixin, DetailView):
target = self.object.target.get_display_name() target = self.object.target.get_display_name()
response = HttpResponse(content_type='application/pdf') response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename="op-%d(%s_on_%s).pdf"' %(num, ti, club_name) response['Content-Disposition'] = 'filename="op-%d(%s_on_%s).pdf"' % (num, ti, club_name)
p = canvas.Canvas(response) p = canvas.Canvas(response)
p.setFont('DejaVu', 12) p.setFont('DejaVu', 12)
@ -441,21 +459,21 @@ class OperationPDFView(CanViewMixin, DetailView):
width, height = letter width, height = letter
im = ImageReader("core/static/core/img/logo.jpg") im = ImageReader("core/static/core/img/logo.jpg")
iw, ih = im.getSize() iw, ih = im.getSize()
p.drawImage(im, 40, height - 50, width=iw/2, height=ih/2) p.drawImage(im, 40, height - 50, width=iw / 2, height=ih / 2)
labelStr = [["%s %s - %s %s" % (_("Journal"), ti, _("Operation"), num)]] labelStr = [["%s %s - %s %s" % (_("Journal"), ti, _("Operation"), num)]]
label = Table(labelStr, colWidths=[150], rowHeights=[20]) label = Table(labelStr, colWidths=[150], rowHeights=[20])
label.setStyle(TableStyle([ label.setStyle(TableStyle([
('ALIGN',(0,0),(-1,-1),'RIGHT'), ('ALIGN', (0, 0), (-1, -1), 'RIGHT'),
])) ]))
w, h = label.wrapOn(label, 0, 0) w, h = label.wrapOn(label, 0, 0)
label.drawOn(p, width-180, height) label.drawOn(p, width - 180, height)
p.drawString(90, height - 100, _("Financial proof: ") + "OP%010d" % (id_op)) #Justificatif du libellé p.drawString(90, height - 100, _("Financial proof: ") + "OP%010d" % (id_op)) # Justificatif du libellé
p.drawString(90, height - 130, _("Club: %(club_name)s") % ({"club_name": club_name})) p.drawString(90, height - 130, _("Club: %(club_name)s") % ({"club_name": club_name}))
p.drawString(90, height - 160, _("Label: %(op_label)s") % {"op_label": op_label if op_label != None else ""}) p.drawString(90, height - 160, _("Label: %(op_label)s") % {"op_label": op_label if op_label is not None else ""})
p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date}) p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date})
data = [] data = []
@ -470,7 +488,7 @@ class OperationPDFView(CanViewMixin, DetailView):
payment_mode += "[\u00D7]" payment_mode += "[\u00D7]"
else: else:
payment_mode += "[ ]" payment_mode += "[ ]"
payment_mode += " %s\n" %(m[1]) payment_mode += " %s\n" % (m[1])
data += [[payment_mode]] data += [[payment_mode]]
@ -478,29 +496,29 @@ class OperationPDFView(CanViewMixin, DetailView):
data += [["%s \n%s" % (_("Comment:"), remark)]] data += [["%s \n%s" % (_("Comment:"), remark)]]
t = Table(data, colWidths=[(width-90*2)/2]*2, rowHeights=[20, 20, 70, 20, 80]) t = Table(data, colWidths=[(width - 90 * 2) / 2] * 2, rowHeights=[20, 20, 70, 20, 80])
t.setStyle(TableStyle([ t.setStyle(TableStyle([
('ALIGN',(0,0),(-1,-1),'CENTER'), ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('VALIGN',(-2,-1),(-1,-1),'TOP'), ('VALIGN', (-2, -1), (-1, -1), 'TOP'),
('VALIGN',(0,0),(-1,-2),'MIDDLE'), ('VALIGN', (0, 0), (-1, -2), 'MIDDLE'),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
('SPAN', (0, 0), (1, 0)), # line DEBIT/CREDIT ('SPAN', (0, 0), (1, 0)), # line DEBIT/CREDIT
('SPAN', (0, 1), (1, 1)), # line amount ('SPAN', (0, 1), (1, 1)), # line amount
('SPAN',(-2, -1), (-1,-1)), # line comment ('SPAN', (-2, -1), (-1, -1)), # line comment
('SPAN', (0, -2), (-1, -2)), # line creditor/debtor ('SPAN', (0, -2), (-1, -2)), # line creditor/debtor
('SPAN', (0, 2), (1, 2)), # line payment_mode ('SPAN', (0, 2), (1, 2)), # line payment_mode
('ALIGN',(0, 2), (1, 2),'LEFT'), # line payment_mode ('ALIGN', (0, 2), (1, 2), 'LEFT'), # line payment_mode
('ALIGN', (-2, -1), (-1, -1), 'LEFT'), ('ALIGN', (-2, -1), (-1, -1), 'LEFT'),
('BOX', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black),
])) ]))
signature = [] signature = []
signature += [[_("Signature:")]] signature += [[_("Signature:")]]
tSig = Table(signature, colWidths=[(width-90*2)], rowHeights=[80]) tSig = Table(signature, colWidths=[(width - 90 * 2)], rowHeights=[80])
tSig.setStyle(TableStyle([ tSig.setStyle(TableStyle([
('VALIGN',(0,0),(-1,-1),'TOP'), ('VALIGN', (0, 0), (-1, -1), 'TOP'),
('BOX', (0,0), (-1,-1), 0.25, colors.black)])) ('BOX', (0, 0), (-1, -1), 0.25, colors.black)]))
w, h = tSig.wrapOn(p, 0, 0) w, h = tSig.wrapOn(p, 0, 0)
tSig.drawOn(p, 90, 200) tSig.drawOn(p, 90, 200)
@ -516,14 +534,15 @@ class OperationPDFView(CanViewMixin, DetailView):
p.save() p.save()
return response return response
class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView): class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
""" """
Display a statement sorted by labels Display a statement sorted by labels
""" """
model = GeneralJournal model = GeneralJournal
pk_url_kwarg = "j_id" pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_nature.jinja' template_name = 'accounting/journal_statement_nature.jinja'
current_tab='nature_statement' current_tab = 'nature_statement'
def statement(self, queryset, movement_type): def statement(self, queryset, movement_type):
ret = collections.OrderedDict() ret = collections.OrderedDict()
@ -531,14 +550,16 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
total_sum = 0 total_sum = 0
for sat in [None] + list(SimplifiedAccountingType.objects.order_by('label').all()): for sat in [None] + list(SimplifiedAccountingType.objects.order_by('label').all()):
sum = queryset.filter(accounting_type__movement_type=movement_type, sum = queryset.filter(accounting_type__movement_type=movement_type,
simpleaccounting_type=sat).aggregate(amount_sum=Sum('amount'))['amount_sum'] simpleaccounting_type=sat).aggregate(amount_sum=Sum('amount'))['amount_sum']
if sat: sat = sat.label if sat:
else: sat = "" sat = sat.label
else:
sat = ""
if sum: if sum:
total_sum += sum total_sum += sum
statement[sat] = sum statement[sat] = sum
ret[movement_type] = statement ret[movement_type] = statement
ret[movement_type+"_sum"] = total_sum ret[movement_type + "_sum"] = total_sum
return ret return ret
def big_statement(self): def big_statement(self):
@ -566,23 +587,24 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
kwargs['statement'] = self.big_statement() kwargs['statement'] = self.big_statement()
return kwargs return kwargs
class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView): class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
""" """
Calculate a dictionary with operation target and sum of operations Calculate a dictionary with operation target and sum of operations
""" """
model = GeneralJournal model = GeneralJournal
pk_url_kwarg = "j_id" pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_person.jinja' template_name = 'accounting/journal_statement_person.jinja'
current_tab='person_statement' current_tab = 'person_statement'
def sum_by_target(self, target_id, target_type, movement_type): def sum_by_target(self, target_id, target_type, movement_type):
return self.object.operations.filter(accounting_type__movement_type=movement_type, return self.object.operations.filter(accounting_type__movement_type=movement_type,
target_id=target_id, target_type=target_type).aggregate(amount_sum=Sum('amount'))['amount_sum'] target_id=target_id, target_type=target_type).aggregate(amount_sum=Sum('amount'))['amount_sum']
def statement(self, movement_type): def statement(self, movement_type):
statement = collections.OrderedDict() statement = collections.OrderedDict()
for op in self.object.operations.filter(accounting_type__movement_type=movement_type).order_by('target_type', for op in self.object.operations.filter(accounting_type__movement_type=movement_type).order_by('target_type',
'target_id').distinct(): 'target_id').distinct():
statement[op.target] = self.sum_by_target(op.target_id, op.target_type, movement_type) statement[op.target] = self.sum_by_target(op.target_id, op.target_type, movement_type)
return statement return statement
@ -598,13 +620,14 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
kwargs['total_debit'] = self.total("DEBIT") kwargs['total_debit'] = self.total("DEBIT")
return kwargs return kwargs
class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView): class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView):
""" """
Calculate a dictionary with operation type and sum of operations Calculate a dictionary with operation type and sum of operations
""" """
model = GeneralJournal model = GeneralJournal
pk_url_kwarg = "j_id" pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_accounting.jinja' template_name = 'accounting/journal_statement_accounting.jinja'
current_tab = "accounting_statement" current_tab = "accounting_statement"
def statement(self): def statement(self):
@ -624,10 +647,12 @@ class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView)
# Company views # Company views
class CompanyListView(CanViewMixin, ListView): class CompanyListView(CanViewMixin, ListView):
model = Company model = Company
template_name = 'accounting/co_list.jinja' template_name = 'accounting/co_list.jinja'
class CompanyCreateView(CanCreateMixin, CreateView): class CompanyCreateView(CanCreateMixin, CreateView):
""" """
Create a company Create a company
@ -648,6 +673,7 @@ class CompanyEditView(CanCreateMixin, UpdateView):
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
success_url = reverse_lazy('accounting:co_list') success_url = reverse_lazy('accounting:co_list')
# Label views # Label views
class LabelListView(CanViewMixin, DetailView): class LabelListView(CanViewMixin, DetailView):
@ -655,11 +681,12 @@ class LabelListView(CanViewMixin, DetailView):
pk_url_kwarg = "clubaccount_id" pk_url_kwarg = "clubaccount_id"
template_name = 'accounting/label_list.jinja' template_name = 'accounting/label_list.jinja'
class LabelCreateView(CanCreateMixin, CreateView): # FIXME we need to check the rights before creating the object
class LabelCreateView(CanCreateMixin, CreateView): # FIXME we need to check the rights before creating the object
model = Label model = Label
form_class = modelform_factory(Label, fields=['name', 'club_account'], widgets={ form_class = modelform_factory(Label, fields=['name', 'club_account'], widgets={
'club_account': HiddenInput, 'club_account': HiddenInput,
}) })
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
def get_initial(self): def get_initial(self):
@ -670,12 +697,14 @@ class LabelCreateView(CanCreateMixin, CreateView): # FIXME we need to check the
ret['club_account'] = obj.id ret['club_account'] = obj.id
return ret return ret
class LabelEditView(CanEditMixin, UpdateView): class LabelEditView(CanEditMixin, UpdateView):
model = Label model = Label
pk_url_kwarg = "label_id" pk_url_kwarg = "label_id"
fields = ['name'] fields = ['name']
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
class LabelDeleteView(CanEditMixin, DeleteView): class LabelDeleteView(CanEditMixin, DeleteView):
model = Label model = Label
pk_url_kwarg = "label_id" pk_url_kwarg = "label_id"
@ -684,9 +713,11 @@ class LabelDeleteView(CanEditMixin, DeleteView):
def get_success_url(self): def get_success_url(self):
return self.object.get_absolute_url() return self.object.get_absolute_url()
class CloseCustomerAccountForm(forms.Form): class CloseCustomerAccountForm(forms.Form):
user = AutoCompleteSelectField('users', label=_('Refound this account'), help_text=None, required=True) user = AutoCompleteSelectField('users', label=_('Refound this account'), help_text=None, required=True)
class RefoundAccountView(FormView): class RefoundAccountView(FormView):
""" """
Create a selling with the same amount than the current user money Create a selling with the same amount than the current user money