From 50b21d62ab9fd05457427a9361bab7a860432628 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 16:11:00 +0200 Subject: [PATCH 001/507] Move system files to branch pkgbuild --- PKGBUILD | 28 ---------------------------- nummi.service | 19 ------------------- nummi.socket | 9 --------- nummi.sysusers | 1 - nummi.tmpfiles | 1 - 5 files changed, 58 deletions(-) delete mode 100644 PKGBUILD delete mode 100644 nummi.service delete mode 100644 nummi.socket delete mode 100644 nummi.sysusers delete mode 100644 nummi.tmpfiles diff --git a/PKGBUILD b/PKGBUILD deleted file mode 100644 index 59e6837..0000000 --- a/PKGBUILD +++ /dev/null @@ -1,28 +0,0 @@ -pkgname=nummi -pkgver=0.1.0 -pkgrel=4 -pkgdesc="Web-based accounting interface" -arch=("any") -url="https://git.edgarpierre.fr/edpibu/nummi" -license=("AGPL3") -depends=( - "gunicorn" - "python-django" -) -optdepends=("postgresql: database") - -source=( - "${pkgname}::git+ssh://gitea@git.edgarpierre.fr:39529/edpibu/nummi.git" - "${pkgname}.service" - "${pkgname}.socket" - "${pkgname}.tmpfiles" - "${pkgname}.sysusers" -) - -package() { - install -Dm755 ${pkgname}/${pkgname} -t "${pkgdir}"/opt/ - install -Dm644 ${pkgname}.service -t "${pkgdir}"/usr/lib/systemd/system/ - install -Dm644 ${pkgname}.socket -t "${pkgdir}"/usr/lib/systemd/system/ - install -Dm644 ${pkgname}.tmpfiles "${pkgdir}"/usr/lib/tmpfiles.d/${pkgname}.conf - install -Dm644 ${pkgname}.sysusers "${pkgdir}"/usr/lib/sysusers.d/${pkgname}.conf -} diff --git a/nummi.service b/nummi.service deleted file mode 100644 index 1fc3c33..0000000 --- a/nummi.service +++ /dev/null @@ -1,19 +0,0 @@ -[Unit] -Description=Nummi server (accounting) -Requires=nummi.socket -After=network.target - -[Service] -Type=notify -User=nummi -Group=nummi -RuntimeDirectory=nummi -WorkingDirectory=/opt/nummi -ExecStart=/usr/bin/gunicorn nummi.asgi:application -ExecReload=/bin/kill -s HUP $MAINPID -KillMode=mixed -TimeoutStopSec=5 -PrivateTmp=true - -[Install] -WantedBy=multi-user.target diff --git a/nummi.socket b/nummi.socket deleted file mode 100644 index 23000f1..0000000 --- a/nummi.socket +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Nummi socket - -[Socket] -ListenStream=/run/nummi.socket -SocketUser=http - -[Install] -WantedBy=sockets.target diff --git a/nummi.sysusers b/nummi.sysusers deleted file mode 100644 index 208e626..0000000 --- a/nummi.sysusers +++ /dev/null @@ -1 +0,0 @@ -u nummi - "Nummi daemon user" /var/lib/nummi /usr/bin/bash diff --git a/nummi.tmpfiles b/nummi.tmpfiles deleted file mode 100644 index ef1e6bf..0000000 --- a/nummi.tmpfiles +++ /dev/null @@ -1 +0,0 @@ -d /var/lib/nummi 0750 nummi nummi From 568c607231cf36b0a9c0c9b911f74eeeae0019d1 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 16:12:39 +0200 Subject: [PATCH 002/507] Set to PROD settings --- nummi/nummi/settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 6262187..111c8f3 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -21,12 +21,12 @@ MEDIA_ROOT = Path("/var/lib/nummi") # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-y+p9uil_br-97e11gtmww8te@7%b^t06-r6pszmk82zj=4z$2f" +SECRET_KEY = "h/0OOuNSBRJy9Suo172Y5sJYGgmDqanh" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["nummi.edgarpierre.fr"] # Application definition From 0eeb3450033eb3844c7bbf22a88634a4f3bb9ad7 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 17:53:44 +0200 Subject: [PATCH 003/507] Add STATIC_ROOT --- nummi/nummi/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 111c8f3..0e74b95 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -119,6 +119,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/4.0/howto/static-files/ STATIC_URL = "static/" +STATIC_ROOT = "/srv/nummi" LOGIN_URL = "login" # Default primary key field type From ad537e737b389b3c77ff2ad12d9e6984e6fac2af Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 18:09:11 +0200 Subject: [PATCH 004/507] Fix CSRF trust --- nummi/nummi/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 0e74b95..06495c5 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -27,6 +27,7 @@ SECRET_KEY = "h/0OOuNSBRJy9Suo172Y5sJYGgmDqanh" DEBUG = False ALLOWED_HOSTS = ["nummi.edgarpierre.fr"] +CSRF_TRUSTED_ORIGINS = ["https://nummi.edgarpierre.fr"] # Application definition From 1300132d6914d7c9c618158c55954c262d97e2b2 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 18:45:53 +0200 Subject: [PATCH 005/507] Add environment config --- nummi/nummi/settings.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 06495c5..e5ecaab 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -11,23 +11,24 @@ https://docs.djangoproject.com/en/4.0/ref/settings/ """ from pathlib import Path +import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -MEDIA_ROOT = Path("/var/lib/nummi") +MEDIA_ROOT = Path(os.environ.get("NUMMI_MEDIA_ROOT", "/var/lib/nummi")) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "h/0OOuNSBRJy9Suo172Y5sJYGgmDqanh" +SECRET_KEY = os.environ.get("NUMMI_SECRET", "dev_sDo6gl1Yf8GIE7XEA2B4xF841eMOpfG1") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = os.environ.get("NUMMI_DEBUG", None) == "True" -ALLOWED_HOSTS = ["nummi.edgarpierre.fr"] -CSRF_TRUSTED_ORIGINS = ["https://nummi.edgarpierre.fr"] +ALLOWED_HOSTS = [os.environ.get("NUMMI_HOST", "localhost")] +CSRF_TRUSTED_ORIGINS = [f"https://{os.environ.get('NUMMI_HOST', 'localhost')}"] # Application definition From ccc7ef14991d26f040f1e8a632816ffecf402aa2 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 18:51:04 +0200 Subject: [PATCH 006/507] Fix heading centering on index --- nummi/main/templates/main/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index c8e8785..7c214b8 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -12,11 +12,11 @@ {% if transactions %}
- Date + Date Nom - Valeur - Commerçant - Catégorie + Valeur + Commerçant + Catégorie Description
{% for trans in transactions %} From 97f4c701160dcd1b4d789ed89e8f471a572396a8 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:01:33 +0200 Subject: [PATCH 007/507] Fix heading alignment for value --- nummi/main/static/css/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/static/css/index.css b/nummi/main/static/css/index.css index 4d1cfd5..ca11863 100644 --- a/nummi/main/static/css/index.css +++ b/nummi/main/static/css/index.css @@ -35,7 +35,7 @@ h1 { #transactions > div > .center { text-align: center; } -#transactions > div > .value { +#transactions > div > span.value { text-align: right; } #transactions > div > .num { From 83203d4e20d489d99e169a3973f29ba8cbffd2e8 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:03:32 +0200 Subject: [PATCH 008/507] Move static for main app to main folder --- nummi/main/static/{ => main}/css/form.css | 0 nummi/main/static/{ => main}/css/index.css | 0 nummi/main/static/{ => main}/css/main.css | 0 nummi/main/static/{ => main}/css/nav.css | 0 .../main/static/{ => main}/fontawesome/LICENSE.txt | 0 .../main/static/{ => main}/fontawesome/css/all.css | 0 .../static/{ => main}/fontawesome/css/all.min.css | 0 .../static/{ => main}/fontawesome/css/brands.css | 0 .../{ => main}/fontawesome/css/brands.min.css | 0 .../{ => main}/fontawesome/css/fontawesome.css | 0 .../{ => main}/fontawesome/css/fontawesome.min.css | 0 .../static/{ => main}/fontawesome/css/regular.css | 0 .../{ => main}/fontawesome/css/regular.min.css | 0 .../static/{ => main}/fontawesome/css/solid.css | 0 .../static/{ => main}/fontawesome/css/solid.min.css | 0 .../{ => main}/fontawesome/css/svg-with-js.css | 0 .../{ => main}/fontawesome/css/svg-with-js.min.css | 0 .../{ => main}/fontawesome/css/v4-font-face.css | 0 .../{ => main}/fontawesome/css/v4-font-face.min.css | 0 .../static/{ => main}/fontawesome/css/v4-shims.css | 0 .../{ => main}/fontawesome/css/v4-shims.min.css | 0 .../{ => main}/fontawesome/css/v5-font-face.css | 0 .../{ => main}/fontawesome/css/v5-font-face.min.css | 0 .../fontawesome/webfonts/fa-brands-400.ttf | Bin .../fontawesome/webfonts/fa-brands-400.woff2 | Bin .../fontawesome/webfonts/fa-regular-400.ttf | Bin .../fontawesome/webfonts/fa-regular-400.woff2 | Bin .../fontawesome/webfonts/fa-solid-900.ttf | Bin .../fontawesome/webfonts/fa-solid-900.woff2 | Bin .../fontawesome/webfonts/fa-v4compatibility.ttf | Bin .../fontawesome/webfonts/fa-v4compatibility.woff2 | Bin nummi/main/templates/main/base.html | 6 +++--- nummi/main/templates/main/category.html | 2 +- nummi/main/templates/main/index.html | 2 +- nummi/main/templates/main/login.html | 2 +- nummi/main/templates/main/transaction.html | 2 +- 36 files changed, 7 insertions(+), 7 deletions(-) rename nummi/main/static/{ => main}/css/form.css (100%) rename nummi/main/static/{ => main}/css/index.css (100%) rename nummi/main/static/{ => main}/css/main.css (100%) rename nummi/main/static/{ => main}/css/nav.css (100%) rename nummi/main/static/{ => main}/fontawesome/LICENSE.txt (100%) rename nummi/main/static/{ => main}/fontawesome/css/all.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/all.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/brands.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/brands.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/fontawesome.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/fontawesome.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/regular.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/regular.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/solid.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/solid.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/svg-with-js.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/svg-with-js.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v4-font-face.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v4-font-face.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v4-shims.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v4-shims.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v5-font-face.css (100%) rename nummi/main/static/{ => main}/fontawesome/css/v5-font-face.min.css (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-brands-400.ttf (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-brands-400.woff2 (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-regular-400.ttf (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-regular-400.woff2 (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-solid-900.ttf (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-solid-900.woff2 (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-v4compatibility.ttf (100%) rename nummi/main/static/{ => main}/fontawesome/webfonts/fa-v4compatibility.woff2 (100%) diff --git a/nummi/main/static/css/form.css b/nummi/main/static/main/css/form.css similarity index 100% rename from nummi/main/static/css/form.css rename to nummi/main/static/main/css/form.css diff --git a/nummi/main/static/css/index.css b/nummi/main/static/main/css/index.css similarity index 100% rename from nummi/main/static/css/index.css rename to nummi/main/static/main/css/index.css diff --git a/nummi/main/static/css/main.css b/nummi/main/static/main/css/main.css similarity index 100% rename from nummi/main/static/css/main.css rename to nummi/main/static/main/css/main.css diff --git a/nummi/main/static/css/nav.css b/nummi/main/static/main/css/nav.css similarity index 100% rename from nummi/main/static/css/nav.css rename to nummi/main/static/main/css/nav.css diff --git a/nummi/main/static/fontawesome/LICENSE.txt b/nummi/main/static/main/fontawesome/LICENSE.txt similarity index 100% rename from nummi/main/static/fontawesome/LICENSE.txt rename to nummi/main/static/main/fontawesome/LICENSE.txt diff --git a/nummi/main/static/fontawesome/css/all.css b/nummi/main/static/main/fontawesome/css/all.css similarity index 100% rename from nummi/main/static/fontawesome/css/all.css rename to nummi/main/static/main/fontawesome/css/all.css diff --git a/nummi/main/static/fontawesome/css/all.min.css b/nummi/main/static/main/fontawesome/css/all.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/all.min.css rename to nummi/main/static/main/fontawesome/css/all.min.css diff --git a/nummi/main/static/fontawesome/css/brands.css b/nummi/main/static/main/fontawesome/css/brands.css similarity index 100% rename from nummi/main/static/fontawesome/css/brands.css rename to nummi/main/static/main/fontawesome/css/brands.css diff --git a/nummi/main/static/fontawesome/css/brands.min.css b/nummi/main/static/main/fontawesome/css/brands.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/brands.min.css rename to nummi/main/static/main/fontawesome/css/brands.min.css diff --git a/nummi/main/static/fontawesome/css/fontawesome.css b/nummi/main/static/main/fontawesome/css/fontawesome.css similarity index 100% rename from nummi/main/static/fontawesome/css/fontawesome.css rename to nummi/main/static/main/fontawesome/css/fontawesome.css diff --git a/nummi/main/static/fontawesome/css/fontawesome.min.css b/nummi/main/static/main/fontawesome/css/fontawesome.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/fontawesome.min.css rename to nummi/main/static/main/fontawesome/css/fontawesome.min.css diff --git a/nummi/main/static/fontawesome/css/regular.css b/nummi/main/static/main/fontawesome/css/regular.css similarity index 100% rename from nummi/main/static/fontawesome/css/regular.css rename to nummi/main/static/main/fontawesome/css/regular.css diff --git a/nummi/main/static/fontawesome/css/regular.min.css b/nummi/main/static/main/fontawesome/css/regular.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/regular.min.css rename to nummi/main/static/main/fontawesome/css/regular.min.css diff --git a/nummi/main/static/fontawesome/css/solid.css b/nummi/main/static/main/fontawesome/css/solid.css similarity index 100% rename from nummi/main/static/fontawesome/css/solid.css rename to nummi/main/static/main/fontawesome/css/solid.css diff --git a/nummi/main/static/fontawesome/css/solid.min.css b/nummi/main/static/main/fontawesome/css/solid.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/solid.min.css rename to nummi/main/static/main/fontawesome/css/solid.min.css diff --git a/nummi/main/static/fontawesome/css/svg-with-js.css b/nummi/main/static/main/fontawesome/css/svg-with-js.css similarity index 100% rename from nummi/main/static/fontawesome/css/svg-with-js.css rename to nummi/main/static/main/fontawesome/css/svg-with-js.css diff --git a/nummi/main/static/fontawesome/css/svg-with-js.min.css b/nummi/main/static/main/fontawesome/css/svg-with-js.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/svg-with-js.min.css rename to nummi/main/static/main/fontawesome/css/svg-with-js.min.css diff --git a/nummi/main/static/fontawesome/css/v4-font-face.css b/nummi/main/static/main/fontawesome/css/v4-font-face.css similarity index 100% rename from nummi/main/static/fontawesome/css/v4-font-face.css rename to nummi/main/static/main/fontawesome/css/v4-font-face.css diff --git a/nummi/main/static/fontawesome/css/v4-font-face.min.css b/nummi/main/static/main/fontawesome/css/v4-font-face.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/v4-font-face.min.css rename to nummi/main/static/main/fontawesome/css/v4-font-face.min.css diff --git a/nummi/main/static/fontawesome/css/v4-shims.css b/nummi/main/static/main/fontawesome/css/v4-shims.css similarity index 100% rename from nummi/main/static/fontawesome/css/v4-shims.css rename to nummi/main/static/main/fontawesome/css/v4-shims.css diff --git a/nummi/main/static/fontawesome/css/v4-shims.min.css b/nummi/main/static/main/fontawesome/css/v4-shims.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/v4-shims.min.css rename to nummi/main/static/main/fontawesome/css/v4-shims.min.css diff --git a/nummi/main/static/fontawesome/css/v5-font-face.css b/nummi/main/static/main/fontawesome/css/v5-font-face.css similarity index 100% rename from nummi/main/static/fontawesome/css/v5-font-face.css rename to nummi/main/static/main/fontawesome/css/v5-font-face.css diff --git a/nummi/main/static/fontawesome/css/v5-font-face.min.css b/nummi/main/static/main/fontawesome/css/v5-font-face.min.css similarity index 100% rename from nummi/main/static/fontawesome/css/v5-font-face.min.css rename to nummi/main/static/main/fontawesome/css/v5-font-face.min.css diff --git a/nummi/main/static/fontawesome/webfonts/fa-brands-400.ttf b/nummi/main/static/main/fontawesome/webfonts/fa-brands-400.ttf similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-brands-400.ttf rename to nummi/main/static/main/fontawesome/webfonts/fa-brands-400.ttf diff --git a/nummi/main/static/fontawesome/webfonts/fa-brands-400.woff2 b/nummi/main/static/main/fontawesome/webfonts/fa-brands-400.woff2 similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-brands-400.woff2 rename to nummi/main/static/main/fontawesome/webfonts/fa-brands-400.woff2 diff --git a/nummi/main/static/fontawesome/webfonts/fa-regular-400.ttf b/nummi/main/static/main/fontawesome/webfonts/fa-regular-400.ttf similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-regular-400.ttf rename to nummi/main/static/main/fontawesome/webfonts/fa-regular-400.ttf diff --git a/nummi/main/static/fontawesome/webfonts/fa-regular-400.woff2 b/nummi/main/static/main/fontawesome/webfonts/fa-regular-400.woff2 similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-regular-400.woff2 rename to nummi/main/static/main/fontawesome/webfonts/fa-regular-400.woff2 diff --git a/nummi/main/static/fontawesome/webfonts/fa-solid-900.ttf b/nummi/main/static/main/fontawesome/webfonts/fa-solid-900.ttf similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-solid-900.ttf rename to nummi/main/static/main/fontawesome/webfonts/fa-solid-900.ttf diff --git a/nummi/main/static/fontawesome/webfonts/fa-solid-900.woff2 b/nummi/main/static/main/fontawesome/webfonts/fa-solid-900.woff2 similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-solid-900.woff2 rename to nummi/main/static/main/fontawesome/webfonts/fa-solid-900.woff2 diff --git a/nummi/main/static/fontawesome/webfonts/fa-v4compatibility.ttf b/nummi/main/static/main/fontawesome/webfonts/fa-v4compatibility.ttf similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-v4compatibility.ttf rename to nummi/main/static/main/fontawesome/webfonts/fa-v4compatibility.ttf diff --git a/nummi/main/static/fontawesome/webfonts/fa-v4compatibility.woff2 b/nummi/main/static/main/fontawesome/webfonts/fa-v4compatibility.woff2 similarity index 100% rename from nummi/main/static/fontawesome/webfonts/fa-v4compatibility.woff2 rename to nummi/main/static/main/fontawesome/webfonts/fa-v4compatibility.woff2 diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index 3b060a6..c23f3e0 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -8,9 +8,9 @@ {% block title %}Nummi{% endblock %} {% block link %} - - - + + + {% endblock %} diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index 364590a..cbd6f59 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -3,7 +3,7 @@ {% block link %} {{ block.super }} - + {% endblock %} {% block body %} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 7c214b8..3bdcc60 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -3,7 +3,7 @@ {% block link %} {{ block.super }} - + {% endblock %} {% block body %} diff --git a/nummi/main/templates/main/login.html b/nummi/main/templates/main/login.html index 195c74b..16454cd 100644 --- a/nummi/main/templates/main/login.html +++ b/nummi/main/templates/main/login.html @@ -3,7 +3,7 @@ {% block link %} {{ block.super }} - + {% endblock %} {% block body %} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index 4ef3573..17b9a30 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -3,7 +3,7 @@ {% block link %} {{ block.super }} - + {% endblock %} {% block body %} From 27d69775187a280b9fc1c494879b605a8c97a8fa Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:09:09 +0200 Subject: [PATCH 009/507] Add README --- nummi/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 nummi/README.md diff --git a/nummi/README.md b/nummi/README.md new file mode 100644 index 0000000..afed63d --- /dev/null +++ b/nummi/README.md @@ -0,0 +1,9 @@ +# Nummi + +Nummi is a web-based accounting software. +Nummi uses Django. + +## Installation + +A PKGBUILD along with system files is provided on the +[pkgbuild](https://git.edgarpierre.fr/edpibu/nummi/src/branch/pkgbuild) branch. From a6afe9fef7411c945a26864a1f003bf23a6219a3 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:09:42 +0200 Subject: [PATCH 010/507] Move README to root --- nummi/README.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename nummi/README.md => README.md (100%) diff --git a/nummi/README.md b/README.md similarity index 100% rename from nummi/README.md rename to README.md From 8cd142741873bfe0879c0beb2bd36b8b46fa933a Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:11:11 +0200 Subject: [PATCH 011/507] Add LICENSE --- LICENSE | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. From ee494e0a9d64c07b7906825eec10a16da3c9adcf Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 19:17:44 +0200 Subject: [PATCH 012/507] Force + on transaction value --- nummi/main/templates/main/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 3bdcc60..876716e 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -23,7 +23,7 @@
{{ trans.date|date:"Y-m-d" }} {{ trans.name }} - {{ trans.value|floatformat:"2g" }} € + {% if trans.value > 0 %}+{% endif %}{{ trans.value|floatformat:"2g" }} € {{ trans.trader|default_if_none:"–" }} {% if trans.category %} From 52eade1159d7022b43c4639a2268838f97f3a187 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 20:23:41 +0200 Subject: [PATCH 013/507] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0308234..151121e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ env __pycache__ -/nummi/media From 29484e3c02bfeace44312176a918d9833c11a1cd Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sat, 21 May 2022 21:00:26 +0200 Subject: [PATCH 014/507] Add snapshots --- nummi/main/admin.py | 3 +- nummi/main/migrations/0009_snapshot.py | 44 +++++++++++++++++ .../0010_alter_snapshot_previous.py | 25 ++++++++++ nummi/main/models.py | 49 +++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 nummi/main/migrations/0009_snapshot.py create mode 100644 nummi/main/migrations/0010_alter_snapshot_previous.py diff --git a/nummi/main/admin.py b/nummi/main/admin.py index d8bde1e..ab84be8 100644 --- a/nummi/main/admin.py +++ b/nummi/main/admin.py @@ -1,7 +1,8 @@ from django.contrib import admin -from .models import Transaction, Invoice, Category +from .models import Transaction, Invoice, Category, Snapshot admin.site.register(Transaction) admin.site.register(Invoice) admin.site.register(Category) +admin.site.register(Snapshot) diff --git a/nummi/main/migrations/0009_snapshot.py b/nummi/main/migrations/0009_snapshot.py new file mode 100644 index 0000000..f572375 --- /dev/null +++ b/nummi/main/migrations/0009_snapshot.py @@ -0,0 +1,44 @@ +# Generated by Django 4.0.4 on 2022-05-21 18:40 + +import datetime +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0008_alter_category_options_category_icon"), + ] + + operations = [ + migrations.CreateModel( + name="Snapshot", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("date", models.DateField(default=datetime.date.today)), + ( + "value", + models.DecimalField(decimal_places=2, default=0, max_digits=12), + ), + ( + "previous", + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.snapshot", + ), + ), + ], + ), + ] diff --git a/nummi/main/migrations/0010_alter_snapshot_previous.py b/nummi/main/migrations/0010_alter_snapshot_previous.py new file mode 100644 index 0000000..53393fd --- /dev/null +++ b/nummi/main/migrations/0010_alter_snapshot_previous.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.4 on 2022-05-21 18:44 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0009_snapshot"), + ] + + operations = [ + migrations.AlterField( + model_name="snapshot", + name="previous", + field=models.OneToOneField( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.snapshot", + ), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 1a22b2d..0cb42e2 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -72,3 +72,52 @@ class InvoiceForm(ModelForm): class Meta: model = Invoice fields = ["name", "file"] + + +class Snapshot(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + date = models.DateField(default=date.today, unique=True) + value = models.DecimalField(max_digits=12, decimal_places=2, default=0) + previous = models.OneToOneField( + "self", on_delete=models.SET_NULL, blank=True, null=True, editable=False + ) + + def __str__(self): + if self.previous is None: + return f"Snapshot {self.date}: {self.value}€" + return f"Snapshot {self.date}: {self.value}€ (Previous: {self.previous.date})" + + def save(self, *args, only_super=False, **kwargs): + if not only_super: + _prev = ( + self.__class__.objects.order_by("-date") + .filter(date__lt=self.date) + .first() + ) + + try: + _next = self.__class__.objects.get(previous=_prev) + except self.__class__.DoesNotExist: + pass + else: + _next.previous = self + _next.save(only_super=True) + + self.previous = _prev + super().save(*args, **kwargs) + + def delete(self, *args, only_super=False, **kwargs): + if not only_super: + try: + _next = self.__class__.objects.get(previous=self) + except self.__class__.DoesNotExist: + pass + else: + _next.previous = self.previous + super().delete(*args, **kwargs) + _next.save(only_super=True) + else: + super().delete(*args, **kwargs) + + class Meta: + ordering = ["-date"] From a3797bb7fbbae8622b199c981c8ec5a4cec8df03 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 08:37:52 +0200 Subject: [PATCH 015/507] Add snapshot list --- nummi/main/static/main/css/index.css | 32 +++++++++++++++++----------- nummi/main/templates/main/index.html | 20 +++++++++++++++-- nummi/main/views.py | 5 ++++- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index ca11863..9a68717 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -6,47 +6,55 @@ h1 { margin: 0; } -#transactions { +.table { display: grid; - grid-template-columns: repeat(6, auto); margin: 2em 0; border-radius: 1em 0 1em 0; overflow: hidden; - border-bottom: .5em solid var(--text); + border-bottom: .5em solid var(--bg-inv); } +.table.col2 {grid-template-columns: repeat(2, auto)} +.table.col3 {grid-template-columns: repeat(3, auto)} +.table.col4 {grid-template-columns: repeat(4, auto)} +.table.col5 {grid-template-columns: repeat(5, auto)} +.table.col6 {grid-template-columns: repeat(6, auto)} -#transactions > div { +.table > div { display: contents; } -#transactions > div > * { +.table > div > * { padding: 1em; white-space: nowrap; } -#transactions > div.g> * { +.table > div.g> * { background: var(--bg-01); } -#transactions > div.header > * { +.table > div.header > * { background: var(--bg-inv); color: var(--text-inv); } -#transactions > div > .center { +.table > div > .center { text-align: center; } -#transactions > div > span.value { +.table > div > .right { text-align: right; } -#transactions > div > .num { +.table > div > .num { font-feature-settings: "tnum", "ss01"; } -#transactions > div > span.text { +.table > div > span.text { overflow: hidden; text-overflow: ellipsis; } #categories > a { - margin-right: 1em; + margin-right: var(--gap); +} + +#snapshots { + max-width: 24rem; } diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 876716e..daa7cef 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -10,7 +10,7 @@

Nummi

{% if transactions %} -
+
Date Nom @@ -23,7 +23,7 @@
{{ trans.date|date:"Y-m-d" }} {{ trans.name }} - {% if trans.value > 0 %}+{% endif %}{{ trans.value|floatformat:"2g" }} € + {% if trans.value > 0 %}+{% endif %}{{ trans.value|floatformat:"2g" }} € {{ trans.trader|default_if_none:"–" }} {% if trans.category %} @@ -41,6 +41,22 @@
{% endif %} +{% if snapshots %} +

Relevés

+
+
+ Date + Valeur +
+ {% for snap in snapshots %} +
+ {{ snap.date|date:"Y-m-d" }} + {{ snap.value }} € +
+ {% endfor %} +
+{% endif %} + {% if categories %}

Catégories

diff --git a/nummi/main/views.py b/nummi/main/views.py index 8afcc8c..f3805df 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -10,17 +10,20 @@ from .models import ( InvoiceForm, Category, CategoryForm, + Snapshot, ) @login_required def index(request): - _transactions = Transaction.objects.order_by("-date")[:5] + _transactions = Transaction.objects.all()[:5] _categories = Category.objects.all() + _snapshots = Snapshot.objects.all()[:5] context = { "transactions": _transactions, "categories": _categories, + "snapshots": _snapshots, } return render(request, "main/index.html", context) From 15a317dc0f0f6a09ecf5b137f46f41ca319c72ba Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 09:21:30 +0200 Subject: [PATCH 016/507] Snapshot table --- ...snapshot_options_snapshot_diff_and_more.py | 30 +++++++++++++++++++ nummi/main/models.py | 20 ++++++++++++- nummi/main/static/main/css/index.css | 4 --- nummi/main/static/main/css/main.css | 6 ++++ nummi/main/templates/main/index.html | 25 ++++++++++++++-- nummi/main/templatetags/__init__.py | 0 nummi/main/templatetags/main_extras.py | 10 +++++++ 7 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py create mode 100644 nummi/main/templatetags/__init__.py create mode 100644 nummi/main/templatetags/main_extras.py diff --git a/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py b/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py new file mode 100644 index 0000000..7a48363 --- /dev/null +++ b/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.0.4 on 2022-05-22 06:43 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0010_alter_snapshot_previous"), + ] + + operations = [ + migrations.AlterModelOptions( + name="snapshot", + options={"ordering": ["-date"]}, + ), + migrations.AddField( + model_name="snapshot", + name="diff", + field=models.DecimalField( + decimal_places=2, default=0, editable=False, max_digits=12 + ), + ), + migrations.AlterField( + model_name="snapshot", + name="date", + field=models.DateField(default=datetime.date.today, unique=True), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 0cb42e2..5f14876 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -81,6 +81,9 @@ class Snapshot(models.Model): previous = models.OneToOneField( "self", on_delete=models.SET_NULL, blank=True, null=True, editable=False ) + diff = models.DecimalField( + max_digits=12, decimal_places=2, default=0, editable=False + ) def __str__(self): if self.previous is None: @@ -94,9 +97,10 @@ class Snapshot(models.Model): .filter(date__lt=self.date) .first() ) + print(_prev) try: - _next = self.__class__.objects.get(previous=_prev) + _next = self.__class__.objects.exclude(id=self.id).get(previous=_prev) except self.__class__.DoesNotExist: pass else: @@ -104,6 +108,11 @@ class Snapshot(models.Model): _next.save(only_super=True) self.previous = _prev + + if self.previous is None: + self.diff = 0 + else: + self.diff = self.value - self.previous.value super().save(*args, **kwargs) def delete(self, *args, only_super=False, **kwargs): @@ -119,5 +128,14 @@ class Snapshot(models.Model): else: super().delete(*args, **kwargs) + @property + def sum(self): + if self.previous is None: + return None + trans = Transaction.objects.filter( + date__lt=self.date, date__gte=self.previous.date + ).aggregate(sum=models.Sum("value")) + return trans["sum"] or 0 + class Meta: ordering = ["-date"] diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index 9a68717..e56063e 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -54,7 +54,3 @@ h1 { #categories > a { margin-right: var(--gap); } - -#snapshots { - max-width: 24rem; -} diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 732bdd8..6cd9552 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -22,6 +22,9 @@ body { --text-link: #0066ff; --gap: 1em; + + --red: #ff6600; + --green: #66cc00; } h1 { @@ -35,3 +38,6 @@ a { a:hover { text-decoration: underline; } + +.red {color: var(--red)} +.green {color: var(--green)} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index daa7cef..fc46057 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -1,5 +1,6 @@ {% extends "main/base.html" %} {% load static %} +{% load main_extras %} {% block link %} {{ block.super }} @@ -23,7 +24,7 @@
{{ trans.date|date:"Y-m-d" }} {{ trans.name }} - {% if trans.value > 0 %}+{% endif %}{{ trans.value|floatformat:"2g" }} € + {{ trans.value|floatformat:"2g"|pm }} € {{ trans.trader|default_if_none:"–" }} {% if trans.category %} @@ -43,15 +44,33 @@ {% if snapshots %}

Relevés

-
+
Date Valeur + Différence + Transactions + Valide
{% for snap in snapshots %}
{{ snap.date|date:"Y-m-d" }} - {{ snap.value }} € + {{ snap.value|floatformat:"2g" }} € + {{ snap.diff|floatformat:"2g"|pm }} € + {% with sum=snap.sum %} + + {% if sum is not None %}{{ sum|floatformat:"2g"|pm }} €{% endif %} + + + {% if snap.previous is not None %} + {% if sum == snap.diff %} + + {% else %} + + {% endif %} + {% endif %} + + {% endwith %}
{% endfor %}
diff --git a/nummi/main/templatetags/__init__.py b/nummi/main/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nummi/main/templatetags/main_extras.py b/nummi/main/templatetags/main_extras.py new file mode 100644 index 0000000..cbdac32 --- /dev/null +++ b/nummi/main/templatetags/main_extras.py @@ -0,0 +1,10 @@ +from django import template +from django.template.defaultfilters import stringfilter + +register = template.Library() + + +@register.filter +@stringfilter +def pm(value): + return f"{'+' if value[0] != '-' else ''}{value}" From 4b784a553b0039cfbe4aa28d832fd0d87b8154e7 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 09:27:48 +0200 Subject: [PATCH 017/507] Update index --- nummi/main/static/main/css/index.css | 45 ---------------------------- nummi/main/static/main/css/table.css | 44 +++++++++++++++++++++++++++ nummi/main/templates/main/index.html | 1 + nummi/main/views.py | 2 +- 4 files changed, 46 insertions(+), 46 deletions(-) create mode 100644 nummi/main/static/main/css/table.css diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index e56063e..fe155a3 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -6,51 +6,6 @@ h1 { margin: 0; } -.table { - display: grid; - margin: 2em 0; - border-radius: 1em 0 1em 0; - overflow: hidden; - border-bottom: .5em solid var(--bg-inv); -} -.table.col2 {grid-template-columns: repeat(2, auto)} -.table.col3 {grid-template-columns: repeat(3, auto)} -.table.col4 {grid-template-columns: repeat(4, auto)} -.table.col5 {grid-template-columns: repeat(5, auto)} -.table.col6 {grid-template-columns: repeat(6, auto)} - -.table > div { - display: contents; -} - -.table > div > * { - padding: 1em; - white-space: nowrap; -} -.table > div.g> * { - background: var(--bg-01); -} - -.table > div.header > * { - background: var(--bg-inv); - color: var(--text-inv); -} - -.table > div > .center { - text-align: center; -} -.table > div > .right { - text-align: right; -} -.table > div > .num { - font-feature-settings: "tnum", "ss01"; -} - -.table > div > span.text { - overflow: hidden; - text-overflow: ellipsis; -} - #categories > a { margin-right: var(--gap); } diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css new file mode 100644 index 0000000..dbf4e0c --- /dev/null +++ b/nummi/main/static/main/css/table.css @@ -0,0 +1,44 @@ +.table { + display: grid; + margin: 2em 0; + border-radius: 1em 0 1em 0; + overflow: hidden; + border-bottom: .5em solid var(--bg-inv); +} +.table.col2 {grid-template-columns: repeat(2, auto)} +.table.col3 {grid-template-columns: repeat(3, auto)} +.table.col4 {grid-template-columns: repeat(4, auto)} +.table.col5 {grid-template-columns: repeat(5, auto)} +.table.col6 {grid-template-columns: repeat(6, auto)} + +.table > div { + display: contents; +} + +.table > div > * { + padding: 1em; + white-space: nowrap; +} +.table > div.g> * { + background: var(--bg-01); +} + +.table > div.header > * { + background: var(--bg-inv); + color: var(--text-inv); +} + +.table > div > .center { + text-align: center; +} +.table > div > .right { + text-align: right; +} +.table > div > .num { + font-feature-settings: "tnum", "ss01"; +} + +.table > div > span.text { + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index fc46057..8413e89 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -5,6 +5,7 @@ {% block link %} {{ block.super }} + {% endblock %} {% block body %} diff --git a/nummi/main/views.py b/nummi/main/views.py index f3805df..f348143 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -16,7 +16,7 @@ from .models import ( @login_required def index(request): - _transactions = Transaction.objects.all()[:5] + _transactions = Transaction.objects.all()[:10] _categories = Category.objects.all() _snapshots = Snapshot.objects.all()[:5] From cb458cf472ca6121c9b20c3b00d5588410efc6fd Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 10:06:44 +0200 Subject: [PATCH 018/507] Add snapshot form --- nummi/main/migrations/0001_initial.py | 114 +++++++++++++----- .../migrations/0002_delete_subcategory.py | 16 --- ...003_category_parent_alter_category_name.py | 29 ----- ...ter_category_options_category_full_name.py | 23 ---- .../0005_alter_category_full_name.py | 18 --- ...ory_options_transaction_trader_and_more.py | 67 ---------- ...ions_alter_transaction_options_and_more.py | 56 --------- ...08_alter_category_options_category_icon.py | 22 ---- nummi/main/migrations/0009_snapshot.py | 44 ------- .../0010_alter_snapshot_previous.py | 25 ---- ...snapshot_options_snapshot_diff_and_more.py | 30 ----- nummi/main/models.py | 7 ++ nummi/main/templates/main/base.html | 4 + nummi/main/templates/main/index.html | 4 +- nummi/main/templates/main/snapshot.html | 26 ++++ nummi/main/urls.py | 4 + nummi/main/views.py | 42 +++++-- 17 files changed, 159 insertions(+), 372 deletions(-) delete mode 100644 nummi/main/migrations/0002_delete_subcategory.py delete mode 100644 nummi/main/migrations/0003_category_parent_alter_category_name.py delete mode 100644 nummi/main/migrations/0004_alter_category_options_category_full_name.py delete mode 100644 nummi/main/migrations/0005_alter_category_full_name.py delete mode 100644 nummi/main/migrations/0006_alter_category_options_transaction_trader_and_more.py delete mode 100644 nummi/main/migrations/0007_alter_category_options_alter_transaction_options_and_more.py delete mode 100644 nummi/main/migrations/0008_alter_category_options_category_icon.py delete mode 100644 nummi/main/migrations/0009_snapshot.py delete mode 100644 nummi/main/migrations/0010_alter_snapshot_previous.py delete mode 100644 nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py create mode 100644 nummi/main/templates/main/snapshot.html diff --git a/nummi/main/migrations/0001_initial.py b/nummi/main/migrations/0001_initial.py index 1da39e1..7685e49 100644 --- a/nummi/main/migrations/0001_initial.py +++ b/nummi/main/migrations/0001_initial.py @@ -1,7 +1,10 @@ -# Generated by Django 4.0.4 on 2022-05-20 12:24 +# Generated by Django 4.0.4 on 2022-05-22 07:45 +import datetime +import django.core.validators from django.db import migrations, models import django.db.models.deletion +import re import uuid @@ -24,8 +27,25 @@ class Migration(migrations.Migration): serialize=False, ), ), - ("name", models.CharField(max_length=256)), + ( + "name", + models.CharField( + default="New Category", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-\\w]+\\Z"), + "Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens.", + "invalid", + ) + ], + ), + ), + ("icon", models.CharField(default="folder", max_length=64)), ], + options={ + "ordering": ["name"], + }, ), migrations.CreateModel( name="Transaction", @@ -39,10 +59,14 @@ class Migration(migrations.Migration): serialize=False, ), ), - ("name", models.CharField(max_length=256)), - ("description", models.TextField()), - ("value", models.DecimalField(decimal_places=2, max_digits=12)), - ("date", models.DateField()), + ("name", models.CharField(default="New Transaction", max_length=256)), + ("description", models.TextField(blank=True, null=True)), + ( + "value", + models.DecimalField(decimal_places=2, default=0, max_digits=12), + ), + ("date", models.DateField(default=datetime.date.today)), + ("trader", models.CharField(blank=True, max_length=128, null=True)), ( "category", models.ForeignKey( @@ -53,6 +77,47 @@ class Migration(migrations.Migration): ), ), ], + options={ + "ordering": ["-date"], + }, + ), + migrations.CreateModel( + name="Snapshot", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("date", models.DateField(default=datetime.date.today, unique=True)), + ( + "value", + models.DecimalField(decimal_places=2, default=0, max_digits=12), + ), + ( + "diff", + models.DecimalField( + decimal_places=2, default=0, editable=False, max_digits=12 + ), + ), + ( + "previous", + models.OneToOneField( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.snapshot", + ), + ), + ], + options={ + "ordering": ["-date"], + }, ), migrations.CreateModel( name="Invoice", @@ -66,8 +131,16 @@ class Migration(migrations.Migration): serialize=False, ), ), - ("name", models.CharField(max_length=256)), - ("file", models.FileField(upload_to="invoices/")), + ("name", models.CharField(default="New Invoice", max_length=256)), + ( + "file", + models.FileField( + upload_to="invoices/", + validators=[ + django.core.validators.FileExtensionValidator(["pdf"]) + ], + ), + ), ( "transaction", models.ForeignKey( @@ -77,29 +150,4 @@ class Migration(migrations.Migration): ), ], ), - migrations.CreateModel( - name="SubCategory", - fields=[ - ( - "category_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="main.category", - ), - ), - ( - "parent", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="category_parent", - to="main.category", - ), - ), - ], - bases=("main.category",), - ), ] diff --git a/nummi/main/migrations/0002_delete_subcategory.py b/nummi/main/migrations/0002_delete_subcategory.py deleted file mode 100644 index 4a772ac..0000000 --- a/nummi/main/migrations/0002_delete_subcategory.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 12:30 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0001_initial"), - ] - - operations = [ - migrations.DeleteModel( - name="SubCategory", - ), - ] diff --git a/nummi/main/migrations/0003_category_parent_alter_category_name.py b/nummi/main/migrations/0003_category_parent_alter_category_name.py deleted file mode 100644 index cede3ea..0000000 --- a/nummi/main/migrations/0003_category_parent_alter_category_name.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 13:33 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0002_delete_subcategory"), - ] - - operations = [ - migrations.AddField( - model_name="category", - name="parent", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="main.category", - ), - ), - migrations.AlterField( - model_name="category", - name="name", - field=models.CharField(max_length=64), - ), - ] diff --git a/nummi/main/migrations/0004_alter_category_options_category_full_name.py b/nummi/main/migrations/0004_alter_category_options_category_full_name.py deleted file mode 100644 index 1af43dd..0000000 --- a/nummi/main/migrations/0004_alter_category_options_category_full_name.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 14:17 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0003_category_parent_alter_category_name"), - ] - - operations = [ - migrations.AlterModelOptions( - name="category", - options={"ordering": ["-parent_id", "name"]}, - ), - migrations.AddField( - model_name="category", - name="full_name", - field=models.CharField(default="", max_length=512), - preserve_default=False, - ), - ] diff --git a/nummi/main/migrations/0005_alter_category_full_name.py b/nummi/main/migrations/0005_alter_category_full_name.py deleted file mode 100644 index af9449f..0000000 --- a/nummi/main/migrations/0005_alter_category_full_name.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 14:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0004_alter_category_options_category_full_name"), - ] - - operations = [ - migrations.AlterField( - model_name="category", - name="full_name", - field=models.CharField(default="", editable=False, max_length=512), - ), - ] diff --git a/nummi/main/migrations/0006_alter_category_options_transaction_trader_and_more.py b/nummi/main/migrations/0006_alter_category_options_transaction_trader_and_more.py deleted file mode 100644 index 9056ef4..0000000 --- a/nummi/main/migrations/0006_alter_category_options_transaction_trader_and_more.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 16:06 - -import datetime -import django.core.validators -from django.db import migrations, models -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0005_alter_category_full_name"), - ] - - operations = [ - migrations.AlterModelOptions( - name="category", - options={"ordering": ["full_name"]}, - ), - migrations.AddField( - model_name="transaction", - name="trader", - field=models.CharField(blank=True, max_length=128, null=True), - ), - migrations.AlterField( - model_name="category", - name="name", - field=models.CharField( - max_length=64, - validators=[ - django.core.validators.RegexValidator( - re.compile("^[-\\w]+\\Z"), - "Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens.", - "invalid", - ) - ], - ), - ), - migrations.AlterField( - model_name="invoice", - name="file", - field=models.FileField( - upload_to="invoices/", - validators=[django.core.validators.FileExtensionValidator(["pdf"])], - ), - ), - migrations.AlterField( - model_name="transaction", - name="date", - field=models.DateField(default=datetime.date.today), - ), - migrations.AlterField( - model_name="transaction", - name="description", - field=models.TextField(blank=True, null=True), - ), - migrations.AlterField( - model_name="transaction", - name="name", - field=models.CharField(default="Transaction", max_length=256), - ), - migrations.AlterField( - model_name="transaction", - name="value", - field=models.DecimalField(decimal_places=2, default=0, max_digits=12), - ), - ] diff --git a/nummi/main/migrations/0007_alter_category_options_alter_transaction_options_and_more.py b/nummi/main/migrations/0007_alter_category_options_alter_transaction_options_and_more.py deleted file mode 100644 index f4baaee..0000000 --- a/nummi/main/migrations/0007_alter_category_options_alter_transaction_options_and_more.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 19:25 - -import django.core.validators -from django.db import migrations, models -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0006_alter_category_options_transaction_trader_and_more"), - ] - - operations = [ - migrations.AlterModelOptions( - name="category", - options={}, - ), - migrations.AlterModelOptions( - name="transaction", - options={"ordering": ["-date"]}, - ), - migrations.RemoveField( - model_name="category", - name="full_name", - ), - migrations.RemoveField( - model_name="category", - name="parent", - ), - migrations.AlterField( - model_name="category", - name="name", - field=models.CharField( - default="New Category", - max_length=64, - validators=[ - django.core.validators.RegexValidator( - re.compile("^[-\\w]+\\Z"), - "Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens.", - "invalid", - ) - ], - ), - ), - migrations.AlterField( - model_name="invoice", - name="name", - field=models.CharField(default="New Invoice", max_length=256), - ), - migrations.AlterField( - model_name="transaction", - name="name", - field=models.CharField(default="New Transaction", max_length=256), - ), - ] diff --git a/nummi/main/migrations/0008_alter_category_options_category_icon.py b/nummi/main/migrations/0008_alter_category_options_category_icon.py deleted file mode 100644 index 3c570ed..0000000 --- a/nummi/main/migrations/0008_alter_category_options_category_icon.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-20 20:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0007_alter_category_options_alter_transaction_options_and_more"), - ] - - operations = [ - migrations.AlterModelOptions( - name="category", - options={"ordering": ["name"]}, - ), - migrations.AddField( - model_name="category", - name="icon", - field=models.CharField(default="folder", max_length=64), - ), - ] diff --git a/nummi/main/migrations/0009_snapshot.py b/nummi/main/migrations/0009_snapshot.py deleted file mode 100644 index f572375..0000000 --- a/nummi/main/migrations/0009_snapshot.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-21 18:40 - -import datetime -from django.db import migrations, models -import django.db.models.deletion -import uuid - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0008_alter_category_options_category_icon"), - ] - - operations = [ - migrations.CreateModel( - name="Snapshot", - fields=[ - ( - "id", - models.UUIDField( - default=uuid.uuid4, - editable=False, - primary_key=True, - serialize=False, - ), - ), - ("date", models.DateField(default=datetime.date.today)), - ( - "value", - models.DecimalField(decimal_places=2, default=0, max_digits=12), - ), - ( - "previous", - models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="main.snapshot", - ), - ), - ], - ), - ] diff --git a/nummi/main/migrations/0010_alter_snapshot_previous.py b/nummi/main/migrations/0010_alter_snapshot_previous.py deleted file mode 100644 index 53393fd..0000000 --- a/nummi/main/migrations/0010_alter_snapshot_previous.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-21 18:44 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0009_snapshot"), - ] - - operations = [ - migrations.AlterField( - model_name="snapshot", - name="previous", - field=models.OneToOneField( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="main.snapshot", - ), - ), - ] diff --git a/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py b/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py deleted file mode 100644 index 7a48363..0000000 --- a/nummi/main/migrations/0011_alter_snapshot_options_snapshot_diff_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 4.0.4 on 2022-05-22 06:43 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("main", "0010_alter_snapshot_previous"), - ] - - operations = [ - migrations.AlterModelOptions( - name="snapshot", - options={"ordering": ["-date"]}, - ), - migrations.AddField( - model_name="snapshot", - name="diff", - field=models.DecimalField( - decimal_places=2, default=0, editable=False, max_digits=12 - ), - ), - migrations.AlterField( - model_name="snapshot", - name="date", - field=models.DateField(default=datetime.date.today, unique=True), - ), - ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 5f14876..c12dca4 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -94,6 +94,7 @@ class Snapshot(models.Model): if not only_super: _prev = ( self.__class__.objects.order_by("-date") + .exclude(id=self.id) .filter(date__lt=self.date) .first() ) @@ -139,3 +140,9 @@ class Snapshot(models.Model): class Meta: ordering = ["-date"] + + +class SnapshotForm(ModelForm): + class Meta: + model = Snapshot + fields = ["date", "value"] diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index c23f3e0..cfc0531 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -29,6 +29,10 @@ class="{% if request.resolver_match.url_name == "category" %} cur{% endif %}"> Add category + + Add snapshot + Log Out diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 8413e89..cc61b65 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -55,7 +55,9 @@
{% for snap in snapshots %}
- {{ snap.date|date:"Y-m-d" }} + + {{ snap.date|date:"Y-m-d" }} + {{ snap.value|floatformat:"2g" }} € {{ snap.diff|floatformat:"2g"|pm }} € {% with sum=snap.sum %} diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html new file mode 100644 index 0000000..b6d60aa --- /dev/null +++ b/nummi/main/templates/main/snapshot.html @@ -0,0 +1,26 @@ +{% extends "main/base.html" %} +{% load static %} + +{% block link %} +{{ block.super }} + +{% endblock %} + +{% block body %} +

{{ snapshot }}

+ +
+ {% csrf_token %} + {% for field in form %} + {{ field.errors }} + + {{ field }} + {% endfor %} +
+ + + +
+
+ +{% endblock %} diff --git a/nummi/main/urls.py b/nummi/main/urls.py index 4114aaf..384ab79 100644 --- a/nummi/main/urls.py +++ b/nummi/main/urls.py @@ -21,4 +21,8 @@ urlpatterns = [ path("category", views.category, name="category"), path("category/", views.category, name="category"), path("category//update", views.update_category, name="update_category"), + path("snapshot", views.snapshot, name="snapshot"), + path("snapshot/", views.snapshot, name="snapshot"), + path("snapshot/update/", views.update_snapshot, name="update_snapshot"), + path("snapshot//del", views.del_snapshot, name="del_snapshot"), ] diff --git a/nummi/main/views.py b/nummi/main/views.py index f348143..0489190 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -11,6 +11,7 @@ from .models import ( Category, CategoryForm, Snapshot, + SnapshotForm, ) @@ -59,10 +60,7 @@ def transaction(request, uuid=None): @login_required def update_transaction(request, uuid): - try: - _transaction = Transaction.objects.get(id=uuid) - except Transaction.DoesNotExist: - _transaction = Transaction(id=uuid) + _transaction, _ = Transaction.objects.get_or_create(id=uuid) _form = TransactionForm(request.POST, instance=_transaction) _form.save() return redirect(transaction, uuid=uuid) @@ -112,10 +110,38 @@ def category(request, uuid=None): @login_required def update_category(request, uuid): - try: - _category = Category.objects.get(id=uuid) - except Category.DoesNotExist: - _category = Category(id=uuid) + _category, _ = Category.objects.get_or_create(id=uuid) _form = CategoryForm(request.POST, instance=_category) _form.save() return redirect(category, uuid=uuid) + + +@login_required +def snapshot(request, date=None): + if date is None: + _snapshot = Snapshot() + else: + _snapshot = get_object_or_404(Snapshot, date=date) + return render( + request, + "main/snapshot.html", + { + "snapshot": _snapshot, + "form": SnapshotForm(instance=_snapshot), + }, + ) + + +@login_required +def update_snapshot(request, uuid): + _snapshot, _ = Snapshot.objects.get_or_create(id=uuid) + _form = SnapshotForm(request.POST, instance=_snapshot) + _form.save() + return redirect(snapshot, date=_snapshot.date) + + +@login_required +def del_snapshot(request, date): + _snapshot = get_object_or_404(Snapshot, date=date) + _snapshot.delete() + return redirect(index) From 43aabf051bd2d3759fe0cdeb8a56413ef76dcba6 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 10:15:42 +0200 Subject: [PATCH 019/507] Add transactions to snapshot page --- nummi/main/templates/main/snapshot.html | 48 ++++++++++++++++++++++++- nummi/main/views.py | 5 +++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index b6d60aa..54289d6 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -1,13 +1,25 @@ {% extends "main/base.html" %} {% load static %} +{% load main_extras %} {% block link %} {{ block.super }} + {% endblock %} {% block body %} -

{{ snapshot }}

+{% with sum=snapshot.sum %} +

+ {% if snapshot.previous is not None %} + {% if sum == snapshot.diff %} + + {% else %} + + {% endif %} + {% endif %} + {{ snapshot }} +

{% csrf_token %} @@ -23,4 +35,38 @@
+{% if transactions %} +

Transactions ({{ sum|floatformat:"2g"|pm }} € / {{ snapshot.diff|floatformat:"2g"|pm }} €)

+ +
+
+ Date + Nom + Valeur + Commerçant + Catégorie + Description +
+ {% for trans in transactions %} +
+ {{ trans.date|date:"Y-m-d" }} + {{ trans.name }} + {{ trans.value|floatformat:"2g"|pm }} € + {{ trans.trader|default_if_none:"–" }} + + {% if trans.category %} + + + {{ trans.category }} + + {% else %} + – + {% endif %} + + {{ trans.description }} +
+ {% endfor %} +
+{% endif %} +{% endwith %} {% endblock %} diff --git a/nummi/main/views.py b/nummi/main/views.py index 0489190..724a404 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -120,14 +120,19 @@ def update_category(request, uuid): def snapshot(request, date=None): if date is None: _snapshot = Snapshot() + _transactions = None else: _snapshot = get_object_or_404(Snapshot, date=date) + _transactions = Transaction.objects.filter( + date__lt=_snapshot.date, date__gte=_snapshot.previous.date + ) return render( request, "main/snapshot.html", { "snapshot": _snapshot, "form": SnapshotForm(instance=_snapshot), + "transactions": _transactions, }, ) From f3d0d3d746465067d4766047f6390f78f8761583 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 10:28:53 +0200 Subject: [PATCH 020/507] Update theme colors --- nummi/main/static/main/css/main.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 6cd9552..2319766 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -14,17 +14,17 @@ body { --bg: #ffffff; --text: #000000de; - --bg-inv: #000000; + --bg-inv: #800d29; --text-inv: #ffffffde; --bg-01: #dedede; - --text-link: #0066ff; + --text-link: #066180de; --gap: 1em; - --red: #ff6600; - --green: #66cc00; + --red: #cc0033; + --green: #149dcc; } h1 { From 57ace376d806b8f9b73dc72951c8c66f06582445 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 10:35:22 +0200 Subject: [PATCH 021/507] Updat transaction list in category with table --- nummi/main/templates/main/category.html | 43 +++++++++++++++++++------ 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index cbd6f59..38bccee 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -1,9 +1,11 @@ {% extends "main/base.html" %} {% load static %} +{% load main_extras %} {% block link %} {{ block.super }} + {% endblock %} {% block body %} @@ -23,15 +25,36 @@ {% if transactions %} -

Transactions ({{ transactions|length }})

- +

Transactions

+ +
+
+ Date + Nom + Valeur + Commerçant + Catégorie + Description +
+ {% for trans in transactions %} +
+ {{ trans.date|date:"Y-m-d" }} + {{ trans.name }} + {{ trans.value|floatformat:"2g"|pm }} € + {{ trans.trader|default_if_none:"–" }} + + {% if trans.category %} + + + {{ trans.category }} + + {% else %} + – + {% endif %} + + {{ trans.description }} +
+ {% endfor %} +
{% endif %} {% endblock %} From 02b0fae3f7099a08ec2c6c795e07471931c6a76f Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 10:39:29 +0200 Subject: [PATCH 022/507] Fix bugs with snapshots: opening earliest snapshot, deleting latest --- nummi/main/models.py | 2 +- nummi/main/views.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index c12dca4..e9dd980 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -121,7 +121,7 @@ class Snapshot(models.Model): try: _next = self.__class__.objects.get(previous=self) except self.__class__.DoesNotExist: - pass + super().delete(*args, **kwargs) else: _next.previous = self.previous super().delete(*args, **kwargs) diff --git a/nummi/main/views.py b/nummi/main/views.py index 724a404..4a200fa 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -123,9 +123,12 @@ def snapshot(request, date=None): _transactions = None else: _snapshot = get_object_or_404(Snapshot, date=date) - _transactions = Transaction.objects.filter( - date__lt=_snapshot.date, date__gte=_snapshot.previous.date - ) + if _snapshot.previous is None: + _transactions = None + else: + _transactions = Transaction.objects.filter( + date__lt=_snapshot.date, date__gte=_snapshot.previous.date + ) return render( request, "main/snapshot.html", From 0e60dfba27ca2349a44498b1f871733df92cb012 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 11:10:52 +0200 Subject: [PATCH 023/507] Fix snapshot updating issues --- nummi/main/models.py | 10 ++++++++-- nummi/main/views.py | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index e9dd980..83c924e 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -76,7 +76,7 @@ class InvoiceForm(ModelForm): class Snapshot(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - date = models.DateField(default=date.today, unique=True) + date = models.DateField(unique=True) value = models.DecimalField(max_digits=12, decimal_places=2, default=0) previous = models.OneToOneField( "self", on_delete=models.SET_NULL, blank=True, null=True, editable=False @@ -98,13 +98,19 @@ class Snapshot(models.Model): .filter(date__lt=self.date) .first() ) - print(_prev) try: _next = self.__class__.objects.exclude(id=self.id).get(previous=_prev) except self.__class__.DoesNotExist: pass else: + try: + _prevnext = self.__class__.objects.exclude(id=self.id).get(previous=self) + except self.__class__.DoesNotExist: + pass + else: + _prevnext.previous = self.__class__.objects.order_by("-date").exclude(id=self.id).filter(date__lt=_prevnext.date).first() + _prevnext.save(only_super=True) _next.previous = self _next.save(only_super=True) diff --git a/nummi/main/views.py b/nummi/main/views.py index 4a200fa..3bd4e6b 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -142,7 +142,10 @@ def snapshot(request, date=None): @login_required def update_snapshot(request, uuid): - _snapshot, _ = Snapshot.objects.get_or_create(id=uuid) + try: + _snapshot = Snapshot.objects.get(id=uuid) + except Snapshot.DoesNotExist: + _snapshot = Snapshot(id=uuid) _form = SnapshotForm(request.POST, instance=_snapshot) _form.save() return redirect(snapshot, date=_snapshot.date) From 5d6f47b85258b3c63766266a1ad460b74acdc7cb Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 11:14:05 +0200 Subject: [PATCH 024/507] Fix snapshot diff update issue --- nummi/main/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nummi/main/models.py b/nummi/main/models.py index 83c924e..d2e761f 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -122,6 +122,13 @@ class Snapshot(models.Model): self.diff = self.value - self.previous.value super().save(*args, **kwargs) + try: + _next = self.__class__.objects.get(previous=self) + except self.__class__.DoesNotExist: + pass + else: + _next.save(only_super=True) + def delete(self, *args, only_super=False, **kwargs): if not only_super: try: From df0882bd88a4bf1e8904b4de08d8e875e94ebf31 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 12:32:26 +0200 Subject: [PATCH 025/507] Fix bugs and update templating --- ...alter_snapshot_date_alter_snapshot_diff.py | 25 ++++++++++++ nummi/main/models.py | 15 +++++-- nummi/main/templates/main/category.html | 31 +-------------- nummi/main/templates/main/index.html | 39 ++++--------------- nummi/main/templates/main/snapshot.html | 32 +-------------- nummi/main/templates/main/tag/pmvalue.html | 8 ++++ .../templates/main/tag/transaction_table.html | 31 +++++++++++++++ nummi/main/templates/main/tag/value.html | 7 ++++ nummi/main/templatetags/main_extras.py | 17 ++++++-- 9 files changed, 105 insertions(+), 100 deletions(-) create mode 100644 nummi/main/migrations/0002_alter_snapshot_date_alter_snapshot_diff.py create mode 100644 nummi/main/templates/main/tag/pmvalue.html create mode 100644 nummi/main/templates/main/tag/transaction_table.html create mode 100644 nummi/main/templates/main/tag/value.html diff --git a/nummi/main/migrations/0002_alter_snapshot_date_alter_snapshot_diff.py b/nummi/main/migrations/0002_alter_snapshot_date_alter_snapshot_diff.py new file mode 100644 index 0000000..2753a1d --- /dev/null +++ b/nummi/main/migrations/0002_alter_snapshot_date_alter_snapshot_diff.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.4 on 2022-05-22 09:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="snapshot", + name="date", + field=models.DateField(unique=True), + ), + migrations.AlterField( + model_name="snapshot", + name="diff", + field=models.DecimalField( + blank=True, decimal_places=2, editable=False, max_digits=12, null=True + ), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index d2e761f..d4cfcf0 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -82,7 +82,7 @@ class Snapshot(models.Model): "self", on_delete=models.SET_NULL, blank=True, null=True, editable=False ) diff = models.DecimalField( - max_digits=12, decimal_places=2, default=0, editable=False + max_digits=12, decimal_places=2, editable=False, blank=True, null=True ) def __str__(self): @@ -105,11 +105,18 @@ class Snapshot(models.Model): pass else: try: - _prevnext = self.__class__.objects.exclude(id=self.id).get(previous=self) + _prevnext = self.__class__.objects.exclude(id=self.id).get( + previous=self + ) except self.__class__.DoesNotExist: pass else: - _prevnext.previous = self.__class__.objects.order_by("-date").exclude(id=self.id).filter(date__lt=_prevnext.date).first() + _prevnext.previous = ( + self.__class__.objects.order_by("-date") + .exclude(id=self.id) + .filter(date__lt=_prevnext.date) + .first() + ) _prevnext.save(only_super=True) _next.previous = self _next.save(only_super=True) @@ -117,7 +124,7 @@ class Snapshot(models.Model): self.previous = _prev if self.previous is None: - self.diff = 0 + self.diff = None else: self.diff = self.value - self.previous.value super().save(*args, **kwargs) diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index 38bccee..c193c60 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -26,35 +26,6 @@ {% if transactions %}

Transactions

- -
-
- Date - Nom - Valeur - Commerçant - Catégorie - Description -
- {% for trans in transactions %} -
- {{ trans.date|date:"Y-m-d" }} - {{ trans.name }} - {{ trans.value|floatformat:"2g"|pm }} € - {{ trans.trader|default_if_none:"–" }} - - {% if trans.category %} - - - {{ trans.category }} - - {% else %} - – - {% endif %} - - {{ trans.description }} -
- {% endfor %} -
+{% transaction_table transactions %} {% endif %} {% endblock %} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index cc61b65..fe09c99 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -12,35 +12,8 @@

Nummi

{% if transactions %} -
-
- Date - Nom - Valeur - Commerçant - Catégorie - Description -
- {% for trans in transactions %} -
- {{ trans.date|date:"Y-m-d" }} - {{ trans.name }} - {{ trans.value|floatformat:"2g"|pm }} € - {{ trans.trader|default_if_none:"–" }} - - {% if trans.category %} - - - {{ trans.category }} - - {% else %} - – - {% endif %} - - {{ trans.description }} -
- {% endfor %} -
+

Transactions

+{% transaction_table transactions %} {% endif %} {% if snapshots %} @@ -58,11 +31,13 @@ {{ snap.date|date:"Y-m-d" }} - {{ snap.value|floatformat:"2g" }} € - {{ snap.diff|floatformat:"2g"|pm }} € + {% value snap.value %} + + {% pmvalue snap.diff %} + {% with sum=snap.sum %} - {% if sum is not None %}{{ sum|floatformat:"2g"|pm }} €{% endif %} + {% pmvalue sum %} {% if snap.previous is not None %} diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index 54289d6..a85bca7 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -36,37 +36,9 @@ {% if transactions %} -

Transactions ({{ sum|floatformat:"2g"|pm }} € / {{ snapshot.diff|floatformat:"2g"|pm }} €)

+

Transactions ({% pmvalue sum %} / {% pmvalue snapshot.diff %})

-
-
- Date - Nom - Valeur - Commerçant - Catégorie - Description -
- {% for trans in transactions %} -
- {{ trans.date|date:"Y-m-d" }} - {{ trans.name }} - {{ trans.value|floatformat:"2g"|pm }} € - {{ trans.trader|default_if_none:"–" }} - - {% if trans.category %} - - - {{ trans.category }} - - {% else %} - – - {% endif %} - - {{ trans.description }} -
- {% endfor %} -
+{% transaction_table transactions %} {% endif %} {% endwith %} {% endblock %} diff --git a/nummi/main/templates/main/tag/pmvalue.html b/nummi/main/templates/main/tag/pmvalue.html new file mode 100644 index 0000000..306aa87 --- /dev/null +++ b/nummi/main/templates/main/tag/pmvalue.html @@ -0,0 +1,8 @@ +{% extends "main/tag/value.html" %} + +{% block "value" %} + {% if value %} + {% if value > 0 %}+{% endif %} + {{ block.super }} + {% else %}–{% endif %} +{% endblock %} diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html new file mode 100644 index 0000000..2ab25d1 --- /dev/null +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -0,0 +1,31 @@ +{% load main_extras %} + +
+
+ Date + Nom + Valeur + Commerçant + Catégorie + Description +
+ {% for trans in transactions %} +
+ {{ trans.date|date:"Y-m-d" }} + {{ trans.name }} + {% pmvalue trans.value %} + {{ trans.trader|default_if_none:"–" }} + + {% if trans.category %} + + + {{ trans.category }} + + {% else %} + – + {% endif %} + + {{ trans.description }} +
+ {% endfor %} +
diff --git a/nummi/main/templates/main/tag/value.html b/nummi/main/templates/main/tag/value.html new file mode 100644 index 0000000..d004f9a --- /dev/null +++ b/nummi/main/templates/main/tag/value.html @@ -0,0 +1,7 @@ +{% spaceless %} + + {% block "value" %} + {{ value|floatformat:"2g" }} € + {% endblock %} + +{% endspaceless %} diff --git a/nummi/main/templatetags/main_extras.py b/nummi/main/templatetags/main_extras.py index cbdac32..4f911e6 100644 --- a/nummi/main/templatetags/main_extras.py +++ b/nummi/main/templatetags/main_extras.py @@ -4,7 +4,16 @@ from django.template.defaultfilters import stringfilter register = template.Library() -@register.filter -@stringfilter -def pm(value): - return f"{'+' if value[0] != '-' else ''}{value}" +@register.inclusion_tag("main/tag/value.html") +def value(value): + return {"value": value} + + +@register.inclusion_tag("main/tag/pmvalue.html") +def pmvalue(value): + return {"value": value} + + +@register.inclusion_tag("main/tag/transaction_table.html") +def transaction_table(transactions): + return {"transactions": transactions} From 83aefe1f8404aad9756313a6234b7a3cc89123e6 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 13:27:57 +0200 Subject: [PATCH 026/507] Add delete button to transaction form --- nummi/main/templates/main/transaction.html | 1 + nummi/main/urls.py | 1 + nummi/main/views.py | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index 17b9a30..78e8355 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -18,6 +18,7 @@ {{ field }} {% endfor %}
+
diff --git a/nummi/main/urls.py b/nummi/main/urls.py index 384ab79..44141fd 100644 --- a/nummi/main/urls.py +++ b/nummi/main/urls.py @@ -11,6 +11,7 @@ urlpatterns = [ path( "transaction//update", views.update_transaction, name="update_transaction" ), + path("transaction//del", views.del_transaction, name="del_transaction"), path("transaction//add_invoice", views.add_invoice, name="add_invoice"), path( "transaction//del_invoice/", diff --git a/nummi/main/views.py b/nummi/main/views.py index 3bd4e6b..b429579 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -66,6 +66,13 @@ def update_transaction(request, uuid): return redirect(transaction, uuid=uuid) +@login_required +def del_transaction(request, uuid): + _transaction = get_object_or_404(Transaction, id=uuid) + _transaction.delete() + return redirect(index) + + @login_required def invoice(request, uuid): _invoice = get_object_or_404(Invoice, id=uuid) From 215787e2048f2d61f67bbba2f3b52db0afcf297e Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 13:36:43 +0200 Subject: [PATCH 027/507] Add real date field to transactions --- .../migrations/0003_transaction_real_date.py | 18 ++++++++++++++++++ nummi/main/models.py | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 nummi/main/migrations/0003_transaction_real_date.py diff --git a/nummi/main/migrations/0003_transaction_real_date.py b/nummi/main/migrations/0003_transaction_real_date.py new file mode 100644 index 0000000..fd79bda --- /dev/null +++ b/nummi/main/migrations/0003_transaction_real_date.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-05-22 11:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0002_alter_snapshot_date_alter_snapshot_diff'), + ] + + operations = [ + migrations.AddField( + model_name='transaction', + name='real_date', + field=models.DateField(blank=True, null=True), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index d4cfcf0..1a1bd8b 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -31,6 +31,7 @@ class Transaction(models.Model): description = models.TextField(null=True, blank=True) value = models.DecimalField(max_digits=12, decimal_places=2, default=0) date = models.DateField(default=date.today) + real_date = models.DateField(blank=True, null=True) trader = models.CharField(max_length=128, blank=True, null=True) category = models.ForeignKey( Category, on_delete=models.SET_NULL, blank=True, null=True @@ -49,7 +50,7 @@ class Transaction(models.Model): class TransactionForm(ModelForm): class Meta: model = Transaction - fields = ["date", "name", "value", "trader", "category", "description"] + fields = ["date", "name", "value", "trader", "category", "real_date", "description"] class Invoice(models.Model): From b45150d4ff9e28e6104b157d3b6530c804a8e1f1 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 13:52:09 +0200 Subject: [PATCH 028/507] Added payment field to transaction --- .../migrations/0003_transaction_real_date.py | 6 +++--- .../migrations/0004_transaction_payment.py | 18 ++++++++++++++++++ nummi/main/models.py | 12 +++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 nummi/main/migrations/0004_transaction_payment.py diff --git a/nummi/main/migrations/0003_transaction_real_date.py b/nummi/main/migrations/0003_transaction_real_date.py index fd79bda..dfa0a25 100644 --- a/nummi/main/migrations/0003_transaction_real_date.py +++ b/nummi/main/migrations/0003_transaction_real_date.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('main', '0002_alter_snapshot_date_alter_snapshot_diff'), + ("main", "0002_alter_snapshot_date_alter_snapshot_diff"), ] operations = [ migrations.AddField( - model_name='transaction', - name='real_date', + model_name="transaction", + name="real_date", field=models.DateField(blank=True, null=True), ), ] diff --git a/nummi/main/migrations/0004_transaction_payment.py b/nummi/main/migrations/0004_transaction_payment.py new file mode 100644 index 0000000..f613d7e --- /dev/null +++ b/nummi/main/migrations/0004_transaction_payment.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-05-22 11:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0003_transaction_real_date"), + ] + + operations = [ + migrations.AddField( + model_name="transaction", + name="payment", + field=models.CharField(blank=True, max_length=128, null=True), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 1a1bd8b..bd4b412 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -33,6 +33,7 @@ class Transaction(models.Model): date = models.DateField(default=date.today) real_date = models.DateField(blank=True, null=True) trader = models.CharField(max_length=128, blank=True, null=True) + payment = models.CharField(max_length=128, blank=True, null=True) category = models.ForeignKey( Category, on_delete=models.SET_NULL, blank=True, null=True ) @@ -50,7 +51,16 @@ class Transaction(models.Model): class TransactionForm(ModelForm): class Meta: model = Transaction - fields = ["date", "name", "value", "trader", "category", "real_date", "description"] + fields = [ + "date", + "name", + "value", + "trader", + "category", + "real_date", + "payment", + "description", + ] class Invoice(models.Model): From b4e218f418aa5b52830a725a51fcfe87ec4fdca5 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 13:57:53 +0200 Subject: [PATCH 029/507] Remove restrictions on category names --- .../migrations/0005_alter_category_name.py | 18 ++++++++++++++++++ nummi/main/models.py | 6 ++---- 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 nummi/main/migrations/0005_alter_category_name.py diff --git a/nummi/main/migrations/0005_alter_category_name.py b/nummi/main/migrations/0005_alter_category_name.py new file mode 100644 index 0000000..b88b522 --- /dev/null +++ b/nummi/main/migrations/0005_alter_category_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-05-22 11:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0004_transaction_payment"), + ] + + operations = [ + migrations.AlterField( + model_name="category", + name="name", + field=models.CharField(default="New Category", max_length=64), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index bd4b412..38aa299 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -2,14 +2,12 @@ from datetime import date import uuid from django.db import models from django.forms import ModelForm -from django.core.validators import validate_unicode_slug, FileExtensionValidator +from django.core.validators import FileExtensionValidator class Category(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - name = models.CharField( - max_length=64, validators=[validate_unicode_slug], default="New Category" - ) + name = models.CharField(max_length=64, default="New Category") icon = models.CharField(max_length=64, default="folder") def __str__(self): From 5c01b8cd61fab6db47676037f7b09d183c5db68a Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 14:17:26 +0200 Subject: [PATCH 030/507] Update css for index categories --- nummi/main/static/main/css/index.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index fe155a3..340a2e4 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -8,4 +8,6 @@ h1 { #categories > a { margin-right: var(--gap); + margin-bottom: var(--gap); + display: inline-block; } From d96450aae204289454d6201177903ea86cf15ae7 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 14:41:15 +0200 Subject: [PATCH 031/507] Fix date range for snapshot transactions --- nummi/main/models.py | 12 +++++++++--- nummi/main/templates/main/snapshot.html | 4 ++-- nummi/main/views.py | 8 -------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index 38aa299..f635fbe 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -162,11 +162,17 @@ class Snapshot(models.Model): def sum(self): if self.previous is None: return None - trans = Transaction.objects.filter( - date__lt=self.date, date__gte=self.previous.date - ).aggregate(sum=models.Sum("value")) + trans = self.transactions.aggregate(sum=models.Sum("value")) return trans["sum"] or 0 + @property + def transactions(self): + if self.previous is None: + return Transaction.objects.none() + return Transaction.objects.filter( + date__lte=self.date, date__gt=self.previous.date + ) + class Meta: ordering = ["-date"] diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index a85bca7..6abb631 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -35,10 +35,10 @@
-{% if transactions %} +{% if snapshot.transactions %}

Transactions ({% pmvalue sum %} / {% pmvalue snapshot.diff %})

-{% transaction_table transactions %} +{% transaction_table snapshot.transactions %} {% endif %} {% endwith %} {% endblock %} diff --git a/nummi/main/views.py b/nummi/main/views.py index b429579..8890288 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -127,22 +127,14 @@ def update_category(request, uuid): def snapshot(request, date=None): if date is None: _snapshot = Snapshot() - _transactions = None else: _snapshot = get_object_or_404(Snapshot, date=date) - if _snapshot.previous is None: - _transactions = None - else: - _transactions = Transaction.objects.filter( - date__lt=_snapshot.date, date__gte=_snapshot.previous.date - ) return render( request, "main/snapshot.html", { "snapshot": _snapshot, "form": SnapshotForm(instance=_snapshot), - "transactions": _transactions, }, ) From e4f70c67e32d0a57390e4e95f9dcb8826a878b52 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 14:52:25 +0200 Subject: [PATCH 032/507] Darken value column in tables --- nummi/main/static/main/css/table.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index dbf4e0c..0e42b34 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -19,9 +19,8 @@ padding: 1em; white-space: nowrap; } -.table > div.g> * { - background: var(--bg-01); -} +.table > div.g> * {background: var(--bg-01)} +.table > div.w> * {background: var(--bg)} .table > div.header > * { background: var(--bg-inv); @@ -37,6 +36,9 @@ .table > div > .num { font-feature-settings: "tnum", "ss01"; } +.table > div > span.value { + filter: brightness(95%); +} .table > div > span.text { overflow: hidden; From fdcdff7bcc3d265cd7bda170c6e0561d7a3f7130 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 22 May 2022 17:07:57 +0200 Subject: [PATCH 033/507] Add paginated transaction view --- nummi/main/templates/main/base.html | 12 +++++--- nummi/main/templates/main/transactions.html | 31 +++++++++++++++++++++ nummi/main/urls.py | 1 + nummi/main/views.py | 10 +++++++ 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 nummi/main/templates/main/transactions.html diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index cfc0531..66732a7 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -18,19 +18,23 @@ {% spaceless %}
{% endif %}
- {% pmvalue cat.sum_p %} + {{ cat.sum_p|pmvalue }}
{% endfor %}
{% if snapshot.transactions %} -

Transactions ({% pmvalue sum %} / {% pmvalue snapshot.diff %})

+

Transactions ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

{% transaction_table snapshot.transactions %} {% endif %} diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html index 2ab25d1..9dd3cf5 100644 --- a/nummi/main/templates/main/tag/transaction_table.html +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -13,7 +13,7 @@
{{ trans.date|date:"Y-m-d" }} {{ trans.name }} - {% pmvalue trans.value %} + {{ trans.value|pmvalue }} {{ trans.trader|default_if_none:"–" }} {% if trans.category %} diff --git a/nummi/main/templates/main/tag/value.html b/nummi/main/templates/main/tag/value.html index d004f9a..9ba2cf7 100644 --- a/nummi/main/templates/main/tag/value.html +++ b/nummi/main/templates/main/tag/value.html @@ -1,7 +1,7 @@ {% spaceless %} {% block "value" %} - {{ value|floatformat:"2g" }} € + {{ value }} € {% endblock %} {% endspaceless %} diff --git a/nummi/main/templatetags/main_extras.py b/nummi/main/templatetags/main_extras.py index 4f911e6..924f4cc 100644 --- a/nummi/main/templatetags/main_extras.py +++ b/nummi/main/templatetags/main_extras.py @@ -1,17 +1,32 @@ from django import template from django.template.defaultfilters import stringfilter +from django.utils import formats +from django.utils.safestring import mark_safe register = template.Library() -@register.inclusion_tag("main/tag/value.html") -def value(value): - return {"value": value} +@register.filter +def value(val, pm=False): + if not val: + return mark_safe("–") + _prefix = "" + _suffix = " €" + _val = formats.number_format(val, 2, use_l10n=True) + + if val > 0: + if pm: + _prefix += "+ " + else: + _val = _val[1:] + _prefix += "− " + + return mark_safe(f"{_prefix}{_val}{_suffix}") -@register.inclusion_tag("main/tag/pmvalue.html") -def pmvalue(value): - return {"value": value} +@register.filter +def pmvalue(val): + return value(val, True) @register.inclusion_tag("main/tag/transaction_table.html") From d7558cfa0cd15a0fc7f0d8528ca8db2caf1310aa Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 24 May 2022 18:14:22 +0200 Subject: [PATCH 049/507] Force grouping on value filter --- nummi/main/templatetags/main_extras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/templatetags/main_extras.py b/nummi/main/templatetags/main_extras.py index 924f4cc..9af8f92 100644 --- a/nummi/main/templatetags/main_extras.py +++ b/nummi/main/templatetags/main_extras.py @@ -12,7 +12,7 @@ def value(val, pm=False): return mark_safe("–") _prefix = "" _suffix = " €" - _val = formats.number_format(val, 2, use_l10n=True) + _val = formats.number_format(val, 2, use_l10n=True, force_grouping=True) if val > 0: if pm: From a911b324b5e034b6f56bea77978a08664764ac73 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 24 May 2022 20:15:38 +0200 Subject: [PATCH 050/507] Add logo --- nummi/main/static/main/css/index.css | 6 ++++++ nummi/main/static/main/css/main.css | 2 +- nummi/main/static/main/css/nav.css | 5 +++++ nummi/main/static/main/svg/logo-white.svg | 22 ++++++++++++++++++++++ nummi/main/static/main/svg/logo.svg | 22 ++++++++++++++++++++++ nummi/main/templates/main/base.html | 3 ++- nummi/main/templates/main/index.html | 2 +- 7 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 nummi/main/static/main/svg/logo-white.svg create mode 100644 nummi/main/static/main/svg/logo.svg diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index 340a2e4..d254083 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -4,6 +4,12 @@ h1 { font-weight: 850; letter-spacing: -.05em; margin: 0; + line-height: 1.2em; +} +h1 img { + height: 1.2em; + vertical-align: top; + margin-right: var(--gap); } #categories > a { diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 1cb4894..72d7151 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -24,7 +24,7 @@ --text-link: #0a35ccde; - --gap: 1em; + --gap: 1rem; --red: #bf1500; --green: var(--theme-2); diff --git a/nummi/main/static/main/css/nav.css b/nummi/main/static/main/css/nav.css index 7523faa..ecf6343 100644 --- a/nummi/main/static/main/css/nav.css +++ b/nummi/main/static/main/css/nav.css @@ -35,3 +35,8 @@ nav > a.home { nav > a.logout { float: right; } +nav > a img { + height: var(--nav-lh); + vertical-align: top; + margin-right: .5rem; +} diff --git a/nummi/main/static/main/svg/logo-white.svg b/nummi/main/static/main/svg/logo-white.svg new file mode 100644 index 0000000..26abbda --- /dev/null +++ b/nummi/main/static/main/svg/logo-white.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/nummi/main/static/main/svg/logo.svg b/nummi/main/static/main/svg/logo.svg new file mode 100644 index 0000000..795f303 --- /dev/null +++ b/nummi/main/static/main/svg/logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index bb65d32..b39d20b 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -8,6 +8,7 @@ {% block title %}Nummi{% endblock %} {% block link %} + @@ -19,7 +20,7 @@
+{% if categories %}

Plot

{% for cat in categories %} @@ -83,6 +84,7 @@
{% endfor %}
+{% endif %} {% if snapshot.transactions %}

Transactions ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

diff --git a/nummi/main/views.py b/nummi/main/views.py index e8ca412..c239e65 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -163,27 +163,28 @@ def snapshot(request, uuid=None): "form": _form, } - context["categories"] = ( - _snapshot.transactions.values("category", "category__name", "category__icon") - .annotate( - sum=models.Sum("value"), - sum_m=models.Sum("value", filter=models.Q(value__lt=0)), - sum_p=models.Sum("value", filter=models.Q(value__gt=0)), - ) - .order_by("-sum") - ) - context["cat_lim"] = max( - map( - abs, - context["categories"] - .aggregate( - max=models.Max("sum_p"), - min=models.Min("sum_m"), + if _snapshot.transactions: + context["categories"] = ( + _snapshot.transactions.values("category", "category__name", "category__icon") + .annotate( + sum=models.Sum("value"), + sum_m=models.Sum("value", filter=models.Q(value__lt=0)), + sum_p=models.Sum("value", filter=models.Q(value__gt=0)), ) - .values(), + .order_by("-sum") ) - ) - context["cat_lim_m"] = -context["cat_lim"] + context["cat_lim"] = max( + map( + abs, + context["categories"] + .aggregate( + max=models.Max("sum_p"), + min=models.Min("sum_m"), + ) + .values(), + ) + ) + context["cat_lim_m"] = -context["cat_lim"] return render( request, "main/snapshot.html", From 5850aa95c342f59e05d641c781db4507233a6ebf Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 24 May 2022 20:52:40 +0200 Subject: [PATCH 052/507] Update form style --- nummi/main/static/main/css/form.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nummi/main/static/main/css/form.css b/nummi/main/static/main/css/form.css index 854d98d..f5be716 100644 --- a/nummi/main/static/main/css/form.css +++ b/nummi/main/static/main/css/form.css @@ -10,7 +10,7 @@ form ul.errorlist { grid-column: 1 / -1; color: var(--red); font-weight: 550; - list-style-type: "! "; + list-style-type: "! "; margin: 0; } @@ -36,7 +36,8 @@ form > input[type="text"], form > input[type="number"], form > textarea { border: none; - border-bottom: 1px solid var(--text); + border-radius: var(--radius); + background: var(--bg-01); } form > .buttons { From 7269fcbc6b282a83f7bbf8f8087448c61267483f Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 24 May 2022 20:53:44 +0200 Subject: [PATCH 053/507] Add empty alt text to logo --- nummi/main/templates/main/base.html | 2 +- nummi/main/templates/main/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index b39d20b..a4c33ab 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -20,7 +20,7 @@
{% endspaceless %} diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index f9ee58c..e6f4fef 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -1,6 +1,7 @@ {% extends "main/base.html" %} {% load static %} {% load main_extras %} +{% load i18n %} {% block link %} {{ block.super }} @@ -18,7 +19,7 @@ {% if transactions %} -

Transactions

+

{% translate "Transactions" %}

{% transaction_table transactions %} {% endif %} {% endblock %} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index c608a41..b618b94 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -1,6 +1,7 @@ {% extends "main/base.html" %} {% load static %} {% load main_extras %} +{% load i18n %} {% block link %} {{ block.super }} @@ -12,19 +13,19 @@

Nummi

{% if transactions %} -

Transactions

+

{% translate "Transactions" %}

{% transaction_table transactions %} {% endif %} {% if snapshots %} -

Relevés

+

{% translate "Snapshots" %}

- Date - Valeur - Différence - Transactions - Valide + {% translate "Date" %} + {% translate "Value" %} + {% translate "Difference" %} + {% translate "Transactions" %} + {% translate "Valid" %}
{% for snap in snapshots %}
@@ -55,7 +56,7 @@ {% endif %} {% if categories %} -

Catégories

+

{% translate "Categories" %}

{% for cat in categories %} {{ cat }} diff --git a/nummi/main/templates/main/login.html b/nummi/main/templates/main/login.html index 16454cd..b76b4a6 100644 --- a/nummi/main/templates/main/login.html +++ b/nummi/main/templates/main/login.html @@ -1,5 +1,6 @@ {% extends "main/base.html" %} {% load static %} +{% load i18n %} {% block link %} {{ block.super }} @@ -8,7 +9,7 @@ {% block body %} -

Login

+

{% translate "Log In" %}

{% csrf_token %} diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index 4bfb42d..4458f25 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -1,6 +1,7 @@ {% extends "main/base.html" %} {% load static %} {% load main_extras %} +{% load i18n %} {% block link %} {{ block.super }} @@ -29,7 +30,7 @@
{% if categories %} -

Plot

+

{% translate "Categories" %}

{% for cat in categories %}
@@ -83,7 +84,7 @@ {% endif %} {% if snapshot.transactions %} -

Transactions ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

+

{% translate "Transactions" %} ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

{% transaction_table snapshot.transactions %} {% endif %} diff --git a/nummi/main/templates/main/tag/form_buttons.html b/nummi/main/templates/main/tag/form_buttons.html index 95aaefd..f682b39 100644 --- a/nummi/main/templates/main/tag/form_buttons.html +++ b/nummi/main/templates/main/tag/form_buttons.html @@ -1,13 +1,15 @@ +{% load i18n %}
{% if not adding %} + {% translate "Delete" as del %} - Delete + {{ del }} {% endif %} - +
diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html index 9dd3cf5..d4a0622 100644 --- a/nummi/main/templates/main/tag/transaction_table.html +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -1,13 +1,14 @@ {% load main_extras %} +{% load i18n %}
- Date - Nom - Valeur - Commerçant - Catégorie - Description + {% translate "Date" %} + {% translate "Name" %} + {% translate "Value" %} + {% translate "Trader" %} + {% translate "Category" %} + {% translate "Description" %}
{% for trans in transactions %}
diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index 1b648e0..f38859f 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -1,6 +1,7 @@ {% extends "main/base.html" %} {% load static %} {% load main_extras %} +{% load i18n %} {% block link %} {{ block.super }} @@ -19,7 +20,7 @@ {% endspaceless %} -

Invoices

+

{% translate "Invoices" %}

{% for inv in invoices %}
diff --git a/nummi/main/templates/main/transactions.html b/nummi/main/templates/main/transactions.html index 0b51203..3293675 100644 --- a/nummi/main/templates/main/transactions.html +++ b/nummi/main/templates/main/transactions.html @@ -1,6 +1,7 @@ {% extends "main/base.html" %} {% load static %} {% load main_extras %} +{% load i18n %} {% block link %} {{ block.super }} @@ -9,7 +10,7 @@ {% endblock %} {% block body %} -

Transactions

+

{% translate "Transactions" %}

{% transaction_table transactions %} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index f38859f..b9666e8 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -26,18 +26,18 @@ {% endfor %}
-

Add Invoice

+

{% translate "Add invoice" %}

{% csrf_token %} {{ invoice_form }} -
+
{% endblock %} diff --git a/nummi/main/templatetags/main_extras.py b/nummi/main/templatetags/main_extras.py index c390711..22c2d3c 100644 --- a/nummi/main/templatetags/main_extras.py +++ b/nummi/main/templatetags/main_extras.py @@ -39,6 +39,5 @@ def form_buttons(instance): return { "instance": instance, "adding": instance._state.adding, - "name": instance.__class__.__name__, "del_url": f"del_{instance.__class__.__name__.lower()}", } From b844947cfdbb97712084afaa655cc0ec04f6db8d Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 11:42:48 +0100 Subject: [PATCH 066/507] Updated text and improved button contrast --- nummi/main/locale/fr/LC_MESSAGES/django.po | 36 +++++++++---------- nummi/main/models.py | 14 +++----- nummi/main/static/main/css/form.css | 10 +++--- nummi/main/static/main/css/main.css | 2 +- .../main/templates/main/tag/form_buttons.html | 2 +- 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index 2bf26d3..5d16edb 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-19 11:17+0100\n" +"POT-Creation-Date: 2022-12-19 11:42+0100\n" "PO-Revision-Date: 2022-05-30 19:00+0200\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -17,79 +17,79 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: .\main\models.py:13 .\main\models.py:22 .\main\models.py:56 +#: .\main\models.py:12 .\main\models.py:21 .\main\models.py:55 #: .\main\templates\main\tag\transaction_table.html:10 msgid "Category" msgstr "Catégorie" -#: .\main\models.py:13 .\main\models.py:37 .\main\models.py:91 +#: .\main\models.py:12 .\main\models.py:36 .\main\models.py:87 #: .\main\templates\main\tag\transaction_table.html:7 msgid "Name" msgstr "Nom" -#: .\main\models.py:15 +#: .\main\models.py:14 msgid "Icon" msgstr "Icône" -#: .\main\models.py:23 .\main\templates\main\index.html:57 +#: .\main\models.py:22 .\main\templates\main\index.html:57 #: .\main\templates\main\snapshot.html:33 msgid "Categories" msgstr "Catégories" -#: .\main\models.py:37 .\main\models.py:67 +#: .\main\models.py:36 .\main\models.py:63 msgid "Transaction" msgstr "Transaction" -#: .\main\models.py:39 .\main\templates\main\tag\transaction_table.html:11 +#: .\main\models.py:38 .\main\templates\main\tag\transaction_table.html:11 msgid "Description" msgstr "Description" -#: .\main\models.py:41 .\main\models.py:125 .\main\templates\main\index.html:23 +#: .\main\models.py:40 .\main\models.py:121 .\main\templates\main\index.html:23 #: .\main\templates\main\tag\transaction_table.html:8 msgid "Value" msgstr "Valeur" -#: .\main\models.py:43 .\main\models.py:123 .\main\templates\main\index.html:22 +#: .\main\models.py:42 .\main\models.py:119 .\main\templates\main\index.html:22 #: .\main\templates\main\tag\transaction_table.html:6 msgid "Date" msgstr "Date" -#: .\main\models.py:44 +#: .\main\models.py:43 msgid "Real date" msgstr "Date réelle" -#: .\main\models.py:46 .\main\templates\main\tag\transaction_table.html:9 +#: .\main\models.py:45 .\main\templates\main\tag\transaction_table.html:9 msgid "Trader" msgstr "Commerçant" -#: .\main\models.py:49 +#: .\main\models.py:48 msgid "Payment" msgstr "Paiement" -#: .\main\models.py:68 .\main\templates\main\base.html:30 +#: .\main\models.py:64 .\main\templates\main\base.html:30 #: .\main\templates\main\category.html:22 .\main\templates\main\index.html:14 #: .\main\templates\main\index.html:25 .\main\templates\main\snapshot.html:87 #: .\main\templates\main\transactions.html:13 msgid "Transactions" msgstr "Transactions" -#: .\main\models.py:91 .\main\models.py:108 +#: .\main\models.py:87 .\main\models.py:104 msgid "Invoice" msgstr "Facture" -#: .\main\models.py:96 +#: .\main\models.py:92 msgid "File" msgstr "Fichier" -#: .\main\models.py:109 .\main\templates\main\transaction.html:23 +#: .\main\models.py:105 .\main\templates\main\transaction.html:23 msgid "Invoices" msgstr "Factures" -#: .\main\models.py:217 +#: .\main\models.py:211 msgid "Snapshot" msgstr "Relevé" -#: .\main\models.py:218 .\main\templates\main\index.html:19 +#: .\main\models.py:212 .\main\templates\main\index.html:19 msgid "Snapshots" msgstr "Relevés" diff --git a/nummi/main/models.py b/nummi/main/models.py index b8f93a3..d23b8e7 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -3,8 +3,7 @@ import uuid from django.db import models from django.forms import ModelForm from django.core.validators import FileExtensionValidator -from django.utils.text import lazy -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext as _ class Category(models.Model): @@ -15,7 +14,7 @@ class Category(models.Model): icon = models.CharField(max_length=64, default="folder", verbose_name=_("Icon")) def __str__(self): - return str(self.name) + return self.name class Meta: ordering = ["name"] @@ -57,10 +56,7 @@ class Transaction(models.Model): ) def __str__(self): - res = f"{self.date} {self.name}: {self.value}€" - if self.category: - return f"{res} ({self.category})" - return res + return f"{self.date} – {self.name}" class Meta: ordering = ["-date"] @@ -132,9 +128,7 @@ class Snapshot(models.Model): ) def __str__(self): - if self.previous is None: - return f"Snapshot {self.date}: {self.value}€" - return f"Snapshot {self.date}: {self.value}€ (Previous: {self.previous.date})" + return f"{_('Snapshot')} {self.date}" def save(self, *args, only_super=False, **kwargs): if not only_super: diff --git a/nummi/main/static/main/css/form.css b/nummi/main/static/main/css/form.css index 3b69adb..0ad5bbf 100644 --- a/nummi/main/static/main/css/form.css +++ b/nummi/main/static/main/css/form.css @@ -21,6 +21,10 @@ form a { padding: 0 var(--gap); } +form input { + color: inherit; +} + form > label, form > input[type="text"], form > input[type="number"], @@ -66,11 +70,7 @@ form > .buttons > *:hover { text-decoration: underline; } form > .buttons input[type="submit"] { - background: var(--green); - color: var(--text-inv); -} -form > .buttons input[type="reset"] { - color: var(--red); + background: var(--green-1); } form > .buttons a.del { background: var(--red); diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 3668f6f..053a0a1 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -30,7 +30,7 @@ --green: var(--theme-0); --red-1: var(--theme-4); - --green-1: var(--theme-1); + --green-1: var(--theme); --border: .5em; --radius: .25em; diff --git a/nummi/main/templates/main/tag/form_buttons.html b/nummi/main/templates/main/tag/form_buttons.html index 2d592e2..86cf785 100644 --- a/nummi/main/templates/main/tag/form_buttons.html +++ b/nummi/main/templates/main/tag/form_buttons.html @@ -4,7 +4,7 @@ {% translate "Delete" as del %} {{ del }} From 0e2fd6e74f7c79dfc93b39fae10ae49a86b9add4 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 11:57:16 +0100 Subject: [PATCH 067/507] Update style, fix contrast issues --- nummi/main/static/main/css/main.css | 15 ++++++++------- nummi/main/static/main/css/table.css | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 053a0a1..9bf03dc 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -5,12 +5,12 @@ } :root { - --theme: #33cc66; - --theme-0: #138037; - --theme-1: #59ff91; + --theme: #66cc66; + --theme-0: #338033; + --theme-1: #99ff99; --theme-2: var(--theme); - --theme-3: #800a06; - --theme-4: #cc3733; + --theme-3: #802653; + --theme-4: #cc6699; --text-theme: var(--text); @@ -22,7 +22,8 @@ --bg-01: #f0f0f0; - --text-link: var(--theme-0); + --text-green: #296629; + --text-link: var(--text-green); --gap: 1rem; @@ -60,4 +61,4 @@ a:hover { } .red {color: var(--red)} -.green {color: var(--green)} +.green {color: var(--text-green)} diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index 7fde49e..e649e9a 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -38,6 +38,7 @@ } .table > div > span.value { filter: brightness(95%); + font-weight: 600; } .table > div > span.text { From a7e3f92469e400c4363ba1425623a9d77362e68d Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 12:03:37 +0100 Subject: [PATCH 068/507] Add form errors --- nummi/main/templates/main/form.html | 7 +++++++ nummi/main/templates/main/login.html | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/nummi/main/templates/main/form.html b/nummi/main/templates/main/form.html index 4f7354b..6ea161d 100644 --- a/nummi/main/templates/main/form.html +++ b/nummi/main/templates/main/form.html @@ -1,3 +1,10 @@ +{% if form.non_field_errors %} +
    + {% for error in form.non_field_errors %} +
  • {{ error }}
  • + {% endfor %} +
+{% endif %} {% for field in form %} {{ field.errors }} diff --git a/nummi/main/templates/main/login.html b/nummi/main/templates/main/login.html index 0571400..3a44ede 100644 --- a/nummi/main/templates/main/login.html +++ b/nummi/main/templates/main/login.html @@ -13,6 +13,13 @@
{% csrf_token %} + {% if form.non_field_errors %} +
    + {% for error in form.non_field_errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} {% for field in form %} {{ field.errors }} From 3cf3cb649ec1bd74d588998dc4655f86ffe38452 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 12:09:02 +0100 Subject: [PATCH 069/507] Default to fr-fr --- nummi/nummi/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index d143ba1..264396e 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -21,4 +21,5 @@ from django.views.generic.base import RedirectView urlpatterns = i18n_patterns( path("", include("main.urls")), path("admin/", admin.site.urls), + prefix_default_language=False, ) From e095d8d35f508575a894a4897ad40a98039c53e4 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 14:18:25 +0100 Subject: [PATCH 070/507] Add first plot --- nummi/main/models.py | 20 +++++++++++++++- nummi/nummi/urls.py | 1 + nummi/plot/__init__.py | 0 nummi/plot/admin.py | 3 +++ nummi/plot/apps.py | 6 +++++ nummi/plot/migrations/__init__.py | 0 nummi/plot/models.py | 3 +++ nummi/plot/nummi.mplstyle | 13 ++++++++++ nummi/plot/tests.py | 3 +++ nummi/plot/urls.py | 7 ++++++ nummi/plot/views.py | 40 +++++++++++++++++++++++++++++++ 11 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 nummi/plot/__init__.py create mode 100644 nummi/plot/admin.py create mode 100644 nummi/plot/apps.py create mode 100644 nummi/plot/migrations/__init__.py create mode 100644 nummi/plot/models.py create mode 100644 nummi/plot/nummi.mplstyle create mode 100644 nummi/plot/tests.py create mode 100644 nummi/plot/urls.py create mode 100644 nummi/plot/views.py diff --git a/nummi/main/models.py b/nummi/main/models.py index d23b8e7..7af054c 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -194,7 +194,7 @@ class Snapshot(models.Model): @property def sum(self): if self.previous is None: - return None + return 0 trans = self.transactions.aggregate(sum=models.Sum("value")) return trans["sum"] or 0 @@ -206,6 +206,24 @@ class Snapshot(models.Model): date__lte=self.date, date__gt=self.previous.date ) + @property + def pos(self): + return ( + self.transactions.filter(value__gt=0).aggregate(sum=models.Sum("value"))[ + "sum" + ] + or 0 + ) + + @property + def neg(self): + return ( + self.transactions.filter(value__lt=0).aggregate(sum=models.Sum("value"))[ + "sum" + ] + or 0 + ) + class Meta: ordering = ["-date"] verbose_name = _("Snapshot") diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 264396e..37a7a5e 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -20,6 +20,7 @@ from django.views.generic.base import RedirectView urlpatterns = i18n_patterns( path("", include("main.urls")), + path("plot/", include("plot.urls")), path("admin/", admin.site.urls), prefix_default_language=False, ) diff --git a/nummi/plot/__init__.py b/nummi/plot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nummi/plot/admin.py b/nummi/plot/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/nummi/plot/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/nummi/plot/apps.py b/nummi/plot/apps.py new file mode 100644 index 0000000..1f7a601 --- /dev/null +++ b/nummi/plot/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PlotConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "plot" diff --git a/nummi/plot/migrations/__init__.py b/nummi/plot/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nummi/plot/models.py b/nummi/plot/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/nummi/plot/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/nummi/plot/nummi.mplstyle b/nummi/plot/nummi.mplstyle new file mode 100644 index 0000000..5fd1a08b --- /dev/null +++ b/nummi/plot/nummi.mplstyle @@ -0,0 +1,13 @@ +font.family: Inter + +lines.linewidth: 2 + +figure.autolayout: True +figure.figsize: 8, 4 +figure.dpi: 300 + +axes.prop_cycle: cycler('color', ["66cc66", "#338033", "#99ff99", "#802653", "#cc6699"]) +axes.xmargin: 0 +axes.grid: True + +svg.fonttype: none diff --git a/nummi/plot/tests.py b/nummi/plot/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/nummi/plot/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/nummi/plot/urls.py b/nummi/plot/urls.py new file mode 100644 index 0000000..dde7b92 --- /dev/null +++ b/nummi/plot/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("timeline", views.timeline, name="timeline"), +] diff --git a/nummi/plot/views.py b/nummi/plot/views.py new file mode 100644 index 0000000..fe417d8 --- /dev/null +++ b/nummi/plot/views.py @@ -0,0 +1,40 @@ +import io + +import matplotlib +import matplotlib.pyplot as plt +from matplotlib import dates as mdates +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse +from django.utils.translation import gettext as _ + +from main.models import ( + Transaction, + Invoice, + Category, + Snapshot, +) + + +matplotlib.use("Agg") +plt.style.use("./plot/nummi.mplstyle") + + +@login_required +def timeline(request): + _snapshots = Snapshot.objects.all() + + fig, ax = plt.subplots() + ax.step( + [s.date for s in _snapshots], + [s.value for s in _snapshots], + where="post", + ) + ax.set(ylabel=_("Snapshots"), ylim=0) + ax.xaxis.set_major_formatter( + mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()) + ) + _io = io.StringIO() + + fig.savefig(_io, format="svg") + + return HttpResponse(_io.getvalue(), headers={"Content-Type": "image/svg+xml"}) From 19490e62b2461aa7c111b9890c2d0cc544d37ba6 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 19 Dec 2022 14:36:02 +0100 Subject: [PATCH 071/507] Add category plot --- nummi/plot/nummi.mplstyle | 2 +- nummi/plot/urls.py | 1 + nummi/plot/views.py | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/nummi/plot/nummi.mplstyle b/nummi/plot/nummi.mplstyle index 5fd1a08b..90249c4 100644 --- a/nummi/plot/nummi.mplstyle +++ b/nummi/plot/nummi.mplstyle @@ -7,7 +7,7 @@ figure.figsize: 8, 4 figure.dpi: 300 axes.prop_cycle: cycler('color', ["66cc66", "#338033", "#99ff99", "#802653", "#cc6699"]) -axes.xmargin: 0 +axes.axisbelow: True axes.grid: True svg.fonttype: none diff --git a/nummi/plot/urls.py b/nummi/plot/urls.py index dde7b92..fbff014 100644 --- a/nummi/plot/urls.py +++ b/nummi/plot/urls.py @@ -4,4 +4,5 @@ from . import views urlpatterns = [ path("timeline", views.timeline, name="timeline"), + path("categories", views.categories, name="categories"), ] diff --git a/nummi/plot/views.py b/nummi/plot/views.py index fe417d8..781ab89 100644 --- a/nummi/plot/views.py +++ b/nummi/plot/views.py @@ -3,6 +3,7 @@ import io import matplotlib import matplotlib.pyplot as plt from matplotlib import dates as mdates +from django.db import models from django.contrib.auth.decorators import login_required from django.http import HttpResponse from django.utils.translation import gettext as _ @@ -33,6 +34,30 @@ def timeline(request): ax.xaxis.set_major_formatter( mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()) ) + ax.autoscale(True, "x", True) + + _io = io.StringIO() + + fig.savefig(_io, format="svg") + + return HttpResponse(_io.getvalue(), headers={"Content-Type": "image/svg+xml"}) + + +@login_required +def categories(request): + _categories = Category.objects.all() + + fig, ax = plt.subplots(figsize=(8, _categories.count() / 4)) + ax.barh( + [str(c) for c in _categories][::-1], + [ + Transaction.objects.filter(category=c).aggregate(sum=models.Sum("value"))[ + "sum" + ] + for c in _categories + ][::-1], + ) + _io = io.StringIO() fig.savefig(_io, format="svg") From 396ef9ead503fbc555b48e8178265d12c3de0761 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 15:28:56 +0100 Subject: [PATCH 072/507] Add budget option to categories --- nummi/main/locale/fr/LC_MESSAGES/django.mo | Bin 1482 -> 1528 bytes nummi/main/locale/fr/LC_MESSAGES/django.po | 78 +++++----- ..._options_alter_invoice_options_and_more.py | 145 ++++++++++++++++++ nummi/main/models.py | 3 +- 4 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.mo b/nummi/main/locale/fr/LC_MESSAGES/django.mo index 02531fd1224b79414f0cf1976c2c537633a2c718..5321cee3ec8d7423be93168810f670ca51765c59 100644 GIT binary patch delta 706 zcmXxiKP&@b7{~GF+H?LCt=4~)7)cD>7$oSzXfd#fHqxOi7$kC?%t$(!Y~5?q#UR8Y z5-SE4jirl-$@h2OzUlLR-n;j`=Y8J0J|un;;cMEj8f}uu6250PgI}n28Z(RI878ob z0bXJc*02lf=wrjp-=Nmtqt-pU`8VeWcAACu$v_EOsKmc+fyb`BTnEk!Cb^zM9<&^G z<2-8PJSxwMyT69Yw}~ob3ze^o9e5NOnpGGqaoQ79;ybcs@DY{Z9hIPoI>|TkGmk7P zAVAHhoLN+!Y1H#McRhzHa1m9=D#qF0)){ES4b%zCIEcrn2hLFsT%b0pp*Fa3^9^_Z z*7<~5|AH!@>1?6Cs^(IJiVw%>CWs-T-3HnNR3Utk=>O4&DnS1ewXuJqqRAaKy%}C) zwDAb`6FOX)P|<37i#ix>HtL7zN28JJmJ0(7_j&K`ectDNd%nU}n7ovNx+6v{e{qa__P7vRzH=S8jUnz} zH|}E>9%6uX?8Fn)yff6iD|>%q-eQ*LcSwEWS`1X!wh2$z!~LuIfd%frQH42nlfwwr zxPsb9)t*nF)|*0YWE!>J0%mZ@T*f&sac+fy7CvRQKDl2tiyA+o-oKfj zsQMpNW1lYRMo}A!P#Y*Ct=u@O&mK1<@BIN!%Q2|{ diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index 5d16edb..2c29bb8 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-19 11:42+0100\n" +"POT-Creation-Date: 2022-12-20 15:28+0100\n" "PO-Revision-Date: 2022-05-30 19:00+0200\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -17,119 +17,123 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: .\main\models.py:12 .\main\models.py:21 .\main\models.py:55 -#: .\main\templates\main\tag\transaction_table.html:10 +#: .\models.py:12 .\models.py:22 .\models.py:56 +#: .\templates\main\tag\transaction_table.html:10 msgid "Category" msgstr "Catégorie" -#: .\main\models.py:12 .\main\models.py:36 .\main\models.py:87 -#: .\main\templates\main\tag\transaction_table.html:7 +#: .\models.py:12 .\models.py:37 .\models.py:88 +#: .\templates\main\tag\transaction_table.html:7 msgid "Name" msgstr "Nom" -#: .\main\models.py:14 +#: .\models.py:14 msgid "Icon" msgstr "Icône" -#: .\main\models.py:22 .\main\templates\main\index.html:57 -#: .\main\templates\main\snapshot.html:33 +#: .\models.py:15 +msgid "Budget" +msgstr "Budget" + +#: .\models.py:23 .\templates\main\index.html:57 +#: .\templates\main\snapshot.html:33 msgid "Categories" msgstr "Catégories" -#: .\main\models.py:36 .\main\models.py:63 +#: .\models.py:37 .\models.py:64 msgid "Transaction" msgstr "Transaction" -#: .\main\models.py:38 .\main\templates\main\tag\transaction_table.html:11 +#: .\models.py:39 .\templates\main\tag\transaction_table.html:11 msgid "Description" msgstr "Description" -#: .\main\models.py:40 .\main\models.py:121 .\main\templates\main\index.html:23 -#: .\main\templates\main\tag\transaction_table.html:8 +#: .\models.py:41 .\models.py:122 .\templates\main\index.html:23 +#: .\templates\main\tag\transaction_table.html:8 msgid "Value" msgstr "Valeur" -#: .\main\models.py:42 .\main\models.py:119 .\main\templates\main\index.html:22 -#: .\main\templates\main\tag\transaction_table.html:6 +#: .\models.py:43 .\models.py:120 .\templates\main\index.html:22 +#: .\templates\main\tag\transaction_table.html:6 msgid "Date" msgstr "Date" -#: .\main\models.py:43 +#: .\models.py:44 msgid "Real date" msgstr "Date réelle" -#: .\main\models.py:45 .\main\templates\main\tag\transaction_table.html:9 +#: .\models.py:46 .\templates\main\tag\transaction_table.html:9 msgid "Trader" msgstr "Commerçant" -#: .\main\models.py:48 +#: .\models.py:49 msgid "Payment" msgstr "Paiement" -#: .\main\models.py:64 .\main\templates\main\base.html:30 -#: .\main\templates\main\category.html:22 .\main\templates\main\index.html:14 -#: .\main\templates\main\index.html:25 .\main\templates\main\snapshot.html:87 -#: .\main\templates\main\transactions.html:13 +#: .\models.py:65 .\templates\main\base.html:30 +#: .\templates\main\category.html:22 .\templates\main\index.html:14 +#: .\templates\main\index.html:25 .\templates\main\snapshot.html:87 +#: .\templates\main\transactions.html:13 msgid "Transactions" msgstr "Transactions" -#: .\main\models.py:87 .\main\models.py:104 +#: .\models.py:88 .\models.py:105 msgid "Invoice" msgstr "Facture" -#: .\main\models.py:92 +#: .\models.py:93 msgid "File" msgstr "Fichier" -#: .\main\models.py:105 .\main\templates\main\transaction.html:23 +#: .\models.py:106 .\templates\main\transaction.html:23 msgid "Invoices" msgstr "Factures" -#: .\main\models.py:211 +#: .\models.py:230 msgid "Snapshot" msgstr "Relevé" -#: .\main\models.py:212 .\main\templates\main\index.html:19 +#: .\models.py:231 .\templates\main\index.html:19 msgid "Snapshots" msgstr "Relevés" -#: .\main\templates\main\base.html:35 +#: .\templates\main\base.html:35 msgid "New transaction" msgstr "Nouvelle transaction" -#: .\main\templates\main\base.html:40 +#: .\templates\main\base.html:40 msgid "New category" msgstr "Nouvelle catégorie" -#: .\main\templates\main\base.html:45 +#: .\templates\main\base.html:45 msgid "New snapshot" msgstr "Nouveau relevé" -#: .\main\templates\main\index.html:24 +#: .\templates\main\index.html:24 msgid "Difference" msgstr "Différence" -#: .\main\templates\main\index.html:26 +#: .\templates\main\index.html:26 msgid "Valid" msgstr "Valide" -#: .\main\templates\main\login.html:12 .\main\templates\main\login.html:24 +#: .\templates\main\login.html:12 .\templates\main\login.html:31 msgid "Log In" msgstr "Se connecter" -#: .\main\templates\main\tag\form_buttons.html:4 -#: .\main\templates\main\transaction.html:29 +#: .\templates\main\tag\form_buttons.html:4 +#: .\templates\main\transaction.html:29 msgid "Delete" msgstr "Supprimer" -#: .\main\templates\main\tag\form_buttons.html:14 +#: .\templates\main\tag\form_buttons.html:14 msgid "Save" msgstr "Enregistrer" -#: .\main\templates\main\transaction.html:36 +#: .\templates\main\transaction.html:36 msgid "Add invoice" msgstr "Ajouter une facture" -#: .\main\templates\main\transaction.html:41 +#: .\templates\main\transaction.html:41 msgid "Add" msgstr "Ajouter" diff --git a/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py b/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py new file mode 100644 index 0000000..4a7ec37 --- /dev/null +++ b/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py @@ -0,0 +1,145 @@ +# Generated by Django 4.1.4 on 2022-12-20 14:26 + +import datetime +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0005_alter_category_name"), + ] + + operations = [ + migrations.AlterModelOptions( + name="category", + options={ + "ordering": ["name"], + "verbose_name": "Catégorie", + "verbose_name_plural": "Catégories", + }, + ), + migrations.AlterModelOptions( + name="invoice", + options={"verbose_name": "Facture", "verbose_name_plural": "Factures"}, + ), + migrations.AlterModelOptions( + name="snapshot", + options={ + "ordering": ["-date"], + "verbose_name": "Relevé", + "verbose_name_plural": "Relevés", + }, + ), + migrations.AlterModelOptions( + name="transaction", + options={ + "ordering": ["-date"], + "verbose_name": "Transaction", + "verbose_name_plural": "Transactions", + }, + ), + migrations.AddField( + model_name="category", + name="budget", + field=models.BooleanField(default=True, verbose_name="Budget"), + ), + migrations.AlterField( + model_name="category", + name="icon", + field=models.CharField( + default="folder", max_length=64, verbose_name="Icône" + ), + ), + migrations.AlterField( + model_name="category", + name="name", + field=models.CharField( + default="Catégorie", max_length=64, verbose_name="Nom" + ), + ), + migrations.AlterField( + model_name="invoice", + name="file", + field=models.FileField( + upload_to="invoices/", + validators=[django.core.validators.FileExtensionValidator(["pdf"])], + verbose_name="Fichier", + ), + ), + migrations.AlterField( + model_name="invoice", + name="name", + field=models.CharField( + default="Facture", max_length=256, verbose_name="Nom" + ), + ), + migrations.AlterField( + model_name="snapshot", + name="date", + field=models.DateField(unique=True, verbose_name="Date"), + ), + migrations.AlterField( + model_name="snapshot", + name="value", + field=models.DecimalField( + decimal_places=2, default=0, max_digits=12, verbose_name="Valeur" + ), + ), + migrations.AlterField( + model_name="transaction", + name="category", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="main.category", + verbose_name="Catégorie", + ), + ), + migrations.AlterField( + model_name="transaction", + name="date", + field=models.DateField(default=datetime.date.today, verbose_name="Date"), + ), + migrations.AlterField( + model_name="transaction", + name="description", + field=models.TextField(blank=True, null=True, verbose_name="Description"), + ), + migrations.AlterField( + model_name="transaction", + name="name", + field=models.CharField( + default="Transaction", max_length=256, verbose_name="Nom" + ), + ), + migrations.AlterField( + model_name="transaction", + name="payment", + field=models.CharField( + blank=True, max_length=128, null=True, verbose_name="Paiement" + ), + ), + migrations.AlterField( + model_name="transaction", + name="real_date", + field=models.DateField(blank=True, null=True, verbose_name="Date réelle"), + ), + migrations.AlterField( + model_name="transaction", + name="trader", + field=models.CharField( + blank=True, max_length=128, null=True, verbose_name="Commerçant" + ), + ), + migrations.AlterField( + model_name="transaction", + name="value", + field=models.DecimalField( + decimal_places=2, default=0, max_digits=12, verbose_name="Valeur" + ), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 7af054c..3e777e4 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -12,6 +12,7 @@ class Category(models.Model): max_length=64, default=_("Category"), verbose_name=_("Name") ) icon = models.CharField(max_length=64, default="folder", verbose_name=_("Icon")) + budget = models.BooleanField(default=True, verbose_name=_("Budget")) def __str__(self): return self.name @@ -27,7 +28,7 @@ class CategoryForm(ModelForm): class Meta: model = Category - fields = ["name", "icon"] + fields = ["name", "icon", "budget"] class Transaction(models.Model): From 60bdff43e7b602ba498dd27a1cb77ccc934157b9 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 15:32:34 +0100 Subject: [PATCH 073/507] Remove non-budget categories for plot --- nummi/plot/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/plot/views.py b/nummi/plot/views.py index 781ab89..e01aecb 100644 --- a/nummi/plot/views.py +++ b/nummi/plot/views.py @@ -45,7 +45,7 @@ def timeline(request): @login_required def categories(request): - _categories = Category.objects.all() + _categories = Category.objects.filter(budget=True) fig, ax = plt.subplots(figsize=(8, _categories.count() / 4)) ax.barh( From d88ba218699bc88a38a47fb3b77e632ea9d8c89e Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 15:45:23 +0100 Subject: [PATCH 074/507] Update style for checkbox compatibility --- nummi/main/static/main/css/form.css | 32 ++++++++++++++++------------- nummi/main/templates/main/form.html | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/nummi/main/static/main/css/form.css b/nummi/main/static/main/css/form.css index 0ad5bbf..28ff0f3 100644 --- a/nummi/main/static/main/css/form.css +++ b/nummi/main/static/main/css/form.css @@ -26,22 +26,28 @@ form input { } form > label, -form > input[type="text"], -form > input[type="number"], -form > input[type="password"], -form > select { +form > div > input[type="text"], +form > div > input[type="number"], +form > div > input[type="password"], +form > div > input[type="file"], +form > div > select, +form > div > textarea, +form > div > select { font-size: inherit; line-height: inherit; font-family: inherit; + height: 100%; + width: 100%; } -form > textarea { - font-size: inherit; - font-family: inherit; +form > div > textarea { + line-height: initial; } -form > input[type="text"], -form > input[type="number"], -form > input[type="password"], -form > textarea { +form > div > input[type="text"], +form > div > input[type="number"], +form > div > input[type="password"], +form > div > input[type="file"], +form > div > textarea, +form > div > select { border: none; border-radius: var(--radius); background: var(--bg-01); @@ -51,9 +57,7 @@ form > .buttons { grid-column: 1 / -1; text-align: right; } -form > .buttons > *, -form select, -form input[type="file"] { +form > .buttons > * { font-size: inherit; line-height: inherit; font-family: inherit; diff --git a/nummi/main/templates/main/form.html b/nummi/main/templates/main/form.html index 6ea161d..e69f304 100644 --- a/nummi/main/templates/main/form.html +++ b/nummi/main/templates/main/form.html @@ -8,5 +8,5 @@ {% for field in form %} {{ field.errors }} -{{ field }} +
{{ field }}
{% endfor %} From bbcaf1c1d333a3e5e932b4ab7b551af7b806a5e9 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 16:14:06 +0100 Subject: [PATCH 075/507] Add timeline per category --- nummi/plot/urls.py | 1 + nummi/plot/views.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/nummi/plot/urls.py b/nummi/plot/urls.py index fbff014..9a07e4e 100644 --- a/nummi/plot/urls.py +++ b/nummi/plot/urls.py @@ -5,4 +5,5 @@ from . import views urlpatterns = [ path("timeline", views.timeline, name="timeline"), path("categories", views.categories, name="categories"), + path("category/", views.category, name="category"), ] diff --git a/nummi/plot/views.py b/nummi/plot/views.py index e01aecb..5abc4d5 100644 --- a/nummi/plot/views.py +++ b/nummi/plot/views.py @@ -5,6 +5,7 @@ import matplotlib.pyplot as plt from matplotlib import dates as mdates from django.db import models from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404 from django.http import HttpResponse from django.utils.translation import gettext as _ @@ -63,3 +64,35 @@ def categories(request): fig.savefig(_io, format="svg") return HttpResponse(_io.getvalue(), headers={"Content-Type": "image/svg+xml"}) + + +@login_required +def category(request, uuid): + _category = get_object_or_404(Category, id=uuid) + _values = ( + Transaction.objects.filter(category=_category) + .annotate(m=models.functions.TruncMonth("date")) + .values("m") + .annotate(sum=models.Sum("value")) + .order_by("m") + ) + + fig, ax = plt.subplots() + ax.step( + [v["m"] for v in _values], + [v["sum"] for v in _values], + where="post", + ) + ax.xaxis.set_major_formatter( + mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()) + ) + ax.autoscale(True, "x", True) + _ym, _yp = ax.get_ylim() + ax.set(ylim=(min(_ym, 0), max(_yp, 0))) + ax.set(ylabel=f"{_category.name} (€)") + + _io = io.StringIO() + + fig.savefig(_io, format="svg") + + return HttpResponse(_io.getvalue(), headers={"Content-Type": "image/svg+xml"}) From d04fc756d4fd27e5b2bd98c27a81387469b0de63 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 16:20:44 +0100 Subject: [PATCH 076/507] Add timeline graph to category page --- nummi/main/templates/main/category.html | 2 ++ nummi/plot/urls.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index e6f4fef..0e54c24 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -18,6 +18,8 @@ {% form_buttons category %} +Graph representing value over time + {% if transactions %}

{% translate "Transactions" %}

{% transaction_table transactions %} diff --git a/nummi/plot/urls.py b/nummi/plot/urls.py index 9a07e4e..1412ba8 100644 --- a/nummi/plot/urls.py +++ b/nummi/plot/urls.py @@ -3,7 +3,7 @@ from django.urls import path from . import views urlpatterns = [ - path("timeline", views.timeline, name="timeline"), - path("categories", views.categories, name="categories"), - path("category/", views.category, name="category"), + path("timeline", views.timeline, name="plot-timeline"), + path("categories", views.categories, name="plot-categories"), + path("category/", views.category, name="plot-category"), ] From b0909026482c28af22b53ca5ad3e9182d6bf4aa7 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Tue, 20 Dec 2022 16:31:03 +0100 Subject: [PATCH 077/507] Update plot style --- nummi/plot/nummi.mplstyle | 2 +- nummi/plot/views.py | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/nummi/plot/nummi.mplstyle b/nummi/plot/nummi.mplstyle index 90249c4..b49262b 100644 --- a/nummi/plot/nummi.mplstyle +++ b/nummi/plot/nummi.mplstyle @@ -6,7 +6,7 @@ figure.autolayout: True figure.figsize: 8, 4 figure.dpi: 300 -axes.prop_cycle: cycler('color', ["66cc66", "#338033", "#99ff99", "#802653", "#cc6699"]) +axes.prop_cycle: cycler('color', ["66cc66", "338033", "99ff99", "802653", "cc6699"]) axes.axisbelow: True axes.grid: True diff --git a/nummi/plot/views.py b/nummi/plot/views.py index 5abc4d5..90ddae2 100644 --- a/nummi/plot/views.py +++ b/nummi/plot/views.py @@ -69,8 +69,17 @@ def categories(request): @login_required def category(request, uuid): _category = get_object_or_404(Category, id=uuid) - _values = ( + _values_p = ( Transaction.objects.filter(category=_category) + .filter(value__gt=0) + .annotate(m=models.functions.TruncMonth("date")) + .values("m") + .annotate(sum=models.Sum("value")) + .order_by("m") + ) + _values_m = ( + Transaction.objects.filter(category=_category) + .filter(value__lt=0) .annotate(m=models.functions.TruncMonth("date")) .values("m") .annotate(sum=models.Sum("value")) @@ -78,10 +87,17 @@ def category(request, uuid): ) fig, ax = plt.subplots() - ax.step( - [v["m"] for v in _values], - [v["sum"] for v in _values], - where="post", + ax.bar( + [v["m"] for v in _values_p], + [v["sum"] for v in _values_p], + width=12, + color="#66cc66", + ) + ax.bar( + [v["m"] for v in _values_m], + [v["sum"] for v in _values_m], + width=12, + color="#cc6699", ) ax.xaxis.set_major_formatter( mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()) From 495c64fcdc02d4979af999c6f2799aeba6a12a9d Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 09:18:47 +0100 Subject: [PATCH 078/507] Update layout Modified navbar content Moved categories up on homepage Load all snapshots on homepage Load 64 transactions per page --- nummi/main/locale/fr/LC_MESSAGES/django.mo | Bin 1528 -> 1365 bytes nummi/main/locale/fr/LC_MESSAGES/django.po | 39 +++++++-------------- nummi/main/templates/main/base.html | 11 ++---- nummi/main/templates/main/category.html | 2 +- nummi/main/templates/main/index.html | 20 +++++------ nummi/main/views.py | 4 +-- 6 files changed, 29 insertions(+), 47 deletions(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.mo b/nummi/main/locale/fr/LC_MESSAGES/django.mo index 5321cee3ec8d7423be93168810f670ca51765c59..f85645910da87dea90baec27a1d700050757f027 100644 GIT binary patch delta 607 zcmXw%KP*F06vmJD`l!C5|CBbJBnFF^O*RwJ!D#3}>?R2*8;MDYMPd<&5nCe?OENfs%0Gh2JM;Z3=QSKLYuYUn8Qeh`w>{zcFTpx+l=W9%e}l?@_w^5` zbKg(}e_$4dbREH*vkaHGR1H$tHt4oUecNOrgIy?t1E`KqAV0fcPy?4x`!~*eD5EE+ z^BsSFfoiY|)kqIg(>{Iu%hv}mroKhADWg2p!3tEN8RtBd(IQl#W#=l?S1KXAlF)gD z{1m!~&W@pRq>zXF6)O`AWmM4H|Yf)JKv&CXs_o_^H+AvYdI6*!72WD+Yl-)8CPz&X?nSFjbgQ5z0W8xBzil~4zqy7{tu ze&M`9t-nVV@ap_P{i>R4CRBXBo39?CjreOVe;rgI{35~sqXAWb{wHc(zXU~-J7{_{ zyvX3-4s0ZJxfr3M)$|s1F`A~$+KEne3RB_jfoXpuvEb$W#dK!VG{~mB)$CF_7YuS4 zFO~Hca?9z|$whcDJTjeLTlbSmUwh7v*|h9i@XT9FWc;MRet!Hr)|!923-6J|A5JV) AumAu6 diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index 2c29bb8..7ff0ccd 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-20 15:28+0100\n" +"POT-Creation-Date: 2022-12-21 09:08+0100\n" "PO-Revision-Date: 2022-05-30 19:00+0200\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: .\models.py:12 .\models.py:22 .\models.py:56 +#: .\models.py:12 .\models.py:22 .\models.py:56 .\templates\main\base.html:35 #: .\templates\main\tag\transaction_table.html:10 msgid "Category" msgstr "Catégorie" @@ -35,12 +35,12 @@ msgstr "Icône" msgid "Budget" msgstr "Budget" -#: .\models.py:23 .\templates\main\index.html:57 +#: .\models.py:23 .\templates\main\index.html:19 #: .\templates\main\snapshot.html:33 msgid "Categories" msgstr "Catégories" -#: .\models.py:37 .\models.py:64 +#: .\models.py:37 .\models.py:64 .\templates\main\base.html:30 msgid "Transaction" msgstr "Transaction" @@ -48,12 +48,12 @@ msgstr "Transaction" msgid "Description" msgstr "Description" -#: .\models.py:41 .\models.py:122 .\templates\main\index.html:23 +#: .\models.py:41 .\models.py:122 .\templates\main\index.html:32 #: .\templates\main\tag\transaction_table.html:8 msgid "Value" msgstr "Valeur" -#: .\models.py:43 .\models.py:120 .\templates\main\index.html:22 +#: .\models.py:43 .\models.py:120 .\templates\main\index.html:31 #: .\templates\main\tag\transaction_table.html:6 msgid "Date" msgstr "Date" @@ -70,10 +70,9 @@ msgstr "Commerçant" msgid "Payment" msgstr "Paiement" -#: .\models.py:65 .\templates\main\base.html:30 -#: .\templates\main\category.html:22 .\templates\main\index.html:14 -#: .\templates\main\index.html:25 .\templates\main\snapshot.html:87 -#: .\templates\main\transactions.html:13 +#: .\models.py:65 .\templates\main\category.html:24 +#: .\templates\main\index.html:14 .\templates\main\index.html:34 +#: .\templates\main\snapshot.html:87 .\templates\main\transactions.html:13 msgid "Transactions" msgstr "Transactions" @@ -89,31 +88,19 @@ msgstr "Fichier" msgid "Invoices" msgstr "Factures" -#: .\models.py:230 +#: .\models.py:230 .\templates\main\base.html:40 msgid "Snapshot" msgstr "Relevé" -#: .\models.py:231 .\templates\main\index.html:19 +#: .\models.py:231 .\templates\main\index.html:28 msgid "Snapshots" msgstr "Relevés" -#: .\templates\main\base.html:35 -msgid "New transaction" -msgstr "Nouvelle transaction" - -#: .\templates\main\base.html:40 -msgid "New category" -msgstr "Nouvelle catégorie" - -#: .\templates\main\base.html:45 -msgid "New snapshot" -msgstr "Nouveau relevé" - -#: .\templates\main\index.html:24 +#: .\templates\main\index.html:33 msgid "Difference" msgstr "Différence" -#: .\templates\main\index.html:26 +#: .\templates\main\index.html:35 msgid "Valid" msgstr "Valide" diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index 965eab2..5b71a72 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -24,25 +24,20 @@ accesskey="h"> Nummi - - {% translate "Transactions" %} - - {% translate "New transaction" %} + {% translate "Transaction" %} - {% translate "New category" %} + {% translate "Category" %} - {% translate "New snapshot" %} + {% translate "Snapshot" %} +{% if transactions %} Graph representing value over time -{% if transactions %}

{% translate "Transactions" %}

{% transaction_table transactions %} {% endif %} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 2aecd7e..4c4f126 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -11,10 +11,19 @@ {% block body %} {% if transactions %} -

{% translate "Transactions" %}

+

{% translate "Transactions" %}

{% transaction_table transactions %} {% endif %} +{% if categories %} +

{% translate "Categories" %}

+
+ {% for cat in categories %} + {{ cat }} + {% endfor %} +
+{% endif %} + {% if snapshots %}

{% translate "Snapshots" %}

@@ -53,13 +62,4 @@
{% endif %} -{% if categories %} -

{% translate "Categories" %}

-
- {% for cat in categories %} - {{ cat }} - {% endfor %} -
-{% endif %} - {% endblock %} diff --git a/nummi/main/views.py b/nummi/main/views.py index e4fe9c2..a98d658 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -23,7 +23,7 @@ from .models import ( def index(request): _transactions = Transaction.objects.all()[:10] _categories = Category.objects.all() - _snapshots = Snapshot.objects.all()[:5] + _snapshots = Snapshot.objects.all() context = { "transactions": _transactions, @@ -43,7 +43,7 @@ class LogoutView(auth_views.LogoutView): class TransactionListView(LoginRequiredMixin, ListView): - paginate_by = 20 + paginate_by = 64 model = Transaction template_name = "main/transactions.html" context_object_name = "transactions" From 7895210aea542303fab63308d79626c58fac1e85 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 09:21:17 +0100 Subject: [PATCH 079/507] Add default date on snapshots --- nummi/main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index 3e777e4..664cc09 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -117,7 +117,7 @@ class InvoiceForm(ModelForm): class Snapshot(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - date = models.DateField(unique=True, verbose_name=_("Date")) + date = models.DateField(default=date.today, unique=True, verbose_name=_("Date")) value = models.DecimalField( max_digits=12, decimal_places=2, default=0, verbose_name=_("Value") ) From 996f6a9f18f8c16baf5c79f720c0c872e865f0bf Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 09:38:17 +0100 Subject: [PATCH 080/507] Add visibility on invoices Add links to invoices on transaction tables Added invoices and has_invoice properties to transactions --- nummi/main/models.py | 8 ++++++++ nummi/main/static/main/css/table.css | 1 + nummi/main/templates/main/tag/transaction_table.html | 10 +++++++++- nummi/main/templates/main/transaction.html | 2 +- nummi/main/views.py | 2 -- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index 664cc09..7238625 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -59,6 +59,14 @@ class Transaction(models.Model): def __str__(self): return f"{self.date} – {self.name}" + @property + def invoices(self): + return Invoice.objects.filter(transaction=self) + + @property + def has_invoice(self): + return self.invoices.count() > 0 + class Meta: ordering = ["-date"] verbose_name = _("Transaction") diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index e649e9a..bfed8a7 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -11,6 +11,7 @@ .table.col4 {grid-template-columns: repeat(4, auto)} .table.col5 {grid-template-columns: repeat(5, auto)} .table.col6 {grid-template-columns: repeat(6, auto)} +.table.col1-6 {grid-template-columns: min-content repeat(6, auto)} .table > div { display: contents; diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html index d4a0622..b27e993 100644 --- a/nummi/main/templates/main/tag/transaction_table.html +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -1,8 +1,9 @@ {% load main_extras %} {% load i18n %} -
+
+ {% translate "Date" %} {% translate "Name" %} {% translate "Value" %} @@ -12,6 +13,13 @@
{% for trans in transactions %}
+ + {% for invoice in trans.invoices %} + + + + {% endfor %} + {{ trans.date|date:"Y-m-d" }} {{ trans.name }} {{ trans.value|pmvalue }} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index b9666e8..bae7974 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -22,7 +22,7 @@

{% translate "Invoices" %}

- {% for inv in invoices %} + {% for inv in transaction.invoices %}
{{ inv.name }} Date: Wed, 21 Dec 2022 14:02:15 +0100 Subject: [PATCH 081/507] Add file selector to snapshots --- ..._alter_invoice_file_alter_snapshot_date.py | 44 +++++++++++++++++++ nummi/main/models.py | 26 ++++++++++- nummi/main/templates/main/snapshot.html | 2 +- nummi/main/views.py | 4 +- nummi/nummi/settings.py | 1 + nummi/nummi/urls.py | 4 +- 6 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py diff --git a/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py b/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py new file mode 100644 index 0000000..c00239e --- /dev/null +++ b/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py @@ -0,0 +1,44 @@ +# Generated by Django 4.1.4 on 2022-12-21 08:53 + +import datetime +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0006_alter_category_options_alter_invoice_options_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="snapshot", + name="file", + field=models.FileField( + blank=True, + max_length=128, + null=True, + upload_to="snapshots/", + validators=[django.core.validators.FileExtensionValidator(["pdf"])], + verbose_name="Fichier", + ), + ), + migrations.AlterField( + model_name="invoice", + name="file", + field=models.FileField( + max_length=128, + upload_to="invoices/", + validators=[django.core.validators.FileExtensionValidator(["pdf"])], + verbose_name="Fichier", + ), + ), + migrations.AlterField( + model_name="snapshot", + name="date", + field=models.DateField( + default=datetime.date.today, unique=True, verbose_name="Date" + ), + ), + ] diff --git a/nummi/main/models.py b/nummi/main/models.py index 7238625..12647d3 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -1,9 +1,11 @@ +import pathlib from datetime import date import uuid from django.db import models from django.forms import ModelForm from django.core.validators import FileExtensionValidator from django.utils.translation import gettext as _ +from django.core.files.storage import Storage class Category(models.Model): @@ -90,15 +92,20 @@ class TransactionForm(ModelForm): ] +def invoice_path(instance, filename): + return pathlib.Path("invoices", str(instance.id), filename) + + class Invoice(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField( max_length=256, default=_("Invoice"), verbose_name=_("Name") ) file = models.FileField( - upload_to="invoices/", + upload_to=invoice_path, validators=[FileExtensionValidator(["pdf"])], verbose_name=_("File"), + max_length=128, ) transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE) @@ -123,6 +130,10 @@ class InvoiceForm(ModelForm): fields = ["name", "file"] +def snapshot_path(instance, filename): + return pathlib.Path("snapshots", str(instance.id)).with_suffix(".pdf") + + class Snapshot(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) date = models.DateField(default=date.today, unique=True, verbose_name=_("Date")) @@ -135,12 +146,22 @@ class Snapshot(models.Model): diff = models.DecimalField( max_digits=12, decimal_places=2, editable=False, blank=True, null=True ) + file = models.FileField( + upload_to=snapshot_path, + validators=[FileExtensionValidator(["pdf"])], + verbose_name=_("File"), + max_length=256, + blank=True, + ) def __str__(self): return f"{_('Snapshot')} {self.date}" def save(self, *args, only_super=False, **kwargs): if not only_super: + _prever = Snapshot.objects.get(id=self.id) + if _prever.file and _prever.file != self.file: + pathlib.Path(_prever.file.path).unlink(missing_ok=True) _prev = ( self.__class__.objects.order_by("-date") .exclude(id=self.id) @@ -188,6 +209,7 @@ class Snapshot(models.Model): _next.save(only_super=True) def delete(self, *args, only_super=False, **kwargs): + self.file.delete() if not only_super: try: _next = self.__class__.objects.get(previous=self) @@ -244,4 +266,4 @@ class SnapshotForm(ModelForm): class Meta: model = Snapshot - fields = ["date", "value"] + fields = ["date", "value", "file"] diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index 4458f25..7396a02 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -23,7 +23,7 @@ {{ snapshot }} -
+ {% csrf_token %} {{ form }} {% form_buttons snapshot %} diff --git a/nummi/main/views.py b/nummi/main/views.py index 6b7e622..a6cb1ca 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -154,9 +154,11 @@ def snapshot(request, uuid=None): _snapshot = Snapshot.objects.get(id=uuid) except Snapshot.DoesNotExist: _snapshot = Snapshot(id=uuid) - _form = SnapshotForm(request.POST, instance=_snapshot) + _form = SnapshotForm(request.POST, request.FILES, instance=_snapshot) if _form.is_valid(): _form.save() + return redirect(snapshot, uuid=uuid) + context = { "snapshot": _snapshot, "form": _form, diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index e5ecaab..fb7478a 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -16,6 +16,7 @@ import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent MEDIA_ROOT = Path(os.environ.get("NUMMI_MEDIA_ROOT", "/var/lib/nummi")) +MEDIA_URL = "files/" # Quick-start development settings - unsuitable for production diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 37a7a5e..e201c47 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -17,10 +17,12 @@ from django.conf.urls.i18n import i18n_patterns from django.contrib import admin from django.urls import include, path from django.views.generic.base import RedirectView +from django.conf import settings +from django.conf.urls.static import static urlpatterns = i18n_patterns( path("", include("main.urls")), path("plot/", include("plot.urls")), path("admin/", admin.site.urls), prefix_default_language=False, -) +) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From 4efc421f042c6e2a6a7b2f036b70bf924bf958de Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:05:15 +0100 Subject: [PATCH 082/507] Fix file selector styling --- nummi/main/static/main/css/form.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nummi/main/static/main/css/form.css b/nummi/main/static/main/css/form.css index 28ff0f3..2035d6a 100644 --- a/nummi/main/static/main/css/form.css +++ b/nummi/main/static/main/css/form.css @@ -36,9 +36,12 @@ form > div > select { font-size: inherit; line-height: inherit; font-family: inherit; - height: 100%; + /*height: 100%;*/ width: 100%; } +form > div > select { + height: 100%; +} form > div > textarea { line-height: initial; } From ba07636a85889f3f4338dd5c2964b40456bb6a3d Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:09:38 +0100 Subject: [PATCH 083/507] Add display for snapshot files on homepage --- nummi/main/static/main/css/table.css | 1 + nummi/main/templates/main/index.html | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index bfed8a7..f60c5a4 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -11,6 +11,7 @@ .table.col4 {grid-template-columns: repeat(4, auto)} .table.col5 {grid-template-columns: repeat(5, auto)} .table.col6 {grid-template-columns: repeat(6, auto)} +.table.col1-5 {grid-template-columns: min-content repeat(5, auto)} .table.col1-6 {grid-template-columns: min-content repeat(6, auto)} .table > div { diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 4c4f126..3c68739 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -26,8 +26,9 @@ {% if snapshots %}

{% translate "Snapshots" %}

-
+
+ {% translate "Date" %} {% translate "Value" %} {% translate "Difference" %} @@ -36,6 +37,13 @@
{% for snap in snapshots %}
+ + {% if snap.file %} + + + + {% endif %} + {{ snap.date|date:"Y-m-d" }} From 043f5e7112264c15b694c29569b42e6efe6fab73 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:23:02 +0100 Subject: [PATCH 084/507] Add private media server using nginx Use internal nginx root with X-Accel-Redirect header --- nummi.nginx | 5 +++++ nummi/nummi/settings.py | 2 +- nummi/nummi/urls.py | 6 +++++- nummi/nummi/views.py | 9 +++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 nummi/nummi/views.py diff --git a/nummi.nginx b/nummi.nginx index f69fd24..28147a4 100644 --- a/nummi.nginx +++ b/nummi.nginx @@ -12,4 +12,9 @@ server { location /static { alias /srv/nummi; } + + location /media { + internal; + alias /var/lib/nummi; + } } diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index fb7478a..0536cfa 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -16,7 +16,7 @@ import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent MEDIA_ROOT = Path(os.environ.get("NUMMI_MEDIA_ROOT", "/var/lib/nummi")) -MEDIA_URL = "files/" +MEDIA_URL = "media/" # Quick-start development settings - unsuitable for production diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index e201c47..21c2231 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -20,7 +20,11 @@ from django.views.generic.base import RedirectView from django.conf import settings from django.conf.urls.static import static -urlpatterns = i18n_patterns( +from . import views + +urlpatterns = [ + path("media/", views.media, name="media"), +] + i18n_patterns( path("", include("main.urls")), path("plot/", include("plot.urls")), path("admin/", admin.site.urls), diff --git a/nummi/nummi/views.py b/nummi/nummi/views.py new file mode 100644 index 0000000..1f84722 --- /dev/null +++ b/nummi/nummi/views.py @@ -0,0 +1,9 @@ +from django.http import HttpResponse +from django.contrib.auth.decorators import login_required + +@login_required +def media(request): + _res = HttpResponse() + _res["Content-Type"] = "" + _res["X-Accel-Redirect"] = request.path + return _res From b995b9a0f52dd60ab8fb85169dda583926f36617 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:24:38 +0100 Subject: [PATCH 085/507] Add missing sysusers config --- nummi.sysusers | 1 + 1 file changed, 1 insertion(+) create mode 100644 nummi.sysusers diff --git a/nummi.sysusers b/nummi.sysusers new file mode 100644 index 0000000..208e626 --- /dev/null +++ b/nummi.sysusers @@ -0,0 +1 @@ +u nummi - "Nummi daemon user" /var/lib/nummi /usr/bin/bash From 55021db55702512d6139f78be29324bfc4a34457 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:28:29 +0100 Subject: [PATCH 086/507] Updated checksums --- PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD b/PKGBUILD index 6729a49..938d5a4 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -25,7 +25,7 @@ b2sums=('SKIP' '9e9b62a141bb4594dc203978d5c56dd397ed6c095e6f83fdea07ded2fa46dd2e052aa8f80729a3b612e3773aa487660fcca791079ad4885b825c9c831df61b45' '2be5a55e8582a680a17c133c28b43f0a27800acc855c90ae670486b3847b91a47216d15a029670cdc3c55c193371b060cfe3b01bf4f858a64b64da9711067188' '3d31754c644e05ec01bc07ebfb89749d563260abb4507297aceaaeebe2f057517ccc3e1c61dbb2eb864779260cd3c7aad01939775525b6bf6461267587dea156' - 'b86c46f17b5445b5631a3725ed3d4cd3bf1e864c68f8db8cecba1f8ae554e1e4872d8a86bfe6ab5172507f8315ebeccf78c9fbe3bb9eeb71c21113450e0df4d5' + '0a4e35264877dc03bcbea11af1e0f5a84bb13b4fb4d84c27a3531b578278ec59f2647cb78d8061e7fe8450dbb06517fb35dc0076a71c0e6e8ec6a20fecd29b0c' '5bdc097ab3fa7e8e128d194bfb6c0fefb5528903e2b8765557a82033f8925c1174dbe73007a595e32c5e415cf6f19957c35bbe463c50d2813894c20c8a28a88d') pkgver() { From 4a1bd56fd97f3c31955c9317aafb446e4aeea8f1 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:39:56 +0100 Subject: [PATCH 087/507] Update nginx proxy of media files --- nummi.nginx | 2 +- nummi/nummi/urls.py | 2 +- nummi/nummi/views.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nummi.nginx b/nummi.nginx index 28147a4..0e8ba04 100644 --- a/nummi.nginx +++ b/nummi.nginx @@ -13,7 +13,7 @@ server { alias /srv/nummi; } - location /media { + location /internal/media { internal; alias /var/lib/nummi; } diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 21c2231..126b44a 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -23,7 +23,7 @@ from django.conf.urls.static import static from . import views urlpatterns = [ - path("media/", views.media, name="media"), + path("media/", views.media, name="media"), ] + i18n_patterns( path("", include("main.urls")), path("plot/", include("plot.urls")), diff --git a/nummi/nummi/views.py b/nummi/nummi/views.py index 1f84722..a79c117 100644 --- a/nummi/nummi/views.py +++ b/nummi/nummi/views.py @@ -2,8 +2,8 @@ from django.http import HttpResponse from django.contrib.auth.decorators import login_required @login_required -def media(request): +def media(request, path): _res = HttpResponse() _res["Content-Type"] = "" - _res["X-Accel-Redirect"] = request.path + _res["X-Accel-Redirect"] = "/internal/media/" + path return _res From 4a41f998d7a9ca9ca07c4ea3c276a7ab4f01a42b Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:43:01 +0100 Subject: [PATCH 088/507] Use path converter in media url --- nummi/nummi/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 126b44a..8217719 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -23,7 +23,7 @@ from django.conf.urls.static import static from . import views urlpatterns = [ - path("media/", views.media, name="media"), + path("media/", views.media, name="media"), ] + i18n_patterns( path("", include("main.urls")), path("plot/", include("plot.urls")), From 100dc9f508fdf3ec3d4f1258fed886029460764d Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:48:55 +0100 Subject: [PATCH 089/507] Update checksums --- PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 938d5a4..9a35bdf 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=nummi-git -pkgver=r80.73ce1a2 +pkgver=r149.4a41f99 pkgrel=1 pkgdesc="Web-based accounting interface" arch=("any") @@ -25,7 +25,7 @@ b2sums=('SKIP' '9e9b62a141bb4594dc203978d5c56dd397ed6c095e6f83fdea07ded2fa46dd2e052aa8f80729a3b612e3773aa487660fcca791079ad4885b825c9c831df61b45' '2be5a55e8582a680a17c133c28b43f0a27800acc855c90ae670486b3847b91a47216d15a029670cdc3c55c193371b060cfe3b01bf4f858a64b64da9711067188' '3d31754c644e05ec01bc07ebfb89749d563260abb4507297aceaaeebe2f057517ccc3e1c61dbb2eb864779260cd3c7aad01939775525b6bf6461267587dea156' - '0a4e35264877dc03bcbea11af1e0f5a84bb13b4fb4d84c27a3531b578278ec59f2647cb78d8061e7fe8450dbb06517fb35dc0076a71c0e6e8ec6a20fecd29b0c' + 'c878c463ecb58d94b3f9b96d798b098a7718aec6df4b424a60674c0a9daf9abcb4556e527e55f67dbb093e109145b0ca17556f7dce66116ba7b170ead61acc16' '5bdc097ab3fa7e8e128d194bfb6c0fefb5528903e2b8765557a82033f8925c1174dbe73007a595e32c5e415cf6f19957c35bbe463c50d2813894c20c8a28a88d') pkgver() { From ee26d0d9a8445ae23e88c55ad1345f529bea1671 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 14:56:28 +0100 Subject: [PATCH 090/507] Update media file server for debugging --- nummi/nummi/urls.py | 6 ++---- nummi/nummi/views.py | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 8217719..059f3e9 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -22,11 +22,9 @@ from django.conf.urls.static import static from . import views -urlpatterns = [ - path("media/", views.media, name="media"), -] + i18n_patterns( +urlpatterns = [path("media/", views.media, name="media"),] + i18n_patterns( path("", include("main.urls")), path("plot/", include("plot.urls")), path("admin/", admin.site.urls), prefix_default_language=False, -) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +) diff --git a/nummi/nummi/views.py b/nummi/nummi/views.py index a79c117..866279f 100644 --- a/nummi/nummi/views.py +++ b/nummi/nummi/views.py @@ -1,8 +1,13 @@ +from django.conf import settings from django.http import HttpResponse from django.contrib.auth.decorators import login_required +from django.views.static import serve + @login_required def media(request, path): + if settings.DEBUG: + return serve(request, path, settings.MEDIA_ROOT) _res = HttpResponse() _res["Content-Type"] = "" _res["X-Accel-Redirect"] = "/internal/media/" + path From cf23e3f79df98073718c74ab8a57cb512a0de675 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:13:21 +0100 Subject: [PATCH 091/507] Try to fix permission issues with nginx --- PKGBUILD | 6 +++--- nummi.sysusers | 1 + nummi.tmpfiles | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 9a35bdf..e20c87d 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=nummi-git -pkgver=r149.4a41f99 +pkgver=r151.ee26d0d pkgrel=1 pkgdesc="Web-based accounting interface" arch=("any") @@ -23,8 +23,8 @@ source=( ) b2sums=('SKIP' '9e9b62a141bb4594dc203978d5c56dd397ed6c095e6f83fdea07ded2fa46dd2e052aa8f80729a3b612e3773aa487660fcca791079ad4885b825c9c831df61b45' - '2be5a55e8582a680a17c133c28b43f0a27800acc855c90ae670486b3847b91a47216d15a029670cdc3c55c193371b060cfe3b01bf4f858a64b64da9711067188' - '3d31754c644e05ec01bc07ebfb89749d563260abb4507297aceaaeebe2f057517ccc3e1c61dbb2eb864779260cd3c7aad01939775525b6bf6461267587dea156' + 'cd42e864d82ca5ea191d2c15cec55afea272a875f19ebc1252e03fb86ef3d62820e2fedd706a8da0b0e3a7aee355e0bb5dcdb7f3bd803497c1320fab540f7d70' + '78bebc6cca3f8b520783565de9122cc57e62eb629d3693dfaa322a77f4be3c55c5cd5a460bd1f6f3028f4dd1b2018ec6166b7f9aaf55ac3be6178bd1a3a00405' 'c878c463ecb58d94b3f9b96d798b098a7718aec6df4b424a60674c0a9daf9abcb4556e527e55f67dbb093e109145b0ca17556f7dce66116ba7b170ead61acc16' '5bdc097ab3fa7e8e128d194bfb6c0fefb5528903e2b8765557a82033f8925c1174dbe73007a595e32c5e415cf6f19957c35bbe463c50d2813894c20c8a28a88d') diff --git a/nummi.sysusers b/nummi.sysusers index 208e626..36b69fa 100644 --- a/nummi.sysusers +++ b/nummi.sysusers @@ -1 +1,2 @@ u nummi - "Nummi daemon user" /var/lib/nummi /usr/bin/bash +m nummi http diff --git a/nummi.tmpfiles b/nummi.tmpfiles index 8cd104e..efb8d05 100644 --- a/nummi.tmpfiles +++ b/nummi.tmpfiles @@ -1,2 +1,2 @@ -d /var/lib/nummi 0750 nummi nummi +d /var/lib/nummi 0750 nummi http d /srv/nummi 0755 nummi nummi From b77c5b6064aca8020fcc51eff20af9385f7c2335 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:18:52 +0100 Subject: [PATCH 092/507] Fix style on login page --- nummi/main/templates/main/login.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/templates/main/login.html b/nummi/main/templates/main/login.html index 3a44ede..cca26dd 100644 --- a/nummi/main/templates/main/login.html +++ b/nummi/main/templates/main/login.html @@ -23,7 +23,7 @@ {% for field in form %} {{ field.errors }} - {{ field }} +
{{ field }}
{% endfor %}
From 08b3c3dd186de61f910ff4abab8876f4182d170e Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:32:51 +0100 Subject: [PATCH 093/507] Use new media server for invoices --- nummi/main/models.py | 2 +- nummi/main/templates/main/tag/transaction_table.html | 4 +++- nummi/main/templates/main/transaction.html | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nummi/main/models.py b/nummi/main/models.py index 12647d3..a711f5c 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -93,7 +93,7 @@ class TransactionForm(ModelForm): def invoice_path(instance, filename): - return pathlib.Path("invoices", str(instance.id), filename) + return pathlib.Path("invoices", str(instance.id)).with_suffix(".pdf") class Invoice(models.Model): diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html index b27e993..299c513 100644 --- a/nummi/main/templates/main/tag/transaction_table.html +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -15,9 +15,11 @@
{% for invoice in trans.invoices %} - + {% spaceless %} + + {% endspaceless %} {% endfor %} {{ trans.date|date:"Y-m-d" }} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index bae7974..07ca350 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -24,7 +24,7 @@
{% for inv in transaction.invoices %}
- {{ inv.name }} + {{ inv.name }} ?')"> From 364ad42c05f031628691a61575533ed33a310e84 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:37:57 +0100 Subject: [PATCH 094/507] Only show budgeted categories on snapshot page --- nummi/main/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nummi/main/views.py b/nummi/main/views.py index a6cb1ca..dd4a2a5 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -166,9 +166,8 @@ def snapshot(request, uuid=None): if _snapshot.transactions: context["categories"] = ( - _snapshot.transactions.values( - "category", "category__name", "category__icon" - ) + _snapshot.transactions.filter(category__budget=True) + .values("category", "category__name", "category__icon") .annotate( sum=models.Sum("value"), sum_m=models.Sum("value", filter=models.Q(value__lt=0)), From 6d0fb174ebf54576dd7b940d413d5830dcc6f68f Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:42:30 +0100 Subject: [PATCH 095/507] Organise imports using isort --profile black --- nummi/main/admin.py | 2 +- nummi/main/migrations/0001_initial.py | 7 ++++--- ...ory_options_alter_invoice_options_and_more.py | 3 ++- ...ile_alter_invoice_file_alter_snapshot_date.py | 1 + nummi/main/models.py | 7 ++++--- nummi/main/views.py | 16 ++++++++-------- nummi/nummi/settings.py | 2 +- nummi/nummi/urls.py | 4 ++-- nummi/nummi/views.py | 2 +- nummi/plot/views.py | 14 ++++---------- 10 files changed, 28 insertions(+), 30 deletions(-) diff --git a/nummi/main/admin.py b/nummi/main/admin.py index ab84be8..2a4c794 100644 --- a/nummi/main/admin.py +++ b/nummi/main/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import Transaction, Invoice, Category, Snapshot +from .models import Category, Invoice, Snapshot, Transaction admin.site.register(Transaction) admin.site.register(Invoice) diff --git a/nummi/main/migrations/0001_initial.py b/nummi/main/migrations/0001_initial.py index 7685e49..fae77ef 100644 --- a/nummi/main/migrations/0001_initial.py +++ b/nummi/main/migrations/0001_initial.py @@ -1,12 +1,13 @@ # Generated by Django 4.0.4 on 2022-05-22 07:45 import datetime -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion import re import uuid +import django.core.validators +import django.db.models.deletion +from django.db import migrations, models + class Migration(migrations.Migration): diff --git a/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py b/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py index 4a7ec37..e0bf69d 100644 --- a/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py +++ b/nummi/main/migrations/0006_alter_category_options_alter_invoice_options_and_more.py @@ -1,9 +1,10 @@ # Generated by Django 4.1.4 on 2022-12-20 14:26 import datetime + import django.core.validators -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py b/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py index c00239e..5a24ab9 100644 --- a/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py +++ b/nummi/main/migrations/0007_snapshot_file_alter_invoice_file_alter_snapshot_date.py @@ -1,6 +1,7 @@ # Generated by Django 4.1.4 on 2022-12-21 08:53 import datetime + import django.core.validators from django.db import migrations, models diff --git a/nummi/main/models.py b/nummi/main/models.py index a711f5c..c815532 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -1,11 +1,12 @@ import pathlib -from datetime import date import uuid +from datetime import date + +from django.core.files.storage import Storage +from django.core.validators import FileExtensionValidator from django.db import models from django.forms import ModelForm -from django.core.validators import FileExtensionValidator from django.utils.translation import gettext as _ -from django.core.files.storage import Storage class Category(models.Model): diff --git a/nummi/main/views.py b/nummi/main/views.py index dd4a2a5..e237547 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -1,21 +1,21 @@ -from django.shortcuts import render, get_object_or_404, redirect -from django.http import HttpResponse -from django.contrib.auth.decorators import login_required from django.contrib.auth import views as auth_views +from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin -from django.views.generic import ListView from django.core.paginator import Paginator from django.db import models +from django.http import HttpResponse +from django.shortcuts import get_object_or_404, redirect, render +from django.views.generic import ListView from .models import ( - Transaction, - TransactionForm, - Invoice, - InvoiceForm, Category, CategoryForm, + Invoice, + InvoiceForm, Snapshot, SnapshotForm, + Transaction, + TransactionForm, ) diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 0536cfa..52da9aa 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -10,8 +10,8 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ -from pathlib import Path import os +from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent diff --git a/nummi/nummi/urls.py b/nummi/nummi/urls.py index 059f3e9..e933645 100644 --- a/nummi/nummi/urls.py +++ b/nummi/nummi/urls.py @@ -13,12 +13,12 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.conf import settings from django.conf.urls.i18n import i18n_patterns +from django.conf.urls.static import static from django.contrib import admin from django.urls import include, path from django.views.generic.base import RedirectView -from django.conf import settings -from django.conf.urls.static import static from . import views diff --git a/nummi/nummi/views.py b/nummi/nummi/views.py index 866279f..15ffea3 100644 --- a/nummi/nummi/views.py +++ b/nummi/nummi/views.py @@ -1,6 +1,6 @@ from django.conf import settings -from django.http import HttpResponse from django.contrib.auth.decorators import login_required +from django.http import HttpResponse from django.views.static import serve diff --git a/nummi/plot/views.py b/nummi/plot/views.py index 90ddae2..115cc33 100644 --- a/nummi/plot/views.py +++ b/nummi/plot/views.py @@ -2,20 +2,14 @@ import io import matplotlib import matplotlib.pyplot as plt -from matplotlib import dates as mdates -from django.db import models from django.contrib.auth.decorators import login_required -from django.shortcuts import get_object_or_404 +from django.db import models from django.http import HttpResponse +from django.shortcuts import get_object_or_404 from django.utils.translation import gettext as _ +from matplotlib import dates as mdates -from main.models import ( - Transaction, - Invoice, - Category, - Snapshot, -) - +from main.models import Category, Invoice, Snapshot, Transaction matplotlib.use("Agg") plt.style.use("./plot/nummi.mplstyle") From d8b00d91e8d192a96b4b43c3730f3124537bacb5 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 15:49:27 +0100 Subject: [PATCH 096/507] Redirect on valid form input --- nummi/main/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nummi/main/views.py b/nummi/main/views.py index e237547..74b5359 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -64,6 +64,7 @@ def transaction(request, uuid=None): _form = TransactionForm(request.POST, instance=_transaction) if _form.is_valid(): _form.save() + return redirect(transaction, uuid=uuid) _inv_form = InvoiceForm(instance=Invoice(transaction=_transaction)) elif request.POST["form"] == "invoice": _transaction = get_object_or_404(Transaction, id=uuid) @@ -71,6 +72,7 @@ def transaction(request, uuid=None): _inv_form = InvoiceForm(request.POST, request.FILES, instance=_invoice) if _inv_form.is_valid(): _inv_form.save() + return redirect(transaction, uuid=uuid) return render( request, @@ -118,6 +120,7 @@ def category(request, uuid=None): _form = CategoryForm(request.POST, instance=_category) if _form.is_valid(): _form.save() + return redirect(category, uuid=uuid) return render( request, From 4b4c5f827da310e607b2257ffe156b316054d0ba Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 17:05:23 +0100 Subject: [PATCH 097/507] Add search --- .../migrations/0008_auto_20221221_1657.py | 16 ++++++++ nummi/main/static/main/css/nav.css | 24 +++++++++++- nummi/main/templates/main/base.html | 6 +++ nummi/main/urls.py | 1 + nummi/main/views.py | 39 +++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 nummi/main/migrations/0008_auto_20221221_1657.py diff --git a/nummi/main/migrations/0008_auto_20221221_1657.py b/nummi/main/migrations/0008_auto_20221221_1657.py new file mode 100644 index 0000000..8174089 --- /dev/null +++ b/nummi/main/migrations/0008_auto_20221221_1657.py @@ -0,0 +1,16 @@ +# Generated by Django 4.1.4 on 2022-12-21 15:57 + +from django.contrib.postgres.operations import TrigramExtension, UnaccentExtension +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("main", "0007_snapshot_file_alter_invoice_file_alter_snapshot_date"), + ] + + operations = [ + TrigramExtension(), + UnaccentExtension(), + ] diff --git a/nummi/main/static/main/css/nav.css b/nummi/main/static/main/css/nav.css index ecf6343..27de1d9 100644 --- a/nummi/main/static/main/css/nav.css +++ b/nummi/main/static/main/css/nav.css @@ -19,7 +19,8 @@ nav { line-height: var(--nav-lh); padding: var(--nav-pad); } -nav > a { +nav > a, +nav > form { display: inline-block; color: inherit; text-decoration: inherit; @@ -40,3 +41,24 @@ nav > a img { vertical-align: top; margin-right: .5rem; } + +nav > form input { + font: inherit; + height: inherit; + border: none; + background: #ffffff35; + padding: 0 var(--gap); +} +nav > form input[type="text"] { + border-radius: var(--radius) 0 0 var(--radius); +} +nav > form input[type="submit"] { + border-radius: 0 var(--radius) var(--radius) 0; +} +nav > form input[type="submit"] { + cursor: pointer; + color: var(--green-text); +} +nav > form input[type="submit"]:hover { + text-decoration: underline; +} diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index 5b71a72..4672d76 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -39,6 +39,12 @@ accesskey="s"> {% translate "Snapshot" %} + + {% csrf_token %} + + + + diff --git a/nummi/main/urls.py b/nummi/main/urls.py index 272fc29..2a76acb 100644 --- a/nummi/main/urls.py +++ b/nummi/main/urls.py @@ -18,4 +18,5 @@ urlpatterns = [ path("snapshot", views.snapshot, name="snapshot"), path("snapshot/", views.snapshot, name="snapshot"), path("snapshot//del", views.del_snapshot, name="del_snapshot"), + path("search", views.search, name="search"), ] diff --git a/nummi/main/views.py b/nummi/main/views.py index 74b5359..ae36576 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -1,6 +1,12 @@ from django.contrib.auth import views as auth_views from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin +from django.contrib.postgres.search import ( + SearchQuery, + SearchRank, + SearchVector, + TrigramSimilarity, +) from django.core.paginator import Paginator from django.db import models from django.http import HttpResponse @@ -202,3 +208,36 @@ def del_snapshot(request, uuid): _snapshot = get_object_or_404(Snapshot, id=uuid) _snapshot.delete() return redirect(index) + + +@login_required +def search(request): + _search = request.POST.get("search") + _transactions = ( + Transaction.objects.annotate( + rank=SearchRank( + SearchVector("name", weight="A") + + SearchVector("description", weight="C"), + SearchQuery(_search, search_type="websearch"), + ), + similarity=TrigramSimilarity("name", _search), + ) + .filter(models.Q(rank__gte=0.1) | models.Q(similarity__gte=0.1)) + .order_by("-rank", "-date") + ) + + if _transactions.count() == 0: + _transactions = ( + Transaction.objects.annotate(rank=TrigramSimilarity("name", _search)) + .filter(rank__gte=0.1) + .order_by("-rank", "-date") + ) + + return render( + request, + "main/transactions.html", + { + "transactions": _transactions, + "search": _search, + }, + ) From 5953d80ff25bc81ba246645fa7edae0827f0000a Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 17:18:02 +0100 Subject: [PATCH 098/507] Improve search Search in trader Combine ranked and trigram --- nummi/main/templates/main/transactions.html | 2 ++ nummi/main/views.py | 12 +++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/nummi/main/templates/main/transactions.html b/nummi/main/templates/main/transactions.html index 3293675..edf421e 100644 --- a/nummi/main/templates/main/transactions.html +++ b/nummi/main/templates/main/transactions.html @@ -13,6 +13,7 @@

{% translate "Transactions" %}

{% transaction_table transactions %} +{% if page_obj %} +{% endif %} {% endblock %} diff --git a/nummi/main/views.py b/nummi/main/views.py index ae36576..fbc6039 100644 --- a/nummi/main/views.py +++ b/nummi/main/views.py @@ -217,22 +217,16 @@ def search(request): Transaction.objects.annotate( rank=SearchRank( SearchVector("name", weight="A") - + SearchVector("description", weight="C"), + + SearchVector("description", weight="B") + + SearchVector("trader", weight="B"), SearchQuery(_search, search_type="websearch"), ), similarity=TrigramSimilarity("name", _search), ) - .filter(models.Q(rank__gte=0.1) | models.Q(similarity__gte=0.1)) + .filter(models.Q(rank__gte=0.1) | models.Q(similarity__gte=0.3)) .order_by("-rank", "-date") ) - if _transactions.count() == 0: - _transactions = ( - Transaction.objects.annotate(rank=TrigramSimilarity("name", _search)) - .filter(rank__gte=0.1) - .order_by("-rank", "-date") - ) - return render( request, "main/transactions.html", From 93d827dea30f6765566116c1e741d5cbfa73bc81 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Wed, 21 Dec 2022 17:31:49 +0100 Subject: [PATCH 099/507] Update translations --- nummi/locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 421 bytes nummi/locale/fr/LC_MESSAGES/django.po | 21 ++++++ nummi/main/locale/fr/LC_MESSAGES/django.mo | Bin 1365 -> 1399 bytes nummi/main/locale/fr/LC_MESSAGES/django.po | 76 +++++++++++---------- nummi/nummi/settings.py | 7 +- 5 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 nummi/locale/fr/LC_MESSAGES/django.mo create mode 100644 nummi/locale/fr/LC_MESSAGES/django.po diff --git a/nummi/locale/fr/LC_MESSAGES/django.mo b/nummi/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..41fef998878fb9c3c52d48845bfccabf9d9a6c50 GIT binary patch literal 421 zcma)$Jx&8L5QP^65^PCL;SvO1?4=-beiQ+T6p4r>EHqS3cH$UqY|HjWa1c5!z&W@F zXJHbGv^>qHnUUUT-p|qAM}pc#j*)X@AL$@#704m-fb@5g, 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: 0.0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-12-21 17:26+0100\n" +"PO-Revision-Date: 2022-12-21 17:30+0100\n" +"Last-Translator: edpibu \n" +"Language-Team: edpibu \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: .\plot\views.py:28 +msgid "Snapshots" +msgstr "Relevés" diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.mo b/nummi/main/locale/fr/LC_MESSAGES/django.mo index f85645910da87dea90baec27a1d700050757f027..2037b7acb3bfdb0026ea86c8a1f7c5304e922928 100644 GIT binary patch delta 580 zcmXZZy)Q#i7{~F`+c&By@vb^pghm>@?I2+>NUZ((_(g>?CGnBz# zFcM3Ln&@OOuvJVF-(UNj^tqqYbDsO0=ib|l{l==T!O*E=OcE)gO-vIn0WORU&$%EL zun$WZ!5xg@9`@h?hVaPtPf+>isJtuNzcFty>Ri>`Gf{y@RN-e!Xmk_YEB3P9vh`0? z-Z$#Lw(bAfdX#Q;a026)#4yg78C>S!@)+fOw@ceYB+6h(TH3n{mkO0)x%TEACj49` a=TG?yi}~za)~{EB7lBBzT+((Ty!sEo^ENa9 delta 551 zcmXZZPbdUo7{~Ett) zE_>s)\n" "Language-Team: edpibu \n" "Language: \n" @@ -17,110 +17,116 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: .\models.py:12 .\models.py:22 .\models.py:56 .\templates\main\base.html:35 -#: .\templates\main\tag\transaction_table.html:10 +#: .\main\models.py:15 .\main\models.py:25 .\main\models.py:59 +#: .\main\templates\main\base.html:35 +#: .\main\templates\main\tag\transaction_table.html:11 msgid "Category" msgstr "Catégorie" -#: .\models.py:12 .\models.py:37 .\models.py:88 -#: .\templates\main\tag\transaction_table.html:7 +#: .\main\models.py:15 .\main\models.py:40 .\main\models.py:103 +#: .\main\templates\main\tag\transaction_table.html:8 msgid "Name" msgstr "Nom" -#: .\models.py:14 +#: .\main\models.py:17 msgid "Icon" msgstr "Icône" -#: .\models.py:15 +#: .\main\models.py:18 msgid "Budget" msgstr "Budget" -#: .\models.py:23 .\templates\main\index.html:19 -#: .\templates\main\snapshot.html:33 +#: .\main\models.py:26 .\main\templates\main\index.html:19 +#: .\main\templates\main\snapshot.html:33 msgid "Categories" msgstr "Catégories" -#: .\models.py:37 .\models.py:64 .\templates\main\base.html:30 +#: .\main\models.py:40 .\main\models.py:75 .\main\templates\main\base.html:30 msgid "Transaction" msgstr "Transaction" -#: .\models.py:39 .\templates\main\tag\transaction_table.html:11 +#: .\main\models.py:42 .\main\templates\main\tag\transaction_table.html:12 msgid "Description" msgstr "Description" -#: .\models.py:41 .\models.py:122 .\templates\main\index.html:32 -#: .\templates\main\tag\transaction_table.html:8 +#: .\main\models.py:44 .\main\models.py:142 .\main\templates\main\index.html:33 +#: .\main\templates\main\tag\transaction_table.html:9 msgid "Value" msgstr "Valeur" -#: .\models.py:43 .\models.py:120 .\templates\main\index.html:31 -#: .\templates\main\tag\transaction_table.html:6 +#: .\main\models.py:46 .\main\models.py:140 .\main\templates\main\index.html:32 +#: .\main\templates\main\tag\transaction_table.html:7 msgid "Date" msgstr "Date" -#: .\models.py:44 +#: .\main\models.py:47 msgid "Real date" msgstr "Date réelle" -#: .\models.py:46 .\templates\main\tag\transaction_table.html:9 +#: .\main\models.py:49 .\main\templates\main\tag\transaction_table.html:10 msgid "Trader" msgstr "Commerçant" -#: .\models.py:49 +#: .\main\models.py:52 msgid "Payment" msgstr "Paiement" -#: .\models.py:65 .\templates\main\category.html:24 -#: .\templates\main\index.html:14 .\templates\main\index.html:34 -#: .\templates\main\snapshot.html:87 .\templates\main\transactions.html:13 +#: .\main\models.py:76 .\main\templates\main\category.html:24 +#: .\main\templates\main\index.html:14 .\main\templates\main\index.html:35 +#: .\main\templates\main\snapshot.html:87 +#: .\main\templates\main\transactions.html:13 msgid "Transactions" msgstr "Transactions" -#: .\models.py:88 .\models.py:105 +#: .\main\models.py:103 .\main\models.py:121 msgid "Invoice" msgstr "Facture" -#: .\models.py:93 +#: .\main\models.py:108 .\main\models.py:153 msgid "File" msgstr "Fichier" -#: .\models.py:106 .\templates\main\transaction.html:23 +#: .\main\models.py:122 .\main\templates\main\transaction.html:23 msgid "Invoices" msgstr "Factures" -#: .\models.py:230 .\templates\main\base.html:40 +#: .\main\models.py:261 .\main\templates\main\base.html:40 msgid "Snapshot" msgstr "Relevé" -#: .\models.py:231 .\templates\main\index.html:28 +#: .\main\models.py:262 .\main\templates\main\index.html:28 msgid "Snapshots" msgstr "Relevés" -#: .\templates\main\index.html:33 +#: .\main\templates\main\base.html:44 .\main\templates\main\base.html:45 +msgid "Search" +msgstr "Rechercher" + +#: .\main\templates\main\index.html:34 msgid "Difference" msgstr "Différence" -#: .\templates\main\index.html:35 +#: .\main\templates\main\index.html:36 msgid "Valid" msgstr "Valide" -#: .\templates\main\login.html:12 .\templates\main\login.html:31 +#: .\main\templates\main\login.html:12 .\main\templates\main\login.html:31 msgid "Log In" msgstr "Se connecter" -#: .\templates\main\tag\form_buttons.html:4 -#: .\templates\main\transaction.html:29 +#: .\main\templates\main\tag\form_buttons.html:4 +#: .\main\templates\main\transaction.html:29 msgid "Delete" msgstr "Supprimer" -#: .\templates\main\tag\form_buttons.html:14 +#: .\main\templates\main\tag\form_buttons.html:14 msgid "Save" msgstr "Enregistrer" -#: .\templates\main\transaction.html:36 +#: .\main\templates\main\transaction.html:36 msgid "Add invoice" msgstr "Ajouter une facture" -#: .\templates\main\transaction.html:41 +#: .\main\templates\main\transaction.html:41 msgid "Add" msgstr "Ajouter" diff --git a/nummi/nummi/settings.py b/nummi/nummi/settings.py index 52da9aa..73cd510 100644 --- a/nummi/nummi/settings.py +++ b/nummi/nummi/settings.py @@ -110,13 +110,12 @@ AUTH_PASSWORD_VALIDATORS = [ # https://docs.djangoproject.com/en/4.0/topics/i18n/ LANGUAGE_CODE = "fr-fr" - TIME_ZONE = "CET" - USE_I18N = True - USE_TZ = True - +LOCALE_PATHS = [ + "locale", +] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ From 3a31eec326421ec53856c0fbc615393cd478148b Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 25 Dec 2022 16:10:39 +0100 Subject: [PATCH 100/507] Update invoice list layout --- nummi/main/static/main/css/main.css | 6 +++ nummi/main/static/main/css/table.css | 2 + nummi/main/templates/main/transaction.html | 51 ++++++++++++++-------- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/nummi/main/static/main/css/main.css b/nummi/main/static/main/css/main.css index 9bf03dc..ab488e9 100644 --- a/nummi/main/static/main/css/main.css +++ b/nummi/main/static/main/css/main.css @@ -62,3 +62,9 @@ a:hover { .red {color: var(--red)} .green {color: var(--text-green)} + +.split { + display: grid; + grid-template-columns: repeat(2, auto); + grid-gap: var(--gap); +} diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index f60c5a4..20f3dca 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -11,6 +11,8 @@ .table.col4 {grid-template-columns: repeat(4, auto)} .table.col5 {grid-template-columns: repeat(5, auto)} .table.col6 {grid-template-columns: repeat(6, auto)} +.table.col1-1 {grid-template-columns: min-content auto} +.table.col1-1-1 {grid-template-columns: min-content auto min-content} .table.col1-5 {grid-template-columns: min-content repeat(5, auto)} .table.col1-6 {grid-template-columns: min-content repeat(6, auto)} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index 07ca350..0009651 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -6,6 +6,7 @@ {% block link %} {{ block.super }} + {% endblock %} {% block body %} @@ -20,24 +21,38 @@ {% endspaceless %} -

{% translate "Invoices" %}

-
- {% for inv in transaction.invoices %} -
- {{ inv.name }} - ?')"> - - +
+ {% if transaction.has_invoice %} +
+

{% translate "Invoices" %}

+
+
+ + {% translate "Name" %} + +
+ {% for inv in transaction.invoices %} + + {% endfor %}
- {% endfor %} +
+ {% endif %} + +
+

{% translate "Add invoice" %}

+
+ {% csrf_token %} + + {{ invoice_form }} +
+
+
- -

{% translate "Add invoice" %}

-
- {% csrf_token %} - - {{ invoice_form }} -
-
{% endblock %} From 16dba4381084fa593e9019c97345f5833ed12a0c Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 25 Dec 2022 16:24:40 +0100 Subject: [PATCH 101/507] Reformat template files with djLint --- nummi/main/templates/main/base.html | 116 +++++++------ nummi/main/templates/main/category.html | 42 ++--- nummi/main/templates/main/form.html | 14 +- nummi/main/templates/main/index.html | 127 +++++++------- nummi/main/templates/main/login.html | 51 +++--- nummi/main/templates/main/snapshot.html | 160 ++++++++---------- .../main/templates/main/tag/form_buttons.html | 22 ++- nummi/main/templates/main/tag/pmvalue.html | 11 +- .../templates/main/tag/transaction_table.html | 73 ++++---- nummi/main/templates/main/tag/value.html | 8 +- nummi/main/templates/main/transaction.html | 107 ++++++------ nummi/main/templates/main/transactions.html | 51 +++--- 12 files changed, 384 insertions(+), 398 deletions(-) diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index 4672d76..ff91452 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -2,58 +2,66 @@ {% load i18n %} - - - - - {% block title %}Nummi{% endblock %} - - {% block link %} - - - - - {% endblock %} - - - {% block nav %} - {% spaceless %} - - {% endspaceless %} - {% endblock %} - {% block body %} - {% endblock %} - + + + + + {% block title %}Nummi{% endblock %} + + {% block link %} + + + + + {% endblock %} + + + {% block nav %} + {% spaceless %} + + {% endspaceless %} + {% endblock %} + {% block body %}{% endblock %} + diff --git a/nummi/main/templates/main/category.html b/nummi/main/templates/main/category.html index 5ec8ab8..17c71fd 100644 --- a/nummi/main/templates/main/category.html +++ b/nummi/main/templates/main/category.html @@ -2,26 +2,28 @@ {% load static %} {% load main_extras %} {% load i18n %} - {% block link %} -{{ block.super }} - - + {{ block.super }} + + {% endblock %} - {% block body %} -

{{ category }}

- -
- {% csrf_token %} - {{ form }} - {% form_buttons category %} -
- -{% if transactions %} -Graph representing value over time - -

{% translate "Transactions" %}

-{% transaction_table transactions %} -{% endif %} -{% endblock %} +

+ {{ category }} +

+
+ {% csrf_token %} + {{ form }} + {% form_buttons category %} +
+ {% if transactions %} + Graph representing value over time +

{% translate "Transactions" %}

+ {% transaction_table transactions %} + {% endif %} + {% endblock %} diff --git a/nummi/main/templates/main/form.html b/nummi/main/templates/main/form.html index e69f304..692f781 100644 --- a/nummi/main/templates/main/form.html +++ b/nummi/main/templates/main/form.html @@ -1,12 +1,10 @@ {% if form.non_field_errors %} -
    - {% for error in form.non_field_errors %} -
  • {{ error }}
  • - {% endfor %} -
+
    + {% for error in form.non_field_errors %}
  • {{ error }}
  • {% endfor %} +
{% endif %} {% for field in form %} -{{ field.errors }} - -
{{ field }}
+ {{ field.errors }} + +
{{ field }}
{% endfor %} diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 3c68739..6dd6534 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -2,72 +2,69 @@ {% load static %} {% load main_extras %} {% load i18n %} - {% block link %} -{{ block.super }} - - + {{ block.super }} + + {% endblock %} - {% block body %} -{% if transactions %} -

{% translate "Transactions" %}

-{% transaction_table transactions %} -{% endif %} - -{% if categories %} -

{% translate "Categories" %}

-
- {% for cat in categories %} - {{ cat }} - {% endfor %} -
-{% endif %} - -{% if snapshots %} -

{% translate "Snapshots" %}

-
-
- - {% translate "Date" %} - {% translate "Value" %} - {% translate "Difference" %} - {% translate "Transactions" %} - {% translate "Valid" %} -
- {% for snap in snapshots %} -
- - {% if snap.file %} - - - - {% endif %} - - - {{ snap.date|date:"Y-m-d" }} - - {{ snap.value|value }} - - {{ snap.diff|pmvalue }} - - {% with sum=snap.sum %} - - {{ sum|pmvalue }} - - - {% if snap.previous is not None %} - {% if sum == snap.diff %} - - {% else %} - - {% endif %} - {% endif %} - - {% endwith %} -
- {% endfor %} -
-{% endif %} - + {% if transactions %} +

+ {% translate "Transactions" %} +

+ {% transaction_table transactions %} + {% endif %} + {% if categories %} +

{% translate "Categories" %}

+
+ {% for cat in categories %} + {{ cat }} + {% endfor %} +
+ {% endif %} + {% if snapshots %} +

{% translate "Snapshots" %}

+
+
+ + {% translate "Date" %} + {% translate "Value" %} + {% translate "Difference" %} + {% translate "Transactions" %} + {% translate "Valid" %} +
+ {% for snap in snapshots %} +
+ + {% if snap.file %} + + + + {% endif %} + + + {{ snap.date|date:"Y-m-d" }} + + {{ snap.value|value }} + {{ snap.diff|pmvalue }} + {% with sum=snap.sum %} + {{ sum|pmvalue }} + + {% if snap.previous is not None %} + {% if sum == snap.diff %} + + {% else %} + + {% endif %} + {% endif %} + + {% endwith %} +
+ {% endfor %} +
+ {% endif %} {% endblock %} diff --git a/nummi/main/templates/main/login.html b/nummi/main/templates/main/login.html index cca26dd..67218e5 100644 --- a/nummi/main/templates/main/login.html +++ b/nummi/main/templates/main/login.html @@ -1,35 +1,30 @@ {% extends "main/base.html" %} {% load static %} {% load i18n %} - {% block link %} -{{ block.super }} - + {{ block.super }} + {% endblock %} - {% block body %} - -

{% translate "Log In" %}

- -
- {% csrf_token %} - {% if form.non_field_errors %} -
    - {% for error in form.non_field_errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} - {% for field in form %} - {{ field.errors }} - -
{{ field }}
- {% endfor %} -
- - - -
-
- +

{% translate "Log In" %}

+
+ {% csrf_token %} + {% if form.non_field_errors %} +
    + {% for error in form.non_field_errors %}
  • {{ error }}
  • {% endfor %} +
+ {% endif %} + {% for field in form %} + {{ field.errors }} + +
{{ field }}
+ {% endfor %} +
+ + + +
+
{% endblock %} diff --git a/nummi/main/templates/main/snapshot.html b/nummi/main/templates/main/snapshot.html index 7396a02..55d9b88 100644 --- a/nummi/main/templates/main/snapshot.html +++ b/nummi/main/templates/main/snapshot.html @@ -2,91 +2,81 @@ {% load static %} {% load main_extras %} {% load i18n %} - {% block link %} -{{ block.super }} - - - + {{ block.super }} + + + {% endblock %} - {% block body %} -{% with sum=snapshot.sum %} -

- {% if snapshot.previous is not None %} - {% if sum == snapshot.diff %} - - {% else %} - - {% endif %} - {% endif %} - {{ snapshot }} -

- -
- {% csrf_token %} - {{ form }} - {% form_buttons snapshot %} -
- -{% if categories %} -

{% translate "Categories" %}

-
- {% for cat in categories %} -
- {% if cat.category %} - - - {{ cat.category__name }} - - {% else %} - - {% endif %} -
-
- {{ cat.sum_m|pmvalue }} -
-
-
-
- {% if cat.sum < 0 %} -
- {{ cat.sum|pmvalue }} -
- {% endif %} -
-
-
-
- {% if cat.sum >= 0 %} -
- {{ cat.sum|pmvalue }} -
- {% endif %} -
-
- {{ cat.sum_p|pmvalue }} -
- {% endfor %} -
-{% endif %} - -{% if snapshot.transactions %} -

{% translate "Transactions" %} ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

- -{% transaction_table snapshot.transactions %} -{% endif %} -{% endwith %} -{% endblock %} + {% with sum=snapshot.sum %} +

+ {% if snapshot.previous is not None %} + {% if sum == snapshot.diff %} + + {% else %} + + {% endif %} + {% endif %} + {{ snapshot }} +

+
+ {% csrf_token %} + {{ form }} + {% form_buttons snapshot %} +
+ {% if categories %} +

{% translate "Categories" %}

+
+ {% for cat in categories %} +
+ {% if cat.category %} + + {{ cat.category__name }} + {% else %} + + {% endif %} +
+
{{ cat.sum_m|pmvalue }}
+
+
+ {% if cat.sum < 0 %} +
+ {{ cat.sum|pmvalue }} +
+ {% endif %} +
+
+
+ {% if cat.sum >= 0 %} +
+ {{ cat.sum|pmvalue }} +
+ {% endif %} +
+
{{ cat.sum_p|pmvalue }}
+ {% endfor %} +
+ {% endif %} + {% if snapshot.transactions %} +

{% translate "Transactions" %} ({{ sum|pmvalue }} / {{ snapshot.diff|pmvalue }})

+ {% transaction_table snapshot.transactions %} + {% endif %} + {% endwith %} + {% endblock %} diff --git a/nummi/main/templates/main/tag/form_buttons.html b/nummi/main/templates/main/tag/form_buttons.html index 86cf785..54c39db 100644 --- a/nummi/main/templates/main/tag/form_buttons.html +++ b/nummi/main/templates/main/tag/form_buttons.html @@ -1,15 +1,13 @@ {% load i18n %}
- {% if not adding %} - {% translate "Delete" as del %} - - {{ del }} - - - {% endif %} - - + {% if not adding %} + {% translate "Delete" as del %} + + {{ del }} + + {% endif %} + +
diff --git a/nummi/main/templates/main/tag/pmvalue.html b/nummi/main/templates/main/tag/pmvalue.html index 306aa87..db9eb45 100644 --- a/nummi/main/templates/main/tag/pmvalue.html +++ b/nummi/main/templates/main/tag/pmvalue.html @@ -1,8 +1,9 @@ {% extends "main/tag/value.html" %} - {% block "value" %} - {% if value %} - {% if value > 0 %}+{% endif %} - {{ block.super }} - {% else %}–{% endif %} + {% if value %} + {% if value > 0 %}+{% endif %} + {{ block.super }} + {% else %} + – + {% endif %} {% endblock %} diff --git a/nummi/main/templates/main/tag/transaction_table.html b/nummi/main/templates/main/tag/transaction_table.html index 299c513..b1a1263 100644 --- a/nummi/main/templates/main/tag/transaction_table.html +++ b/nummi/main/templates/main/tag/transaction_table.html @@ -1,42 +1,39 @@ {% load main_extras %} {% load i18n %} -
-
- - {% translate "Date" %} - {% translate "Name" %} - {% translate "Value" %} - {% translate "Trader" %} - {% translate "Category" %} - {% translate "Description" %} -
- {% for trans in transactions %} -
- - {% for invoice in trans.invoices %} - {% spaceless %} - - - - {% endspaceless %} - {% endfor %} - - {{ trans.date|date:"Y-m-d" }} - {{ trans.name }} - {{ trans.value|pmvalue }} - {{ trans.trader|default_if_none:"–" }} - - {% if trans.category %} - - - {{ trans.category }} - - {% else %} - – - {% endif %} - - {{ trans.description }} -
- {% endfor %} +
+ + {% translate "Date" %} + {% translate "Name" %} + {% translate "Value" %} + {% translate "Trader" %} + {% translate "Category" %} + {% translate "Description" %} +
+ {% for trans in transactions %} +
+ + {% for invoice in trans.invoices %} + {% spaceless %} + + + + {% endspaceless %} + {% endfor %} + + {{ trans.date|date:"Y-m-d" }} + {{ trans.name }} + {{ trans.value|pmvalue }} + {{ trans.trader|default_if_none:"–" }} + + {% if trans.category %} + + {{ trans.category }} + {% else %} + – + {% endif %} + + {{ trans.description }} +
+ {% endfor %}
diff --git a/nummi/main/templates/main/tag/value.html b/nummi/main/templates/main/tag/value.html index 9ba2cf7..3cdbb41 100644 --- a/nummi/main/templates/main/tag/value.html +++ b/nummi/main/templates/main/tag/value.html @@ -1,7 +1,5 @@ {% spaceless %} - - {% block "value" %} - {{ value }} € - {% endblock %} - + + {% block "value" %}{{ value }} €{% endblock %} + {% endspaceless %} diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index 0009651..fe34167 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -2,57 +2,62 @@ {% load static %} {% load main_extras %} {% load i18n %} - {% block link %} -{{ block.super }} - - + {{ block.super }} + + {% endblock %} - {% block body %} -

{{ transaction }}

- -{% spaceless %} -
- {% csrf_token %} - - {{ form }} - {% form_buttons transaction %} -
-{% endspaceless %} - -
- {% if transaction.has_invoice %} -
-

{% translate "Invoices" %}

-
-
- - {% translate "Name" %} - -
- {% for inv in transaction.invoices %} - - {% endfor %} -
-
- {% endif %} - -
-

{% translate "Add invoice" %}

-
- {% csrf_token %} - - {{ invoice_form }} -
-
-
-
-{% endblock %} +

{{ transaction }}

+ {% spaceless %} +
+ {% csrf_token %} + + {{ form }} + {% form_buttons transaction %} +
+ {% endspaceless %} +
+ {% if transaction.has_invoice %} +
+

{% translate "Invoices" %}

+
+
+ + {% translate "Name" %} + +
+ {% for inv in transaction.invoices %} + + {% endfor %} +
+
+ {% endif %} +
+

{% translate "Add invoice" %}

+
+ {% csrf_token %} + + {{ invoice_form }} +
+ +
+
+
+
+ {% endblock %} diff --git a/nummi/main/templates/main/transactions.html b/nummi/main/templates/main/transactions.html index edf421e..eeca920 100644 --- a/nummi/main/templates/main/transactions.html +++ b/nummi/main/templates/main/transactions.html @@ -2,34 +2,31 @@ {% load static %} {% load main_extras %} {% load i18n %} - {% block link %} -{{ block.super }} - - + {{ block.super }} + + {% endblock %} - {% block body %} -

{% translate "Transactions" %}

-{% transaction_table transactions %} - -{% if page_obj %} - -{% endif %} +

{% translate "Transactions" %}

+ {% transaction_table transactions %} + {% if page_obj %} + + {% endif %} {% endblock %} From 47b9d6a3fb7ce09126a3ef09d647ee047a033e92 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Sun, 25 Dec 2022 16:33:41 +0100 Subject: [PATCH 102/507] Update categories layout on homepage --- nummi/main/static/main/css/index.css | 3 +-- nummi/main/templates/main/index.html | 17 +++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/nummi/main/static/main/css/index.css b/nummi/main/static/main/css/index.css index 93d6df1..712c4ac 100644 --- a/nummi/main/static/main/css/index.css +++ b/nummi/main/static/main/css/index.css @@ -13,9 +13,8 @@ h1 img { } #categories > a { - margin-right: var(--gap); - margin-bottom: var(--gap); display: inline-block; + padding: 1em; } #categories > a > i { margin-right: .5rem; diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html index 6dd6534..d7c9053 100644 --- a/nummi/main/templates/main/index.html +++ b/nummi/main/templates/main/index.html @@ -14,17 +14,22 @@ {% block body %} {% if transactions %}

- {% translate "Transactions" %} + {% translate "Transactions" %} + + +

{% transaction_table transactions %} {% endif %} {% if categories %}

{% translate "Categories" %}

-
- {% for cat in categories %} - {{ cat }} - {% endfor %} -
+ {% spaceless %} +
+ {% for cat in categories %} + {{ cat }} + {% endfor %} +
+ {% endspaceless %} {% endif %} {% if snapshots %}

{% translate "Snapshots" %}

From 542ddbc78179763973f84179343c43894af3d2af Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 26 Dec 2022 17:50:03 +0100 Subject: [PATCH 103/507] Update theme Set background color of table header to theme color --- nummi/main/static/main/css/table.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nummi/main/static/main/css/table.css b/nummi/main/static/main/css/table.css index 20f3dca..edec06e 100644 --- a/nummi/main/static/main/css/table.css +++ b/nummi/main/static/main/css/table.css @@ -4,7 +4,6 @@ border-radius: var(--radius); overflow: hidden; border-bottom: var(--border) solid var(--theme); - border-top: var(--border) solid var(--theme); } .table.col2 {grid-template-columns: repeat(2, auto)} .table.col3 {grid-template-columns: repeat(3, auto)} @@ -28,7 +27,7 @@ .table > div.w> * {background: var(--bg)} .table > div.header > * { - background: var(--bg-inv); + background: var(--theme); } .table > div > .center { From 01710a9476ced5f357cc242ee2cff51e4de531b0 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 26 Dec 2022 17:54:14 +0100 Subject: [PATCH 104/507] Fix whitespace in navbar --- nummi/main/static/main/css/nav.css | 8 +++++--- nummi/main/templates/main/base.html | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/nummi/main/static/main/css/nav.css b/nummi/main/static/main/css/nav.css index 27de1d9..f488b03 100644 --- a/nummi/main/static/main/css/nav.css +++ b/nummi/main/static/main/css/nav.css @@ -30,9 +30,6 @@ nav > form { nav > a.cur { font-weight: 750; } -nav > a.home { - font-variant: small-caps; -} nav > a.logout { float: right; } @@ -41,6 +38,11 @@ nav > a img { vertical-align: top; margin-right: .5rem; } +nav > a h1 { + display: inline; + font: inherit; + font-variant: small-caps; +} nav > form input { font: inherit; diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index ff91452..9360af7 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -31,7 +31,7 @@ class="home{% if request.resolver_match.url_name == 'index' %} cur{% endif %}" accesskey="h"> - Nummi +

Nummi

Date: Mon, 26 Dec 2022 18:00:03 +0100 Subject: [PATCH 105/507] Improve accessibility --- nummi/main/locale/fr/LC_MESSAGES/django.po | 62 ++++++++++++---------- nummi/main/templates/main/base.html | 4 +- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index 3d7ea69..dd01263 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-21 17:26+0100\n" +"POT-Creation-Date: 2022-12-26 17:59+0100\n" "PO-Revision-Date: 2022-12-21 17:30+0100\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -18,13 +18,14 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: .\main\models.py:15 .\main\models.py:25 .\main\models.py:59 -#: .\main\templates\main\base.html:35 -#: .\main\templates\main\tag\transaction_table.html:11 +#: .\main\templates\main\base.html:44 +#: .\main\templates\main\tag\transaction_table.html:10 msgid "Category" msgstr "Catégorie" #: .\main\models.py:15 .\main\models.py:40 .\main\models.py:103 -#: .\main\templates\main\tag\transaction_table.html:8 +#: .\main\templates\main\tag\transaction_table.html:7 +#: .\main\templates\main\transaction.html:33 msgid "Name" msgstr "Nom" @@ -36,26 +37,26 @@ msgstr "Icône" msgid "Budget" msgstr "Budget" -#: .\main\models.py:26 .\main\templates\main\index.html:19 -#: .\main\templates\main\snapshot.html:33 +#: .\main\models.py:26 .\main\templates\main\index.html:25 +#: .\main\templates\main\snapshot.html:37 msgid "Categories" msgstr "Catégories" -#: .\main\models.py:40 .\main\models.py:75 .\main\templates\main\base.html:30 +#: .\main\models.py:40 .\main\models.py:75 .\main\templates\main\base.html:39 msgid "Transaction" msgstr "Transaction" -#: .\main\models.py:42 .\main\templates\main\tag\transaction_table.html:12 +#: .\main\models.py:42 .\main\templates\main\tag\transaction_table.html:11 msgid "Description" msgstr "Description" -#: .\main\models.py:44 .\main\models.py:142 .\main\templates\main\index.html:33 -#: .\main\templates\main\tag\transaction_table.html:9 +#: .\main\models.py:44 .\main\models.py:142 .\main\templates\main\index.html:40 +#: .\main\templates\main\tag\transaction_table.html:8 msgid "Value" msgstr "Valeur" -#: .\main\models.py:46 .\main\models.py:140 .\main\templates\main\index.html:32 -#: .\main\templates\main\tag\transaction_table.html:7 +#: .\main\models.py:46 .\main\models.py:140 .\main\templates\main\index.html:39 +#: .\main\templates\main\tag\transaction_table.html:6 msgid "Date" msgstr "Date" @@ -63,7 +64,7 @@ msgstr "Date" msgid "Real date" msgstr "Date réelle" -#: .\main\models.py:49 .\main\templates\main\tag\transaction_table.html:10 +#: .\main\models.py:49 .\main\templates\main\tag\transaction_table.html:9 msgid "Trader" msgstr "Commerçant" @@ -71,10 +72,10 @@ msgstr "Commerçant" msgid "Payment" msgstr "Paiement" -#: .\main\models.py:76 .\main\templates\main\category.html:24 -#: .\main\templates\main\index.html:14 .\main\templates\main\index.html:35 -#: .\main\templates\main\snapshot.html:87 -#: .\main\templates\main\transactions.html:13 +#: .\main\models.py:76 .\main\templates\main\category.html:26 +#: .\main\templates\main\index.html:17 .\main\templates\main\index.html:42 +#: .\main\templates\main\snapshot.html:78 +#: .\main\templates\main\transactions.html:15 msgid "Transactions" msgstr "Transactions" @@ -86,47 +87,52 @@ msgstr "Facture" msgid "File" msgstr "Fichier" -#: .\main\models.py:122 .\main\templates\main\transaction.html:23 +#: .\main\models.py:122 .\main\templates\main\transaction.html:29 msgid "Invoices" msgstr "Factures" -#: .\main\models.py:261 .\main\templates\main\base.html:40 +#: .\main\models.py:261 .\main\templates\main\base.html:49 msgid "Snapshot" msgstr "Relevé" -#: .\main\models.py:262 .\main\templates\main\index.html:28 +#: .\main\models.py:262 .\main\templates\main\index.html:35 msgid "Snapshots" msgstr "Relevés" -#: .\main\templates\main\base.html:44 .\main\templates\main\base.html:45 +#: .\main\templates\main\base.html:55 .\main\templates\main\base.html:57 msgid "Search" msgstr "Rechercher" -#: .\main\templates\main\index.html:34 +#: .\main\templates\main\base.html:59 +#| msgid "Log In" +msgid "Log out" +msgstr "Se connecter" + +#: .\main\templates\main\index.html:41 msgid "Difference" msgstr "Différence" -#: .\main\templates\main\index.html:36 +#: .\main\templates\main\index.html:43 msgid "Valid" msgstr "Valide" -#: .\main\templates\main\login.html:12 .\main\templates\main\login.html:31 +#: .\main\templates\main\login.html:11 .\main\templates\main\login.html:27 msgid "Log In" msgstr "Se connecter" #: .\main\templates\main\tag\form_buttons.html:4 -#: .\main\templates\main\transaction.html:29 +#: .\main\templates\main\transaction.html:41 msgid "Delete" msgstr "Supprimer" -#: .\main\templates\main\tag\form_buttons.html:14 +#: .\main\templates\main\tag\form_buttons.html:12 msgid "Save" msgstr "Enregistrer" -#: .\main\templates\main\transaction.html:36 +#: .\main\templates\main\transaction.html:50 msgid "Add invoice" msgstr "Ajouter une facture" -#: .\main\templates\main\transaction.html:41 +#: .\main\templates\main\transaction.html:58 msgid "Add" msgstr "Ajouter" diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index 9360af7..afa55f6 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -56,9 +56,7 @@ {% if search %}value="{{ search }}"{% endif %}/> - - - + {% translate "Log out" %} {% endspaceless %} {% endblock %} From 8b859651e84a6cf668991553ac92b2e5a9486157 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 26 Dec 2022 18:04:16 +0100 Subject: [PATCH 106/507] Improve accessibility Replace trash-can icon with text --- nummi/main/locale/fr/LC_MESSAGES/django.po | 10 +++++----- nummi/main/templates/main/transaction.html | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index dd01263..65d352d 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-26 17:59+0100\n" +"POT-Creation-Date: 2022-12-26 18:02+0100\n" "PO-Revision-Date: 2022-12-21 17:30+0100\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -104,7 +104,6 @@ msgid "Search" msgstr "Rechercher" #: .\main\templates\main\base.html:59 -#| msgid "Log In" msgid "Log out" msgstr "Se connecter" @@ -121,7 +120,8 @@ msgid "Log In" msgstr "Se connecter" #: .\main\templates\main\tag\form_buttons.html:4 -#: .\main\templates\main\transaction.html:41 +#: .\main\templates\main\transaction.html:42 +#: .\main\templates\main\transaction.html:43 msgid "Delete" msgstr "Supprimer" @@ -129,10 +129,10 @@ msgstr "Supprimer" msgid "Save" msgstr "Enregistrer" -#: .\main\templates\main\transaction.html:50 +#: .\main\templates\main\transaction.html:51 msgid "Add invoice" msgstr "Ajouter une facture" -#: .\main\templates\main\transaction.html:58 +#: .\main\templates\main\transaction.html:59 msgid "Add" msgstr "Ajouter" diff --git a/nummi/main/templates/main/transaction.html b/nummi/main/templates/main/transaction.html index fe34167..617a4fd 100644 --- a/nummi/main/templates/main/transaction.html +++ b/nummi/main/templates/main/transaction.html @@ -31,15 +31,16 @@
{% translate "Name" %} - +
{% for inv in transaction.invoices %} {% endfor %} From b61108546719073750617079cf4aa9f1989142b0 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 26 Dec 2022 18:11:09 +0100 Subject: [PATCH 107/507] Update __str__ of snapshots --- nummi/main/locale/fr/LC_MESSAGES/django.mo | Bin 1399 -> 1506 bytes nummi/main/locale/fr/LC_MESSAGES/django.po | 7 ++++++- nummi/main/models.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.mo b/nummi/main/locale/fr/LC_MESSAGES/django.mo index 2037b7acb3bfdb0026ea86c8a1f7c5304e922928..9193a6d3bf7420f37a921714e531035e8b4cf5e1 100644 GIT binary patch delta 729 zcmYk)KP*F06vy$~dX)D0TmMV)7EvpMK_X(2hy{yLlQs;frbQx=mspI*i`7Di$!5h1NkJ|r;+V^VLKmPR17lQ~3Kd1r~bWvd!bv=$Mn6PsX zYnUhP^?ua;LDc_;?fRI#K8ZTO47!-cO3an?jag$b!rg9QoP`Uzsqr0Z{)lSujwcnu?FRl8xL1h-I$?_I#-e}KKfUe?=g{R1lQ z3u<4-`G4Jdgl<(h0pl30I*C zmK=AWzS=ONmS@^Ogp^OF{My@x5=iyEBx*pGM58FJ7px!YcE->M(tpBDdp6EUP48B8 wvaSudNvgXrUnm%wC~fU+m)486P$_H_%eI&=*IWLTW+u?^)t`b#_03S_4>R32djJ3c diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.po b/nummi/main/locale/fr/LC_MESSAGES/django.po index 65d352d..b0a0a64 100644 --- a/nummi/main/locale/fr/LC_MESSAGES/django.po +++ b/nummi/main/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-12-26 18:02+0100\n" +"POT-Creation-Date: 2022-12-26 18:10+0100\n" "PO-Revision-Date: 2022-12-21 17:30+0100\n" "Last-Translator: edpibu \n" "Language-Team: edpibu \n" @@ -91,6 +91,11 @@ msgstr "Fichier" msgid "Invoices" msgstr "Factures" +#: .\main\models.py:159 +#, python-format +msgid "%(date)s snapshot" +msgstr "Relevé du %(date)s" + #: .\main\models.py:261 .\main\templates\main\base.html:49 msgid "Snapshot" msgstr "Relevé" diff --git a/nummi/main/models.py b/nummi/main/models.py index c815532..b2bef5f 100644 --- a/nummi/main/models.py +++ b/nummi/main/models.py @@ -156,7 +156,7 @@ class Snapshot(models.Model): ) def __str__(self): - return f"{_('Snapshot')} {self.date}" + return _("%(date)s snapshot") % {"date": self.date} def save(self, *args, only_super=False, **kwargs): if not only_super: From c58ef42bd006f2cc240977d71ec505e022762df3 Mon Sep 17 00:00:00 2001 From: "Edgar P. Burkhart" Date: Mon, 26 Dec 2022 18:17:58 +0100 Subject: [PATCH 108/507] Fix translation error --- nummi/main/locale/fr/LC_MESSAGES/django.mo | Bin 1506 -> 1509 bytes nummi/main/locale/fr/LC_MESSAGES/django.po | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/nummi/main/locale/fr/LC_MESSAGES/django.mo b/nummi/main/locale/fr/LC_MESSAGES/django.mo index 9193a6d3bf7420f37a921714e531035e8b4cf5e1..66f405c201d280d164628ab32f0f2cbec6b162e5 100644 GIT binary patch delta 122 zcmaFF{git{3u7uj0|P?>D+2>FkS+ky96-7RNb>;cS|H60q`QDL7m%I?q}hS=LLd!N mw-PG92}D+2>Fkj@3t96-7dNQ1 Date: Mon, 26 Dec 2022 18:50:02 +0100 Subject: [PATCH 109/507] Update search to use listview Enables pagination --- nummi/main/templates/main/base.html | 4 +-- nummi/main/urls.py | 3 +- nummi/main/views.py | 49 ++++++++++++++++------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/nummi/main/templates/main/base.html b/nummi/main/templates/main/base.html index afa55f6..6d51bc3 100644 --- a/nummi/main/templates/main/base.html +++ b/nummi/main/templates/main/base.html @@ -48,8 +48,8 @@ accesskey="s"> {% translate "Snapshot" %} -