From 71d671e493ad2a6dbd2bc3e41dfc618b534860ff 2020-06-14 12:53:27 From: Brett Smith Date: 2020-06-14 12:53:27 Subject: [PATCH] data: Add Metadata.human_name() classmethod. --- diff --git a/conservancy_beancount/data.py b/conservancy_beancount/data.py index 6fdab6178db73ea05287777408f22d15ef01457a..ddb6b8cb77a2e4a7704636cc3c1f98fd574a19a1 100644 --- a/conservancy_beancount/data.py +++ b/conservancy_beancount/data.py @@ -23,6 +23,7 @@ import collections import datetime import decimal import functools +import re from beancount.core import account as bc_account from beancount.core import amount as bc_amount @@ -213,6 +214,13 @@ class Metadata(MutableMapping[MetaKey, MetaValue]): for common parsing and query tasks. """ __slots__ = ('meta',) + _HUMAN_NAMES: MutableMapping[MetaKey, str] = { + # Initialize this dict with special cases. + # We use it as a cache for other metadata names as they're queried. + 'check-id': 'Check Number', + 'paypal-id': 'PayPal ID', + 'rt-id': 'Ticket', + } def __init__(self, source: MutableMapping[MetaKey, MetaValue]) -> None: self.meta = source @@ -256,6 +264,22 @@ class Metadata(MutableMapping[MetaKey, MetaValue]): except (IndexError, TypeError): return default + @classmethod + def human_name(cls, key: MetaKey) -> str: + """Return the "human" version of a metadata name + + This is usually the metadata key with punctuation replaced with spaces, + and then titlecased, with a few special cases. The return value is + suitable for using in reports. + """ + try: + retval = cls._HUMAN_NAMES[key] + except KeyError: + retval = key.replace('-', ' ').title() + retval = re.sub(r'\bId$', 'ID', retval) + cls._HUMAN_NAMES[key] = retval + return retval + class PostingMeta(Metadata): """Combined access to posting metadata with its parent transaction metadata diff --git a/conservancy_beancount/reports/accrual.py b/conservancy_beancount/reports/accrual.py index 544d2948d15afafd71fb8b783eb4874695bb1d1e..f37cb2999c31aa4ea2043e087d4c47aa0abca96a 100644 --- a/conservancy_beancount/reports/accrual.py +++ b/conservancy_beancount/reports/accrual.py @@ -273,17 +273,20 @@ class BaseReport: class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]): + DOC_COLUMNS = [ + 'rt-id', + 'invoice', + 'approval', + 'contract', + 'purchase-order', + ] COLUMNS = [ 'Date', - 'Entity', + data.Metadata.human_name('entity'), 'Invoice Amount', 'Booked Amount', - 'Project', - 'Ticket', - 'Invoice', - 'Approval', - 'Contract', - 'Purchase Order', + data.Metadata.human_name('project'), + *(data.Metadata.human_name(key) for key in DOC_COLUMNS), ] COL_COUNT = len(COLUMNS) @@ -410,11 +413,8 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]): amount_cell, self.balance_cell(row.end_balance), self.multiline_cell(sorted(projects)), - self.meta_links_cell(row.all_meta_links('rt-id')), - self.meta_links_cell(row.all_meta_links('invoice')), - self.meta_links_cell(row.all_meta_links('approval')), - self.meta_links_cell(row.all_meta_links('contract')), - self.meta_links_cell(row.all_meta_links('purchase-order')), + *(self.meta_links_cell(row.all_meta_links(key)) + for key in self.DOC_COLUMNS), ) diff --git a/tests/test_data_metadata.py b/tests/test_data_metadata.py index effba9dc3109c4f2a7a1ed8a82a9f6e672afb9bc..9ea94b6aad5220b6cf05daaa504615393ba3091b 100644 --- a/tests/test_data_metadata.py +++ b/tests/test_data_metadata.py @@ -89,3 +89,17 @@ def test_first_link_bad_type_default(simple_txn, meta_value): simple_txn.meta['badmeta'] = meta_value meta = data.PostingMeta(simple_txn, 1) assert meta.first_link('badmeta', '_') == '_' + +@pytest.mark.parametrize('meta_name,expected', [ + ('approval', 'Approval'), + ('bank-id', 'Bank ID'), + ('bank-statement', 'Bank Statement'), + ('check-id', 'Check Number'), + ('paypal-id', 'PayPal ID'), + ('purchase-order', 'Purchase Order'), + ('receipt', 'Receipt'), + ('rt-id', 'Ticket'), + ('tax-statement', 'Tax Statement'), +]) +def test_human_name(meta_name, expected): + assert data.Metadata.human_name(meta_name) == expected