diff --git a/deployment/docker/standalone/Dockerfile b/deployment/docker/standalone/Dockerfile index 6c2001a5a..94bfb7b54 100644 --- a/deployment/docker/standalone/Dockerfile +++ b/deployment/docker/standalone/Dockerfile @@ -4,6 +4,7 @@ RUN apt-get update && apt-get install -y python3 git python3-pip \ libxml2-dev libxslt1-dev python-dev python-virtualenv locales libffi-dev \ build-essential python3-dev zlib1g-dev libssl-dev npm gettext git \ libpq-dev libmysqlclient-dev libmemcached-dev libjpeg-dev \ + aqbanking-tools \ --no-install-recommends WORKDIR / diff --git a/src/pretix/plugins/banktransfer/__init__.py b/src/pretix/plugins/banktransfer/__init__.py index b51364987..9a52cfcf3 100644 --- a/src/pretix/plugins/banktransfer/__init__.py +++ b/src/pretix/plugins/banktransfer/__init__.py @@ -27,6 +27,10 @@ class BankTransferApp(AppConfig): import chardet # NOQA except ImportError: errs.append(_("Install the python package 'chardet' for better CSV import capabilities.")) + try: + import defusedxml # NOQA + except ImportError: + errs.append(_("Please install the python package 'defusedxml' for security reasons.")) return errs diff --git a/src/pretix/plugins/banktransfer/hbci.py b/src/pretix/plugins/banktransfer/hbci.py new file mode 100644 index 000000000..8748179d0 --- /dev/null +++ b/src/pretix/plugins/banktransfer/hbci.py @@ -0,0 +1,112 @@ +import subprocess +import tempfile +import time +from decimal import Decimal + + +def hbci_transactions(event, conf): + try: + from defusedxml import ElementTree + except: + from xml.etree import ElementTree + + log = [] + data = [] + accname = event.identity + '_' + str(int(time.time())) + try: + try: + subprocess.call([ + 'aqhbci-tool4', 'deluser', '-a', '--all', + '-b', conf['hbci_blz'], + '-u', conf['hbci_userid'] + ]) + except subprocess.CalledProcessError: + pass + aqhbci_params = [ + 'aqhbci-tool4', 'adduser', + '-N', accname, + '-b', conf['hbci_blz'], + '-s', conf['hbci_server'], + '-t', conf['hbci_tokentype'], + '-u', conf['hbci_userid'] + ] + if conf['hbci_customerid']: + aqhbci_params += ['-c', conf['hbci_customerid']] + if conf['hbci_tokenname']: + aqhbci_params += ['-n', conf['hbci_tokenname']] + if conf['hbci_version']: + aqhbci_params += ['--hbciversion=' + str(conf['hbci_version'])] + aqhbci_add = subprocess.check_output(aqhbci_params) + log.append("$ " + " ".join(aqhbci_params)) + log.append(aqhbci_add.decode("utf-8")) + with tempfile.NamedTemporaryFile() as f, tempfile.NamedTemporaryFile() as g: + f.write(('PIN_%s_%s = "%s"\n' % ( + conf['hbci_blz'], + conf['hbci_userid'], + conf['pin'], + )).encode("utf-8")) + f.flush() + aqhbci_params = [ + 'aqhbci-tool4', + '-P', f.name, + '-n', '-A', + 'getsysid' + ] + aqhbci_test = subprocess.check_output(aqhbci_params) + log.append("$ " + " ".join(aqhbci_params)) + log.append(aqhbci_test.decode("utf-8")) + aqbanking_params = [ + 'aqbanking-cli', + '-P', f.name, '-A', '-n', + 'request', + '--transactions', + '-c', g.name + ] + aqbanking_trans = subprocess.check_output(aqbanking_params) + log.append("$ " + " ".join(aqbanking_params)) + log.append(aqbanking_trans.decode("utf-8")) + aqbanking_params = [ + 'aqbanking-cli', + 'listtrans', + '-c', g.name, + '--exporter=xmldb', + ] + aqbanking_conv = subprocess.check_output(aqbanking_params) + log.append("$ " + " ".join(aqbanking_params)) + + root = ElementTree.fromstring(aqbanking_conv) + trans_list = root.find('accountInfoList').find('accountInfo').find('transactionList') + for trans in trans_list.findall('transaction'): + payer = [] + for child in trans: + if child.tag.startswith('remote'): + payer.append(child.find('value').text) + date = '%s-%02d-%02d' % ( + trans.find('date').find('date').find('year').find('value').text, + int(trans.find('date').find('date').find('month').find('value').text), + int(trans.find('date').find('date').find('day').find('value').text) + ) + value = trans.find('value').find('value').find('value').text + if "/" in value: + parts = value.split("/") + num = int(parts[0]) + denom = int(parts[1]) + value = Decimal(num) / Decimal(denom) + value = str(value.quantize(Decimal('.01'))) + data.append({ + 'payer': "\n".join(payer), + 'reference': trans.find('purpose').find('value').text, + 'amount': value, + 'date': date + }) + except subprocess.CalledProcessError as e: + log.append("Command %s failed with %d and output:" % (e.cmd, e.returncode)) + log.append(e.output.decode("utf-8")) + except Exception as e: + log.append(str(e)) + finally: + subprocess.call([ + 'aqhbci-tool4', 'deluser', '-a', '-N', accname + ]) + log = "\n".join(log) + return data, log diff --git a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/hbci_log.html b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/hbci_log.html new file mode 100644 index 000000000..a4311e7c7 --- /dev/null +++ b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/hbci_log.html @@ -0,0 +1,9 @@ +{% extends "pretixplugins/banktransfer/import_base.html" %} +{% load i18n %} +{% load bootstrap3 %} +{% block inner %} +
{{ log }}
+{% endblock %}
diff --git a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
index 8d461b20c..44cad1e0a 100644
--- a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
+++ b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
@@ -1,25 +1,50 @@
{% extends "pretixplugins/banktransfer/import_base.html" %}
{% load i18n %}
+{% load bootstrap3 %}
{% block inner %}
- {% blocktrans trimmed %} - This page allows you to upload bank statement files to process incoming payments. - {% endblocktrans %}
-{% blocktrans trimmed %}
- Currently, this feature supports .csv files and files in the MT940 format.
- {% endblocktrans %}
{% blocktrans trimmed %} + This page allows you to upload bank statement files to process incoming payments. + {% endblocktrans %}
+{% blocktrans trimmed %}
+ Currently, this feature supports .csv files and files in the MT940 format.
+ {% endblocktrans %}