I didn't originally write it (it's a fork of
https://github.com/higoramp/python-financier), but I added some capabilities with regards to splits and transfers. I structure my bi-weekly paycheck as a split transaction with subtractions for all the deductions (healthcare, insurance, etc.) so I have a record of the gross wages. Since that doesn't typically change from week to week, I wrote a method that automates paycheck entry, including two transfers into a retirement account. It is not on the github (since it has private information), but I've been using it for about a year now without issues (until this issue popped up... not sure where it came from...).
Here's a sanitized version of what I'm using (this method goes in pythonfinancier/financier.py):
def add_paycheck(self, account_name):
"""
Add an instance of a paycheck to an account.
Parameters
----------
account_name : str
Name of the account to use
Returns
-------
JSON response of the database upon inserting the transaction
"""
from datetime import datetime
this_id = str(uuid.uuid4())
memo = "2019 pay period ## paycheck"
date = datetime.now().strftime('%Y-%m-%d')
this_retire1_uuid = str(uuid.uuid4())
this_retire2_uuid = str(uuid.uuid4())
other_retire1_uuid = str(uuid.uuid4())
other_retire2_uuid = str(uuid.uuid4())
# getting account from either map or database
account_id = self.find_account(account_name)['_id']
retire_name = 'retirement account name'
# getting payee or creating a new one
payee_id = self.get_or_create_payee("my workplace")['_id']
id_transaction = self.get_id_transaction(this_id)
tr = self.get_transaction(id_transaction)
net_value = 9999.99 * 100
retire1_val = 888.88 * 100
retire2_val = 777.77 * 100
transactions = [{'value': -111.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split1',
'id': str(uuid.uuid4())},
{'value': -1 * retire1_val,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split2',
'transfer': other_retire1_uuid,
'id': this_retire1_uuid},
{'value': -1 * retire2_val,
'payee_name': '',
'category_name': 'incomeNextMonth',
'transfer': other_retire2_uuid,
'memo': '#split3',
'id': this_retire2_uuid},
{'value': -111.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split4',
'id': str(uuid.uuid4())},
{'value': -111.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split5',
'id': str(uuid.uuid4())},
{'value': -111.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split6',
'id': str(uuid.uuid4())},
{'value': -11.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split7',
'id': str(uuid.uuid4())},
{'value': -11.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split8',
'id': str(uuid.uuid4())},
{'value': -11.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split9',
'id': str(uuid.uuid4())},
{'value': -11.11 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#split10',
'id': str(uuid.uuid4())},
{'value': 99999 * 100,
'payee_name': '',
'category_name': 'incomeNextMonth',
'memo': '#gross_wages',
'id': str(uuid.uuid4())}]
for i, t in enumerate(transactions):
t['category'] = self.find_category(t.pop('category_name'))['_id']
if t['payee_name'] is not '':
t['payee'] = self.get_or_create_payee(t.pop('payee_name'))['_id']
else:
# null payee
pass
transactions\[i\] = t
if not tr or '_id' not in tr:
# category is "split"
doc = {'_id': id_transaction, 'value': value,
'account': account_id,
'payee': payee_id, 'date': date,
'category': 'split', 'memo': memo,
'splits': transactions}
self.logger.debug('Adding', doc)
if '_rev' in tr:
doc['_rev'] = tr['_rev']
self.logger.debug(
'importing transaction {0}'.format(doc['_id']))
added_doc = self.cdb.save(self.user_db, doc)
inserted = self.find_transaction(memo=memo, date=date)[0][
'splits']
self.save_transaction(account_name=retire_name,
category_name=None,
value=retire1_val,
date=date,
payee_name=None,
memo='#retirement',
id=other_retire1_uuid,
transfer_id=this_retire1_uuid)
self.save_transaction(account_name=retire_name,
category_name=None,
value=retire2_val,
date=date,
payee_name=None,
memo='#retirement2',
id=other_retire2_uuid,
transfer_id=this_retire2_uuid)
return added_doc
else:
self.logger.warning(
'transaction {0} has already been imported '.format(
tr['_id']))
So I suppose it's mostly manual still, but it would not be too much work to write a small extension to take the output of a ofx file or something and batch upload transactions.