~trufas/ledgeroni

54d0024ec158effb05bcd6c29f686cc779c9072d — rafacastillol 1 year, 11 months ago 29b1d9d + 1d958fc
Merge pull request #3 from rafacastillol/verify-balance

Add balance verification
M ledgeroni/commands/balance.py => ledgeroni/commands/balance.py +7 -0
@@ 28,6 28,13 @@ def print_balance(ctx, filter_strs):
    for filename in ctx.obj.get('LEDGER_FILES', []):
        journal.add_from_file(filename)

    errors = journal.verify_transaction_balances()
    if errors:
        for error in errors:
            errstr = 'ERROR! Transaction unbalanced: {}'.format(error.header)
            click.echo(errstr, err=True)
        sys.exit(1)

    aggregate.add_from_journal(journal)

    balances = list(aggregate.iter_aggregates())

M ledgeroni/commands/print.py => ledgeroni/commands/print.py +8 -1
@@ 1,11 1,11 @@
"""
print.py: Defines the `print` subcommand
"""
import sys
import click
from ledgeroni.journal import Journal
from ledgeroni import expression


@click.command()
@click.argument('filter_strs', nargs=-1)
@click.pass_context


@@ 24,6 24,13 @@ def print_transactions(ctx, filter_strs):
    for filename in ctx.obj.get('LEDGER_FILES', []):
        journal.add_from_file(filename)

    errors = journal.verify_transaction_balances()
    if errors:
        for error in errors:
            errstr = 'ERROR! Transaction unbalanced: {}'.format(error.header)
            click.echo(errstr, err=True)
        sys.exit(1)

    if sorter:
        sorter.sort_journal(journal)


M ledgeroni/commands/register.py => ledgeroni/commands/register.py +7 -0
@@ 53,6 53,13 @@ def print_register(ctx, filter_strs):
    for filename in ctx.obj.get('LEDGER_FILES', []):
        journal.add_from_file(filename)

    errors = journal.verify_transaction_balances()
    if errors:
        for error in errors:
            errstr = 'ERROR! Transaction unbalanced: {}'.format(error.header)
            click.echo(errstr, err=True)
        sys.exit(1)

    if sorter:
        sorter.sort_journal(journal)


M ledgeroni/journal.py => ledgeroni/journal.py +8 -0
@@ 60,3 60,11 @@ class Journal:
                total = (posting.amounts, posting_total)
                trans_total[posting.account_name] = total
            yield transaction, trans_total

    def verify_transaction_balances(self) -> List[Transaction]:
        errors = []
        for transaction in self.transactions:
            if not transaction.verify_balance():
                errors.append(transaction)

        return errors

M ledgeroni/types.py => ledgeroni/types.py +16 -0
@@ 92,6 92,22 @@ class Transaction:
        return '\n'.join([self.header] + [p.as_journal_format()
                                          for p in self.postings])

    def verify_balance(self) -> bool:
        totals = defaultdict(Fraction)
        for posting in self.postings:
            # If a null amount posting exists, we're done
            if posting.amounts is None:
                return True
            for commodity, amount in posting.amounts.items():
                totals[commodity] += amount

        if len(totals) == 2:
            # Can auto balance if we have exactly two commodities
            return True

        return all(a == 0 for a in totals.values())


    def calc_totals(self) -> Transaction:
        """
        Returns a new transaction where postings with implicit amounts are