Changeset - 3f0b201d1603
[Not reviewed]
0 4 0
Brett Smith - 4 years ago 2020-07-16 19:12:20
brettcsmith@brettcsmith.org
ledger: --account accepts a classification.

This makes it easier for users to specify a group of accounts.
4 files changed with 67 insertions and 25 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/ledger.py
Show inline comments
...
 
@@ -62,2 +62,3 @@ from typing import (
 
    Sequence,
 
    Set,
 
    TextIO,
...
 
@@ -403,3 +404,3 @@ date was also not specified.
 
        '--account', '-a',
 
        dest='sheet_names',
 
        dest='accounts',
 
        metavar='ACCOUNT',
...
 
@@ -407,4 +408,5 @@ date was also not specified.
 
        help="""Show this account in the report. You can specify this option
 
multiple times. If not specified, the default set adapts to your search
 
criteria.
 
multiple times. You can specify a part of the account hierarchy, or an account
 
classification from metadata. If not specified, the default set adapts to your
 
search criteria.
 
""")
...
 
@@ -438,5 +440,5 @@ metadata to match. A single ticket number is a shortcut for
 
    args = parser.parse_args(arglist)
 
    if args.sheet_names is None:
 
    if args.accounts is None:
 
        if any(term.meta_key == 'project' for term in args.search_terms):
 
            args.sheet_names = [
 
            args.accounts = [
 
                'Income',
...
 
@@ -444,8 +446,8 @@ metadata to match. A single ticket number is a shortcut for
 
                'Assets:Receivable',
 
                'Liabilities:Payable',
 
                'Assets:Prepaid',
 
                'Liabilities:UnearnedIncome',
 
                'Liabilities:Payable',
 
            ]
 
        else:
 
            args.sheet_names = list(LedgerODS.ACCOUNT_COLUMNS)
 
            args.accounts = list(LedgerODS.ACCOUNT_COLUMNS)
 
    return args
...
 
@@ -485,5 +487,5 @@ def main(arglist: Optional[Sequence[str]]=None,
 
    if books_loader is None:
 
        entries, load_errors, _ = books.Loader.load_none(config.config_file_path())
 
        entries, load_errors, options = books.Loader.load_none(config.config_file_path())
 
    else:
 
        entries, load_errors, _ = books_loader.load_fy_range(args.start_date, args.stop_date)
 
        entries, load_errors, options = books_loader.load_fy_range(args.start_date, args.stop_date)
 
    for error in load_errors:
...
 
@@ -492,3 +494,15 @@ def main(arglist: Optional[Sequence[str]]=None,
 

	
 
    postings = data.Posting.from_entries(entries)
 
    data.Account.load_from_books(entries, options)
 
    accounts: Set[data.Account] = set()
 
    sheet_names: Dict[str, None] = collections.OrderedDict()
 
    for acct_arg in args.accounts:
 
        for account in data.Account.iter_accounts(acct_arg):
 
            accounts.add(account)
 
            if not account.is_under(*sheet_names):
 
                new_sheet = account.is_under(*LedgerODS.ACCOUNT_COLUMNS)
 
                assert new_sheet is not None
 
                sheet_names[new_sheet] = None
 

	
 
    postings = (post for post in data.Posting.from_entries(entries)
 
                if post.account in accounts)
 
    for search_term in args.search_terms:
...
 
@@ -502,3 +516,3 @@ def main(arglist: Optional[Sequence[str]]=None,
 
        args.stop_date,
 
        args.sheet_names,
 
        list(sheet_names),
 
        rt_wrapper,
tests/books/ledger.beancount
Show inline comments
...
 
@@ -2,7 +2,13 @@
 
2018-01-01 open Assets:Checking
 
  classification: "Cash"
 
2018-01-01 open Assets:Receivable:Accounts
 
  classification: "Accounts receivable"
 
2018-01-01 open Expenses:Other
 
  classification: "Other expenses"
 
2018-01-01 open Income:Other
 
  classification: "Other income"
 
2018-01-01 open Liabilities:CreditCard
 
  classification: "Accounts payable"
 
2018-01-01 open Liabilities:Payable:Accounts
 
  classification: "Accounts payable"
 

	
tests/test_reports_ledger.py
Show inline comments
...
 
@@ -17,2 +17,3 @@
 
import collections
 
import contextlib
 
import copy
...
 
@@ -35,2 +36,4 @@ from conservancy_beancount.reports import ledger
 

	
 
clean_account_meta = contextlib.contextmanager(testutil.clean_account_meta)
 

	
 
Acct = data.Account
...
 
@@ -45,3 +48,2 @@ DEFAULT_REPORT_SHEETS = [
 
    'Liabilities:Payable',
 
    'Assets:PayPal',
 
    'Assets',
...
 
@@ -49,11 +51,4 @@ DEFAULT_REPORT_SHEETS = [
 
]
 
PROJECT_REPORT_SHEETS = [
 
    'Balance',
 
    'Income',
 
    'Expenses',
 
    'Assets:Receivable',
 
    'Assets:Prepaid',
 
    'Liabilities:UnearnedIncome',
 
    'Liabilities:Payable',
 
]
 
PROJECT_REPORT_SHEETS = DEFAULT_REPORT_SHEETS[:6]
 
del PROJECT_REPORT_SHEETS[3]
 
OVERSIZE_RE = re.compile(
...
 
@@ -277,3 +272,4 @@ def run_main(arglist, config=None):
 
    errors = io.StringIO()
 
    retcode = ledger.main(arglist, output, errors, config)
 
    with clean_account_meta():
 
        retcode = ledger.main(arglist, output, errors, config)
 
    output.seek(0)
...
 
@@ -294,2 +290,26 @@ def test_main(ledger_entries):
 

	
 
@pytest.mark.parametrize('acct_arg', [
 
    'Liabilities',
 
    'Accounts payable',
 
])
 
def test_main_account_limit(ledger_entries, acct_arg):
 
    retcode, output, errors = run_main([
 
        '-a', acct_arg,
 
        '-b', START_DATE.isoformat(),
 
        '-e', STOP_DATE.isoformat(),
 
    ])
 
    assert not errors.getvalue()
 
    assert retcode == 0
 
    ods = odf.opendocument.load(output)
 
    assert get_sheet_names(ods) == ['Balance', 'Liabilities']
 
    postings = data.Posting.from_entries(ledger_entries)
 
    for account, expected in ExpectedPostings.group_by_account(postings):
 
        should_find = account.startswith('Liabilities')
 
        try:
 
            expected.check_report(ods, START_DATE, STOP_DATE)
 
        except NotFound:
 
            assert not should_find
 
        else:
 
            assert should_find
 

	
 
@pytest.mark.parametrize('project,start_date,stop_date', [
tests/testutil.py
Show inline comments
...
 
@@ -46,5 +46,7 @@ TESTS_DIR = Path(__file__).parent
 
def clean_account_meta():
 
    yield
 
    data.Account.load_options_map(bc_options.OPTIONS_DEFAULTS)
 
    data.Account._meta_map.clear()
 
    try:
 
        yield
 
    finally:
 
        data.Account.load_options_map(bc_options.OPTIONS_DEFAULTS)
 
        data.Account._meta_map.clear()
 

	
0 comments (0 inline, 0 general)