diff --git a/.gitignore b/.gitignore index feaaa10..36e5602 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ cli/config/dbconfig.ini *~ .*~ .vscode/ +cli/*.tex +cli/*.log +cli/*.pdf +cli/*.aux diff --git a/ci-script-api b/ci-script-api deleted file mode 100644 index ec12e15..0000000 --- a/ci-script-api +++ /dev/null @@ -1,61 +0,0 @@ -stages: - - check - - build - - deploy - -variables: - IMAGE_NAME: $CI_REGISTRY/$CI_PROJECT_PATH - -check: - image: registry.hottis.de/dockerized/base-build-env:latest - stage: check - tags: - - hottis - - linux - - docker - rules: - - if: $CI_COMMIT_TAG - script: - - checksemver.py -v - --versionToValidate "${CI_COMMIT_TAG}" - --validateMessage - --messageToValidate "${CI_COMMIT_MESSAGE}" - -build: - image: registry.hottis.de/dockerized/docker-bash:latest - stage: build - tags: - - hottis - - linux - - docker - script: - - docker build --tag $IMAGE_NAME:latest . - - if [ "$CI_COMMIT_TAG" != "" ]; then - docker tag $IMAGE_NAME:latest $IMAGE_NAME:${CI_COMMIT_TAG}; - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY; - docker push $IMAGE_NAME:latest; - docker push $IMAGE_NAME:${CI_COMMIT_TAG}; - fi - -deploy: - stage: deploy - image: registry.hottis.de/dockerized/docker-bash:latest - only: - - tags - tags: - - hottis - - linux - - docker - variables: - GIT_STRATEGY: none - script: - - CONTAINER_NAME=$CI_PROJECT_NAME - - SERVICE_VOLUME=$CI_PROJECT_NAME"-conf" - - SERVICE_PORT=5000 - - docker volume inspect $SERVICE_VOLUME || docker volume create $SERVICE_VOLUME - - docker stop $CONTAINER_NAME || echo "$CONTAINER_NAME not running, anyway okay" - - docker rm $CONTAINER_NAME || echo "$CONTAINER_NAME not exsting, anyway okay" - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY; - - docker pull $IMAGE_NAME:${CI_COMMIT_TAG} - - docker run -d --restart always --name $CONTAINER_NAME --network docker-server --ip 172.16.10.38 -v $SERVICE_VOLUME:/opt/app/config $IMAGE_NAME:${CI_COMMIT_TAG} - diff --git a/ci-script-ui b/ci-script-ui deleted file mode 100644 index e6ada01..0000000 --- a/ci-script-ui +++ /dev/null @@ -1,88 +0,0 @@ -stages: - - check - - build - - dockerize - - deploy - -variables: - IMAGE_NAME: $CI_REGISTRY/$CI_PROJECT_PATH - -check: - image: registry.hottis.de/dockerized/base-build-env:latest - stage: check - tags: - - hottis - - linux - - docker - rules: - - if: $CI_COMMIT_TAG - script: - - checksemver.py -v - --versionToValidate "$CI_COMMIT_TAG" - --validateMessage - --messageToValidate "$CI_COMMIT_MESSAGE" - - -build: - image: registry.hottis.de/hv2/hv2-node-build-env:1.0.0 - stage: build - variables: - GIT_SUBMODULE_STRATEGY: recursive - tags: - - hottis - - linux - - docker - artifacts: - paths: - - dist.tgz - expire_in: 1 day - script: - - cd hv2-ui - - if [ "$CI_COMMIT_TAG" != "" ]; then - sed -i -e 's/GITTAGVERSION/'"$CI_COMMIT_TAG"':'"$CI_COMMIT_SHORT_SHA"'/' ./src/app/navigation/navigation.component.html; - fi - - npm install - - for F in ./src/app/*.tmpl; do - python ../helpers/hv2-api/generate.py -s ../helpers/hv2-api/schema.json -t $F; - done - - ./node_modules/.bin/ng build --prod - - tar -czf ../dist.tgz dist - - - -dockerize: - image: registry.hottis.de/dockerized/docker-bash:latest - stage: dockerize - tags: - - hottis - - linux - - docker - rules: - - if: $CI_COMMIT_TAG - script: - - tar -xzf dist.tgz - - docker build --tag $IMAGE_NAME:latest --tag $IMAGE_NAME:$CI_COMMIT_TAG . - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - docker push $IMAGE_NAME:latest - - docker push $IMAGE_NAME:$CI_COMMIT_TAG - - -deploy: - stage: deploy - image: registry.hottis.de/dockerized/docker-bash:latest - only: - - tags - tags: - - hottis - - linux - - docker - variables: - GIT_STRATEGY: none - script: - - CONTAINER_NAME=$CI_PROJECT_NAME - - docker stop $CONTAINER_NAME || echo "$CONTAINER_NAME not running, anyway okay" - - docker rm $CONTAINER_NAME || echo "$CONTAINER_NAME not exsting, anyway okay" - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY; - - docker pull $IMAGE_NAME:${CI_COMMIT_TAG} - - docker run -d --restart always --name $CONTAINER_NAME --network docker-server --ip 172.16.10.39 $IMAGE_NAME:${CI_COMMIT_TAG} - diff --git a/cli/OverheadAccounts.py b/cli/OverheadAccounts.py index 5acd6ca..192f799 100644 --- a/cli/OverheadAccounts.py +++ b/cli/OverheadAccounts.py @@ -2,18 +2,16 @@ from db import dbGetMany, dbGetOne import datetime from loguru import logger from decimal import * +from utils import getParam +from Cheetah.Template import Template + def perform(dbh, params): - try: - year = params['year'] - except KeyError: - year = datetime.datetime.today().year + year = getParam(params, 'year', datetime.datetime.today().year) startDate = datetime.datetime(year, 1, 1, 0, 0, 0) endDate = datetime.datetime(year, 12, 31, 23, 59, 59) premises = (1, 2) - - # get overhead sums by object, category and timespan overheadSums = dbGetMany( dbh, @@ -73,13 +71,12 @@ def perform(dbh, params): for overheadSum in overheadSums: logger.info(f"house: {overheadSum['house']}, considerMinusArea: {overheadSum['considerminusarea']}, category: {overheadSum['category']}, sum: {overheadSum['sum']}") - subtotal = {} - for premise in premises: - v = [ x['sum'] for x in overheadSums if x['house_id'] == premise ] - logger.info(f"{v=}") - subtotal[premise] = sum(v) - logger.info(f"{subtotal=}") - + #subtotal = {} + #for premise in premises: + # v = [ x['sum'] for x in overheadSums if x['house_id'] == premise ] + # logger.info(f"{v=}") + # subtotal[premise] = sum(v) + # logger.info(f"{subtotal=}") # get areas and factors totalAreas = {} @@ -169,6 +166,11 @@ def perform(dbh, params): logger.info(f"{totalAreas=}") + + + ##### ATTENTION: SCRIPT ABORT TEMPORALY INSERTED HERE ##### + return + ########################################################### # get flat tenants by object and timespan with paid overhead and due overhead @@ -178,10 +180,17 @@ def perform(dbh, params): "statement": """ select t.id as tenant_id, + t.salutation as tenant_salutation, t.firstname as tenant_firstname, t.lastname as tenant_lastname, + t.address1 as tenant_address1, + t.address2 as tenant_address2, + t.address3 as tenant_address3, + t.zip as tenant_zip, + t.city as tenant_city, f.id as flat_id, f.description as flat, + f.area as flat_area, p.id as house_id, p.description as house, ty.startdate as startdate, @@ -207,8 +216,9 @@ def perform(dbh, params): } ) + letters = [] for tenant in tenants: - logger.info(f"firstname: {tenant['tenant_firstname']}, lastname: {tenant['tenant_lastname']}, house: {tenant['house']}, account: {tenant['tenant_account']}") + letter = {} paidTotal = dbGetOne( dbh, @@ -228,6 +238,8 @@ def perform(dbh, params): } } ) + tenant['paid_total'] = paidTotal['sum'] + receivableFee = dbGetOne( dbh, { @@ -246,13 +258,33 @@ def perform(dbh, params): } } ) - - logger.info(f"Payments: cnt: {paidTotal['cnt']}, sum: {paidTotal['sum']}") - logger.info(f"Receivable fees: cnt: {receivableFee['cnt']}, sum: {receivableFee['sum']}") + tenant['receivable_fee'] = receivableFee['sum'] + tenant['rent_time'] = receivableFee['cnt'] - paidOverheadAdvance = paidTotal['sum'] - receivableFee['sum'] - logger.info(f"Paid overhead: {paidOverheadAdvance} (by month: {paidOverheadAdvance / Decimal(12)})") - + tenant['paid_overhead'] = paidTotal['sum'] - receivableFee['sum'] + + letter['tenant'] = tenant + letter['year'] = year + letter['flat_area'] = totalAreas[tenant['house_id']]['flat_area'] + + letters.append(letter) + + logger.info(f"{letter=}") + + + printLetters = getParam(params, 'printLetters', False) + if printLetters: + letterTemplate = getParam(params, 'letterTemplate', 'jahresabrechnung.tmpl') + letterPrefix = getParam(params, 'letterPrefix', 'letter') + letterSuffix = getParam(params, 'letterSuffix', 'tex') + + for letter in letters: + logger.debug(f"Processing item: {letter}") + outputFile = f"{letterPrefix}-{letter['tenant']['tenant_id']}.{letterSuffix}" + tmpl = Template(file=letterTemplate, searchList=[ letter ]) + logger.debug(tmpl) + with open(outputFile, 'w') as f: + f.write(str(tmpl)) diff --git a/cli/jahresabrechnung.tmpl b/cli/jahresabrechnung.tmpl new file mode 100644 index 0000000..65ed006 --- /dev/null +++ b/cli/jahresabrechnung.tmpl @@ -0,0 +1,94 @@ +\documentclass[12pt]{dinbrief} +\usepackage{german} +\usepackage{eurosym} + +\address{Heribert Ludger Nober\\ + Hemsingskotten 40\\ + 45259 Essen} +\backaddress{H. L. Nober, Hemsingskotten 40, 45259 Essen} +\signature{Heribert Ludger Nober} +\nowindowrules +\bottomtext{\sffamily\footnotesize Telefon: 0201-467955\\ + Bankverbindung: IBAN DE14 3605 0105 0001 5130 35, Sparkasse Essen} + +\begin{document} + \pagenumbering{gobble} + \begin{letter}{$tenant['tenant_firstname'] $tenant['tenant_lastname']\\ + $tenant['tenant_address1']\\ + $tenant['tenant_address2']\\ + $tenant['tenant_address3']\\ + $tenant['tenant_zip'] $tenant['tenant_city']} + \subject{Betriebskostenabrechnung $year} + \opening{$tenant['tenant_salutation'],} + + f"ur die im vergangenen Jahr angefallenen Betriebskosten ergibt sich f"ur Sie folgende Abrechnung. + + \texttt{ + \begin{tabular}{|p{10cm}|p{5cm}|} + \hline Jahr & $year \\ + \hline Haus & $tenant['house'] \\ + \hline Betriebskosten gesamt & gesamtbetriebskosten\,\euro{} \\ + \hline Gesamt-Wohnfl"ache & $flat_area\,m\textsuperscript{2} \\ + \hline Ihre Wohnung & $tenant['flat'] \\ + \hline Ihre Wohnfl"ache & $tenant['flat_area']\,m\textsuperscript{2} \\ + \hline Ihr Betriebskostenanteil nach Fl"ache & anteilproflaeche\,\euro{} \\ + #if $tenant['rent_time'] != 12 + \hline Ihre Mietzeit & $tenant['rent_time']\,Monate \\ + \hline Betriebskostenanteil nach Fl"ache und Mietzeit & anteilproflaechenutzungszeit\,\euro{} \\ + #end if + \hline Ihre Zahlungen & $tenant['paid_total']\,\euro{} \\ + \hline davon Anteil Miete & $tenant['receivable_fee']\,\euro{} \\ + \hline davon Anteil Betriebskostenvorauszahlung & $tenant['paid_overhead']\,\euro{} \\ + \hline + #if 1 > 0 + Zuwenig + #else + Zuviel + #end if + gezahlte Betriebskosten & nachzahlungunsigned\,\euro{} \\ + \hline + \end{tabular} + } + + #if 1 > 0 + Bitte "uberweisen Sie den Betrag von nachzahlungunsigned\,\euro{} kurzfristig auf mein Konto. + #else + Ich werde den Betrag von nachzahlungunsigned\,\euro{} in den n"achsten Tagen auf Ihr Konto "uberweisen. + #end if + + Eine tabellarische "Ubersicht "uber die Zusammensetzung der Gesamt-Betriebskosten + finden Sie in der Anlage. Bitte beachten Sie auch die Information zur Datenspeicherung und -verarbeitung + in der Anlage. + + \closing{Mit freundlichen Gr"u"sen} + + + \pagebreak + \textbf{Information zur Datenspeicherung, -verarbeitung und -weitergabe} + + Hiermit weise ich Sie darauf hin, dass ich im Folgenden aufgeführte personenbezogene Daten zur Erf"ullung + meiner Pflichten aus dem Mietvertrag speichere und verarbeite: + + \begin{itemize} + \item Vor- und Nachname, Anrede und Postanschrift + \item Telefonnummer, gegebenenfalls EMail-Adresse + \item Bankverbindung + \item Das Haus, in dem sich Ihre Wohnung befindet, sowie Ihre Wohnung und die Wohnfl"ache + \item Das Datum Ihres Einzugs und gegebenenfalls Ihres Auszugs + \item Die H"ohe Ihrer Miete und Ihrer Betriebskostenvorauszahlung + \item Das Datum und die H"ohe Ihrer monatlichen Miet- und Betriebskostenvorauszahlungen + \item Korrespondenz w"ahrend des Mietverh"altnisses + \end{itemize} + + Es findet keine Auftragsdatenverarbeitung statt. + + Im Fall von Beauftragungen im Zusammenhang mit Wartungs- oder Instandhaltungsarbeiten gebe + ich falls erforderlich Namen, Anschrift, Telefonnummer und gegebenenfalls EMail-Adresse an Handwerker, + Sachverständige bzw. Gutachter, andere Dienstleister oder Versicherer weiter. + + Die Rechtm"a"sigkeit der Speicherung, Verarbeitung und Weitergabe dieser Daten ergibt sich aus + DSGVO Art.\,6\,(1)\,b. + + + \end{letter} +\end{document} diff --git a/cli/utils.py b/cli/utils.py new file mode 100644 index 0000000..7f916cb --- /dev/null +++ b/cli/utils.py @@ -0,0 +1,2 @@ +def getParam(params, attr, default): + return params[attr] if attr in params else default diff --git a/generate.py b/generate.py index 709343b..736375f 100644 --- a/generate.py +++ b/generate.py @@ -3,6 +3,10 @@ from Cheetah.Template import Template import glob import argparse + + + + parser = argparse.ArgumentParser(description="generate.py") parser.add_argument('--schema', '-s', help='Schema file. Default: schema.json in the current folder.',