rustfava 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rustfava/__init__.py +30 -0
- rustfava/_ctx_globals_class.py +55 -0
- rustfava/api_models.py +36 -0
- rustfava/application.py +534 -0
- rustfava/beans/__init__.py +6 -0
- rustfava/beans/abc.py +327 -0
- rustfava/beans/account.py +79 -0
- rustfava/beans/create.py +377 -0
- rustfava/beans/flags.py +20 -0
- rustfava/beans/funcs.py +38 -0
- rustfava/beans/helpers.py +52 -0
- rustfava/beans/ingest.py +75 -0
- rustfava/beans/load.py +31 -0
- rustfava/beans/prices.py +151 -0
- rustfava/beans/protocols.py +82 -0
- rustfava/beans/str.py +454 -0
- rustfava/beans/types.py +63 -0
- rustfava/cli.py +187 -0
- rustfava/context.py +13 -0
- rustfava/core/__init__.py +729 -0
- rustfava/core/accounts.py +161 -0
- rustfava/core/attributes.py +145 -0
- rustfava/core/budgets.py +207 -0
- rustfava/core/charts.py +301 -0
- rustfava/core/commodities.py +37 -0
- rustfava/core/conversion.py +229 -0
- rustfava/core/documents.py +87 -0
- rustfava/core/extensions.py +132 -0
- rustfava/core/fava_options.py +255 -0
- rustfava/core/file.py +542 -0
- rustfava/core/filters.py +484 -0
- rustfava/core/group_entries.py +97 -0
- rustfava/core/ingest.py +509 -0
- rustfava/core/inventory.py +167 -0
- rustfava/core/misc.py +105 -0
- rustfava/core/module_base.py +18 -0
- rustfava/core/number.py +106 -0
- rustfava/core/query.py +180 -0
- rustfava/core/query_shell.py +301 -0
- rustfava/core/tree.py +265 -0
- rustfava/core/watcher.py +219 -0
- rustfava/ext/__init__.py +232 -0
- rustfava/ext/auto_commit.py +61 -0
- rustfava/ext/portfolio_list/PortfolioList.js +34 -0
- rustfava/ext/portfolio_list/__init__.py +29 -0
- rustfava/ext/portfolio_list/templates/PortfolioList.html +15 -0
- rustfava/ext/rustfava_ext_test/RustfavaExtTest.js +42 -0
- rustfava/ext/rustfava_ext_test/__init__.py +207 -0
- rustfava/ext/rustfava_ext_test/templates/RustfavaExtTest.html +45 -0
- rustfava/ext/rustfava_ext_test/templates/RustfavaExtTestInclude.html +1 -0
- rustfava/help/__init__.py +15 -0
- rustfava/help/_index.md +29 -0
- rustfava/help/beancount_syntax.md +156 -0
- rustfava/help/budgets.md +31 -0
- rustfava/help/conversion.md +29 -0
- rustfava/help/extensions.md +111 -0
- rustfava/help/features.md +179 -0
- rustfava/help/filters.md +103 -0
- rustfava/help/import.md +27 -0
- rustfava/help/options.md +289 -0
- rustfava/helpers.py +30 -0
- rustfava/internal_api.py +221 -0
- rustfava/json_api.py +952 -0
- rustfava/plugins/__init__.py +3 -0
- rustfava/plugins/link_documents.py +107 -0
- rustfava/plugins/tag_discovered_documents.py +44 -0
- rustfava/py.typed +0 -0
- rustfava/rustledger/__init__.py +31 -0
- rustfava/rustledger/constants.py +76 -0
- rustfava/rustledger/engine.py +485 -0
- rustfava/rustledger/loader.py +273 -0
- rustfava/rustledger/options.py +202 -0
- rustfava/rustledger/query.py +331 -0
- rustfava/rustledger/types.py +830 -0
- rustfava/serialisation.py +220 -0
- rustfava/static/app.css +2988 -0
- rustfava/static/app.css.map +7 -0
- rustfava/static/app.js +12854 -0
- rustfava/static/app.js.map +7 -0
- rustfava/static/beancount-JFV44ZVZ.css +5 -0
- rustfava/static/beancount-JFV44ZVZ.css.map +7 -0
- rustfava/static/beancount-VTTKRGSK.js +4642 -0
- rustfava/static/beancount-VTTKRGSK.js.map +7 -0
- rustfava/static/bql-MGFRUMBP.js +333 -0
- rustfava/static/bql-MGFRUMBP.js.map +7 -0
- rustfava/static/chunk-E7ZF4ASL.js +23061 -0
- rustfava/static/chunk-E7ZF4ASL.js.map +7 -0
- rustfava/static/chunk-V24TLQHT.js +12673 -0
- rustfava/static/chunk-V24TLQHT.js.map +7 -0
- rustfava/static/favicon.ico +0 -0
- rustfava/static/fira-mono-cyrillic-400-normal-BLAGXRCE.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-500-normal-EN7JUAAW.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-ext-400-normal-EX7VARTS.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-ext-500-normal-ZDPTUPRR.woff2 +0 -0
- rustfava/static/fira-mono-greek-400-normal-COGHKMOA.woff2 +0 -0
- rustfava/static/fira-mono-greek-500-normal-4EN2PKZT.woff2 +0 -0
- rustfava/static/fira-mono-greek-ext-400-normal-DYEQIJH7.woff2 +0 -0
- rustfava/static/fira-mono-greek-ext-500-normal-SG73CVKQ.woff2 +0 -0
- rustfava/static/fira-mono-latin-400-normal-NA3VLV7E.woff2 +0 -0
- rustfava/static/fira-mono-latin-500-normal-YC77GFWD.woff2 +0 -0
- rustfava/static/fira-mono-latin-ext-400-normal-DIKTZ5PW.woff2 +0 -0
- rustfava/static/fira-mono-latin-ext-500-normal-ZWY4UO4V.woff2 +0 -0
- rustfava/static/fira-mono-symbols2-400-normal-UITXT77Q.woff2 +0 -0
- rustfava/static/fira-mono-symbols2-500-normal-VWPC2EFN.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-400-normal-KLQMBCA6.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-500-normal-NFG7UD6J.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-ext-400-normal-GWO44OPC.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-ext-500-normal-SP47E5SC.woff2 +0 -0
- rustfava/static/fira-sans-greek-400-normal-UMQBTLC3.woff2 +0 -0
- rustfava/static/fira-sans-greek-500-normal-4ZKHN4FQ.woff2 +0 -0
- rustfava/static/fira-sans-greek-ext-400-normal-O2DVJAJZ.woff2 +0 -0
- rustfava/static/fira-sans-greek-ext-500-normal-SK6GNWGO.woff2 +0 -0
- rustfava/static/fira-sans-latin-400-normal-OYYTPMAV.woff2 +0 -0
- rustfava/static/fira-sans-latin-500-normal-SMQPZW5A.woff2 +0 -0
- rustfava/static/fira-sans-latin-ext-400-normal-OAUP3WK5.woff2 +0 -0
- rustfava/static/fira-sans-latin-ext-500-normal-LY3YDR5Y.woff2 +0 -0
- rustfava/static/fira-sans-vietnamese-400-normal-OBMQ72MR.woff2 +0 -0
- rustfava/static/fira-sans-vietnamese-500-normal-Y4NZR5EU.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-400-normal-TO22V6M3.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-500-normal-OGBWWWYW.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-ext-400-normal-XH44UCIA.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-ext-500-normal-3Z6MMVM6.woff2 +0 -0
- rustfava/static/source-code-pro-greek-400-normal-OUXXUQWK.woff2 +0 -0
- rustfava/static/source-code-pro-greek-500-normal-JA2Z5UXO.woff2 +0 -0
- rustfava/static/source-code-pro-greek-ext-400-normal-WCDKMX7U.woff2 +0 -0
- rustfava/static/source-code-pro-greek-ext-500-normal-ZHVI4VKW.woff2 +0 -0
- rustfava/static/source-code-pro-latin-400-normal-QOGTXED5.woff2 +0 -0
- rustfava/static/source-code-pro-latin-500-normal-X57QEOLQ.woff2 +0 -0
- rustfava/static/source-code-pro-latin-ext-400-normal-QXC74NBF.woff2 +0 -0
- rustfava/static/source-code-pro-latin-ext-500-normal-QGOY7MTT.woff2 +0 -0
- rustfava/static/source-code-pro-vietnamese-400-normal-NPDCDTBA.woff2 +0 -0
- rustfava/static/source-code-pro-vietnamese-500-normal-M6PJKTR5.woff2 +0 -0
- rustfava/static/tree-sitter-beancount-MLXFQBZ5.wasm +0 -0
- rustfava/static/web-tree-sitter-RNOQ6E74.wasm +0 -0
- rustfava/template_filters.py +64 -0
- rustfava/templates/_journal_table.html +156 -0
- rustfava/templates/_layout.html +26 -0
- rustfava/templates/_query_table.html +88 -0
- rustfava/templates/beancount_file +18 -0
- rustfava/templates/help.html +23 -0
- rustfava/templates/macros/_account_macros.html +5 -0
- rustfava/templates/macros/_commodity_macros.html +13 -0
- rustfava/translations/bg/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/bg/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ca/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ca/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/de/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/de/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/es/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/es/LC_MESSAGES/messages.po +619 -0
- rustfava/translations/fa/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/fa/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/fr/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/fr/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ja/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ja/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/nl/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/nl/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/pt/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/pt/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/pt_BR/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/pt_BR/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ru/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ru/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/sk/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/sk/LC_MESSAGES/messages.po +623 -0
- rustfava/translations/sv/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/sv/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/uk/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/uk/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/zh/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/zh/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/zh_Hant_TW/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/zh_Hant_TW/LC_MESSAGES/messages.po +618 -0
- rustfava/util/__init__.py +157 -0
- rustfava/util/date.py +576 -0
- rustfava/util/excel.py +118 -0
- rustfava/util/ranking.py +79 -0
- rustfava/util/sets.py +18 -0
- rustfava/util/unreachable.py +20 -0
- rustfava-0.1.0.dist-info/METADATA +102 -0
- rustfava-0.1.0.dist-info/RECORD +187 -0
- rustfava-0.1.0.dist-info/WHEEL +5 -0
- rustfava-0.1.0.dist-info/entry_points.txt +2 -0
- rustfava-0.1.0.dist-info/licenses/AUTHORS +11 -0
- rustfava-0.1.0.dist-info/licenses/LICENSE +21 -0
- rustfava-0.1.0.dist-info/top_level.txt +1 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Template filters for Fava.
|
|
2
|
+
|
|
3
|
+
All functions in this module will be automatically added as template filters.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from decimal import Decimal
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from re import sub
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
from unicodedata import normalize
|
|
13
|
+
|
|
14
|
+
from rustfava.context import g
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
17
|
+
from typing import TypeVar
|
|
18
|
+
|
|
19
|
+
from rustfava.beans.abc import Meta
|
|
20
|
+
from rustfava.beans.abc import MetaValue
|
|
21
|
+
|
|
22
|
+
T = TypeVar("T")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
ZERO = Decimal()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def meta_items(meta: Meta | None) -> list[tuple[str, MetaValue]]:
|
|
29
|
+
"""Remove keys from a dictionary."""
|
|
30
|
+
if not meta: # pragma: no cover
|
|
31
|
+
return []
|
|
32
|
+
return [
|
|
33
|
+
(key, value)
|
|
34
|
+
for key, value in meta.items()
|
|
35
|
+
if not (key in {"filename", "lineno"} or key.startswith("__"))
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def replace_numbers(value: T) -> str | None:
|
|
40
|
+
"""Replace numbers, to be used in incognito mode."""
|
|
41
|
+
return sub(r"[0-9]", "X", str(value)) if value is not None else None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def passthrough_numbers(value: T) -> T:
|
|
45
|
+
"""Pass through value unchanged."""
|
|
46
|
+
return value
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def format_currency(value: Decimal, currency: str | None = None) -> str:
|
|
50
|
+
"""Format a value using the derived precision for a specified currency."""
|
|
51
|
+
return g.ledger.format_decimal(value or ZERO, currency)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
FLAGS_TO_TYPES = {"*": "cleared", "!": "pending"}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def flag_to_type(flag: str) -> str:
|
|
58
|
+
"""Names for entry flags."""
|
|
59
|
+
return FLAGS_TO_TYPES.get(flag, "other")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def basename(file_path: str) -> str:
|
|
63
|
+
"""Return the basename of a filepath."""
|
|
64
|
+
return normalize("NFC", Path(file_path).name)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{% from 'macros/_commodity_macros.html' import render_num, render_amount %}
|
|
2
|
+
|
|
3
|
+
{% set short_type = {
|
|
4
|
+
'balance': 'Bal',
|
|
5
|
+
'close': 'Close',
|
|
6
|
+
'document': 'Doc',
|
|
7
|
+
'note': 'Note',
|
|
8
|
+
'open': 'Open',
|
|
9
|
+
} %}
|
|
10
|
+
|
|
11
|
+
{# Normalize rustledger type names (e.g., 'rltransaction' -> 'transaction') #}
|
|
12
|
+
{% macro _normalize_type(raw_type) %}
|
|
13
|
+
{%- if raw_type.startswith('rl') -%}
|
|
14
|
+
{{ raw_type[2:] }}
|
|
15
|
+
{%- else -%}
|
|
16
|
+
{{ raw_type }}
|
|
17
|
+
{%- endif -%}
|
|
18
|
+
{% endmacro %}
|
|
19
|
+
|
|
20
|
+
{% macro _account_link(name) %}<a href='{{ url_for('account', name=name) }}'>{{ name }}</a>{% endmacro %}
|
|
21
|
+
|
|
22
|
+
{% macro _render_metadata_indicators(metadata) -%}
|
|
23
|
+
{% for key, value in metadata %}
|
|
24
|
+
<span class='metadata-indicator' title='{{ key }}: {{ value }}'>{{ key[:2] }}</span>
|
|
25
|
+
{% endfor %}
|
|
26
|
+
{%- endmacro %}
|
|
27
|
+
|
|
28
|
+
{% macro _render_metadata(metadata, entry_hash=None) -%}
|
|
29
|
+
{% if metadata %}
|
|
30
|
+
<dl class='metadata'>
|
|
31
|
+
{% for key, value in metadata %}
|
|
32
|
+
<dt>{{ key }}:</dt>
|
|
33
|
+
<dd>
|
|
34
|
+
{%- if key.startswith('document') %}<a class='filename' data-remote target=_blank href='{{ url_for('statement', entry_hash=entry_hash, key=key) }}'>{{ value }}</a>
|
|
35
|
+
{% elif value is string and (value.startswith('http://') or value.startswith('https://')) %}<a class='url' data-remote target=_blank rel='noopener noreferrer' href='{{ value }}'>{{ value }}</a>
|
|
36
|
+
{% else %}
|
|
37
|
+
{{ value }}
|
|
38
|
+
{% endif -%}
|
|
39
|
+
</dd>
|
|
40
|
+
{% endfor %}
|
|
41
|
+
</dl>
|
|
42
|
+
{% endif %}
|
|
43
|
+
{% endmacro %}
|
|
44
|
+
|
|
45
|
+
{% macro _render_tags_links(entry) -%}
|
|
46
|
+
{% for tag in entry.tags|sort %}<span class='tag'>#{{ tag }}</span>{% endfor %}
|
|
47
|
+
{% for link_ in entry.links|sort %}<span class='link'>^{{ link_ }}</span>{% endfor %}
|
|
48
|
+
{%- endmacro %}
|
|
49
|
+
|
|
50
|
+
{% macro journal_table_contents(entries, show_change_and_balance=False, ledger=None) %}
|
|
51
|
+
{% set ledger = ledger or g.ledger %}
|
|
52
|
+
{% autoescape false %}
|
|
53
|
+
{% for entry in entries %}
|
|
54
|
+
{% if show_change_and_balance %}
|
|
55
|
+
{% set index, entry, change, balance = entry %}
|
|
56
|
+
{% else %}
|
|
57
|
+
{% set index, entry = entry %}
|
|
58
|
+
{% endif %}
|
|
59
|
+
{% set raw_type = entry.__class__.__name__.lower() %}
|
|
60
|
+
{% set type = _normalize_type(raw_type)|trim %}
|
|
61
|
+
{% set metadata_items = entry.meta|meta_items %}
|
|
62
|
+
{% set entry_hash = entry|hash_entry -%}
|
|
63
|
+
<li class='{{ type }} {{ entry.type or '' }} {{ entry.flag|flag_to_type if entry.flag else '' }}{{ ' linked' if entry.tags and 'linked' in entry.tags else '' }}{{ ' discovered' if entry.tags and 'discovered' in entry.tags else '' }}'>
|
|
64
|
+
<p>
|
|
65
|
+
<span class='datecell' data-sort-value='{{ index }}'><a href='#context-{{ entry_hash }}'>{{ entry.date }}</a></span>
|
|
66
|
+
<span class='flag'>{% if type == 'transaction' %}{{ entry.flag }}{% else %}{{ short_type.get(type, type[:3]) }}{% endif %}</span>
|
|
67
|
+
<span class='description'>
|
|
68
|
+
{% if type == 'open' or type == 'close' %}
|
|
69
|
+
{{ _account_link(entry.account) }}
|
|
70
|
+
{% elif type == 'note' %}
|
|
71
|
+
{{ entry.comment }}
|
|
72
|
+
{% elif type == 'query' %}
|
|
73
|
+
<a href='{{ url_for('report', report_name='query', query_string='run "{}"'.format(entry.name)) }}'>{{ entry.name }}</a>
|
|
74
|
+
{% elif type == 'pad' %}
|
|
75
|
+
{{ _account_link(entry.account) }} from {{ _account_link(entry.source_account) }}
|
|
76
|
+
{% elif type == 'custom' %}
|
|
77
|
+
<strong>{{ entry.type }}</strong>
|
|
78
|
+
{%- for value in entry['values'] -%}
|
|
79
|
+
{% if value.dtype|string == "<AccountDummy>" %}{{ _account_link(value.value) }}
|
|
80
|
+
{%- elif value.dtype|string == "<class 'beancount.core.amount.Amount'>" %}{{ render_amount(ledger, value.value) }}
|
|
81
|
+
{%- elif value.dtype|string == "<class 'str'>" %}"{{ value.value }}"
|
|
82
|
+
{%- elif value.dtype|string == "<class 'bool'>" %}{{ value.value }}
|
|
83
|
+
{%- elif value.dtype|string == "<class 'datetime.date'>" %}{{ value.value }}{% endif -%}
|
|
84
|
+
{%- endfor -%}
|
|
85
|
+
{% elif type == 'document' %}
|
|
86
|
+
{{ _account_link(entry.account) }}
|
|
87
|
+
<a class='filename' data-remote target=_blank href='{{ url_for('document', filename=entry.filename) }}'>{{ entry.filename|basename }}</a>
|
|
88
|
+
{{ _render_tags_links(entry) }}
|
|
89
|
+
{% elif type == 'balance' %}
|
|
90
|
+
{{ _account_link(entry.account) }}
|
|
91
|
+
{% if entry.diff_amount %}
|
|
92
|
+
<span class='spacer'></span>
|
|
93
|
+
accumulated <span class='num'>{{ (entry.amount.number + entry.diff_amount.number)|format_currency(entry.amount.currency) }} {{ entry.amount.currency }}</span>
|
|
94
|
+
{% endif %}
|
|
95
|
+
{% elif type == 'transaction' %}
|
|
96
|
+
<strong class='payee'>{{ entry.payee or '' }}</strong>{% if entry.payee and entry.narration %}<span class='separator'></span>{% endif %}{{ entry.narration or '' }}
|
|
97
|
+
{{ _render_tags_links(entry) }}
|
|
98
|
+
{% endif %}
|
|
99
|
+
</span>
|
|
100
|
+
<span class='indicators'>
|
|
101
|
+
{{- _render_metadata_indicators(metadata_items) -}}
|
|
102
|
+
{%- for posting in entry.postings -%}
|
|
103
|
+
<span{% if posting.flag %} class='{{ posting.flag|flag_to_type }}'{% endif %}></span>
|
|
104
|
+
{{- _render_metadata_indicators(posting.meta|meta_items) -}}
|
|
105
|
+
{%- endfor -%}
|
|
106
|
+
</span>
|
|
107
|
+
{% if type == 'balance' %}
|
|
108
|
+
{{ render_amount(ledger, entry.amount, 'num bal' + (' pending' if entry.diff_amount else '')) }}
|
|
109
|
+
{% if entry.diff_amount %}
|
|
110
|
+
<span class='change num bal pending'>
|
|
111
|
+
{{- render_num(ledger, entry.diff_amount.currency, entry.diff_amount.number) -}}
|
|
112
|
+
</span>
|
|
113
|
+
{% else %}
|
|
114
|
+
<span class='change num'></span>
|
|
115
|
+
{% endif %}
|
|
116
|
+
{% if not show_change_and_balance %}
|
|
117
|
+
<span class='change num'></span>
|
|
118
|
+
{% endif %}
|
|
119
|
+
{% endif %}
|
|
120
|
+
{% if show_change_and_balance %}
|
|
121
|
+
{% if type == 'transaction' %}
|
|
122
|
+
<span class='change num'>
|
|
123
|
+
{%- for currency, number in change.items() %}{{ render_num(ledger, currency, number) }}<br>{% endfor -%}
|
|
124
|
+
</span>
|
|
125
|
+
{% endif %}
|
|
126
|
+
<span class='num'>
|
|
127
|
+
{%- for currency, number in balance.items() %}{{ render_num(ledger, currency, number) }}<br>{% endfor -%}
|
|
128
|
+
</span>
|
|
129
|
+
{% endif %}
|
|
130
|
+
</p>
|
|
131
|
+
{{ _render_metadata(metadata_items, entry_hash) }}
|
|
132
|
+
{% if entry.postings %}
|
|
133
|
+
<ul class='postings'>
|
|
134
|
+
{% for posting in entry.postings %}
|
|
135
|
+
<li{% if posting.flag %} class='{{ posting.flag|flag_to_type }}'{% endif %}>
|
|
136
|
+
<p>
|
|
137
|
+
<span class='datecell'></span>
|
|
138
|
+
<span class='flag'>{{ posting.flag or '' }}</span>
|
|
139
|
+
<span class='description'>{{ _account_link(posting.account) }}</span>
|
|
140
|
+
{# We want the output these amounts with the same precision as in the input file.
|
|
141
|
+
For computed values this might give a lot of digits, so format the price using the DisplayContext for now.#}
|
|
142
|
+
<span class='num'>{% if posting.units %}{{ posting.units.number|incognito }} {{ posting.units.currency }}{% endif %}</span>
|
|
143
|
+
<span class='num'>{{ posting.cost.number|incognito }} {{ posting.cost.currency }}
|
|
144
|
+
{{- ', {}'.format(posting.cost.date) if posting.cost.date else '' }}
|
|
145
|
+
{{- ', "{}"'.format(posting.cost.label) if posting.cost.label else '' }}</span>
|
|
146
|
+
{{ render_amount(ledger, posting.price) }}
|
|
147
|
+
</p>
|
|
148
|
+
{{ _render_metadata(posting.meta|meta_items) }}
|
|
149
|
+
</li>
|
|
150
|
+
{% endfor %}
|
|
151
|
+
</ul>
|
|
152
|
+
{% endif %}
|
|
153
|
+
</li>
|
|
154
|
+
{%- endfor %}
|
|
155
|
+
{% endautoescape %}
|
|
156
|
+
{%- endmacro %}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{% set partial = request.args.get('partial') %}
|
|
2
|
+
{% if not partial %}
|
|
3
|
+
<!doctype html>
|
|
4
|
+
<html>
|
|
5
|
+
<head>
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<link rel="shortcut icon" href="{{ static_url('favicon.ico') }}">
|
|
8
|
+
<link rel="stylesheet" href="{{ static_url('app.css') }}">
|
|
9
|
+
<title>{{ page_title or "" }} - {{ ledger.options.title }}</title>
|
|
10
|
+
<script type="module" src="{{ static_url('app.js') }}"></script>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<!-- <header> and <aside> get inserted here -->
|
|
14
|
+
<article>
|
|
15
|
+
{%- endif %}
|
|
16
|
+
{% block content %}{{ content }}{% endblock %}
|
|
17
|
+
{% if page_title %}<script type="application/json" id="page-title">{{ page_title|tojson }}</script>{% endif %}
|
|
18
|
+
{% if partial %}<script type="application/json" id="ledger-mtime">{{ ledger.mtime|tojson }}</script>{% endif %}
|
|
19
|
+
{%- if not partial %}
|
|
20
|
+
</article>
|
|
21
|
+
<script type="application/json" id="ledger-data">{{ get_ledger_data()|tojson }}</script>
|
|
22
|
+
<script type="application/json" id="ledger-mtime">{{ ledger.mtime|tojson }}</script>
|
|
23
|
+
<script type="application/json" id="translations">{{ translations()|tojson }}</script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
26
|
+
{%- endif %}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{% import 'macros/_account_macros.html' as account_macros %}
|
|
2
|
+
{% import 'macros/_commodity_macros.html' as commodity_macros %}
|
|
3
|
+
|
|
4
|
+
{% set sort_type = {
|
|
5
|
+
"<class 'decimal.Decimal'>": 'num',
|
|
6
|
+
"<class 'cdecimal.Decimal'>": 'num',
|
|
7
|
+
"<class 'int'>": 'num',
|
|
8
|
+
"<class 'beancount.core.amount.Amount'>": 'num',
|
|
9
|
+
"<class 'beancount.core.inventory.Inventory'>": 'num',
|
|
10
|
+
"<class 'beancount.core.position.Position'>": 'num',
|
|
11
|
+
} %}
|
|
12
|
+
|
|
13
|
+
{% macro querycell(ledger, name, value, type_) %}
|
|
14
|
+
{% set type = type_|string %}
|
|
15
|
+
{% if type == "<class 'beancount.core.inventory.Inventory'>" %}
|
|
16
|
+
<td class="num">
|
|
17
|
+
{% for position in value|sort(attribute='units.currency') %}
|
|
18
|
+
{{ commodity_macros.render_amount(ledger, position.units) }}<br>
|
|
19
|
+
{% endfor %}
|
|
20
|
+
</td>
|
|
21
|
+
{% elif type == "<class 'str'>" %}
|
|
22
|
+
<td>
|
|
23
|
+
{% if name == "account" %}
|
|
24
|
+
{{ account_macros.account_name(ledger, value) }}
|
|
25
|
+
{% elif name == "id" %}
|
|
26
|
+
<a href="#context-{{ value }}">{{ value }}</a>
|
|
27
|
+
{% else %}
|
|
28
|
+
{{ value }}
|
|
29
|
+
{% endif %}
|
|
30
|
+
</td>
|
|
31
|
+
{% elif type == "<class 'decimal.Decimal'>" or type == "<class 'cdecimal.Decimal'>" %}
|
|
32
|
+
<td class="num" data-sort-value="{{ value or 0 }}">{{ value|format_currency }}</td>
|
|
33
|
+
{% elif type == "<class 'beancount.core.amount.Amount'>" %}
|
|
34
|
+
<td class="num" data-sort-value="{{ value.number or 0 }}">
|
|
35
|
+
{{ commodity_macros.render_amount(ledger, value) }}
|
|
36
|
+
</td>
|
|
37
|
+
{% elif type == "<class 'bool'>" %}
|
|
38
|
+
<td>{{ value|upper }}</td>
|
|
39
|
+
{% elif type == "<class 'int'>" %}
|
|
40
|
+
<td class="num">{{ value }}</td>
|
|
41
|
+
{% elif type == "<class 'set'>" %}
|
|
42
|
+
<td>{{ value|join(',') }}</td>
|
|
43
|
+
{% elif type == "<class 'datetime.date'>" %}
|
|
44
|
+
<td>{{ value or '' }}</td>
|
|
45
|
+
{% elif type == "<class 'beancount.core.position.Position'>" %}
|
|
46
|
+
<td class="num">{{ commodity_macros.render_amount(ledger, value.units) }}</td>
|
|
47
|
+
{% else %}
|
|
48
|
+
<td class="query-error" title="Type {{ type|string }} not recognized">{{ value }}</td>
|
|
49
|
+
{% endif %}
|
|
50
|
+
{% endmacro %}
|
|
51
|
+
|
|
52
|
+
{% macro querytable(ledger, contents, types, rows, filter_empty=None, footer=None) %}
|
|
53
|
+
<p class="deprecation-notice">
|
|
54
|
+
The querytable macro is deprecated, please switch to the frontend-rendered query result.
|
|
55
|
+
See rustfava.ext.rustfava_ext_test for an example of how to use them.
|
|
56
|
+
<p>
|
|
57
|
+
{% if contents %}
|
|
58
|
+
<pre><code>{{ contents }}</code></pre>
|
|
59
|
+
{% elif types %}
|
|
60
|
+
<table is="sortable-table" class="queryresults">
|
|
61
|
+
<thead>
|
|
62
|
+
<tr>
|
|
63
|
+
{% for name, type in types %}
|
|
64
|
+
<th data-sort="{{ sort_type[type|string] or "string" }}">{{ name }}</th>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</tr>
|
|
67
|
+
</thead>
|
|
68
|
+
<tbody>
|
|
69
|
+
{% for row in rows if filter_empty == None or not row[filter_empty].is_empty() %}
|
|
70
|
+
<tr>
|
|
71
|
+
{% for name, type in types %}
|
|
72
|
+
{{ querycell(ledger, name, row[name], type) }}
|
|
73
|
+
{% endfor %}
|
|
74
|
+
</tr>
|
|
75
|
+
{% endfor %}
|
|
76
|
+
</tbody>
|
|
77
|
+
{% if footer %}
|
|
78
|
+
<tfoot>
|
|
79
|
+
<tr>
|
|
80
|
+
{% for type, value in footer %}
|
|
81
|
+
{{ querycell(ledger, '', value, type) }}
|
|
82
|
+
{% endfor %}
|
|
83
|
+
</tr>
|
|
84
|
+
</tfoot>
|
|
85
|
+
{% endif %}
|
|
86
|
+
</table>
|
|
87
|
+
{% endif %}
|
|
88
|
+
{% endmacro %}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
;; -*- mode: org; mode: beancount; -*-
|
|
2
|
+
|
|
3
|
+
option "title" "{{ ledger.options.title }} - Journal Export"
|
|
4
|
+
|
|
5
|
+
{% for currency in ledger.options.operating_currency -%}
|
|
6
|
+
option "operating_currency" "{{ currency }}"
|
|
7
|
+
{% endfor -%}
|
|
8
|
+
|
|
9
|
+
option "name_assets" "{{ ledger.options.name_assets }}"
|
|
10
|
+
option "name_liabilities" "{{ ledger.options.name_liabilities }}"
|
|
11
|
+
option "name_equity" "{{ ledger.options.name_equity }}"
|
|
12
|
+
option "name_income" "{{ ledger.options.name_income }}"
|
|
13
|
+
option "name_expenses" "{{ ledger.options.name_expenses }}"
|
|
14
|
+
plugin "beancount.plugins.auto_accounts"
|
|
15
|
+
|
|
16
|
+
{% for rendered_entry in ledger.file.render_entries(g.filtered.entries) %}
|
|
17
|
+
{{ rendered_entry|safe }}
|
|
18
|
+
{% endfor %}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{% extends "_layout.html" %}
|
|
2
|
+
|
|
3
|
+
{% set page_title = _('Help') %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="help">
|
|
7
|
+
<div class="help-sidebar">
|
|
8
|
+
<h3>{{ _('Help pages') }}</h3>
|
|
9
|
+
<ul>
|
|
10
|
+
{% for slug, title in HELP_PAGES|dictsort %}
|
|
11
|
+
<li>
|
|
12
|
+
<a href="{{ url_for('help_page', page_slug=slug) }}"{% if slug == page_slug %} class="selected"{% endif %}>
|
|
13
|
+
{{ title }}
|
|
14
|
+
</a>
|
|
15
|
+
</li>
|
|
16
|
+
{% endfor %}
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="help-text">
|
|
20
|
+
{{ help_html }}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
{% endblock %}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{% macro render_amount(ledger, amount, class="num") %}
|
|
2
|
+
{% if amount is none or amount.number is none -%}
|
|
3
|
+
<span class='{{ class }}'></span>
|
|
4
|
+
{%- else -%}
|
|
5
|
+
<span class='{{ class }}' title='{{ ledger.commodities.name(amount.currency) }}'>
|
|
6
|
+
{{- amount.number|format_currency(amount.currency)|incognito }} {{ amount.currency -}}
|
|
7
|
+
</span>
|
|
8
|
+
{%- endif %}
|
|
9
|
+
{% endmacro %}
|
|
10
|
+
|
|
11
|
+
{% macro render_num(ledger, currency, number) -%}
|
|
12
|
+
<span title='{{ ledger.commodities.name(currency) }}'>{{ number|format_currency(currency)|incognito }} {{ currency }}</span>
|
|
13
|
+
{%- endmacro %}
|
|
Binary file
|