tenant letter nearly done

This commit is contained in:
2022-01-29 13:42:58 +01:00
parent b3a49b0fb6
commit f2f2100b8c
7 changed files with 156 additions and 169 deletions

4
.gitignore vendored
View File

@ -6,3 +6,7 @@ cli/config/dbconfig.ini
*~ *~
.*~ .*~
.vscode/ .vscode/
cli/*.tex
cli/*.log
cli/*.pdf
cli/*.aux

View File

@ -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}

View File

@ -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}

View File

@ -2,18 +2,16 @@ from db import dbGetMany, dbGetOne
import datetime import datetime
from loguru import logger from loguru import logger
from decimal import * from decimal import *
from utils import getParam
from Cheetah.Template import Template
def perform(dbh, params): def perform(dbh, params):
try: year = getParam(params, 'year', datetime.datetime.today().year)
year = params['year']
except KeyError:
year = datetime.datetime.today().year
startDate = datetime.datetime(year, 1, 1, 0, 0, 0) startDate = datetime.datetime(year, 1, 1, 0, 0, 0)
endDate = datetime.datetime(year, 12, 31, 23, 59, 59) endDate = datetime.datetime(year, 12, 31, 23, 59, 59)
premises = (1, 2) premises = (1, 2)
# get overhead sums by object, category and timespan # get overhead sums by object, category and timespan
overheadSums = dbGetMany( overheadSums = dbGetMany(
dbh, dbh,
@ -73,13 +71,12 @@ def perform(dbh, params):
for overheadSum in overheadSums: for overheadSum in overheadSums:
logger.info(f"house: {overheadSum['house']}, considerMinusArea: {overheadSum['considerminusarea']}, category: {overheadSum['category']}, sum: {overheadSum['sum']}") logger.info(f"house: {overheadSum['house']}, considerMinusArea: {overheadSum['considerminusarea']}, category: {overheadSum['category']}, sum: {overheadSum['sum']}")
subtotal = {} #subtotal = {}
for premise in premises: #for premise in premises:
v = [ x['sum'] for x in overheadSums if x['house_id'] == premise ] # v = [ x['sum'] for x in overheadSums if x['house_id'] == premise ]
logger.info(f"{v=}") # logger.info(f"{v=}")
subtotal[premise] = sum(v) # subtotal[premise] = sum(v)
logger.info(f"{subtotal=}") # logger.info(f"{subtotal=}")
# get areas and factors # get areas and factors
totalAreas = {} totalAreas = {}
@ -169,6 +166,11 @@ def perform(dbh, params):
logger.info(f"{totalAreas=}") logger.info(f"{totalAreas=}")
##### ATTENTION: SCRIPT ABORT TEMPORALY INSERTED HERE #####
return
###########################################################
# get flat tenants by object and timespan with paid overhead and due overhead # get flat tenants by object and timespan with paid overhead and due overhead
@ -178,10 +180,17 @@ def perform(dbh, params):
"statement": "statement":
""" """
select t.id as tenant_id, select t.id as tenant_id,
t.salutation as tenant_salutation,
t.firstname as tenant_firstname, t.firstname as tenant_firstname,
t.lastname as tenant_lastname, 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.id as flat_id,
f.description as flat, f.description as flat,
f.area as flat_area,
p.id as house_id, p.id as house_id,
p.description as house, p.description as house,
ty.startdate as startdate, ty.startdate as startdate,
@ -207,8 +216,9 @@ def perform(dbh, params):
} }
) )
letters = []
for tenant in tenants: 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( paidTotal = dbGetOne(
dbh, dbh,
@ -228,6 +238,8 @@ def perform(dbh, params):
} }
} }
) )
tenant['paid_total'] = paidTotal['sum']
receivableFee = dbGetOne( receivableFee = dbGetOne(
dbh, dbh,
{ {
@ -246,13 +258,33 @@ def perform(dbh, params):
} }
} }
) )
tenant['receivable_fee'] = receivableFee['sum']
logger.info(f"Payments: cnt: {paidTotal['cnt']}, sum: {paidTotal['sum']}") tenant['rent_time'] = receivableFee['cnt']
logger.info(f"Receivable fees: cnt: {receivableFee['cnt']}, sum: {receivableFee['sum']}")
paidOverheadAdvance = paidTotal['sum'] - receivableFee['sum'] tenant['paid_overhead'] = paidTotal['sum'] - receivableFee['sum']
logger.info(f"Paid overhead: {paidOverheadAdvance} (by month: {paidOverheadAdvance / Decimal(12)})")
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))

94
cli/jahresabrechnung.tmpl Normal file
View File

@ -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}

2
cli/utils.py Normal file
View File

@ -0,0 +1,2 @@
def getParam(params, attr, default):
return params[attr] if attr in params else default

View File

@ -3,6 +3,10 @@ from Cheetah.Template import Template
import glob import glob
import argparse import argparse
parser = argparse.ArgumentParser(description="generate.py") parser = argparse.ArgumentParser(description="generate.py")
parser.add_argument('--schema', '-s', parser.add_argument('--schema', '-s',
help='Schema file. Default: schema.json in the current folder.', help='Schema file. Default: schema.json in the current folder.',