Thanks for the pointer. But that option will invert signs for both debit and credit numbers. But I only need to invert debit sign.
W.E. On Sunday, May 17, 2020 at 5:38:04 AM UTC-4, Martin Michlmayr wrote: > > Note that the cvs importer in the Mercurial repo has an invert_sign > option now, which might do what you need. > > invert_sign: Optional[bool] = False, > > invert_sign: If true, invert the amount's sign unconditionally. > > > * [email protected] <javascript:> <[email protected] <javascript:>> > [2020-05-17 01:27]: > > Posting the previous made me think about this some more. > > > > I think this is more concise and generalised: > > > > def normalise(func): > > @wraps(func) > > def wrapper(*args, **kwargs): > > """Makes all debits negative, and all credits positive.""" > > debit, credit = func(*args, **kwargs) > > return ( > > -abs(debit) if debit else debit, > > abs(credit) if credit else credit > > ) > > return wrapper > > > > # Monkey patch function in csv module. > > csv.get_amounts = normalise(csv.get_amounts) > > > > > > On Sunday, May 17, 2020 at 12:00:44 PM UTC+10, [email protected] > wrote: > > > > > > 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, [email protected] > 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 [email protected] <javascript:>. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/beancount/2bf01ddf-c99c-4507-8fc2-034ed07deba2%40googlegroups.com. > > > > > -- > Martin Michlmayr > https://www.cyrius.com/ > -- 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/a112c39c-31ea-4b0d-a20c-b2067486e877%40googlegroups.com.
