Changeset - 7cd569be7b52
[Not reviewed]
0 3 0
Brett Smith - 4 years ago 2020-03-19 14:23:55
brettcsmith@brettcsmith.org
data.Account: Add is_income method.
3 files changed with 17 insertions and 1 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/data.py
Show inline comments
...
 
@@ -14,48 +14,51 @@
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 

	
 
import collections.abc
 

	
 
from beancount.core import account as bc_account
 

	
 
from typing import (
 
    Iterable,
 
    Iterator,
 
    MutableMapping,
 
    Optional,
 
)
 

	
 
from .beancount_types import (
 
    MetaKey,
 
    MetaValue,
 
    Posting as BasePosting,
 
    Transaction,
 
)
 

	
 
class Account(str):
 
    SEP = bc_account.sep
 

	
 
    def is_income(self) -> bool:
 
        return self.is_under('Income:', 'UnearnedIncome:') is not None
 

	
 
    def is_real_asset(self) -> bool:
 
        return bool(
 
            self.is_under('Assets:')
 
            and not self.is_under('Assets:PrepaidExpenses')
 
            and not self.is_under('Assets:PrepaidVacation')
 
        )
 

	
 
    def is_under(self, *acct_seq: str) -> Optional[str]:
 
        for prefix in acct_seq:
 
            if self.startswith(prefix) and (
 
                prefix.endswith(self.SEP)
 
                or self == prefix
 
                or self[len(prefix)] == self.SEP
 
            ):
 
                return prefix
 
        return None
 

	
 

	
 
class PostingMeta(collections.abc.MutableMapping):
 
    def __init__(self,
 
                 txn: Transaction,
 
                 index: int,
 
                 post: Optional[BasePosting]=None,
 
    ) -> None:
conservancy_beancount/plugin/meta_income_type.py
Show inline comments
...
 
@@ -22,31 +22,31 @@ from ..beancount_types import (
 
    Transaction,
 
)
 

	
 
class MetaIncomeType(core._NormalizePostingMetadataHook):
 
    VALUES_ENUM = core.MetadataEnum('income-type', {
 
        'Donations',
 
        'Payable-Derecognition',
 
        'RBI',
 
        'UBTI',
 
    })
 
    DEFAULT_VALUES = {
 
        'Income:Donations': 'Donations',
 
        'Income:Honoraria': 'RBI',
 
        'Income:Interest': 'RBI',
 
        'Income:Interest:Dividend': 'RBI',
 
        'Income:Royalties': 'RBI',
 
        'Income:Sales': 'RBI',
 
        'Income:SoftwareDevelopment': 'RBI',
 
        'Income:TrademarkLicensing': 'RBI',
 
        'UnearnedIncome:Conferences:Registrations': 'RBI',
 
        'UnearnedIncome:MatchPledges': 'Donations',
 
    }
 

	
 
    def _run_on_post(self, txn: Transaction, post: data.Posting) -> bool:
 
        return post.account.is_under('Income:', 'UnearnedIncome:') is not None
 
        return post.account.is_income()
 

	
 
    def _default_value(self, txn: Transaction, post: data.Posting) -> MetaValueEnum:
 
        try:
 
            return self.DEFAULT_VALUES[post.account]
 
        except KeyError:
 
            raise errormod.InvalidMetadataError(txn, post, self.METADATA_KEY) from None
tests/test_data_account.py
Show inline comments
...
 
@@ -24,37 +24,50 @@ from conservancy_beancount import data
 
    ('Expenses:Tax:Sales', 'Expenses:Tax:', True),
 
    ('Expenses:Tax:Sales', 'Expenses:Tax', True),
 
    ('Expenses:Tax:Sales', 'Expenses:', True),
 
    ('Expenses:Tax:Sales', 'Expenses', True),
 
    ('Expenses:Tax:Sales', 'Expense', False),
 
    ('Expenses:Tax:Sales', 'Accrued:', False),
 
    ('Expenses:Tax:Sales', 'Accrued', False),
 
])
 
def test_is_under_one_arg(acct_name, under_arg, expected):
 
    expected = under_arg if expected else None
 
    assert data.Account(acct_name).is_under(under_arg) == expected
 

	
 
@pytest.mark.parametrize('acct_name,expected', [
 
    ('Income:Other', 'Income'),
 
    ('UnearnedIncome:Other', 'UnearnedIncome'),
 
    ('Accrued:AccountsPayable', None),
 
    ('Expenses:General', None),
 
])
 
def test_is_under_multi_arg(acct_name, expected):
 
    assert data.Account(acct_name).is_under('Income', 'UnearnedIncome') == expected
 
    if expected:
 
        expected += ':'
 
    assert data.Account(acct_name).is_under('Income:', 'UnearnedIncome:') == expected
 

	
 
@pytest.mark.parametrize('acct_name,expected', [
 
    ('Accrued:AccountsReceivable', False),
 
    ('Assets:Cash', False),
 
    ('Expenses:General', False),
 
    ('Income:Donations', True),
 
    ('Income:Sales', True),
 
    ('Income:Other', True),
 
    ('Liabilities:CreditCard', False),
 
    ('UnearnedIncome:MatchPledges', True),
 
])
 
def test_is_income(acct_name, expected):
 
    assert data.Account(acct_name).is_income() == expected
 

	
 
@pytest.mark.parametrize('acct_name,expected', [
 
    ('Accrued:AccountsPayable', False),
 
    ('Accrued:AccountsReceivable', False),
 
    ('Assets:Cash', True),
 
    ('Assets:Cash:EUR', True),
 
    ('Assets:PrepaidExpenses', False),
 
    ('Assets:PrepaidVacation', False),
 
    ('Assets:Bank:Checking', True),
 
    ('Expenses:General', False),
 
    ('Income:Donations', False),
 
])
 
def test_is_real_asset(acct_name, expected):
 
    assert data.Account(acct_name).is_real_asset() == expected
0 comments (0 inline, 0 general)