"""meta_receipt - Validate receipt metadata""" # Copyright © 2020 Brett Smith # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from decimal import Decimal from . import core from .. import config as configmod from .. import data from .. import errors as errormod from ..beancount_types import ( MetaKey, Transaction, ) from typing import ( Callable, ) class MetaReceipt(core._RequireLinksPostingMetadataHook): CHECKED_METADATA = ['receipt'] def __init__(self, config: configmod.Config) -> None: self.payment_threshold = abs(config.payment_threshold()) def _run_on_post(self, txn: Transaction, post: data.Posting) -> bool: return ( (post.account.is_cash_equivalent() or post.account.is_credit_card()) and not post.account.is_under('Assets:PayPal') and post.units.number is not None and abs(post.units.number) >= self.payment_threshold ) def _run_checking_debit(self, txn: Transaction, post: data.Posting) -> errormod.Iter: receipt_errors = list(self._check_metadata(txn, post, self.CHECKED_METADATA)) if not receipt_errors: return for error in receipt_errors: if error.value is not None: yield error try: check_id = post.meta['check-id'] except KeyError: check_id_ok = False else: check_id_ok = (isinstance(check_id, Decimal) and check_id >= 1 and not check_id % 1) if not check_id_ok: yield errormod.InvalidMetadataError(txn, 'check-id', check_id, post, Decimal) if not check_id_ok: yield errormod.InvalidMetadataError(txn, 'receipt/check-id', post=post) def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter: keys = list(self.CHECKED_METADATA) is_checking = post.account.is_checking() if is_checking and post.is_debit(): return self._run_checking_debit(txn, post) elif is_checking: keys.append('check') elif post.account.is_credit_card() and not post.is_credit(): keys.append('invoice') return self._check_metadata(txn, post, keys)