Commit f79ffbee authored by Skia's avatar Skia
Browse files

Merge branch 'bilanTresorerie' into 'master'

Bilan tresorerie

See merge request !36
parents 168622a0 b07b408e
Pipeline #576 passed with stage
in 2 minutes and 20 seconds
......@@ -22,6 +22,7 @@
<p>{% trans %}Journal is closed, you can not create operation{% endtrans %}</p>
{% else %}
<p><a href="{{ url('accounting:op_new', j_id=object.id) }}">{% trans %}New operation{% endtrans %}</a></p>
</br>
{% endif %}
<table>
<thead>
......
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %}
{% block content %}
<h3>{% trans %}Accounting statement: {% endtrans %} {{ object.name }}</h3>
<table>
<thead>
<tr>
<td>{% trans %}Operation type{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for k,v in statement.items() %}
<tr>
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }}</p>
<p><strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }}</p>
{% endblock %}
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %}
{% macro display_tables(dict) %}
<h6>{% trans %}Credit{% endtrans %}</h6>
<table>
<thead>
<tr>
<td>{% trans %}Nature of operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for k,v in dict['CREDIT'].items() %}
<tr>
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% trans %}Total: {% endtrans %}{{ dict['CREDIT_sum'] }}
<h6>{% trans %}Debit{% endtrans %}</h6>
<table>
<thead>
<tr>
<td>{% trans %}Nature of operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for k,v in dict['DEBIT'].items() %}
<tr>
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% trans %}Total: {% endtrans %}{{ dict['DEBIT_sum'] }}
{% endmacro %}
{% block content %}
<h3>{% trans %}Statement by nature: {% endtrans %} {{ object.name }}</h3>
{% for k,v in statement.items() %}
<h4 style="background: lightblue; padding: 4px;">{{ k }} : {{ v['CREDIT_sum'] - v['DEBIT_sum'] }}</h4>
{{ display_tables(v) }}
<hr>
{% endfor %}
{% endblock %}
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %}
{% block content %}
<h3>{% trans %}Statement by person: {% endtrans %} {{ object.name }}</h3>
<h4>{% trans %}Credit{% endtrans %}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Target of the operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for key in credit_statement.keys() %}
<tr>
{% if key.target_type == "OTHER" %}
<td>{{ o.target_label }}</td>
{% elif key %}
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
{% else %}
<td></td>
{% endif %}
<td>{{ credit_statement[key] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p>Total : {{ total_credit }}</p>
<h4>{% trans %}Debit{% endtrans %}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Target of the operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for key in debit_statement.keys() %}
<tr>
{% if key.target_type == "OTHER" %}
<td>{{ o.target_label }}</td>
{% elif key %}
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
{% else %}
<td></td>
{% endif %}
<td>{{ debit_statement[key] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p>Total : {{ total_debit }}</p>
{% endblock %}
......@@ -26,6 +26,10 @@ urlpatterns = [
url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'),
url(r'^journal/(?P<j_id>[0-9]+)$', JournalDetailView.as_view(), name='journal_details'),
url(r'^journal/(?P<j_id>[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/nature$', JournalNatureStatementView.as_view(), name='journal_nature_statement'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/person$', JournalPersonStatementView.as_view(), name='journal_person_statement'),
url(r'^journal/(?P<j_id>[0-9]+)/statement/accounting$', JournalAccountingStatementView.as_view(), name='journal_accounting_statement'),
# Operations
url(r'^operation/create/(?P<j_id>[0-9]+)$', OperationCreateView.as_view(), name='op_new'),
url(r'^operation/(?P<op_id>[0-9]+)$', OperationEditView.as_view(), name='op_edit'),
......
......@@ -7,16 +7,18 @@ from django.forms.models import modelform_factory
from django.core.exceptions import PermissionDenied
from django.forms import HiddenInput
from django.db import transaction
from django.db.models import Sum
from django.conf import settings
from django import forms
from django.http import HttpResponseRedirect, HttpResponse
from django.utils.translation import ugettext as _
from django.conf import settings
import collections
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
from core.views.forms import SelectFile, SelectDate
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company, SimplifiedAccountingType, Label
from counter.models import Counter, Selling, Product
......@@ -165,6 +167,34 @@ class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete
# Journal views
class JournalTabsMixin(TabedViewMixin):
def get_tabs_title(self):
return _("Journal")
def get_list_of_tabs(self):
tab_list = []
tab_list.append({
'url': reverse('accounting:journal_details', kwargs={'j_id': self.object.id}),
'slug': 'journal',
'name': _("Journal"),
})
tab_list.append({
'url': reverse('accounting:journal_nature_statement', kwargs={'j_id': self.object.id}),
'slug': 'nature_statement',
'name': _("Statement by nature"),
})
tab_list.append({
'url': reverse('accounting:journal_person_statement', kwargs={'j_id': self.object.id}),
'slug': 'person_statement',
'name': _("Statement by person"),
})
tab_list.append({
'url': reverse('accounting:journal_accounting_statement', kwargs={'j_id': self.object.id}),
'slug': 'accounting_statement',
'name': _("Accounting statement"),
})
return tab_list
class JournalCreateView(CanCreateMixin, CreateView):
"""
Create a general journal
......@@ -182,13 +212,14 @@ class JournalCreateView(CanCreateMixin, CreateView):
ret['club_account'] = obj.id
return ret
class JournalDetailView(CanViewMixin, DetailView):
class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView):
"""
A detail view, listing every operation
"""
model = GeneralJournal
pk_url_kwarg = "j_id"
template_name = 'accounting/journal_details.jinja'
current_tab = 'journal'
class JournalEditView(CanEditMixin, UpdateView):
"""
......@@ -334,8 +365,6 @@ class OperationPDFView(CanViewMixin, DetailView):
pdfmetrics.registerFont(TTFont('DejaVu', 'DejaVuSerif.ttf'))
self.object = self.get_object()
amount = self.object.amount
remark = self.object.remark
......@@ -355,7 +384,6 @@ class OperationPDFView(CanViewMixin, DetailView):
else:
target = self.object.target.get_display_name()
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="op-%d(%s_on_%s).pdf"' %(num, ti, club_name)
p = canvas.Canvas(response)
......@@ -367,11 +395,11 @@ class OperationPDFView(CanViewMixin, DetailView):
im = ImageReader("core/static/core/img/logo.jpg")
iw, ih = im.getSize()
p.drawImage(im, 40, height - 50, width=iw/2, height=ih/2)
labelStr = [["%s %s - %s %s" % (_("Journal"), ti, _("Operation"), num)]]
label = Table(labelStr, colWidths=[150], rowHeights=[20])
label.setStyle(TableStyle([
('ALIGN',(0,0),(-1,-1),'CENTER'),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
......@@ -385,11 +413,11 @@ class OperationPDFView(CanViewMixin, DetailView):
p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date})
data = []
data += [["%s" % (_("Credit").upper() if nature == 'CREDIT' else _("Debit").upper())]]
data += [[_("Amount: %(amount).2f €") % {"amount": amount}]]
payment_mode = ""
for m in settings.SITH_ACCOUNTING_PAYMENT_METHOD:
if m[0] == mode:
......@@ -399,11 +427,11 @@ class OperationPDFView(CanViewMixin, DetailView):
payment_mode += " %s\n" %(m[1])
data += [[payment_mode]]
data += [["%s : %s" % (_("Debtor") if nature == 'CREDIT' else _("Creditor"), target), ""]]
data += [["%s \n%s" % (_("Comment:"), remark)]]
t = Table(data, colWidths=[(width-90*2)/2]*2, rowHeights=[20, 20, 70, 20, 80])
t.setStyle(TableStyle([
('ALIGN',(0,0),(-1,-1),'CENTER'),
......@@ -435,8 +463,6 @@ class OperationPDFView(CanViewMixin, DetailView):
t.drawOn(p, 90, 350)
p.drawCentredString(10.5 * cm, 2 * cm, club_name)
p.drawCentredString(10.5 * cm, 1 * cm, club_address)
......@@ -444,6 +470,112 @@ class OperationPDFView(CanViewMixin, DetailView):
p.save()
return response
class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
"""
Display a statement sorted by labels
"""
model = GeneralJournal
pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_nature.jinja'
current_tab='nature_statement'
def statement(self, queryset, movement_type):
ret = collections.OrderedDict()
statement = collections.OrderedDict()
total_sum = 0
for sat in [None] + list(SimplifiedAccountingType.objects.order_by('label').all()):
sum = queryset.filter(accounting_type__movement_type=movement_type,
simpleaccounting_type=sat).aggregate(amount_sum=Sum('amount'))['amount_sum']
if sat: sat = sat.label
else: sat = ""
if sum:
total_sum += sum
statement[sat] = sum
ret[movement_type] = statement
ret[movement_type+"_sum"] = total_sum
return ret
def big_statement(self):
label_list = self.object.operations.order_by('label').values_list('label').distinct()
labels = Label.objects.filter(id__in=label_list).all()
statement = collections.OrderedDict()
gen_statement = collections.OrderedDict()
no_label_statement = collections.OrderedDict()
gen_statement.update(self.statement(self.object.operations.all(), "CREDIT"))
gen_statement.update(self.statement(self.object.operations.all(), "DEBIT"))
statement[_("General statement")] = gen_statement
no_label_statement.update(self.statement(self.object.operations.filter(label=None).all(), "CREDIT"))
no_label_statement.update(self.statement(self.object.operations.filter(label=None).all(), "DEBIT"))
statement[_("No label operations")] = no_label_statement
for l in labels:
l_stmt = collections.OrderedDict()
l_stmt.update(self.statement(self.object.operations.filter(label=l).all(), "CREDIT"))
l_stmt.update(self.statement(self.object.operations.filter(label=l).all(), "DEBIT"))
statement[l] = l_stmt
return statement
def get_context_data(self, **kwargs):
""" Add infos to the context """
kwargs = super(JournalNatureStatementView, self).get_context_data(**kwargs)
kwargs['statement'] = self.big_statement()
return kwargs
class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
"""
Calculate a dictionary with operation target and sum of operations
"""
model = GeneralJournal
pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_person.jinja'
current_tab='person_statement'
def sum_by_target(self, target_id, target_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']
def statement(self, movement_type):
statement = collections.OrderedDict()
for op in self.object.operations.filter(accounting_type__movement_type=movement_type).order_by('target_type',
'target_id').distinct():
statement[op.target] = self.sum_by_target(op.target_id, op.target_type, movement_type)
return statement
def total(self, movement_type):
return sum(self.statement(movement_type).values())
def get_context_data(self, **kwargs):
""" Add journal to the context """
kwargs = super(JournalPersonStatementView, self).get_context_data(**kwargs)
kwargs['credit_statement'] = self.statement("CREDIT")
kwargs['debit_statement'] = self.statement("DEBIT")
kwargs['total_credit'] = self.total("CREDIT")
kwargs['total_debit'] = self.total("DEBIT")
return kwargs
class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView):
"""
Calculate a dictionary with operation type and sum of operations
"""
model = GeneralJournal
pk_url_kwarg = "j_id"
template_name='accounting/journal_statement_accounting.jinja'
current_tab = "accounting_statement"
def statement(self):
statement = collections.OrderedDict()
for at in AccountingType.objects.order_by('code').all():
sum_by_type = self.object.operations.filter(
accounting_type__code__startswith=at.code).aggregate(amount_sum=Sum('amount'))['amount_sum']
if sum_by_type:
statement[at] = sum_by_type
return statement
def get_context_data(self, **kwargs):
""" Add journal to the context """
kwargs = super(JournalAccountingStatementView, self).get_context_data(**kwargs)
kwargs['statement'] = self.statement()
return kwargs
# Company views
class CompanyListView(CanViewMixin, ListView):
......@@ -477,7 +609,7 @@ class LabelListView(CanViewMixin, DetailView):
pk_url_kwarg = "clubaccount_id"
template_name = 'accounting/label_list.jinja'
class LabelCreateView(CanEditMixin, 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
form_class = modelform_factory(Label, fields=['name', 'club_account'], widgets={
'club_account': HiddenInput,
......
......@@ -295,10 +295,17 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
ca.save()
gj = GeneralJournal(name="A16", start_date=date.today(), club_account=ca)
gj.save()
credit = AccountingType(code=74, label="Someone gave us money", movement_type='CREDIT')
credit = AccountingType(code='74', label="Someone gave us money", movement_type='CREDIT')
credit.save()
debit = AccountingType(code=607, label="Had to pay a beer", movement_type='DEBIT')
debit = AccountingType(code='607', label="Had to pay a beer", movement_type='DEBIT')
debit.save()
t = AccountingType(code='602', label="Gros test de malade", movement_type='DEBIT')
t.save()
Operation(journal=gj, date=date.today(), amount=32.3, remark="...", mode="CASH", done=True, accounting_type=t, target_type="USER", target_id=skia.id).save()
t = AccountingType(code='60', label="...", movement_type='DEBIT')
t.save()
Operation(journal=gj, date=date.today(), amount=32.3, remark="...", mode="CASH", done=True, accounting_type=t, target_type="USER", target_id=skia.id).save()
Operation(journal=gj, date=date.today(), amount=46.42, remark="An answer to life...", mode="CASH", done=True, accounting_type=t, target_type="USER", target_id=skia.id).save()
Operation(journal=gj, date=date.today(), amount=666.42,
remark="An answer to life...", mode="CASH", done=True, accounting_type=credit, target_type="USER",
target_id=skia.id).save()
......
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-21 02:37+0100\n"
"POT-Creation-Date: 2016-12-21 05:22+0100\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
......@@ -161,7 +161,7 @@ msgstr "type comptable"
#: accounting/models.py:205 accounting/models.py:299 accounting/models.py:325
#: accounting/models.py:348 counter/models.py:282
msgid "label"
msgstr "intitulé"
msgstr "étiquette"
#: accounting/models.py:206
msgid "target type"
......@@ -244,11 +244,17 @@ msgstr "Un code comptable ne contient que des numéros"
msgid "movement type"
msgstr "type de mouvement"
#: accounting/models.py:300 accounting/views.py:389
#: accounting/models.py:300
#: accounting/templates/accounting/journal_statement_nature.jinja:8
#: accounting/templates/accounting/journal_statement_person.jinja:11
#: accounting/views.py:417
msgid "Credit"
msgstr "Crédit"
#: accounting/models.py:300 accounting/views.py:389
#: accounting/models.py:300
#: accounting/templates/accounting/journal_statement_nature.jinja:27
#: accounting/templates/accounting/journal_statement_person.jinja:37
#: accounting/views.py:417
msgid "Debit"
msgstr "Débit"
......@@ -340,7 +346,7 @@ msgstr "Nouveau compte club"
#: accounting/templates/accounting/bank_account_details.jinja:26
#: accounting/templates/accounting/bank_account_list.jinja:21
#: accounting/templates/accounting/club_account_details.jinja:55
#: accounting/templates/accounting/journal_details.jinja:72 club/views.py:54
#: accounting/templates/accounting/journal_details.jinja:73 club/views.py:54
#: core/templates/core/file.jinja:38 core/templates/core/page.jinja:31
#: core/templates/core/user_tools.jinja:38 core/views/user.py:152
#: counter/templates/counter/cash_summary_list.jinja:53
......@@ -413,7 +419,7 @@ msgid "End"
msgstr "Fin"
#: accounting/templates/accounting/club_account_details.jinja:31
#: accounting/templates/accounting/journal_details.jinja:32
#: accounting/templates/accounting/journal_details.jinja:33
#: core/templates/core/user_account_detail.jinja:53
#: core/templates/core/user_account_detail.jinja:80
#: counter/templates/counter/last_ops.jinja:17
......@@ -429,17 +435,17 @@ msgid "Closed"
msgstr "Fermé"
#: accounting/templates/accounting/club_account_details.jinja:34
#: accounting/templates/accounting/journal_details.jinja:40
#: accounting/templates/accounting/journal_details.jinja:41
msgid "Actions"
msgstr "Actions"
#: accounting/templates/accounting/club_account_details.jinja:50
#: accounting/templates/accounting/journal_details.jinja:60
#: accounting/templates/accounting/journal_details.jinja:61
msgid "Yes"
msgstr "Oui"
#: accounting/templates/accounting/club_account_details.jinja:52
#: accounting/templates/accounting/journal_details.jinja:62
#: accounting/templates/accounting/journal_details.jinja:63
msgid "No"
msgstr "Non"
......@@ -464,10 +470,14 @@ msgstr "Entreprises"
#: accounting/templates/accounting/journal_details.jinja:4
#: accounting/templates/accounting/journal_details.jinja:15
#: accounting/templates/accounting/journal_statement_accounting.jinja:4
#: accounting/templates/accounting/journal_statement_nature.jinja:4
#: accounting/templates/accounting/journal_statement_person.jinja:4
msgid "General journal:"
msgstr "Classeur : "
#: accounting/templates/accounting/journal_details.jinja:19
#: accounting/templates/accounting/journal_statement_accounting.jinja:29
#: core/templates/core/user_account.jinja:38
#: core/templates/core/user_account_detail.jinja:10
#: counter/templates/counter/counter_click.jinja:32
......@@ -475,6 +485,7 @@ msgid "Amount: "
msgstr "Montant : "
#: accounting/templates/accounting/journal_details.jinja:20
#: accounting/templates/accounting/journal_statement_accounting.jinja:30
msgid "Effective amount: "
msgstr "Montant effectif: "
......@@ -486,12 +497,12 @@ msgstr "Le classeur est fermé, vous ne pouvez pas créer d'opération"
msgid "New operation"
msgstr "Nouvelle opération"
#: accounting/templates/accounting/journal_details.jinja:29
#: accounting/templates/accounting/journal_details.jinja:30
#: counter/templates/counter/stats.jinja:14
msgid "Nb"
msgstr "No"
#: accounting/templates/accounting/journal_details.jinja:30
#: accounting/templates/accounting/journal_details.jinja:31
#: club/templates/club/club_sellings.jinja:19
#: core/templates/core/user_account_detail.jinja:17
#: core/templates/core/user_account_detail.jinja:50
......@@ -502,50 +513,94 @@ msgstr "No"
msgid "Date"
msgstr "Date"
#: accounting/templates/accounting/journal_details.jinja:31
#: accounting/templates/accounting/journal_details.jinja:32
#: club/templates/club/club_sellings.jinja:23
#: core/templates/core/user_account_detail.jinja:20
#: counter/templates/counter/last_ops.jinja:42
msgid "Label"
msgstr "Étiquette"
#: accounting/templates/accounting/journal_details.jinja:33
#: accounting/templates/accounting/journal_details.jinja:34
msgid "Payment mode"
msgstr "Méthode de paiement"
#: accounting/templates/accounting/journal_details.jinja:34
#: accounting/templates/accounting/journal_details.jinja:35
msgid "Target"
msgstr "Cible"
#: accounting/templates/accounting/journal_details.jinja:35
#: accounting/templates/accounting/journal_details.jinja:36
msgid "Code"
msgstr "Code"
#: accounting/templates/accounting/journal_details.jinja:36
#: accounting/templates/accounting/journal_details.jinja:37
msgid "Nature"
msgstr "Nature"
#: accounting/templates/accounting/journal_details.jinja:37
#: accounting/templates/accounting/journal_details.jinja:38
msgid "Done"
msgstr "Effectué"
#: accounting/templates/accounting/journal_details.jinja:38
#: accounting/templates/accounting/journal_details.jinja:39