Source

flowrate / flowrate / ledger.py

Full commit
import flowrate


accounts = {}

class Account(object):

    fields = ('name', 'type')

    def __init__(self, id, **kwargs):
        self.id = id
        self.row = dict((k, kwargs[k]) for k in self.fields)

    @classmethod
    def load_all(cls):
        """Populate the accounts dictionary from the database."""
        for row in flowrate.db.execute("SELECT * FROM accounts;").fetchall():
            acct = cls(row.id, **dict((k, row[k]) for k in cls.fields))
            accounts[row.id] = acct

    def __getitem__(self, key):
        return self.row[key]

    def __setitem__(self, key, value):
        self.row[key] = value

    def create(self):
        flowrate.db.execute(
            "INSERT INTO accounts (id, name, type) "
            "VALUES (%(id)s, %(name)s, %(type)s);",
            {'id': self.id, 'name': self['name'], 'type': self['type']}
            )
        accounts[self.id] = self

    def update(self):
        row = {'id': self.id}
        row.update(self.row)
        flowrate.db.execute(
            "UPDATE accounts SET name = %(name)s, type = %(type)s "
            "WHERE id = %(id)s;", row)

    def delete(self):
        flowrate.db.execute(
            "DELETE FROM accounts WHERE id = %s;", (self.id,))
        accounts.pop(self.id, None)


transactions = {}

class Transaction(object):

    fields = ('postdate', 'credit', 'debit', 'description',
              'amount', 'credit_mult', 'debit_mult')

    def __init__(self, id, **kwargs):
        self.id = id
        self.row = dict((k, kwargs[k]) for k in self.fields)
        self.fulfillments = []

    @classmethod
    def load_all(cls):
        """Populate the transactions dictionary from the database."""
        for row in flowrate.db.execute("SELECT * FROM transactions;").fetchall():
            data = {}
            for k in cls.fields:
                f = k
                if f in ('credit', 'debit'):
                    f = f + '_account'
                data[k] = row[f]
            tx = cls(row.id, **data)
            transactions[row.id] = tx

    def __getitem__(self, key):
        return self.row[key]

    def __setitem__(self, key, value):
        self.row[key] = value

    def save(self):
        if self.id is None:
            row = flowrate.db.execute(
                "INSERT INTO transactions"
                " (postdate, credit_account, debit_account, description,"
                " amount, credit_mult, debit_mult) "
                "VALUES (%(postdate)s, %(credit)s, %(debit)s,"
                " %(description)s, %(amount)s, %(credit_mult)s, %(debit_mult)s) "
                "RETURNING *", self.row).fetchone()
            self.id = row.id
            transactions[self.id] = self
        else:
            row = {'id': self.id}
            row.update(self.row)
            flowrate.db.execute(
                "UPDATE transactions SET postdate = %(postdate)s, "
                "credit_account = %(credit)s, "
                "debit_account = %(debit)s, "
                "description = %(description)s, amount = %(amount)s "
                "credit_mult = %(credit_mult)s, debit_mult = %(debit_mult)s, "
                "WHERE id = %(id)s;", row)

    def delete(self):
        flowrate.db.execute(
            "DELETE FROM transactions WHERE id = %s;", (self.id,))
        transactions.pop(self.id, None)


def find_transactions(filters):
    """Return Transaction objects (dicts) matching the given criteria."""
    if not filters:
        # If there are no filters, return nothing instead of everything
        return []

    txs = [{'id': tx.id, 'postdate': tx['postdate'],
            'credit': tx['credit'], 'debit': tx['debit'],
            'description': tx['description'], 'amount': tx['amount']}
           for tx in transactions.itervalues()
           if all(f(tx) for f in filters)]
    return flowrate.ordered(txs, '-postdate', 'credit', 'debit')