I recently encountered a very similar situation. I have transaction statements where values in the debit column are negative, but credit values are positive-valued. I am also subclassing the built-in csv importer class.
At first I thought about using a decorator to wrap the built-in `get_amounts()` function. But the values in rows passed to `get_amounts()` are strings. Stripping the `-` characters from these strings worked alright but didn't feel too clean (I guess transactions parsing is anything but clean!). Or maybe negating the debit values returned from the function. To make matters worse, I found that exporting CSV values from my bank's website sometimes had negative values, but other times they are positive -- for the same transactions! In the end I just decided to reimplement `get_values()` instead of decorating it. That resulted in a more general solution that handles the shitty situation above. I just negate the absolute value of debit values. I then monkey patch the function in the CSV module. If you haven't got a good handle on how Python namespaces work, you may get tripped up by monkey patching. Spend a bit of time getting familiar with it. You'll change the behaviour of your other importers depending on the CSV module if you're not careful. def get_amounts(iconfig, row): """Get the amount columns of a row. This is based on the original function in the built-in CSV importer module. In the original function, debit amounts are negated before returning. If you export transactions from the transaction listing screen, debit values are positive. But if you export transactions from the transaction search screen, the very same debit values are negative. How bizarre! This is handled by negating the absolute value of debit values. Credit values are positive regardless of where the CSV export came from. Sometimes transactions are pending (authorisation only). In this case, the "Transaction Type" column is empty. We use this to ignore these transactions: None is returned for both debit and credit. The `allow_zero_amounts` argument and corresponding logic has been removed from the original function. Args: iconfig: A dict of Col to row index. row: A row array containing the values of the given row. Returns: A pair of (debit-amount, credit-amount), both of which are either an instance of Decimal or None, or not available. """ # If transaction type is not populated, the transaction is pending. Return # None instead of actual values. if not row[iconfig[csv.Col.DRCR]]: return (None, None) debit, credit = None, None if csv.Col.AMOUNT in iconfig: credit = row[iconfig[csv.Col.AMOUNT]] else: debit, credit = [row[iconfig[col]] if col in iconfig else None for col in [csv.Col.AMOUNT_DEBIT, csv.Col.AMOUNT_CREDIT]] # Take the absolute debit value, then negate it. return (-abs(csv.D(debit)) if debit else None, csv.D(credit) if credit else None) # Monkey patch function in csv module. csv.get_amounts = get_amounts On Sunday, May 10, 2020 at 5:11:59 AM UTC+10, walle...@gmail.com wrote: > > Hello, > > I am working on csv importers by subclassing the provided csv class and > wrapping __init__ to setup config, etc. It worked well, but some of my csv > files have a different numbering format. The ones I run into are: debit > shown as negative number, and some gives me 0 for debit when it's a credit > so that I have an additional line of 0 amount. > > These are all easy fixes, through monkey patching the get_amounts (with > wrapping old) function in the csv module. The problem is that when I have > to patch it twice for the above 2 situations, the patches spill over and > change the outcomes depending on how I import my custom importers in > xxx.import file. > > I can pass the test for each individual importer, but not when I run all > tests. > > I can surely just copy and change the original csv module to move > get_amounts as a class method. But I just want to check if I am doing it > right. > > Thanks for any suggestion. > > W.E. > > -- 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 beancount+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/beancount/f075b7fb-5d35-48ad-b298-323bcba2985e%40googlegroups.com.