oops, old email.... On Mon, Feb 26, 2024 at 10:54 AM CD <[email protected]> wrote:
> You wrote... > > "First comment; the code > withdrawal_amount % 2 != 0" > > How about... fee_amount = withdrawal_amount % 10... > that's probably a good heuristic within the US, i don't think many ATMs dispense denominations less than 10USD, and I don't think I've ever seen one that charges as much as 10USD in fees. Might not work if you're traveling overseas and withdrawing in a foreign currency.... > > I almost have a working script. I'll post the completed one up shortly. > On Monday, February 26, 2024 at 12:22:51 PM UTC-5 [email protected] > wrote: > >> First comment; the code >> withdrawal_amount % 2 != 0 >> >> checks for "evenness" in the sense of odd (1, 3, 5) vs even (2, 4, 6) >> numbers. This doesn't seem like what you'd want, since if your fee were >> $5 and you withdraw $100, it would count it one way, but if the fee were $2 >> it would count it the other. Only you can come up with the best heuristic >> for yourself (based on your typical withdrawal amounts and typical fees) >> but you might want to revisit this one. >> >> >> as for not appending the posting, it's a bit hard to figure out from your >> two code snippets since I can't tell where the 2nd code snippet lives in >> relation to the 1st. But I suspect that in the 2nd snippet, the "txn" >> you're adding the postings to is not the one you expect. If the 2nd >> snippet actually lives in the context of the >> if "ATM" in description: >> condition in the first snippet, then you're adding to "txn" before you >> create the txn for this input. That means you're probably adding it to the >> txn from the previous iteration, which is still visible and accessible >> (thanks, Python). >> >> On Mon, Feb 26, 2024 at 7:11 AM CDT <[email protected]> wrote: >> >>> 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 >>> <https://groups.google.com/d/msgid/beancount/6225321a-b905-4b23-ac5d-6eeb44289122n%40googlegroups.com?utm_medium=email&utm_source=footer> >>> . >>> >> -- > 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/af0f6e5b-f236-4b40-b1dc-60b91d2e31a1n%40googlegroups.com > <https://groups.google.com/d/msgid/beancount/af0f6e5b-f236-4b40-b1dc-60b91d2e31a1n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- 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/CAFXPr0veRa%3DsQTEQm9cx6K9oRw33733Bo%2B-c2CdxhB37DGyELQ%40mail.gmail.com.
