Calculate tax owed up to income limit or additional tax after income limit

23 views

Gulshan Singh

Apr 18, 2022, 2:54:57 PM4/18/22
to Ledger
For some taxes in the US like Medicare and Social Security, tax is collected at a certain rate only up to some income limit. For example, I would have to pay 6.2% social security tax for the first \$147,000 I earn in 2022, but I would not have to pay any social security tax for income over that amount. Similarly for Medicare, I have to pay 1.45% tax on all income, but for income above \$200,000 I have to pay an addition 0.9% in Medicare taxes.

I would like to calculate the tax I owe in both of these scenarios. I'm using automatic transactions and virtual accounts to calculate my income tax liability in general, but in these particular cases I'm struggling with only calculating the tax up to a certain income amount or only taxing income above a certain amount.

I've tried something like this for the Medicare example, but it doesn't work as abs(O) is dealing with the transaction amount, and not the total balance of the account:
```
account Assets:Bank
account Income:Hooli

account Liabilities:Taxes:Medicare

= expr "account =~ /Income:Hooli/ and abs(O)>200000"

= expr "account =~ /Income:Hooli/"
(Liabilities:Taxes:Medicare)                .0145

2022-04-15 * Payroll
Income:Hooli                               -150,000 USD
Assets:Bank

2022-04-01 * Payroll
Income:Hooli                               -150,000 USD
Assets:Bank
```

Is there a way I can condition the automatic transactions based off the total account balance instead of the transaction amount?

Martin Michlmayr

Apr 18, 2022, 7:36:44 PM4/18/22
* Gulshan Singh <gsing...@gmail.com> [2022-04-17 00:06]:
> I've tried something like this for the Medicare example, but it
> doesn't work as abs(O) is dealing with the transaction amount, and
> not the total balance of the account:

There is a syntax to refer to the total of an account:
account("...").total

However, that's not going to work for your cause. If you go from,
let's say, \$180k income to \$240k, there's afaik no way to tell ledger
to apply something exactly at \$200k.

account Assets:Bank
account Income:Hooli

account Liabilities:Taxes:Medicare

= expr "account =~ /Income:Hooli/ and account('Income:Hooli').total <= -200000 USD"

= expr "account =~ /Income:Hooli/"
(Liabilities:Taxes:Medicare) .0145

2022-04-15 * Payroll
Income:Hooli -150,000 USD
Assets:Bank

2022-04-01 * Payroll
Income:Hooli -150,000 USD
Assets:Bank

2022-04-01 * Payroll
Income:Hooli -150,000 USD
Assets:Bank

--
Martin Michlmayr
https://www.cyrius.com/

Gulshan Singh

Apr 19, 2022, 12:57:20 AM4/19/22
Thanks! Even with the issue you mention, when my income exceeds
\$200,000, the paycheck that puts it over that amount isn't going to
put it over by a large amount, so I think I could live with that
margin of error or correct it manually later. I can't find anything
related to the `account()` function in the docs, is it not documented
or am I just missing it?

While this solution would probably be good enough, I've figured out an
improvement which allows me to calculate this exactly. The idea is
that if the account total before the transaction is greater than
-200,000, then we can apply the .9% tax as normal. But if the account
total before the transaction is greater than -200,000 and the total
after is less than -200,000, then we calculate the difference between
the total after and -200,000, and apply the .9% tax just to this
amount, and just for this one transaction.

```
account Assets:Bank
account Income:Hooli

account Liabilities:Taxes:Medicare

define total_after(account_name) = account(account_name).total
define total_before(account_name, amount) = account(account_name).total - amount
define did_cross_threshold(low, high, threshold) = low < threshold and
high > threshold
did_cross_threshold(total_after(account_name),
total_before(account_name, amount), -200000)

= expr "account =~ /Income:Hooli/ and
((total_after('Income:Hooli') + 200000 USD) * {0.009})

= expr "account =~ /Income:Hooli/ and total_before('Income:Hooli', O)
<= -200000 USD"

= expr "account =~ /Income:Hooli/"
(Liabilities:Taxes:Medicare) .0145

2022-04-29 * Payroll
Income:Hooli -150,000 USD
Assets:Bank

2022-04-15 * Payroll
Income:Hooli -150,000 USD
Assets:Bank

2022-04-01 * Payroll
Income:Hooli -150,000 USD
Assets:Bank
```

The result is:
```
-8,775 USD Liabilities:Taxes:Medicare
--------------------
-8,775 USD
```
Which shows that the additional tax was computed on the \$250,000 that
was above \$200,000, while the 1.45% tax was computed on the entire
\$450,000 amount.

Thanks for putting me on the right track!
> --
>
> ---
> You received this message because you are subscribed to a topic in the Google Groups "Ledger" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/ledger-cli/VPXzQsto4KE/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to ledger-cli+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/ledger-cli/Yl32BAzHYxErEudt%40jirafa.cyrius.com.

Martin Michlmayr

Apr 19, 2022, 2:17:03 AM4/19/22
* Gulshan Singh <gsing...@gmail.com> [2022-04-18 21:57]:
> I can't find anything related to the `account()` function in the
> docs, is it not documented or am I just missing it?

It would be great if someone could add it to the documentation.

https://github.com/ledger/ledger/issues/2099

o1bigtenor

Apr 19, 2022, 8:08:18 AM4/19/22
to Ledger
I am NOT a programmer so perhaps I shouldn't be saying anything - - - but
- - - IMHO wouldn't this be a good place to use the logic flow if --
then -- else?

(meaning - - - a calculation happens, if value is less than or equal to y then
action a happens, if the value is larger than y - - -well then action b happens)

(Hopefully not quite a stupid interjection!)

Regards

Gulshan Singh

Apr 19, 2022, 11:45:02 AM4/19/22
If you're referring to using an if-statement for the general idea of adding to some account if the account balance is above a certain value, then I think the value expression in the automatic transaction is essentially that:
```

= expr "account =~ /Income:Hooli/ and total_before('Income:Hooli', O) <= -200000 USD"
```

If you're referring to using an if-statement to combine the two cases I mentioned in my last message, one where we're already above the limit and one where we just crossed the limit, then I think this could be handled with an if-statement (using the ternary `?:` operator, I'm not sure if there are other conditionals I can use), but personally I think it looks a lot messier:
```
= expr "account =~ /Income:Hooli/ and (should_compute_additional_medicare('Income:Hooli', O) or total_before('Income:Hooli', O) <= -200000 USD)"