commit 8bc69e9b1541cc439b655d9e9c59e95cd9f9c5f4 Author: Julien Palard Date: Sun Apr 2 23:32:30 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d53c66e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.venv/ +dist/ +build/ +__pycache__/ +.envrc diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..21b2929 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include quittance/templates/quittance.html +include quittance/templates/quittance.css +include quittance/templates/*.ttf +include quittance/templates/*.otf diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3bb8d4 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Quittance + +Génère des quittances de loyers, au format PDF. + + +## Installation + + pip install quittance + + +## Configuration + +Il faut d’abord configurer quelques informations (addresses, noms…), +le plus simple est d’exécuter : + + quittance config + +qui vous génèrera un fichier de configuration et vous proposera de +l’éditer. + +Il est possible d’éditer la configuration en ligne de commande : + + quittance config --bailleur-city Lyon --bailleur-country France + +C’est pratique pour de petites corrections, mais pour tout configurer +préférez éditer le fichier `toml`. + + +## Utilisation + +Pour générer une nouvelle quittance, exécutez : + + quittance + +Une nouvelle quittance sera générée au format PDF. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..582a1b3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,36 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "quittance" +description = "Génère des quittances de loyers." +readme = "README.md" +license = {text = "MIT License"} +authors = [ + {name = "Julien Palard", email = "julien@palard.fr"}, +] +requires-python = ">= 3.7" +dependencies = [ + "weasyprint", + "tomlkit", + "jinja2", +] +dynamic = ["version"] + +[project.urls] +homepage = "https://git.afpy.org/mdk/quittance" + +[project.scripts] +quittance = "quittance.__main__:main" + +[tool.setuptools] +include-package-data = true + +[tool.setuptools.packages] +find = {} + +[tool.setuptools.dynamic.version] +attr = "quittance.__version__" + +[tool.black] \ No newline at end of file diff --git a/quittance/__init__.py b/quittance/__init__.py new file mode 100644 index 0000000..a4e2017 --- /dev/null +++ b/quittance/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1" diff --git a/quittance/__main__.py b/quittance/__main__.py new file mode 100644 index 0000000..fab697c --- /dev/null +++ b/quittance/__main__.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +from pathlib import Path +from datetime import date, timedelta +import sys +import json +import locale +from argparse import ArgumentParser + +from weasyprint import HTML +from jinja2 import Environment, PackageLoader, select_autoescape +import tomlkit as toml + + +def parse_args(): + parser = ArgumentParser(description="Génère une quittance de loyer") + subparsers = parser.add_subparsers(required=False) + + parser_conf = subparsers.add_parser( + "config", + help="Quittance configuration. Run without argument to see the current configuration.", + ) + parser_conf.add_argument("--bailleur-name", metavar="'Ano Nymous'") + parser_conf.add_argument("--bailleur-address", metavar="'10 route de la corniche'") + parser_conf.add_argument("--bailleur-code-postal", metavar="69000") + parser_conf.add_argument("--bailleur-city", metavar="'Lyon'") + parser_conf.add_argument("--bailleur-country", metavar="'France'") + parser_conf.add_argument("--locataire-name", metavar="'Ano Nymous'") + parser_conf.add_argument("--locataire-address", metavar="'10 route de la corniche'") + parser_conf.add_argument("--locataire-code-postal", metavar="'69000'") + parser_conf.add_argument("--locataire-city", metavar="'Lyon'") + parser_conf.add_argument("--locataire-country", metavar="'France'") + parser_conf.add_argument("--dernier-numero", type=int, metavar="123") + parser_conf.add_argument("--loyer-hors-charges", type=int, metavar="123") + parser_conf.add_argument("--charges", type=int, metavar="123") + parser_conf.set_defaults(func=main_config) + + parser.set_defaults(func=main_new) + + return parser.parse_args() + + +def main(): + args = parse_args() + func = args.func + del args.func + return func(args) + + +def load_config(): + try: + with open(Path.home() / ".config" / "quittance.toml", "r") as f: + config = toml.load(f) + except FileNotFoundError: + config = {} + return config + + +def save_config(config): + with open(Path.home() / ".config" / "quittance.toml", "w") as f: + toml.dump(config, f) + + +def main_config(args): + keys = set(vars(args).keys()) + args = {key: value for key, value in vars(args).items() if value is not None} + config = load_config() + config.update(args) + if "dernier_numero" not in config: + config["dernier_numero"] = 0 + for missing_key in sorted(keys - set(config)): + config[missing_key] = "" + save_config(config) + print( + f"You can edit the configuration file: {Path.home() / '.config' / 'quittance.toml'}" + ) + print(toml.dumps(config)) + + +def get_prev_month(): + today = date.today() + first_of_month = today.replace(day=1) + last_day_of_last_month = first_of_month - timedelta(days=1) + first_day_of_last_month = last_day_of_last_month.replace(day=1) + return f"du {first_day_of_last_month:%A %d %B %Y} au {last_day_of_last_month:%A %d %B %Y}" + + +def main_new(args): + locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8") + env = Environment(loader=PackageLoader("quittance"), autoescape=select_autoescape()) + template = env.get_template("quittance.html") + config = load_config() + + env = config.copy() + + env["date"] = date.today().strftime("%A %d %B %Y") + env["periode"] = get_prev_month() + + config["dernier_numero"] += 1 + env["quittance_no"] = config["dernier_numero"] + save_config(config) + + output = f"{date.today():%Y-%m-%d} quittance-{env['quittance_no']}.pdf" + HTML( + string=template.render(**env), base_url=str(Path(template.filename).parent) + ).write_pdf(output) + print("Nouvelle quittance :", output) + + +if __name__ == "__main__": + main() diff --git a/quittance/templates/pacifico.ttf b/quittance/templates/pacifico.ttf new file mode 100644 index 0000000..122e451 Binary files /dev/null and b/quittance/templates/pacifico.ttf differ diff --git a/quittance/templates/quittance.css b/quittance/templates/quittance.css new file mode 100644 index 0000000..575f872 --- /dev/null +++ b/quittance/templates/quittance.css @@ -0,0 +1,82 @@ +@font-face { + font-family: Pacifico; + src: url(pacifico.ttf); +} +@font-face { + font-family: Source Sans Pro; + font-weight: 400; + src: url(sourcesanspro-regular.otf); +} +@font-face { + font-family: Source Sans Pro; + font-weight: 700; + src: url(sourcesanspro-bold.otf); +} + +@page { + font-family: Pacifico; + margin: 3cm; +} + +html { + color: #14213d; + font-family: Source Sans Pro; + font-size: 11pt; + line-height: 1.6; +} +body { + margin: 0; +} + +h1 { + color: #1ee494; + font-family: Pacifico; + font-size: 40pt; + margin: 0; +} + +aside { + display: flex; + margin: 2em 0 4em; +} +aside address { + font-style: normal; + white-space: pre-line; +} +aside address#from { + color: #a9a; + flex: 1; +} +aside address#to { + text-align: right; +} + +dl#informations { + position: absolute; + right: 0; + text-align: right; + top: 0; +} + +dt, dd { + display: inline; + margin: 0; +} +dt { + color: #a9a; +} +dt::before { + content: ''; + display: block; +} +dt::after { + content: ' : '; +} + +b#recu { + font-size: 16pt; +} + +p#legal { + font-size: 8pt; +} diff --git a/quittance/templates/quittance.html b/quittance/templates/quittance.html new file mode 100644 index 0000000..0bc3a1d --- /dev/null +++ b/quittance/templates/quittance.html @@ -0,0 +1,71 @@ + + + + + Quittance de loyer + + + + +

Quittance de loyer

+ + + +
+
Quittance №
+
{{ quittance_no }}
+
+ +
+
Reçu de
+
{{ locataire_name }}
+
La somme de
+
{{ loyer_hors_charges + charges }} €
+
Au titre du paiement du loyer et des charges du logement sis
+
{{ locataire_address }} {{locataire_city }}
+
Pour la période de location
+
{{ periode }}
+
Date du règlement
+
{{ date }}
+
+ +
+

Détail de la quittance de loyer

+ +
+
Loyer hors charge
{{ loyer_hors_charges}} €
+
Charges / Provisions de charges
{{ charges }} €
+
Régularisation annuelle
ø
+
Total
{{ loyer_hors_charges + charges}} €
+
+
+
+
Fait à
+
{{ bailleur_city }}
+
Le
+
{{ date }}
+
Signature du bailleur
+
{{ bailleur_name }}
+
+ + + + diff --git a/quittance/templates/sourcesanspro-bold.otf b/quittance/templates/sourcesanspro-bold.otf new file mode 100644 index 0000000..98dbee7 Binary files /dev/null and b/quittance/templates/sourcesanspro-bold.otf differ diff --git a/quittance/templates/sourcesanspro-regular.otf b/quittance/templates/sourcesanspro-regular.otf new file mode 100644 index 0000000..bdcfb27 Binary files /dev/null and b/quittance/templates/sourcesanspro-regular.otf differ