diff --git a/conservancy_beancount/plugin/core.py b/conservancy_beancount/plugin/core.py index f0e7f65..e94b477 100644 --- a/conservancy_beancount/plugin/core.py +++ b/conservancy_beancount/plugin/core.py @@ -239,3 +239,25 @@ class _NormalizePostingMetadataHook(_PostingHook): post.meta[self.METADATA_KEY] = set_value else: yield error + + +class _RequireLinksPostingMetadataHook(_PostingHook): + """Base class to require that posting metadata include links""" + # This base class confirms that a posting's metadata has one or more links + # under METADATA_KEY. + # Most subclasses only need to define METADATA_KEY and _run_on_post. + METADATA_KEY: str + + def __init_subclass__(cls) -> None: + super().__init_subclass__() + cls.HOOK_GROUPS = cls.HOOK_GROUPS.union(['metadata', cls.METADATA_KEY]) + + def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter: + try: + problem = not post.meta.get_links(self.METADATA_KEY) + value = None + except TypeError: + problem = True + value = post.meta[self.METADATA_KEY] + if problem: + yield errormod.InvalidMetadataError(txn, self.METADATA_KEY, value, post) diff --git a/conservancy_beancount/plugin/meta_invoice.py b/conservancy_beancount/plugin/meta_invoice.py index 47866ab..5ab7f43 100644 --- a/conservancy_beancount/plugin/meta_invoice.py +++ b/conservancy_beancount/plugin/meta_invoice.py @@ -22,19 +22,8 @@ from ..beancount_types import ( Transaction, ) -class MetaInvoice(core._PostingHook): +class MetaInvoice(core._RequireLinksPostingMetadataHook): METADATA_KEY = 'invoice' - HOOK_GROUPS = frozenset(['metadata', METADATA_KEY]) def _run_on_post(self, txn: Transaction, post: data.Posting) -> bool: return post.account.is_under('Accrued') is not None - - def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter: - try: - problem = not post.meta.get_links(self.METADATA_KEY) - value = None - except TypeError: - problem = True - value = post.meta[self.METADATA_KEY] - if problem: - yield errormod.InvalidMetadataError(txn, self.METADATA_KEY, value, post)