ComptaClub/tools/pdf_generator.py

672 lines
23 KiB
Python
Raw Normal View History

2022-09-19 12:59:53 +02:00
from reportlab.pdfgen.canvas import Canvas
2020-02-26 15:18:19 +01:00
from reportlab.lib.pagesizes import A4
2022-09-19 12:59:53 +02:00
from reportlab.lib.units import cm
from reportlab.platypus import Table, TableStyle, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors
2020-02-26 15:18:19 +01:00
from django.conf import settings
from datetime import date, datetime, timedelta
2022-09-19 12:59:53 +02:00
from django.db.models import Q, Sum
2020-02-26 15:18:19 +01:00
import os
import locale
from PIL import Image
2022-09-16 15:18:18 +02:00
from textwrap import wrap
2020-02-26 15:18:19 +01:00
from comptabilite.models import (
Transaction,
TransactionType,
EvaluationRules,
EvaluationRulesAdaptation,
Annuality,
ComplementaryInformations,
)
from comptabilite.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,
)
import os
import yaml
2020-03-03 20:53:01 +01:00
import re
2020-02-26 15:18:19 +01:00
2020-03-03 20:53:01 +01:00
EXPENSES = 0
2020-02-26 15:18:19 +01:00
RECETTES = 1
X = 35
Y = 841.89
INDENT = 5
RIGHT_X = 595.27 - X
TITLED_X = 125
INDENTED_X = X + INDENT
INDENTED_RIGHT_X = RIGHT_X - INDENT
MIDDLE = (RIGHT_X - X) / 2
COMMON_LINE_HEIGHT = -15
2022-09-19 14:33:29 +02:00
SMALL_LINE_HEIGHT = -10
LARGE_LINE_HEIGHT = -20
2020-02-26 15:18:19 +01:00
DOUBLE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 2
BIG_LINE_HEIGHT = COMMON_LINE_HEIGHT * 3
HUGE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 4
class PDFDocument(object):
2022-09-19 14:33:29 +02:00
""" Create the PDF object, using the response object as its "file" """
2020-02-26 15:18:19 +01:00
def __init__(self, response):
2022-09-19 12:59:53 +02:00
self.document = Canvas(response, pagesize=A4)
2020-02-26 15:18:19 +01:00
self.y = Y - X
self.__load_config()
2020-02-26 15:18:19 +01:00
def __load_config(self):
2020-02-29 14:18:43 +01:00
""" Charge le contenu du fichier SITE_CONFIG.YAML qui contient les données relatives à
l'ASBL.
2020-02-26 15:18:19 +01:00
"""
current_path = os.path.dirname(os.path.realpath(__file__))
self.club_infos = None
with open(os.path.join(current_path, "site_config.yaml"), "r") as stream:
try:
2020-03-03 20:56:10 +01:00
self.club_infos = yaml.load(stream, Loader=yaml.FullLoader)
2020-02-26 15:18:19 +01:00
except yaml.YAMLError as exc:
print(exc)
2020-03-03 20:53:01 +01:00
def add_vspace(self, height=COMMON_LINE_HEIGHT):
2022-09-19 14:33:29 +02:00
""" Passe à la ligne avec une hauteur de ligne passée en paramètre.
2020-02-26 15:18:19 +01:00
Args:
2020-03-03 20:53:01 +01:00
height (int): hauteur de la ligne.
Returns:
ne retourne rien.
2020-02-26 15:18:19 +01:00
"""
2020-03-03 20:53:01 +01:00
self.y += height
2020-02-26 15:18:19 +01:00
# if y < 120;
# document.PageBreak()
# y = 790
def add_string(
self, x, string, font_family="Helvetica", font_decoration=None, font_size=10
):
2020-03-03 20:53:01 +01:00
if font_decoration:
font_family += "-" + font_decoration
self.document.setFont(font_family, font_size)
self.document.drawString(x, self.y, string)
def add_new_line(
self,
x,
string,
2020-03-03 20:53:01 +01:00
height=COMMON_LINE_HEIGHT,
font_family="Helvetica",
font_decoration=None,
font_size=10,
):
self.add_vspace(height)
self.add_string(x, string, font_family, font_decoration, font_size)
def add_header(self, contract=None):
""" Génère le header du document.
Args:
contract (contract): instance de la class Contract.
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
"""
rect_height = 40
self.document.rect(X, self.y, RIGHT_X - X, -rect_height, fill=0)
self.add_new_line(INDENTED_X, self.club_infos["NAME"])
self.document.drawRightString(
INDENTED_RIGHT_X, self.y, "N° Entreprise : " + self.club_infos["BCE_NUMBER"]
)
self.add_new_line(
INDENTED_X,
"Siège social : "
+ self.club_infos["ADDRESS"]
+ " - "
+ self.club_infos["CITY"]
+ " "
+ self.club_infos["ZIP"],
)
if contract is not None:
self.document.drawRightString(
INDENTED_RIGHT_X, self.y, "N° de Référence : " + str(contract.reference)
)
self.add_vspace(BIG_LINE_HEIGHT)
2020-03-03 20:53:01 +01:00
def download(self):
2022-09-19 14:33:29 +02:00
""" Close the PDF object cleanly, and send it to download. """
2020-03-03 20:53:01 +01:00
self.document.showPage()
self.document.save()
2020-03-03 20:53:01 +01:00
class SpfDocument(PDFDocument):
def generate(self, accounting_year):
""" Genère un document aux normes du SPF Finance.
2020-03-03 20:53:01 +01:00
Args:
accounting_year (int): année comptable.
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
"""
self.add_header()
self.add_title(accounting_year)
self.add_recette_expenses(accounting_year)
self.add_annexes(accounting_year)
2020-03-03 20:53:01 +01:00
def add_title(self, accounting_year):
2020-02-29 14:18:43 +01:00
""" Ajoute un titre au document.
Args:
accounting_year (int): année comptable.
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
2020-02-29 14:18:43 +01:00
"""
self.add_string(
130,
"Comptes simplifiés de l'exercice " + accounting_year,
font_decoration="Bold",
font_size=20,
)
self.add_vspace(DOUBLE_LINE_HEIGHT)
2020-03-03 20:53:01 +01:00
def add_recette_expenses(self, accounting_year):
""" Ajoute l'état des recettes et dépense pour une année comptable passée en paramètre.
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
self.add_string(
X, "Etat recettes/dépenses (en €)", font_decoration="Oblique", font_size=14
)
2020-03-03 20:53:01 +01:00
self.__display_transactiontypes_table(accounting_year)
self.add_vspace()
2020-03-03 20:53:01 +01:00
def add_annexes(self, accounting_year):
""" Ajoute les annexes au document PDF
2020-03-03 20:53:01 +01:00
Args:
accounting_year (int): année comptable.
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
"""
self.add_new_line(X, "Annexes", font_decoration="Oblique", font_size=14)
self.add_evaluation_rules(accounting_year)
self.add_modification_evaluation_rules(accounting_year)
self.add_additional_information(accounting_year)
self.add_patrimony(accounting_year)
self.add_right_engagement(accounting_year)
def add_evaluation_rules(self, accounting_year):
""" Ajoute les règles d'évaluation au PDF
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
Returns:
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
self.add_new_line(X, "1. Résumé des règles 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)
if rules_list:
for rule in rules_list:
self.add_new_line(
INDENTED_X + INDENT * 2,
rule.label + " : " + rule.explanation,
font_size=9,
)
else:
self.add_new_line(
INDENTED_X + INDENT * 2, "Pas de règle d'évaluation.", font_size=9
)
self.add_vspace()
2020-03-03 20:53:01 +01:00
def add_modification_evaluation_rules(self, accounting_year):
""" Ajoute les modifications d'évaluation au PDF
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
Returns:
2020-03-03 20:53:01 +01:00
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
self.add_new_line(X, "2. Adaptation des règles d'évaluation")
rules_adaptation_list = EvaluationRulesAdaptation.objects.filter(
start_date__year=accounting_year
)
2020-03-03 20:53:01 +01:00
if rules_adaptation_list:
for line in rules_adaptation_list:
self.add_new_line(
INDENTED_X + INDENT * 2,
line.label + " : " + line.information,
font_size=9,
)
else:
self.add_new_line(
INDENTED_X + INDENT * 2,
"Pas d'adaptation des règles d'évaluation.",
font_size=9,
)
self.add_vspace()
2020-03-03 20:53:01 +01:00
def add_additional_information(self, accounting_year):
""" Ajoute les informations complémentaires au PDF
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
Returns:
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
self.add_new_line(X, "3. Informations complémentaires")
annuality = Annuality.objects.filter(year__year=accounting_year)
complementary_informations = ComplementaryInformations.objects.filter(
annuality=annuality[0]
)
if complementary_informations:
for line in complementary_informations:
self.add_new_line(
INDENTED_X + INDENT * 2,
line.label + " : " + line.information,
font_size=9,
)
else:
self.add_new_line(
INDENTED_X + INDENT * 2,
"Pas d'informations complémentaires.",
font_size=9,
)
self.add_vspace()
2020-03-03 20:53:01 +01:00
def add_patrimony(self, accounting_year):
""" Ajoute les informations du patrimoine au PDF
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
Returns:
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
self.add_new_line(X, "4. Etat du patrimoine")
annuality = Annuality.objects.filter(year__year=accounting_year)
tmp_compta_expenses = get_transactiontype_and_sum_for_spf_export(
accounting_year, EXPENSES
2020-02-29 14:21:56 +01:00
)
2020-03-03 20:53:01 +01:00
tmp_compta_recettes = get_transactiontype_and_sum_for_spf_export(
accounting_year, RECETTES
2020-02-29 14:21:56 +01:00
)
2020-03-03 20:53:01 +01:00
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
+ tmp_compta_recettes["sum_total_transaction"]
- tmp_compta_expenses["sum_total_transaction"]
)
2020-03-03 20:53:01 +01:00
liability_list = get_asset_liability_and_sump_spf(accounting_year, category=1)
2020-03-03 20:53:01 +01:00
self.__display_table_header("AVOIRS", "DETTES")
save = self.y
self.__display_table_two_column(1, assets_list)
longest_y = self.y
self.y = save
self.__display_table_two_column(2, liability_list)
if self.y > longest_y:
self.y = longest_y
self.add_vspace()
def add_right_engagement(self, accounting_year):
""" Ajoute les droits & engagements au PDF
2020-02-29 14:18:43 +01:00
Args:
2020-03-03 20:53:01 +01:00
accounting_year (int): année comptable.
Returns:
ne retourne rien
2020-02-29 14:18:43 +01:00
"""
2020-03-03 20:53:01 +01:00
self.add_new_line(
X,
"5. Droits et engagements importants qui ne sont pas susceptibles d'être quantifiés",
)
# self.__display_table_header("DROITS", "ENGAGEMENT")
self.add_new_line(
INDENTED_X + INDENT * 2, "Pas de droits ou d'engagements.", font_size=9
)
self.add_vspace()
def __display_transactiontypes_table(self, accounting_year):
""" Ajoute le table pour les recettes & dépenses d'une année comptable.
Args:
accounting_year (int): année comptable
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
"""
2020-03-03 20:53:01 +01:00
expenses = get_transactiontype_and_sum_for_spf_export(accounting_year, EXPENSES)
2020-02-29 14:21:56 +01:00
recettes = get_transactiontype_and_sum_for_spf_export(accounting_year, RECETTES)
self.__display_table_header("DEPENSES", "RECETTES")
self.__display_transactiontype_table_body(
2020-03-03 20:53:01 +01:00
expenses,
recettes,
2020-03-03 20:53:01 +01:00
int(expenses["sum_total_transaction"]),
int(recettes["sum_total_transaction"]),
2020-02-29 14:21:56 +01:00
)
def __display_table_header(self, title_left, title_right):
self.add_vspace()
self.document.rect(X, self.y - 5, RIGHT_X - X, -COMMON_LINE_HEIGHT, fill=0)
self.add_string(INDENTED_X, title_left, font_decoration="Bold", font_size=9)
self.add_string(
MIDDLE + INDENTED_X, title_right, font_decoration="Bold", font_size=9
)
def __display_transactiontype_table_body(
2020-03-03 20:53:01 +01:00
self, expenses, recettes, totalexpenses, totalrecettes
):
for i in range(4):
self.__display_table_line(
2020-03-03 20:53:01 +01:00
expenses["transaction_type_info"][i]["label"],
int(expenses["transaction_type_info"][i]["sum_total_amount"]),
recettes["transaction_type_info"][i]["label"],
int(recettes["transaction_type_info"][i]["sum_total_amount"]),
)
self.add_vspace()
self.document.rect(
X, self.y - 5, MIDDLE, 5 * -COMMON_LINE_HEIGHT
) # Séparation en deux
self.document.rect(
MIDDLE, self.y - 5, MIDDLE, 5 * -COMMON_LINE_HEIGHT
) # Séparation descriptif et montant recettes
self.y -= COMMON_LINE_HEIGHT
2020-02-29 14:21:56 +01:00
self.__display_table_line(
"Total des dépenses",
totalexpenses,
"Total des recettes",
totalrecettes,
font_decoration="Bold",
)
def __display_key_part(self, column_number, key, font_decoration=None):
2020-02-27 13:58:08 +01:00
""" Ajoute dans la colonne d'un tableau (à deux colonnes) la clef d'un couple clef/valeur.
Args:
column_number (int): numéro de la colonne du tableau
key (str): la clef à afficher
font_decoration (str): décoration de la police de carectères
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
2020-02-27 13:58:08 +01:00
"""
if column_number == 1:
space = INDENTED_X
else:
space = MIDDLE + INDENTED_X
2020-02-29 14:21:56 +01:00
self.add_string(space, key, font_decoration=font_decoration, font_size=9)
def __display_value_part(self, column_number, value):
2020-02-27 13:58:08 +01:00
""" Ajoute dans la colonne d'un tableau (à deux colonnes) la valeur d'un couple clef/valeur
Args:
column_number (int): numéro de la colonne du tableau
value (str): la valeur à afficher
2020-03-03 20:53:01 +01:00
Returns:
ne retourne rien.
2020-02-27 13:58:08 +01:00
"""
if column_number == 1:
space = MIDDLE + X - INDENT
else:
space = INDENTED_RIGHT_X
self.document.drawRightString(
2020-02-29 14:21:56 +01:00
space, self.y, str(locale.format("%d", int(value), grouping=True)),
)
def __display_column(self, column_number, key, value, font_decoration):
self.__display_key_part(column_number, key, font_decoration)
self.__display_value_part(column_number, value)
def __display_table_line(self, key1, value1, key2, value2, font_decoration=None):
self.document.rect(X, self.y - 5, RIGHT_X - X, COMMON_LINE_HEIGHT, fill=0)
self.add_vspace()
self.__display_column(1, key1, value1, font_decoration)
self.__display_column(2, key2, value2, font_decoration)
2020-03-03 20:53:01 +01:00
def __display_table_two_column(self, column_number, list):
if column_number == 1:
begin_rect_line = X
begin_rect_res = MIDDLE
begin_text = INDENTED_X
begin_res = MIDDLE + X - INDENT
else:
begin_rect_line = MIDDLE + X
begin_rect_res = MIDDLE * 2
begin_text = MIDDLE + INDENTED_X
begin_res = INDENTED_RIGHT_X
2020-03-03 20:53:01 +01:00
total = 0
2022-08-14 11:28:49 +02:00
# locale.setlocale(locale.LC_ALL, "pt_br.utf-8")
2020-03-03 20:53:01 +01:00
for line in list:
self.document.rect(
begin_rect_line, self.y - 5, MIDDLE, COMMON_LINE_HEIGHT, fill=0
)
self.document.rect(
begin_rect_res, self.y - 5, X, COMMON_LINE_HEIGHT, fill=0
)
self.add_new_line(begin_text, line[0], font_size=9)
self.document.drawRightString(
begin_res, self.y, str(locale.format("%d", int(line[1]), grouping=True))
)
total += int(line[1])
return total
2020-03-03 20:53:01 +01:00
class BillPaper(PDFDocument):
def generate(self, contract):
""" Génère une facture pour un contrat
Args:
2020-03-03 20:53:01 +01:00
contract (contract): instance de la class Contract.
Returns:
2020-03-03 20:53:01 +01:00
ne retourne rien
"""
2020-03-03 20:53:01 +01:00
self.amount = 0
2022-09-19 14:33:29 +02:00
self.styles = getSampleStyleSheet()
self.style = self.styles["BodyText"]
2020-03-03 20:53:01 +01:00
self.add_header(contract)
2022-09-20 08:59:59 +02:00
self.add_bill_title(contract)
2020-03-03 20:53:01 +01:00
self.add_prestations(contract)
self.add_conclusion(contract)
self.add_signature()
2022-09-20 08:59:59 +02:00
self.add_terms_of_sales()
2022-09-20 08:59:59 +02:00
def add_bill_title(self, contract):
2022-09-19 14:33:29 +02:00
""" Génère le titre de la facture.
Args:
2020-03-03 20:53:01 +01:00
contract (contract): instance de la class Contract.
Returns:
2020-03-03 20:53:01 +01:00
ne retourne rien
"""
2022-09-20 14:16:37 +02:00
self.y = 650
2022-09-20 08:59:59 +02:00
text = (("<b>" + contract.client.name + "</b>") if contract.client.is_company else "") + "<br />" + "A l'attention de <b>" + contract.client.contact + "</b><br />" + contract.client.address + "<br />" + str(contract.client.postal_code) + " " + contract.client.city + "<br /><br />Concernant la/le <b>" + contract.title + "</b>"
2020-03-03 20:53:01 +01:00
2022-09-19 14:33:29 +02:00
paragraph = Paragraph(text, self.style)
2022-09-20 11:59:43 +02:00
width, height = paragraph.wrap(10*cm, 10*cm)
2022-09-20 14:16:37 +02:00
paragraph.drawOn(self.document, TITLED_X, self.y)
self.add_vspace(BIG_LINE_HEIGHT)
2022-09-20 08:59:59 +02:00
def __add_section_title(self, title_text):
""" Ajout le titre d'une section """
text = "<b>" + title_text + "</b>"
paragraph = Paragraph(text, self.style)
2022-09-20 14:16:37 +02:00
width, height = paragraph.wrap(8*cm, 8*cm)
paragraph.drawOn(self.document, INDENTED_X, self.y)
2022-09-20 08:59:59 +02:00
self.add_vspace(-height)
2020-03-03 20:53:01 +01:00
def add_prestations(self, contract):
""" Génère l'affichage des prestations : tableau, liste des prestations, …
Args:
2020-03-03 20:53:01 +01:00
contract (contract): instance de la class Contract.
Returns:
2020-03-03 20:53:01 +01:00
ne retourne rien.
"""
2022-09-20 08:59:59 +02:00
self.__add_section_title("Prestations")
2022-09-19 12:59:53 +02:00
total = 0
elements = []
2022-09-19 12:59:53 +02:00
prestations_list = contract.get_prestation.all()
for prestation in prestations_list:
total += prestation.total_amount
2022-09-19 12:59:53 +02:00
data = [['Date', 'Libellé', 'Nbre', 'Prix Unit.', 'Total']]
for prestation in prestations_list:
data.append(
[
str(prestation.date),
prestation.label,
str(prestation.unit),
str(prestation.unit_price),
str(prestation.total_amount)
]
)
data.append([' ', ' ', ' ', 'Total', str(total)])
style = TableStyle(
[
('BACKGROUND', (0,0), (-1,0), '#317BB5'), # première ligne bleue
2022-09-20 11:59:43 +02:00
('TEXTCOLOR', (0,0), (-1,0), '#FFFFFF'),
2022-09-19 12:59:53 +02:00
('ALIGN', (2,0), (-1, 0), 'CENTER'),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('BACKGROUND', (0,-1), (-1,-1), '#317BB5'), # dernière ligne bleue
('ALIGN', (2,1), (-1, -1), 'RIGHT'),
('FONTNAME', (0,-1), (-1,-1), 'Helvetica-Bold'),
2022-09-20 11:59:43 +02:00
('TEXTCOLOR', (0,-1), (-1,-1), '#FFFFFF'),
2022-09-19 12:59:53 +02:00
]
)
table = Table(data, [2.6*cm, 8.2*cm, 2.6*cm, 2.6*cm, 2.6*cm])
table.setStyle(style)
2022-09-20 14:16:37 +02:00
width, height = table.wrapOn(self.document, 19*cm, 15*cm)
self.add_vspace(-(9 * height / 10))
2022-09-19 12:59:53 +02:00
table.drawOn(self.document, X, self.y)
2022-09-20 11:59:43 +02:00
self.add_vspace(-height / 3)
2022-09-20 11:59:43 +02:00
self.document.drawRightString(INDENTED_X + 442, self.y, "Acompte")
2022-09-19 12:59:53 +02:00
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(contract.advance))
self.add_vspace()
2020-03-03 20:53:01 +01:00
self.document.setFont("Helvetica-Bold", 10)
2022-09-20 11:59:43 +02:00
self.document.drawRightString(INDENTED_X + 442, self.y, "Solde à payer")
2022-09-19 12:59:53 +02:00
self.amount = total - contract.advance
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(self.amount))
2020-03-03 20:53:01 +01:00
def add_conclusion(self, contract):
""" Affiche la add_add_conclusion de la facture.
Args:
2020-03-03 20:53:01 +01:00
contract (contract): instance de la class Contract.
Returns:
2020-03-03 20:53:01 +01:00
ne retourne rien.
"""
2022-09-20 11:59:43 +02:00
self.add_vspace(HUGE_LINE_HEIGHT)
text = "Merci de bien vouloir payer la somme de "
self.add_new_line(INDENTED_X, text)
space = len(text)
self.add_string(INDENTED_X + (space * 4.55), str(self.amount), font_decoration="Bold")
space += len(str(self.amount) + " ")
self.add_string(INDENTED_X + (space * 4.55), "€ sur le compte ")
space += len("€ sur le compte")
2020-03-03 20:53:01 +01:00
self.add_string(
INDENTED_X + (space * 4.55), self.club_infos["IBAN"], font_decoration="Bold"
2020-03-03 20:53:01 +01:00
)
space += len(" " + self.club_infos["IBAN"] + " ")
2020-03-03 20:53:01 +01:00
self.add_string(
INDENTED_X + (space * 4.55),
2020-03-03 20:53:01 +01:00
" (" + self.club_infos["BIC"] + " - " + self.club_infos["BANK"] + ")",
)
self.add_vspace(COMMON_LINE_HEIGHT)
if not contract.is_paid:
the_date = datetime.now()
2022-09-20 08:59:59 +02:00
pay_date = the_date + timedelta(days=25)
2020-03-03 20:53:01 +01:00
self.add_string(INDENTED_X, "Pour le ")
space = len("Pour le ")
date = str(pay_date.day) + "/" + str(pay_date.month) + "/" + str(pay_date.year)
self.add_string(INDENTED_X + (space * 4.55), date, font_decoration="Bold")
space += len(date + " ")
self.add_string(INDENTED_X + (space * 4.55), " au plus tard, avec la référence :")
space += len("au plus tard, avec la référence:")
2020-03-03 20:53:01 +01:00
self.add_string(
INDENTED_X + (space * 4.55),
2020-03-03 20:53:01 +01:00
'"' + str(contract.reference) + '"',
font_decoration="Bold",
)
def add_signature(self):
""" Génère la signature. """
2022-09-20 11:59:43 +02:00
self.add_vspace(HUGE_LINE_HEIGHT)
2020-03-03 20:53:01 +01:00
self.document.drawString(
INDENTED_X,
self.y,
self.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")
self.add_vspace(DOUBLE_LINE_HEIGHT)
self.document.drawImage(url, INDENTED_X + 340, self.y, width=180, height=39)
2022-09-20 08:59:59 +02:00
def add_terms_of_sales(self):
2022-09-16 15:23:09 +02:00
""" Ajoute les conditions générales de payement au bas de la facture """
self.y = 125
2022-09-20 08:59:59 +02:00
self.__add_section_title("Conditions générales de paiement")
2022-09-16 15:18:18 +02:00
lines = [
"Facture payable au comptant.",
"En cas de défaut de paiement à l'échéance, il est dû de plein droit et sans mise en demeure, un interêt fixé au taux de 15% l'an.",
"Tout réclamation, pour être admise, doit être faite dans les huit jours de la réception de la facture.",
2022-09-19 14:33:29 +02:00
"En cas de litige concernant la présente facture, seuls les tribunaux de Mons seront compétents."
2022-09-16 15:18:18 +02:00
]
text_object = self.document.beginText()
text_object.setTextOrigin(INDENTED_X, self.y)
text_object.setFont("Helvetica", 11)
for line in lines:
2022-09-19 14:33:29 +02:00
wraped_text = "\n".join(wrap(line, 108))
2022-09-16 15:18:18 +02:00
text_object.textLines(wraped_text)
self.document.drawText(text_object)