I don't like to carry much cash when I travel for business, so from time to
time I use my ATM card at a machine when I'm away and it charges a fee that
is included in the total.
ie - I get $500 cash but the full amount shows as one transaction of
$507.99 (the fee isn't separated)
I am trying to figure out a way to have this separated out when I use an
Importer so that it would show up as $500 USD in cash and 7.99 USD in fees
I have a working CSV import for my PNC transactions, but I can't seem to
figure out how to include this.
Here's the code I use at them moment (without the fees)...
from beancount.ingest.importer import ImporterProtocol
from beancount.core import data
from beancount.core import amount
from beancount.core.number import D
from dateutil.parser import parse
import datetime
import csv
import re
import logging
import warnings
from beancount.core import flags
class PNCChecking(ImporterProtocol):
def __init__(self, account, currency="USD"):
self.account = account
self.currency = currency
super().__init__()
def identify(self, file):
# Check if the file name contains "pnc checking" and ends with
".csv"
if "pnc checking" in file.name.lower() and file
.name.lower().endswith('.csv'):
return True
else:
return False
def file_account(self, file):
return self.account
def extract(self, file):
entries = []
with open(file.name) as infile:
reader = csv.reader(infile)
next(reader, None) # Skip the header row
for index, row in enumerate(reader):
if len(row) < 5: # Checking if the row has at least 5
elements
logging.warning("Row %d does not have enough elements.
Skipping.", index)
continue
meta = data.new_metadata(file.name, index) # Beancount meta
date = datetime.datetime.strptime(row[0], "%m/%d/%Y").date()
# Parse the date of the transaction
# Extracting relevant information from the description to
determine payee and other_account
description = row[1] # Assuming description is in the
second column
payee = "" # Placeholder, modify this based on the
description
other_account = "Expenses" # Placeholder, modify this
based on the description
# Check if the description contains "CARD PMT"
if "CARD PMT" in description:
payee = "PNC Cash Rewards"
other_account = "Liabilities:PNC:CashRewards"
# Check if this is an ATM withdrawal
# and then subtract their ATM Fee and put that in separate
expense
if "ATM" in description:
other_account = "Assets:Cash"
# Determining the credit/debit type based on withdrawals
and deposits
withdrawal = row[2] # Withdrawals amount
deposit = row[3] # Deposits amount
if withdrawal:
units = -amount.Amount(D(withdrawal.replace('$', '')),
self.currency) # Using withdrawal amount
elif deposit:
units = amount.Amount(D(deposit.replace('$', '')), self.
currency) # Using deposit amount
else:
logging.warning("Invalid row: %s", row)
continue
account = self.account # Modify this according to your data
txn = data.Transaction(
meta,
date,
None, # No specific flag
payee,
description,
data.EMPTY_SET,
data.EMPTY_SET,
[
data.Posting(
account, units, None, None, None, None
),
data.Posting(
other_account, -units, None, None, None, None
),
],
)
entries.append(txn)
return entries
This works well and I get this kind of output...
2019-03-01 None "ATM WITHDRAWAL"
Assets:PNC:Checking -407.99 USD
Assets:Cash 407.99 USD
In the section where the ATM transactions are figured out through the
descriptor I added this...
# Check if this is an ATM withdrawal
# and then subtract their ATM Fee and put that in separate expense
if "ATM" in description:
other_account = "Assets:Cash"
# Calculate the ATM fee
atm_fee_amount = D("0.00") # Initialize ATM fee amount
withdrawal_amount = abs(units.number) # Absolute value
of the withdrawal amount
# Check if the withdrawal amount is greater than an
even number
if withdrawal_amount % 2 != 0: # If it's not an even
number
atm_fee_amount = D(withdrawal_amount - (
withdrawal_amount // 2) * 2) # Calculate the fee as the remainder after
division by 2
# Adjust the ATM fee amount
atm_fee_amount = -atm_fee_amount
# Convert the ATM fee amount to a beancount.Amount
object
atm_fee = amount.Amount(atm_fee_amount, self.currency)
# Create a posting for the ATM fee
atm_fee_posting = data.Posting(
"Expenses:BankFees:ATM", atm_fee_amount, None, None,
None, None
)
# Adjust the units for the main account posting
main_account_units = units + atm_fee_amount
# Add the adjusted main account posting
main_account_posting = data.Posting(
account, main_account_units, None, None, None, None
)
txn.postings.append(main_account_posting)
# Add the ATM fee posting to the transaction
txn.postings.append(atm_fee_posting)
But I can't seem to get it to append properly to the postings.
I'd like the output to look like this...
2019-03-01 None "ATM WITHDRAWAL"
Assets:PNC:Checking -407.99 USD
Assets:Cash 400.00 USD
Expenses:BankFees:ATM -7.99 USD
Any help would be appreciated.
I'll probably figure it out eventually, but if anyone has done this already
I would love to hear how you did it. So far I have been sort of
Frankensteining pieces from Beancount examples I've found so I my
understanding of everything is not great yet.
--
You received this message because you are subscribed to the Google Groups
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/beancount/6225321a-b905-4b23-ac5d-6eeb44289122n%40googlegroups.com.