Skip to content

Instantly share code, notes, and snippets.

@psybers
Forked from duplaja/simplefin-transactions.py
Last active May 2, 2024 18:21
Show Gist options
  • Save psybers/60e7332f93dc59f3ac5f636827921e17 to your computer and use it in GitHub Desktop.
Save psybers/60e7332f93dc59f3ac5f636827921e17 to your computer and use it in GitHub Desktop.
SimpleFIN Print Transactions (to terminal)
#!/usr/bin/env python3
import argparse
import base64
import datetime
import pickle
import re
import requests
import sys
import time
def multiselect_from_list(choices, choice_name, deselect = False):
selected = list(range(len(choices))) if deselect else []
while True:
print(f'Choose a set of {choice_name} from this list:')
for i in range(len(choices)):
print(f' {"+ " if i in selected else "- "}{i + 1})\t{choices[i]}'.expandtabs(4))
selection = input(f'Toggle selected {choice_name} (or press enter to finish): ').strip()
sys.stdout.flush()
if selection == '':
return [choices[i] for i in selected]
if selection.lower() == 'all':
selected = list(range(len(choices)))
continue
if selection.lower() == 'none':
selected = []
continue
items = set()
for item in re.split('[^0-9-]+', selection):
try:
if '-' in item:
if item[0] == '-':
item = '1' + item
elif item[-1] == '-':
item = item + str(len(choices))
start, end = map(int, item.split('-'))
for x in range(start - 1, end):
items.add(x)
else:
items.add(int(item) - 1)
except ValueError:
pass
for toggle in list(items):
try:
if toggle < 0 or toggle >= len(choices):
raise Exception(toggle)
if toggle in selected:
selected = [s for s in selected if s != toggle]
else:
selected = sorted(selected + [toggle])
except Exception as e:
print(f'Error: Selection "{e.args[0] + 1}" must be between 1 and {len(choices)}, inclusive.\n')
def setup_function(file_name):
setup_token = input('SimpleFin setup token: ')
claim_url = base64.b64decode(setup_token)
response = requests.post(claim_url)
access_url = response.text
data = { 'access_url': access_url }
with open(file_name, 'wb') as file:
pickle.dump(data, file)
file.close()
return None
def email(errors):
import smtplib
from email.mime.text import MIMEText
errors = str(errors)
msg = MIMEText(f'https://beta-bridge.simplefin.org/auth/login\n\nErrors: {errors}')
msg['Subject'] = 'SimpleFin broke - AGAIN'
msg['From'] = 'EMAIL'
msg['To'] = 'EMAIL'
with smtplib.SMTP_SSL('smtp.mailserver.com', 465) as s:
s.login('USER', 'PW')
s.sendmail(msg['From'], msg['To'], msg.as_string())
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--errorcheck', action='store_true', help='test for errors only')
parser.add_argument('--select', action='store_true', help='select accounts')
parser.add_argument('--deselect', action='store_true', help='deselect accounts')
args = parser.parse_args()
file_name = 'simplefin-data.pickle'
try:
with open(file_name,'rb') as file:
data = pickle.load(file)
access_url = data['access_url']
file.close()
except IOError:
access_url = ''
if not access_url:
setup_function(file_name)
with open(file_name,'rb') as file:
data = pickle.load(file)
access_url = data['access_url']
file.close()
scheme, rest = access_url.split('//', 1)
auth, rest = rest.split('@', 1)
url = scheme + '//' + rest + '/accounts'
username, password = auth.split(':', 1)
#end_datetime = datetime.date(2024, 2, 26)
end_datetime = datetime.datetime.now()
end_unixtime = int(round(time.mktime(end_datetime.timetuple())))
start_datetime = end_datetime - datetime.timedelta(days=30)
start_unixtime = int(round(time.mktime(start_datetime.timetuple())))
response = requests.get(url, auth=(username, password),params={'start-date': start_unixtime, 'end-date': end_unixtime, 'pending': 1})
data = response.json()
accounts = data['accounts']
if args.select or args.deselect:
names = [account['name'] for account in accounts]
selected = multiselect_from_list(names, 'accounts', args.deselect)
accounts = [account for account in accounts if account['name'] in selected]
errors = data['errors']
if errors:
if args.errorcheck:
email(errors)
print(errors)
if args.errorcheck:
sys.exit(0)
for account in accounts:
import json
print(json.dumps(account, indent=2))
name = '\n'+account['org']['name']+' - '+account['name']+' - '+account['balance']+'\n\n'
print(name)
transactions = account['transactions']
for transaction in transactions:
print(transaction)
print('--------------------------------------------------')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment