diff options
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | account.sample.ini | 9 | ||||
-rw-r--r-- | requirements.txt | 4 | ||||
-rw-r--r-- | transaction_details.py | 78 | ||||
-rwxr-xr-x | transfers.py | 55 |
5 files changed, 32 insertions, 119 deletions
@@ -1,5 +1,4 @@ # Finanzstatus scripts +## transfers.py -## transfers - -fetch transactions via hbci and send jabber notices.
\ No newline at end of file +fetch transactions via hbci and send matrix notices.
\ No newline at end of file diff --git a/account.sample.ini b/account.sample.ini index 0d54dfd..a4ac063 100644 --- a/account.sample.ini +++ b/account.sample.ini @@ -10,7 +10,8 @@ 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 +[matrix] +user = username +pass = password.... +host = matrix.org +room = #bot-room:matrix.org diff --git a/requirements.txt b/requirements.txt index ceba34e..e473e82 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -fints==0.2.1 +fints==2.1.1 peewee==2.10.2 -slixmpp==1.2.4.post1
\ No newline at end of file +matrix_client==0.3.2
\ No newline at end of file diff --git a/transaction_details.py b/transaction_details.py deleted file mode 100644 index baa6ef3..0000000 --- a/transaction_details.py +++ /dev/null @@ -1,78 +0,0 @@ -# see https://github.com/raphaelm/python-fints/pull/8 - -# https://www.db-bankline.deutsche-bank.com/download/MT940_Deutschland_Structure2002.pdf -DETAIL_KEYS = { - '': 'Geschäftsvorfall-Code', - '00': 'Buchungstext', - '10': 'Primanota', - '20': 'Verwendungszweck', - '30': 'Auftraggeber BLZ', - '31': 'Auftraggeber Kontonummer', - '32': 'Auftraggeber Name', - '34': 'Rücklastschriften', - '35': 'Empfänger: Name', - '60': 'Zusätzl. Verwendungszweckangaben', -} - -# https://www.hettwer-beratung.de/sepa-spezialwissen/sepa-technische-anforderungen/sepa-geschäftsvorfallcodes-gvc-mt-940/ -VERWENDUNGSZWECK_KEYS = { - '': 'Verwendungszweck', - 'IBAN': 'Auftraggeber IBAN', - 'BIC': 'Auftraggeber BIC', - 'EREF': 'End to End Referenz', - 'MREF': 'Mandatsreferenz', - 'CRED': 'Auftraggeber Creditor ID', - 'PURP': 'Purpose Code', - 'SVWZ': 'Verwendungszweck', - 'MDAT': 'Mandatsdatum', - 'ABWA': 'Abweichender Auftraggeber', - 'ABWE': 'Abweichender Empfänger', - 'SQTP': 'FRST / ONE / OFF /RECC', - 'ORCR': 'SEPA Mandatsänderung: alte SEPA CI', - 'ORMR': 'SEPA Mandatsänderung: alte SEPA Mandatsreferenz', - 'DDAT': 'SEPA Settlement Tag für R- Message', - 'KREF': 'Kundenreferenz', - 'DEBT': 'Debtor Identifier bei SEPA Überweisung', - 'COAM': 'Compensation Amount', - 'OAMT': 'Original Amount', -} - - -def parse_transaction_details(details): - detail_str = ''.join(d.strip() for d in details.splitlines()) - detail_str = detail_str[3:] - result = dict(map(lambda k: [k,None], DETAIL_KEYS.values())) - result.update(dict(map(lambda k: [k,None], VERWENDUNGSZWECK_KEYS.values()))) - pre_result = {} - for segment in detail_str.split('?'): - pre_result[segment[0:2]] = segment[2:] - for key, value in pre_result.items(): - if key in DETAIL_KEYS: - result[DETAIL_KEYS[key]] = value - else: - if key == '33': - result[DETAIL_KEYS['32']] = (result[DETAIL_KEYS['32']] or '') + value - elif key.startswith('2'): - result[DETAIL_KEYS['20']] = (result[DETAIL_KEYS['20']] or '') + value - else: - raise ValueError('Found Key ?{}, which is not documented'.format(key)) - post_result = {} - segment_type = None - text = '' - for index, char in enumerate(result['Verwendungszweck']): - if char == '+' and result['Verwendungszweck'][index-4:index] in VERWENDUNGSZWECK_KEYS: - if segment_type: - post_result[segment_type] = text[:-4] - text = '' - else: - text = '' - segment_type = result['Verwendungszweck'][index-4:index] - else: - text += char - if segment_type: - post_result[segment_type] = text - else: - post_result[''] = text - for key, value in post_result.items(): - result[VERWENDUNGSZWECK_KEYS[key]] = value - return result
\ No newline at end of file diff --git a/transfers.py b/transfers.py index 3271832..63e051f 100755 --- a/transfers.py +++ b/transfers.py @@ -6,8 +6,8 @@ import logging from fints.client import FinTS3PinTanClient import peewee as p -from slixmpp import ClientXMPP -import transaction_details +from playhouse.fields import PickledField +from matrix_client.client import MatrixClient logging.basicConfig(level=logging.INFO) @@ -25,21 +25,20 @@ db = p.SqliteDatabase(args.db) class Transaction(p.Model): created_date = p.DateField(default=datetime.date.today) accountnumber = p.CharField() + identifier = p.CharField() sepa_entry_date = p.DateField() - sepa_amount = p.DecimalField() - sepa_transaction_details = p.CharField() - sepa_status = p.CharField() - sepa_currency = p.CharField() + details = PickledField() - def format_message(self): - details = transaction_details.parse_transaction_details(self.sepa_transaction_details) - return '{transaction[accountnumber]} {details[Buchungstext]}: {transaction[sepa_amount]} ' \ - '{transaction[sepa_currency]} {details[Auftraggeber Name]} {details[Verwendungszweck]}'.format( - transaction=self._data, details=details) + def format_message_html(self): + return """\ +{accountnumber} <b>{details[posting_text]}</b>: +<code>{details[amount].amount}</code> {details[amount].currency} +{details[applicant_name]} <i>{details[purpose]} {details[end_to_end_reference]}</i> +""".format(**self._data) class Meta: database = db - indexes = ((('accountnumber', 'sepa_entry_date', 'sepa_transaction_details'), True),) + indexes = ((('accountnumber', 'identifier'), True),) db.create_tables([Transaction], True) @@ -59,17 +58,14 @@ 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()) +transactions = f.get_transactions(account, last_transaction_date, datetime.date.today()) new_transactions = [] for t in transactions: - filter_pred = { - 'accountnumber': config['bank']['accountnumber'], - 'sepa_entry_date': datetime.date.fromordinal(t.data['entry_date'].toordinal()), - 'sepa_transaction_details': t.data['transaction_details'], - } - data = {'sepa_amount': t.data['amount'].amount, 'sepa_status': t.data['status'], - 'sepa_currency': t.data['currency']} + date = datetime.date.fromordinal(t.data['entry_date'].toordinal()), + identifier = "{applicant_bin}-{applicant_iban}-{mydate}".format(mydate=date, **t.data) + filter_pred = {'accountnumber': config['bank']['accountnumber'], 'identifier': identifier} + data = {'details': t.data, 'sepa_entry_date': date} try: record = Transaction.get(**filter_pred) record.update(data) @@ -82,18 +78,13 @@ for t in transactions: record.save() if len(new_transactions) > 0: - cl = ClientXMPP(config['jabber']['jid'], config['jabber']['password']) + client = MatrixClient(config['matrix']['host']) + token = client.login(config['matrix']['user'], config['matrix']['pass']) + room = client.join_room(config['matrix']['room']) - def session_start(event): - for t in new_transactions: - message = t.format_message() - cl.send_message(config['jabber']['recipient'], message, mtype='chat') - logging.info("Sent info %s", message) - cl.disconnect() + for t in new_transactions: + message = t.format_message_html() + room.send_html(message) - - cl.add_event_handler('session_start', session_start) - cl.add_event_handler('killed', lambda *_: cl.loop.stop()) - cl.connect() - cl.process() + client.logout() |