~trufas/ledgeroni

e14e037c87f372c2e735b66c152b4ad1453fa683 — Rafael Castillo 1 year, 11 months ago 29b1d9d
Verify transaction balances
3 files changed, 33 insertions(+), 1 deletions(-)

M ledgeroni/commands/print.py
M ledgeroni/journal.py
M ledgeroni/types.py
M ledgeroni/commands/print.py => ledgeroni/commands/print.py +9 -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,14 @@ 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/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