Skip to content

Commit

Permalink
Fix(split_income): Convert positions to weight before subtracting tax…
Browse files Browse the repository at this point in the history
…es (#8)

Previously, the code assumed that income and taxes used the same
currency. If the postings had an additional associated cost or price,
this was not considered. Now, to obtain the correct amount, the
beancount.core.convert.get_weight function is used. It provides the
amount that will need to be balanced from a posting of a transaction.

Appropriate tests are included.

Fixes #7
  • Loading branch information
op3 authored Jan 20, 2025
1 parent fd8519f commit 6165f77
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
6 changes: 4 additions & 2 deletions fava_plugins/split_income.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import copy
import re

from beancount.core import convert
from beancount.core import data
from beancount.core import getters
from beancount.core.inventory import Inventory
Expand Down Expand Up @@ -112,14 +113,15 @@ def split_income(entries, options_map, config_str):
income = collections.defaultdict(Inventory)
taxes = collections.defaultdict(Decimal)
for posting in list(entry.postings):
weight = convert.get_weight(posting)
if posting.account.startswith(config["income"]):
new_entry.postings.append(posting)
entry.postings.remove(posting)
income[posting.account].add_amount(posting.units)
income[posting.account].add_amount(weight)
elif re.match(config["taxes"], posting.account):
new_entry.postings.append(posting)
entry.postings.remove(posting)
taxes[posting.units.currency] += posting.units.number
taxes[weight.currency] += weight.number

for account, inv in income.items():
net_account = account.replace(
Expand Down
74 changes: 74 additions & 0 deletions tests/test_split_income.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,77 @@ def test_split_income_config(load_doc):

assert len(entries) == 9
assert len([e for e in entries if isinstance(e, data.Open)]) == 7


def test_split_income_mixed_currency_income(load_doc):
"""
plugin "fava_plugins.split_income" ""
plugin "beancount.plugins.auto_accounts"
2025-01-01 * "Employer" "Income"
Income:Work -10 USD @@ 9 EUR
Expenses:Taxes 1 EUR
Assets:Account 8 EUR
"""

entries, errors, __ = load_doc

entries_after, _, __ = load_string(
"""
2025-01-01 * "Employer" "Income"
Assets:Account 8 EUR
Income:Net:Work -8 EUR
2025-01-01 * "Employer" "Income" #pretax
Income:Work -10 USD @ 0.9 EUR
Expenses:Taxes 1 EUR
Income:Net:Work 8 EUR
""",
dedent=True,
)

assert not errors
assert "pretax" in entries[5].tags

_compare_postings(entries[5], entries_after[1])
_compare_postings(entries[4], entries_after[0])

assert len(entries) == 6
assert len([e for e in entries if isinstance(e, data.Open)]) == 4


def test_split_income_mixed_currency_others(load_doc):
"""
plugin "fava_plugins.split_income" ""
plugin "beancount.plugins.auto_accounts"
2025-01-01 * "Employer" "Income"
Income:Work -11 USD
Expenses:Taxes 1 EUR @ 1.1 USD
Assets:Account 9 EUR @ 1.1 USD
"""

entries, errors, __ = load_doc

entries_after, _, __ = load_string(
"""
2025-01-01 * "Employer" "Income"
Assets:Account 9 EUR @ 1.1 USD
Income:Net:Work -9.9 USD
2025-01-01 * "Employer" "Income" #pretax
Income:Work -11 USD
Expenses:Taxes 1 EUR @ 1.1 USD
Income:Net:Work 9.9 USD
""",
dedent=True,
)

assert not errors
assert "pretax" in entries[5].tags

_compare_postings(entries[5], entries_after[1])
_compare_postings(entries[4], entries_after[0])

assert len(entries) == 6
assert len([e for e in entries if isinstance(e, data.Open)]) == 4

0 comments on commit 6165f77

Please sign in to comment.