summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--README.md5
-rw-r--r--account.sample.ini16
-rw-r--r--requirements.txt3
-rwxr-xr-xtransfers.py91
5 files changed, 119 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..69a43fc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+account.ini
+*.db
+*.iml
+*.idea \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..996ed6e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# Finanzstatus scripts
+
+## transfers
+
+fetch transactions via hbci and send jabber notices. \ No newline at end of file
diff --git a/account.sample.ini b/account.sample.ini
new file mode 100644
index 0000000..0d54dfd
--- /dev/null
+++ b/account.sample.ini
@@ -0,0 +1,16 @@
+[bank]
+; The banks hbci url
+url=https://brokerage-hbci.consors.de/hbci
+; Bankleitzeil
+blz=76030080
+; Login (Consorsbank: Kontonummer + Berechtigtennummer 001)
+username=123123123001
+; PIN
+password=secre
+; The account-number to be inspected (kontonummer)
+accountnumber=123123123
+
+[jabber]
+jid = bot@domain.tld
+password = bot-password
+recipient = receiver-of-notifications \ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..ceba34e
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+fints==0.2.1
+peewee==2.10.2
+slixmpp==1.2.4.post1 \ No newline at end of file
diff --git a/transfers.py b/transfers.py
new file mode 100755
index 0000000..c14055f
--- /dev/null
+++ b/transfers.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python3
+import configparser
+import argparse
+import datetime
+import logging
+
+from fints.client import FinTS3PinTanClient
+import peewee as p
+from slixmpp import ClientXMPP
+
+logging.basicConfig(level=logging.INFO)
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--config', nargs=1, required=True, help='Account .ini config file')
+parser.add_argument('--db', nargs=1, default='log.db', help='Database')
+parser.add_argument('--fetch-last', metavar='DAYS', default=None, type=int, help='Fetch all last DAYS')
+args = parser.parse_args()
+
+config = configparser.ConfigParser()
+config.read(args.config)
+db = p.SqliteDatabase(args.db)
+
+
+class Transaction(p.Model):
+ created_date = p.DateField(default=datetime.date.today)
+ accountnumber = p.CharField()
+ sepa_entry_date = p.DateField()
+ sepa_amount_str = p.CharField()
+ sepa_transaction_details = p.CharField()
+
+ class Meta:
+ database = db
+ indexes = ((('accountnumber', 'sepa_entry_date', 'sepa_transaction_details'), True),)
+
+
+db.create_tables([Transaction], True)
+
+if args.fetch_last is None:
+ # Look for last date of a saved transaction or fallback default timesamp
+ last_transaction_date = Transaction \
+ .select(p.fn.max(Transaction.sepa_entry_date)) \
+ .where(Transaction.accountnumber == config['bank']['accountnumber']) \
+ .scalar(convert=True) or datetime.date.today() - datetime.timedelta(30)
+else:
+ last_transaction_date = datetime.date.today() - datetime.timedelta(args.fetch_last)
+
+f = FinTS3PinTanClient(config['bank']['blz'], config['bank']['username'], config['bank']['password'],
+ config['bank']['url'])
+accounts = f.get_sepa_accounts()
+account = list(filter(lambda a: a.accountnumber == config['bank']['accountnumber'], accounts))[0]
+
+logging.info("select transactions on account %s starting from %s", account.accountnumber, last_transaction_date)
+transactions = f.get_statement(account, last_transaction_date, datetime.date.today())
+
+new_transactions = []
+for t in transactions:
+ y, m, d, *_ = t.data['entry_date'].timetuple()
+ entry_date = datetime.date(y, m, d)
+ filter_pred = {
+ 'accountnumber': config['bank']['accountnumber'],
+ 'sepa_entry_date': entry_date,
+ 'sepa_transaction_details': t.data['transaction_details'],
+ }
+ data = {'sepa_amount_str': str(t.data['amount'])}
+ try:
+ record = Transaction.get(**filter_pred)
+ record.update(data)
+ logging.info("Updated %s", record.id)
+ except Transaction.DoesNotExist:
+ data.update(filter_pred)
+ record = Transaction.create(**data)
+ new_transactions += [record]
+ logging.info("Created %s", record.id)
+ record.save()
+
+cl = ClientXMPP(config['jabber']['jid'], config['jabber']['password'])
+
+
+def session_start(event):
+ cl.send_presence()
+ for t in new_transactions:
+ message = "{} {} {}".format(t.accountnumber, t.sepa_amount_str, t.sepa_transaction_details)
+ cl.send_message(config['jabber']['recipient'], message, mtype='chat')
+ logging.info("Sent info %s", message)
+ cl.disconnect()
+
+
+cl.add_event_handler('session_start', session_start)
+cl.add_event_handler('killed', lambda *_: cl.loop.stop())
+cl.connect()
+cl.process()