Hi Sirio, IIRC the SQL client doesn't use nor respect the functionality implemented by DisplayContext: https://bitbucket.org/blais/beancount/src/tip/TODO?fileviewer=file-view-default#TODO-480 I want to rewrite the SQL client entirely at some point, and I figured I'd leave that for the rewrite.
Read this doc for info on tolerances: http://furius.ca/beancount/doc/tolerances Also, reading the source code of the DisplayContext and its related classes should provide a good overview of how that's all implemented: https://bitbucket.org/blais/beancount/src/tip/beancount/core/display_context.py On Fri, May 26, 2017 at 9:21 AM, <[email protected]> wrote: > Ciao Martin, > > I'm building some reporting/form generation on top of Beancount, and have > a question about how best to handle rounding/tolerance in the code. > > The problem I'm trying to solve is to safely assert invariants which will > detect accounting errors. > > Let me give an example: > > > from beancount.query.query import run_query > from beancount.query.query_render import render_text > from beancount.core.amount import Amount, mul as amount_mul > from beancount.core.number import Decimal > > > def total_query_(entries, options, currency, query_string): > '''Runs a query, then returns the last value (or 0 if no result) as > an Amount > ''' > qy_types, qy_rows = run_query(entries, options, query_string) > if len(qy_rows): > return qy_rows[-1].total.get_units(currency) > else: > return Amount(Decimal('0.00'), currency) > > > taxable_earnings = total_query_(entries, options, currency, > '''SELECT sum(position) as total > WHERE account ~ "EarningsBlahBlah" > '''.format(fiscal_quarter.query()) > ) > > tax_owed = total_query_(entries, options, currency, > '''SELECT sum(position) as total > WHERE account ~ "SpecificTaxAccount" > '''.format(fiscal_quarter.query()) > ) > > tax_rate = Decimal('0.07') > currency = 'WHATEVER' > > # invariant: bookings to SpecificTaxAccount must equal EarningsBlahBlah > times the tax rate > assert amount_mul(taxable_earnings, tax_rate) == tax_owed, ( > 'taxable earnings {0} * {1} = {2} != tax_owed {3}'.format( > taxable_earnings, tax_rate, > amount_mul(taxable_earnings, tax_rate), > tax_owed) > ) > > This might fail because 1.4188 != 1.42 > However, accounting errors might create a (perfectly valid, error-free) > ledger where there is much more discrepancy between the figures - and I > need to catch that. > > As a note, I'm running with: > > option "inferred_tolerance_default" "*:0.005" > > It's not immediately obvious to me how to best plug into Beancount's > "standard" rounding approach (and TBH I don't fully understand that > approach yet :P) > > I could of course just hack something like this: > > assert round(amount_mul(taxable_earnings, tax_rate).number, 2) == > round(tax_owed.number, 2) > > ... but that's so ugly it hurts and I'm also hard-coding a rounding value > disregarding beancount's tolerance figures. > > Any advice is appreciated. > > Thank you and all the best, > > Sirio > > -- > 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 post to this group, send email to [email protected]. > To view this discussion on the web visit https://groups.google.com/d/ > msgid/beancount/2ddc2c79-952c-448d-ad95-ddf6490b9b2a%40googlegroups.com > <https://groups.google.com/d/msgid/beancount/2ddc2c79-952c-448d-ad95-ddf6490b9b2a%40googlegroups.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > -- 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 post to this group, send email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/beancount/CAK21%2BhPOz7NcvJ6esJGsqkvikH8eMHytx4z8AB23B3-fwhL54A%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
