#!/usr/bin/python3 import configparser import argparse import datetime import logging from fints.client import FinTS3PinTanClient import peewee as p from slixmpp import ClientXMPP import transaction_details 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() def format_message(self): details = transaction_details.parse_transaction_details(self.sepa_transaction_details) return "{accountnumber} {details[Buchungstext]}: {amount_str} {details[Verwendungszweck]}".format( entry_date=self.sepa_entry_date, accountnumber=self.accountnumber, amount_str=self.sepa_amount_str, details=details) 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 = t.format_message() 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()