diff options
Diffstat (limited to 'beancount_extras_kris7t/plugins/default_tolerance.py')
-rw-r--r-- | beancount_extras_kris7t/plugins/default_tolerance.py | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/beancount_extras_kris7t/plugins/default_tolerance.py b/beancount_extras_kris7t/plugins/default_tolerance.py new file mode 100644 index 0000000..52fa956 --- /dev/null +++ b/beancount_extras_kris7t/plugins/default_tolerance.py | |||
@@ -0,0 +1,47 @@ | |||
1 | ''' | ||
2 | Plugin that sets the tolerance values of balance assertions to an amount determined by the account. | ||
3 | ''' | ||
4 | __copyright__ = 'Copyright (c) 2020 Kristóf Marussy <kristof@marussy.com>' | ||
5 | __license__ = 'GNU GPLv2' | ||
6 | |||
7 | from decimal import Decimal | ||
8 | from typing import Any, Dict, List, NamedTuple, Optional, Tuple | ||
9 | |||
10 | from beancount.core.data import Open, Balance, Directive, Entries, Meta | ||
11 | |||
12 | __plugins__ = ('set_tolerances_to_default',) | ||
13 | |||
14 | DEFAULT_TOLERANCE_META = 'default-balance-tolerance' | ||
15 | |||
16 | |||
17 | class DefaultToleranceError(NamedTuple): | ||
18 | source: Optional[Meta] | ||
19 | message: str | ||
20 | entry: Directive | ||
21 | |||
22 | |||
23 | def set_tolerances_to_default(entries: Entries, | ||
24 | options_map: Dict[str, Any], | ||
25 | config_str: Optional[str] = None) -> \ | ||
26 | Tuple[Entries, List[DefaultToleranceError]]: | ||
27 | errors: List[DefaultToleranceError] = [] | ||
28 | accounts: Dict[str, Optional[Decimal]] = {} | ||
29 | for entry in entries: | ||
30 | if not isinstance(entry, Open): | ||
31 | continue | ||
32 | if tolerance := entry.meta.get(DEFAULT_TOLERANCE_META, None): | ||
33 | if isinstance(tolerance, Decimal): | ||
34 | accounts[entry.account] = tolerance | ||
35 | else: | ||
36 | errors.append(DefaultToleranceError( | ||
37 | entry.meta, | ||
38 | f'{DEFAULT_TOLERANCE_META} must be decimal, got {tolerance} instead', | ||
39 | entry)) | ||
40 | new_entries: Entries = [] | ||
41 | for entry in entries: | ||
42 | if isinstance(entry, Balance) and entry.tolerance is None and entry.account in accounts: | ||
43 | account_tolerance = accounts[entry.account] | ||
44 | new_entries.append(entry._replace(tolerance=account_tolerance)) | ||
45 | else: | ||
46 | new_entries.append(entry) | ||
47 | return new_entries, errors | ||