ComptaClub/comptabilite/views.py

434 lines
14 KiB
Python

from itertools import zip_longest
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.db.models import Q
from django.urls import reverse
from collections import OrderedDict
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from .models import (
Transaction,
TransactionType,
EvaluationRules,
EvaluationRulesAdaptation,
Annuality,
ComplementaryInformations,
)
from .forms import TransactionForm
from .tools import (
get_transactions_and_sums_for_year_and_type,
get_transactiontypes_and_total_amount_transactions,
get_transactiontype_and_sum_for_spf_export,
get_right_engagement_and_sump_spf,
get_asset_liability_and_sump_spf,
)
from tools.pdf_generator import (
SpfDocument,
BillPaper,
)
import locale
EXTENSES = 0
RECETTES = 1
@login_required
@require_http_methods(["GET"])
def comptability_export(request, accounting_year, export_type):
"""
Définit une fonction d'export.
Args:
request: La requête HTTP
accounting_year (int): L'année à exporter.
export_type (string): à choisir parmi `sxs` (side by side) ou `ooo` (one over other).
Returns:
render_to_response sur la page HTML correspondante.
"""
if export_type == "sxs":
return get_transaction_list_for_accountingyear_sxs(request, accounting_year)
else:
return get_transaction_list_for_accountingyear_ooo(request, accounting_year)
@login_required
@require_http_methods(["GET"])
def get_transaction_list_for_accountingyear_ooo(request, accounting_year):
"""
Affichage et calcul des `Recettes` et `Dépenses` pour une année donnée dans deux tableaux l'un
au dessus de l'autre (one over other - ooo).
Args:
accounting_year (int): année comptable
"""
transactions_list_expenses = get_transactions_and_sums_for_year_and_type(
accounting_year, EXTENSES
)
transactions_list_recettes = get_transactions_and_sums_for_year_and_type(
accounting_year, RECETTES
)
context = {
"transactions_list_expenses": transactions_list_expenses,
"accounting_year": accounting_year,
"transactions_list_recettes": transactions_list_recettes,
}
return render(request, "comptability/year_transaction_export_ooo.html", context)
@login_required
@require_http_methods(["GET"])
def get_transaction_list_for_accountingyear_sxs(request, accounting_year):
"""
Calcule et affiche la comptabilité d'une année passée en parametre dans un unique tableau (side
by side).
Args:
accounting_year (int): année comptable
"""
expenses_transactiontypes_list = get_transactiontypes_and_total_amount_transactions(
accounting_year, EXTENSES
)
recettes_transactiontypes_list = get_transactiontypes_and_total_amount_transactions(
accounting_year, RECETTES
)
transactiontypes_list = zip_longest(
recettes_transactiontypes_list["transactiontypes_info_list"],
expenses_transactiontypes_list["transactiontypes_info_list"],
)
context = {
"transactiontypes_list": transactiontypes_list,
"accounting_year": accounting_year,
"total_expenses": expenses_transactiontypes_list["total"],
"total_recettes": recettes_transactiontypes_list["total"],
}
return render(request, "comptability/year_transaction_export_sxs.html", context)
@login_required
@require_http_methods(["GET"])
def export_year_spf_finance(request, accounting_year):
"""
Calcule et affiche la comptabilité d'une année passée en parametre dans un unique tableau (side
by side).
Args:
accounting_year (int): année comptable
"""
annuality = Annuality.objects.filter(year__year=accounting_year)
transactiontypes_list_expenses = get_transactiontype_and_sum_for_spf_export(
accounting_year, EXTENSES
)
transactiontypes_list_recettes = get_transactiontype_and_sum_for_spf_export(
accounting_year, RECETTES
)
transactiontypes_list = [
x
for x in zip_longest(
transactiontypes_list_recettes["transaction_type_info"],
transactiontypes_list_expenses["transaction_type_info"],
)
]
# règle d'évaluation
rules_list = EvaluationRules.objects.filter(
Q(stop_date__year__lte=accounting_year) | Q(stop_date__isnull=True)
).exclude(start_date__year__gt=accounting_year)
rules_adaptation_list = EvaluationRulesAdaptation.objects.filter(
start_date__year=accounting_year
)
complementary_informations = ComplementaryInformations.objects.filter(
annuality=annuality[0]
)
liquidity = 0
assets_list = get_asset_liability_and_sump_spf(accounting_year, category=0)
for item in assets_list:
if item[0] == "Liquidité":
item[1] += (
annuality[0].opening_balance
+ transactiontypes_list_recettes["sum_total_transaction"]
- transactiontypes_list_expenses["sum_total_transaction"]
)
liquidity = item[1]
asset_liability_list = get_asset_liability_and_sump_spf(accounting_year, category=1)
asset_liability_sum = [x for x in zip_longest(assets_list, asset_liability_list)]
right_list = get_right_engagement_and_sump_spf(accounting_year, category=0)
engagement_list = get_right_engagement_and_sump_spf(accounting_year, category=1)
right_engagement_sum = [x for x in zip_longest(right_list, engagement_list)]
if len(right_engagement_sum) == 0:
right_engagement_sum = None
annuality[0].closing_balance = liquidity
annuality[0].save()
context = {
"transactiontypes_list": transactiontypes_list,
"accounting_year": accounting_year,
"total_expenses": transactiontypes_list_expenses["sum_total_transaction"],
"total_recette": transactiontypes_list_recettes["sum_total_transaction"],
"rules_list": rules_list,
"rules_adaptation_list": rules_adaptation_list,
"complementary_informations": complementary_informations,
"asset_liability_sum": asset_liability_sum,
"right_engagement_sum": right_engagement_sum,
}
return render(request, "comptability/year_transaction_export_spf.html", context)
@login_required
@require_http_methods(["GET"])
def generate_pdf_for_spf(request, accounting_year):
""" Génère un fichier PDF suivant les contraintes du SPF Finances
Args:
accounting_year (int): année
Returns:
???
"""
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
'attachment; filename="comptes_simplifies_annuels_' + str(accounting_year) + '.pdf"'
)
document = SpfDocument(response)
document.generate(str(accounting_year))
document.download()
return response
def __get_transactions_for_accounting_year_and_kind(
accounting_year, transaction_kind=None
):
"""
"""
transactions_list = Transaction.objects.by_year(accounting_year)
if transaction_kind == "bank":
transaction_kind = "Banque"
transactions_list = transactions_list.filter(bkAmount__isnull=False).exclude(
bkAmount=0
)
elif transaction_kind == "box":
transaction_kind = "Caisse"
transactions_list = transactions_list.filter(bxAmount__isnull=False).exclude(
bxAmount=0
)
else:
transaction_kind = "Tous"
transactions_list = transactions_list.order_by("registrationDate")
return transactions_list, transaction_kind
@login_required
@require_http_methods(["GET"])
def transaction_by_year_listing(request, accounting_year, transaction_kind=None):
""" Liste toutes les lignes de comptabilité pour une année recue en paramètre
Args:
accounting_year (int): année comptable
transaction_kind (string):
"""
(
transactions_list,
transaction_kind,
) = __get_transactions_for_accounting_year_and_kind(
accounting_year, transaction_kind
)
# pour mon dictionnaire date/total
previous_date = None
date_sum = OrderedDict()
tmp_Total = 0
tmp_Amount = 0
sum_extense = 0
sum_extense_simulated = 0
sumrecette = 0
sumrecette_simulated = 0
transaction_list_and_sum = []
for transaction in transactions_list:
# transaction type :
# 0 : dépense
# 1 : recette
# Suivant le type de la transaction, on ajoute son montant aux recettes ou au dépenses et
# on ajoute le signe ("+" ou "-") afin de pouvoir l'utiliser dans des calculs après.
tmp_Amount = transaction.totalAmount
if transaction.transaction_type.transaction_type == EXTENSES:
sum_extense_simulated += tmp_Amount
if transaction.is_simulated is not None and transaction.is_simulated == 0:
sum_extense += tmp_Amount
tmp_Amount = -tmp_Amount
else:
sumrecette_simulated += tmp_Amount
if transaction.is_simulated is not None and transaction.is_simulated == 0:
sumrecette += tmp_Amount
# Si la transaction n'est pas simulée on ajoute la transaction au total temporaire.
if (
transaction.is_simulated is not None and transaction.is_simulated == 0
) and (transaction.is_done is not None and transaction.is_done == 1):
tmp_Total += tmp_Amount
transaction_list_and_sum.append((transaction, tmp_Total))
if transaction.registrationDate.date() in date_sum:
date_sum[transaction.registrationDate.date()] += tmp_Amount
else:
if previous_date is not None:
date_sum[transaction.registrationDate.date()] = (
date_sum[previous_date] + tmp_Amount
)
else:
date_sum[transaction.registrationDate.date()] = tmp_Amount
previous_date = transaction.registrationDate.date()
total = sumrecette - sum_extense
total_simulated = sumrecette_simulated - sum_extense_simulated
nb_transaction = transactions_list.count()
context = {
"transaction_list": transaction_list_and_sum,
"accounting_year": accounting_year,
"totaldepense": sum_extense,
"totalrecette": sumrecette,
"totaldepense_simulated": sum_extense_simulated,
"totalrecette_simulated": sumrecette_simulated,
"total": total,
"total_simulated": total_simulated,
"date_sum": date_sum,
"nb_transaction": nb_transaction,
"t_type": transaction_kind,
}
return render(request, "comptability/transactions/listing.html", context)
@login_required
@require_http_methods(["GET"])
def year_listing(request):
"""
Liste toutes les années pour lesquelles il y a des transactions.
"""
years = Transaction.objects.dates("registrationDate", "year")
year_list = []
for year in years:
year_list.append((year.year, Transaction.objects.by_year(year.year).count(),))
context = {"year_list": year_list}
return render(request, "comptability/year_listing.html", context)
@login_required
@require_http_methods(["GET"])
def transaction_listing_for_year_and_type(
request, accounting_year, transaction_type_id
):
"""
Liste toutes les transactions d'un `type de transaction` et pour une année passés en paramètre.
Args:
request (???):
accounting_year (int): année
transaction_type_id (int): id d'un type de transaction
Returns:
(???)
"""
transaction_type = TransactionType.objects.get(pk=transaction_type_id)
# by_year_condition = Q(registrationDate__year=accounting_year)
by_type_condition = Q(transaction_type=transaction_type_id)
by_parent_type_condition = Q(transaction_type__parent=transaction_type_id)
transaction_list = (
Transaction.objects.by_year(accounting_year)
.filter((by_type_condition | by_parent_type_condition))
.order_by("registrationDate")
)
total = 0
total_simulated = 0
transaction_list_and_sum = []
for transaction in transaction_list:
total_simulated += transaction.totalAmount
if transaction.is_simulated is not None and transaction.is_simulated == 0:
total += transaction.totalAmount
transaction_list_and_sum.append((transaction, total))
context = {
"transaction_list": transaction_list_and_sum,
"transaction_type": str(transaction_type),
"accounting_year": accounting_year,
"total_simulated": total_simulated,
"total": total,
}
return render(request, "comptability/transactions/listing.html", context)
@login_required
@require_http_methods(["GET"])
def transaction_details(request, transaction_id):
"""
Renvoie les détails d'une ligne de comptabilité.
"""
transaction = Transaction.objects.get(pk=transaction_id)
context = {"event": transaction.event, "transaction": transaction}
# changed template
return render(request, "comptability/transactions/details.html", context)
@login_required
@require_http_methods(["GET", "POST"])
def transaction_create_or_update(request, transaction_id=None):
""" Création ou modificatin d'une transaction.
Args:
transaction_id (int): identifiant d'une transaction.
"""
if transaction_id:
transaction = get_object_or_404(Transaction, pk=transaction_id)
else:
transaction = None
if request.method == "POST":
form = TransactionForm(request.POST, instance=transaction)
if form.is_valid():
transaction = form.save()
return HttpResponseRedirect(reverse("transaction_details", args=(transaction.pk, )))
else:
form = TransactionForm(instance=transaction)
context = {"form": form, "transaction_id": transaction_id}
return render(request, "comptability/transactions/create.html", context)