I think I've come across a bug in my budget...
I do split transactions for my paychecks. One of these splits is a transfer to an off-budget retirement account. I have two transactions in the retirement account that are listed as transfers to my checking account, but neither one has a matching split in the checking account. I cannot delete these transactions from my retirement account because it says "Cannot delete transfer of split transaction. This transfer is from a split transaction. To remove it, modify the split transaction this transfer originates from."
Is there a "super delete" option? I'm not sure how I ended up in this state.
@jat255 Was the split transaction entered using the mobile app? I remember having some issues with transfers in splits, and I'm almost certain the main app had the same issue. It's on my list of things to revisit. I remember that refreshing the browser sometimes would fix things after entering a split that contained a transfer. Have you tried that?
I think it came about as a result of some code that I have to automatically enter my paychecks that I added using https://github.com/jat255/python-financier/
Using GET requests, I can see that there are no splits defined for that transaction, but I'm wondering if some other deleted transaction is referencing it and that's why the front-end is getting messed up. I can use PUTs to change the memo and set the value to 0, but I'm getting a 409 conflict response when I try to issue a DELETE on the document.
What happens if you use a PUT request to set "_deleted = true"?
It worked! My savior :)
Awesome, I'll have to check out that python code. Are you automating transaction import, or using for quick manual entries?
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.