simonmichael / hledger

Robust, fast, intuitive plain text accounting tool with CLI, TUI and web interfaces.
https://hledger.org
GNU General Public License v3.0
3k stars 320 forks source link

Rounding in auto posting to the nearest cent, to calculate VAT #1092

Open georghendrik opened 5 years ago

georghendrik commented 5 years ago

What are you suggesting? Hledger support for rounding of auto-posting amounts to the nearest cent.

How would that be useful? Hledger's current auto-posting / transaction modifiers may assist in automatically calculating VAT and other taxes. However, hledger keeps all decimals for the calculated auto-posting VAT amounts, while e.g. Dutch and German tax law requires rounding of the VAT amounts for every transaction.

The following example.journal may help to illustrate this:

# Declare the default commodity to mathematically round to 2 decimal digits. 
# This appears only to affect reports, not calculations of automatic postings
D 1.00

= tag:VAT21
    liability:vat  *-0.21
    assets:receivable  *0.21

1/1 Invoice 1 with 21% VAT on 1.50, that's 0.32
    assets:receivable  -1.50 ; VAT21:
    revenue

1/1 Invoice 2 with 21% VAT on 1.50, that's 0.32 again
    assets:receivable  -1.50 ; VAT21:
    revenue

# > hledger --auto bal
#                -3.63  assets:receivable
#                 0.63  liability:vat
#                 3.00  revenue
# --------------------
#                    0

# Dutch tax law requires rounding to the cent on every invoice. 
# To support that, the liability:vat balance should be 0.64 (that is: 2x 0.32).
# Instead, it's 2x 0.315.
georghendrik commented 5 years ago

Prior art

ledger-cli seems to support a roundto function, although for the latest release on windows, some hoop-jumping seems to be required to get it to actually round the posting amounts. In practice the following currently rounds the above example to 0.31, not 0.32:

= tag("VAT21")
    liability:vat   (-1 / amount * roundto(amount * 0.21, 2) )
    assets:receivable  (1 / amount * roundto(amount * 0.21, 2))

I would have expected the following to have worked:

= tag("VAT21")
    liability:vat   (roundto(amount * -0.21, 2) )
    assets:receivable  (roundto(amount * 0.21, 2))

beancount: I could not locate a user-callable rounding function in the current beancount docs.

georghendrik commented 5 years ago

Is a directive a more natural way to support this use case?

The source for hledger's TransactionModifers supports multiplication with a single constant amount, not the evaluation of an expression tree. Altering TransactionModifiers and journal file parsing and more parsing to support even simple expressions is not trivial, and may not be worth the trade-off to complexity / maintainability, just for this use case.

Instead, a transaction-modifier-rounding-decimals directive that affects transaction modifiers in scope may be a better fit? For instance:

# round all transaction modifiers in this scope to 2 decimals
transaction-modifier-rounding-decimals 2

= tag:VAT21
    liability:vat  *-0.21
    assets:receivable  *0.21

1/1 Invoice 1 with 21% VAT on 1.50, that's 0.32
    assets:receivable  -1.50 ; VAT21:
    revenue

# liability:vat is now 0.32 instead of 0.315
simonmichael commented 5 years ago

Thanks @georghendrik. As discussed on IRC, I think this sounds useful enough to be worth doing.

A possible quick solution: add simple syntax to the auto posting rules, eg *N^2 means multiply by N then round up to two decimal places.

A possible more thorough solution: revive and finish #934 (general amount expressions). Make sure it works in auto posting rules also. Add support for named functions. Add one or more rounding functions. (Top of head "comprehensive" rounding options: round/roundup/rounddown/roundpos/roundneg(N,PLACES) - round N to PLACES decimal places, respectively to the nearest using digit "5" as the cutoff, away from zero, towards zero, in the positive direction, in the negative direction).

I don't know where are the beancount rounding discussions I was thinking of, but I remember some talk of other rounding strategies used in the financial world.

varac commented 4 years ago

I'm also looking forward for this feature because it screws up my tax reporting as freelancer.

Bradeskojest commented 3 years ago

This works in Ledger CLI version Ledger 3.1.3-20190331: image