Code lisibility improvement.

This commit is contained in:
Trullemans Gregory 2020-02-25 21:50:56 +01:00
parent db1cb5babe
commit 9500e9bd08
18 changed files with 170 additions and 139 deletions

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.contrib import admin
from .models import (

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.apps import AppConfig

View File

@ -7,11 +7,11 @@ def loadBillingConfig(request):
Charge le contenu du fichier SITE_CONFIG.YAML qui contient les données relatives à l'ASBL
"""
current_path = os.path.dirname(os.path.realpath(__file__))
informations = None
club_informations = None
with open(os.path.join(current_path, "billing_config.yaml"), "r") as stream:
try:
informations = yaml.load(stream)
club_informations = yaml.load(stream)
except yaml.YAMLError as exc:
print(exc)
return informations
return club_informations

View File

@ -1,9 +1,12 @@
NAME: 'Flying Acrobatics Trampoline Club A.S.B.L.'
ADDRESS: Champ de l'Epine, 7
CITY: '7090 Hennuyères'
GSM: '0484/14.25.28'
COMPANY_NUMBER: '0660.737.571'
TVA: 'N.A.'
BANK: 'CRELAN'
IBAN: 'BE49 1030 4549 3371'
BIC: 'NICABEBB'
SITE_TITLE: 'Flying Acrobatics Trampoline'
CLUB_NAME: 'Flying Acrobatics Trampoline Club'
NAME: "Flying Acrobatics Trampoline Club A.S.B.L."
ADDRESS: "Champ de l'Epine, 7"
CITY: "Hennuyères"
ZIP: "7090"
GSM: "0484/14.25.28"
BCE_NUMBER: "0660.737.571"
TVA: "N.A."
BANK: "CRELAN"
IBAN: "BE49 1030 4549 3371"
BIC: "NICABEBB"

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.db import models
@ -46,9 +44,7 @@ class Contract(models.Model):
return "%s" % (self.name)
def __generate_reference(self):
"""
Génère automatiquement la référence du contract
"""
""" Génère automatiquement la référence du contract """
if self.reference is None:
if self.id is None:
object_id = "XX"
@ -59,9 +55,7 @@ class Contract(models.Model):
self.reference = str(self.date.year) + "-" + object_id
def save(self, *args, **kwargs):
"""
Enregistre l'objet en DB après avoir calculé le montant total.
"""
""" Enregistre l'objet en DB après avoir calculé le montant total. """
super().save(*args, **kwargs)
self.__generate_reference()
super().save(*args, **kwargs)
@ -93,14 +87,10 @@ class Prestation(models.Model):
)
def __compute_total_amount(self):
"""
Calcule le montant total de la prestation.
"""
""" Calcule le montant total de la prestation. """
self.total_amount = self.unit * self.unit_price
def save(self, *args, **kwargs):
"""
Enregistre l'objet en DB après avoir calculé le montant total.
"""
""" Enregistre l'objet en DB après avoir calculé le montant total. """
self.__compute_total_amount()
super().save(*args, **kwargs)

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.conf.urls import url
from .views import (
@ -15,9 +13,11 @@ app_name = "billing"
urlpatterns = [
url(r"^client/$", client_listing, name="client_listing"),
url(r"^contract/$", contract_listing, name="contract_listing"),
url(r"^contract/(?P<contractid>[0-9]+)/$", contract_detail, name="contract_detail"),
url(
r"^contract/pdf/(?P<contractid>[0-9]+)$",
r"^contract/(?P<contract_id>[0-9]+)/$", contract_detail, name="contract_detail"
),
url(
r"^contract/pdf/(?P<contract_id>[0-9]+)$",
contract_export,
name="contract_export",
),

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.shortcuts import render
from django.http import HttpResponse
from django.db.models import Sum
@ -7,7 +5,8 @@ from django.db.models import Sum
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
# from PIL import Image
from PIL import Image
import os
from django.conf import settings
@ -24,7 +23,6 @@ from .models import (
def contract_listing(request):
""" Récupère la liste de tous les contrats. """
contract_list = Contract.objects.all()
context = {"contract_list": contract_list}
return render(request, "contract_listing.html", context)
@ -69,8 +67,8 @@ def prestation_listing(request):
# Est-ce que ces variables ne devraient pas être dans un fichier de configuration à part ?
Y = 841.89
X = 35
Y = 841.89
RIGHT_X = 595.27 - X
TITLED_X = 125
INDENTED_X = X + 5
@ -81,6 +79,8 @@ PRESTATION_COLUMN_3 = INDENTED_X + 400
PRESTATION_COLUMN_4 = INDENTED_X + 455
COMMON_LINE_HEIGHT = -15
SMALL_LINE_HEIGHT = COMMON_LINE_HEIGHT + 5
LARGE_LINE_HEIGHT = COMMON_LINE_HEIGHT - 5
DOUBLE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 2
BIG_LINE_HEIGHT = COMMON_LINE_HEIGHT * 3
HUGE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 4
@ -99,8 +99,10 @@ class MyDocument(object):
self.amount = 0
def newline(self, height=None):
"""
Passe à la ligne, la hauteur de la ligne étant passée en paramètre.
""" Passe à la ligne, la hauteur de la ligne étant passée en paramètre.
Args:
height (int): hauteur de la ligne
"""
if height == DOUBLE_LINE_HEIGHT:
self.y += DOUBLE_LINE_HEIGHT
@ -136,23 +138,28 @@ class MyDocument(object):
self.newline(height)
self.drawString(x, string, font_family, font_decoration, font_size)
def header(self, info, contract):
"""
Génère le header de la facture.
def header(self, club_infos, contract):
""" Génère le header de la facture.
Args:
club_infos (array<string>): informations du club.
contract (contract): instance de la class Contract.
"""
# self.document.rect(X, 735, 525, 70, fill=0)
self.drawNewLine(INDENTED_X, info["NAME"])
self.drawNewLine(INDENTED_X, club_infos["NAME"])
self.document.drawRightString(
RIGHT_X, self.y, "N° de Référence : " + str(contract.reference)
)
self.drawNewLine(INDENTED_X, info["ADDRESS"])
self.drawNewLine(INDENTED_X, info["CITY"])
self.drawNewLine(INDENTED_X, info["GSM"])
self.drawNewLine(INDENTED_X, club_infos["ADDRESS"])
self.drawNewLine(INDENTED_X, club_infos["CITY"] + " " + club_infos["ZIP"])
self.drawNewLine(INDENTED_X, club_infos["GSM"])
self.newline(DOUBLE_LINE_HEIGHT)
def title(self, contract):
"""
Génère le "titre" de la facture.
""" Génère le "titre" de la facture.
Args:
contract (contract): instance de la class Contract.
"""
res = contract.client.contact.count("i")
res += contract.client.contact.count("t")
@ -179,14 +186,17 @@ class MyDocument(object):
self.drawString(200, contract.name, font_decoration="Bold")
self.newline()
def payementInformation(self, info, contract):
"""
Génère les informations de payement.
def payementInformation(self, club_infos, contract):
""" Génère les informations de payement.
Args:
club_infos (array<string>): informations du club.
contract (contract): instance de la class Contract.
"""
self.newline()
height = 40
self.document.rect(X, self.y - height, RIGHT_X - X, height, fill=0)
self.drawNewLine(INDENTED_X, "N° Entreprise : " + info["COMPANY_NUMBER"])
self.drawNewLine(INDENTED_X, "N° Entreprise : " + club_infos["BCE_NUMBER"])
if contract.client.company_number:
self.document.drawRightString(
@ -197,18 +207,20 @@ class MyDocument(object):
self.drawNewLine(
INDENTED_X,
"IBAN : "
+ info["IBAN"]
+ club_infos["IBAN"]
+ " (BIC : "
+ info["BIC"]
+ club_infos["BIC"]
+ " - "
+ info["BANK"]
+ club_infos["BANK"]
+ ")",
)
self.newline(DOUBLE_LINE_HEIGHT)
def prestations(self, contract):
"""
Génère l'affichage des prestations : tableau, liste des prestations, …
""" Génère l'affichage des prestations : tableau, liste des prestations, …
Args:
contract (contract): instance de la class Contract.
"""
self.drawNewLine(X, "Prestations", font_decoration="Bold")
total = self.drawPrestationsTable(contract.get_prestation.all())
@ -223,9 +235,7 @@ class MyDocument(object):
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(self.amount))
def drawColoredRow(self):
"""
Génère une ligne colorée.
"""
""" Génère une ligne colorée. """
self.document.setFillColorCMYK(0.43, 0.2, 0, 0)
self.document.rect(
X, self.y - 4, RIGHT_X - X, COMMON_LINE_HEIGHT, fill=True, stroke=False
@ -233,9 +243,7 @@ class MyDocument(object):
self.document.setFillColorCMYK(0, 0, 0, 1)
def drawHeaderPrestationsTable(self):
"""
Génère le header de la table des prestations.
"""
""" Génère le header de la table des prestations. """
self.drawColoredRow()
self.newline()
@ -249,8 +257,10 @@ class MyDocument(object):
self.document.drawRightString(INDENTED_X + 510, self.y, "Total")
def drawFooterPrestationTable(self, total):
"""
Génère le footer de la table des prestations.
""" Génère le footer de la table des prestations.
Args:
total (int): somme totale des prestations.
"""
self.drawColoredRow()
self.newline()
@ -259,8 +269,14 @@ class MyDocument(object):
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(total))
def displayPrestation(self, prestation, total):
"""
Affiche une ligne de prestations dans le tableau.
""" Affiche une ligne de prestation dans le tableau.
Args:
prestation (prestation): instance de la classe Prestation.
total (int): somme totale des prestations.
Returns:
total (int): somme totale des prestations.
"""
total += prestation.total_amount
self.drawNewLine(INDENTED_X, str(prestation.date))
@ -274,27 +290,32 @@ class MyDocument(object):
)
return total
def drawPrestationsTable(self, prestation_list):
"""
Génère le tableau des prestations.
def drawPrestationsTable(self, prestations_list):
""" Génère le tableau des prestations.
Args:
prestations_list (list): liste des prestations d'un contrat
"""
self.drawHeaderPrestationsTable()
total = 0
for prestation in prestation_list:
for prestation in prestations_list:
total = self.displayPrestation(prestation, total)
self.drawFooterPrestationTable(total)
return total
def conclusion(self, info, contract):
"""
Affiche la conclusion de la facture.
def conclusion(self, club_infos, contract):
""" Affiche la conclusion de la facture.
Args:
club_infos (array<string>): informations du club.
contract (contract): instance de la class Contract.
"""
self.newline(DOUBLE_LINE_HEIGHT)
self.document.rect(X, self.y, RIGHT_X - X, BIG_LINE_HEIGHT, fill=0)
self.drawNewLine(INDENTED_X, "Merci de bien vouloir payer la somme de ")
self.drawString(INDENTED_X + 184, str(self.amount), font_decoration="Bold")
self.drawString(INDENTED_X + 215, "€ sur le compte ")
self.drawString(INDENTED_X + 290, info["IBAN"], font_decoration="Bold")
self.drawString(INDENTED_X + 290, club_infos["IBAN"], font_decoration="Bold")
self.newline(COMMON_LINE_HEIGHT)
if not contract.is_paid:
@ -317,13 +338,17 @@ class MyDocument(object):
font_decoration="Bold",
)
def addSignature(self):
"""
Génère la signature.
def addSignature(self, club_infos):
""" Génère la signature.
Args:
club_infos (array<string>): informations du club.
"""
self.newline(BIG_LINE_HEIGHT)
self.document.drawString(
INDENTED_X, self.y, "Hennuyères, le " + date.today().strftime("%d-%m-%Y")
INDENTED_X,
self.y,
club_infos["CITY"] + ", le " + date.today().strftime("%d-%m-%Y"),
)
self.document.drawRightString(RIGHT_X, self.y, "Président")
url = os.path.join(settings.STATICFILES_DIRS[0], "img/signature.png")
@ -331,9 +356,7 @@ class MyDocument(object):
self.document.drawImage(url, INDENTED_X + 340, self.y, width=180, height=39)
def footer(self):
"""
Ajoute les conditions générales de payement au document.
"""
""" Ajoute les conditions générales de payement. """
self.y = 175
self.newline(DOUBLE_LINE_HEIGHT)
self.drawNewLine(
@ -363,13 +386,15 @@ class MyDocument(object):
self.document.save()
def contract_export(request, contractid):
"""
Génere une fichier PDF pour fournir au client.
def contract_export(request, contract_id):
""" Génere un fichier PDF pour fournir au client.
Args:
contract_id (int): identifiant d'un contract.
"""
info = loadBillingConfig(request)
contract = Contract.objects.get(pk=contractid)
club_infos = loadBillingConfig(request)
contract = Contract.objects.get(pk=contract_id)
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type="application/pdf")
@ -378,12 +403,12 @@ def contract_export(request, contractid):
)
document = MyDocument(response)
document.header(info, contract)
document.header(club_infos, contract)
document.title(contract)
document.payementInformation(info, contract)
document.payementInformation(club_infos, contract)
document.prestations(contract)
document.conclusion(info, contract)
document.addSignature()
document.conclusion(club_infos, contract)
document.addSignature(club_infos)
document.footer()
document.download()

View File

@ -46,7 +46,7 @@ ROOT_URLCONF = "comptaClub.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "templates"), ],
"DIRS": [os.path.join(BASE_DIR, "templates"),],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
@ -81,9 +81,9 @@ AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", },
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", },
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", },
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
]

View File

@ -1,5 +1,3 @@
# coding=utf-8
import os
import yaml

View File

@ -1,4 +1,13 @@
SITE_TITLE: 'Flying Acrobatics Trampoline'
CLUB_NAME: 'Flying Acrobatics Trampoline Club'
BCE: '0660.7375.71'
SIEGE_SOCIAL: "Champ de l'épine, 7 - 7090 Hennuyères"
NAME: "Flying Acrobatics Trampoline Club A.S.B.L."
ADDRESS: "Champ de l'Epine, 7"
CITY: "Hennuyères"
ZIP: "7090"
GSM: "0484/14.25.28"
COMPANY_NUMBER: "0660.737.571"
TVA: "N.A."
BANK: "CRELAN"
IBAN: "BE49 1030 4549 3371"
BIC: "NICABEBB"

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.contrib import admin
from comptabilite.models import (
Transaction,

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.apps import AppConfig

View File

@ -1,5 +1,3 @@
# coding=utf-8
import csv
import math
import datetime

View File

@ -1,5 +1,3 @@
# coding=utf-8
import markdown
from django.core.exceptions import ValidationError

View File

@ -1,5 +1,3 @@
# coding=utf-8
from decimal import Decimal
from django.db.models import Sum
from .models import (

View File

@ -1,5 +1,3 @@
# coding=utf-8
from django.conf.urls import url
from .views import (

View File

@ -1,5 +1,3 @@
# coding=utf-8
from itertools import zip_longest
from reportlab.pdfgen import canvas
@ -43,7 +41,7 @@ def comptability_export(request, accounting_year, export_type):
Args:
request: La requête HTTP
accounting_year (int): L'année à exporter.
export_type: à choisir parmi `sxs` (side by side) ou `ooo` (one over other).
export_type (string): à choisir parmi `sxs` (side by side) ou `ooo` (one over other).
Returns:
render_to_response sur la page HTML correspondante.
@ -58,6 +56,9 @@ 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
@ -79,6 +80,9 @@ 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
@ -106,8 +110,8 @@ 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).
La fonction va chercher chaque type de dépenses/recettes père (n'ayant pas de parent).
Pour chacun de ces types, <<< on fait quoi >>> ?
Args:
accounting_year (int): année comptable
"""
annuality = Annuality.objects.filter(year__year=accounting_year)
@ -120,7 +124,8 @@ def export_year_spf_finance(request, accounting_year):
list_sum = [
x
for x in zip_longest(
transactiontypes_list_recettes["sum"], transactiontypes_list_expenses["sum"]
transactiontypes_list_recettes["transaction_type_info"],
transactiontypes_list_expenses["transaction_type_info"],
)
]
@ -175,6 +180,7 @@ def export_year_spf_finance(request, accounting_year):
return render(request, "year_transaction_export_spf.html", context)
# Est-ce que ces variables ne devraient pas être dans un fichier de configuration à part ?
X = 35
Y = 841.89
INDENT = 5
@ -197,7 +203,10 @@ HUGE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 4
class MyDocument(object):
# Create the PDF object, using the response object as its "file."
# http://www.reportlab.com/docs/reportlab-userguide.pdf
# canvas.rect(x, y, width, height, stroke=1, fill=0)
# localhost:8000/billing/contract/pdf/2
def __init__(self, response):
# Create the PDF object, using the response object as its "file."
@ -205,21 +214,17 @@ class MyDocument(object):
self.y = Y - X
def newline(self, height=None):
"""
Passe à la ligne, la hauteur de la ligne est passée en paramètre.
"""
if height == SMALL_LINE_HEIGHT:
self.y += SMALL_LINE_HEIGHT
""" Passe à la ligne, la hauteur de la ligne étant passée en paramètre.
elif height == DOUBLE_LINE_HEIGHT:
Args:
height (int): hauteur de la ligne
"""
if height == DOUBLE_LINE_HEIGHT:
self.y += DOUBLE_LINE_HEIGHT
elif height == BIG_LINE_HEIGHT:
self.y += BIG_LINE_HEIGHT
elif height == HUGE_LINE_HEIGHT:
self.y += HUGE_LINE_HEIGHT
else:
self.y += COMMON_LINE_HEIGHT
@ -248,19 +253,27 @@ class MyDocument(object):
self.newline(height)
self.drawString(x, string, font_family, font_decoration, font_size)
def download(self):
# Close the PDF object cleanly, and we're done.
self.document.showPage()
self.document.save()
def header(self, club_infos):
""" Génère le header de la facture.
def header(self, info):
Args:
club_infos (array<string>): informations du club.
"""
rect_height = 40
self.document.rect(X, self.y, RIGHT_X - X, -rect_height, fill=0)
self.drawNewLine(INDENTED_X, "A.S.B.L. : " + info["CLUB_NAME"])
self.drawNewLine(INDENTED_X, "A.S.B.L. : " + club_infos["CLUB_NAME"])
self.document.drawRightString(
INDENTED_RIGHT_X, self.y, "N° Entreprise : " + info["BCE"]
INDENTED_RIGHT_X, self.y, "N° Entreprise : " + club_infos["BCE_NUMBER"]
)
self.drawNewLine(
INDENTED_X,
"Siège social : "
+ club_infos["ADDRESS"]
+ " - "
+ club_infos["CITY"]
+ " "
+ club_infos["ZIP"],
)
self.drawNewLine(INDENTED_X, "Siège social : " + info["SIEGE_SOCIAL"])
self.newline(BIG_LINE_HEIGHT)
def title(self, accounting_year):
@ -272,7 +285,7 @@ class MyDocument(object):
)
self.newline(DOUBLE_LINE_HEIGHT)
def recette_depense(self, accounting_year):
def recette_expenses(self, accounting_year):
self.drawString(
X, "Etat recettes/dépenses (en €)", font_decoration="Oblique", font_size=14
)
@ -567,6 +580,11 @@ class MyDocument(object):
)
self.newline()
def download(self):
# Close the PDF object cleanly, and we're done.
self.document.showPage()
self.document.save()
def generate_pdf_for_spf(request, accounting_year):
""" Génère un fichier PDF suivant les contraintes du SPF Finances
@ -586,7 +604,7 @@ def generate_pdf_for_spf(request, accounting_year):
document.header(info)
document.title(accounting_year)
document.recette_depense(accounting_year)
document.recette_expenses(accounting_year)
document.annexes(accounting_year)
document.download()
@ -767,7 +785,10 @@ def transaction_listing_for_year_and_type(
def transaction_details(request, transactionid):
"""
Récupère les détails d'une transaction
Récupère les détails d'une transaction.
Args:
transactionid (int): identifiant d'une transaction.
"""
transaction = Transaction.objects.get(pk=transactionid)
context = {"transaction": transaction}

View File

@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load intdot %}
{% block content %}
@ -32,7 +33,7 @@
{% endfor %}
<tr>
<td colspan="4" class="push-right"><b>Total :</b></td>
<td class="push-right"><b>{{ total }}</b></td>
<td class="push-right"><b>{{ total|floatformat:2|intdot }}</b></td>
</tr>
</table>
<p class="right"><a href="/billing/contract/pdf/{{ contract.id }}" class="btn btn-default btn-primary" role="button">Facture PDF</a></p>