def get_notifications():
     """
     Return all notifications that should be displayed at the top of pages,
     as a list in the order they should appear. Each list item is a dict
     with keys "classes" and "content", where classes is the string that
     should appear in the notification div's "class" attribute, and content
     is the string content of the div.
     """
     res = []
     num_stale = NotificationsController.num_stale_accounts()
     if num_stale > 0:
         a = 'Accounts'
         if num_stale == 1:
             a = 'Account'
         res.append({
             'classes':
             'alert alert-danger',
             'content':
             '%d %s with stale data. <a href="/accounts" '
             'class="alert-link">View Accounts</a>.' % (num_stale, a)
         })
     accounts_bal = NotificationsController.budget_account_sum()
     unrec_amt = NotificationsController.budget_account_unreconciled()
     standing_bal = NotificationsController.standing_budgets_sum()
     curr_pp = NotificationsController.pp_sum()
     logger.info('accounts_bal=%s standing_bal=%s curr_pp=%s unrec=%s',
                 accounts_bal, standing_bal, curr_pp, unrec_amt)
     if accounts_bal < (standing_bal + curr_pp + unrec_amt):
         res.append({
             'classes':
             'alert alert-danger',
             'content':
             'Combined balance of all <a href="/accounts">'
             'budget-funding accounts</a> '
             '(%s) is less than all allocated funds total of '
             '%s (%s <a href="/budgets">standing budgets</a>; '
             '%s <a href="/pay_period_for">current pay '
             'period remaining</a>; %s <a href="/reconcile">'
             'unreconciled</a>)!'
             '' % (fmt_currency(accounts_bal),
                   fmt_currency((standing_bal + curr_pp + unrec_amt)),
                   fmt_currency(standing_bal), fmt_currency(curr_pp),
                   fmt_currency(unrec_amt))
         })
     unreconciled_ofx = NotificationsController.num_unreconciled_ofx()
     if unreconciled_ofx > 0:
         res.append({
             'classes':
             'alert alert-warning unreconciled-alert',
             'content':
             '%s <a href="/reconcile" class="alert-link">'
             'Unreconciled OFXTransactions'
             '</a>.' % unreconciled_ofx
         })
     return res
示例#2
0
def dollars_filter(x):
    """
    Format as currency using :py:func:`~.utils.fmt_currency`.

    :param x: currency amount, int, float, decimal, etc.
    :return: formatted currency
    :rtype: str
    """
    if x == '' or x is None or isinstance(x, Undefined):
        return ''
    return fmt_currency(x)
示例#3
0
    def _payoffs_list(self, ih):
        """
        Return a payoffs list suitable for rendering.

        :param ih: interest helper instance
        :type ih: biweeklybudget.interest.InterestHelper
        :return: list of payoffs suitable for rendering
        :rtype: list
        """
        res = ih.calculate_payoffs()
        payoffs = []
        for methname in sorted(res.keys(), reverse=True):
            tmp = {
                'name': methname,
                'description': res[methname]['description'],
                'doc': res[methname]['doc'],
                'results': []
            }
            if 'error' in res[methname]:
                tmp['error'] = res[methname]['error']
                continue
            total_pymt = Decimal('0')
            total_int = Decimal('0')
            total_next = Decimal('0')
            max_mos = 0
            for k in sorted(res[methname]['results'].keys()):
                r = res[methname]['results'][k]
                acct = ih.accounts[k]
                tmp['results'].append({
                    'name': '%s (%d) (%s @ %s%%)' % (
                        acct.name, k,
                        fmt_currency(abs(acct.balance.ledger)),
                        (acct.effective_apr * Decimal('100')).quantize(
                            Decimal('.01')
                        )
                    ),
                    'total_payments': r['total_payments'],
                    'total_interest': r['total_interest'],
                    'payoff_months': r['payoff_months'],
                    'next_payment': r['next_payment']
                })
                total_pymt += r['total_payments']
                total_int += r['total_interest']
                total_next += r['next_payment']
                if r['payoff_months'] > max_mos:
                    max_mos = r['payoff_months']
            tmp['total'] = {
                'total_payments': total_pymt,
                'total_interest': total_int,
                'payoff_months': max_mos,
                'next_payment': total_next
            }
            payoffs.append(tmp)
        return payoffs
def handle_new_transaction(session):
    """
    ``before_flush`` event handler
    (:py:meth:`sqlalchemy.orm.events.SessionEvents.before_flush`)
    on the DB session, to handle creation of *new* Transactions. For updates to
    existing Transactions, we rely on :py:func:`~.handle_trans_amount_change`.

    If the Transaction's :py:attr:`~.Transaction.budget` is a
    :py:class:`~.Budget` with :py:attr:`~.Budget.is_periodic` ``False`` (i.e. a
    standing budget), update the Budget's :py:attr:`~.Budget.current_balance`
    for this transaction.

    :param session: current database session
    :type session: sqlalchemy.orm.session.Session
    """
    updated = 0
    for obj in session.new:
        if not isinstance(obj, Transaction):
            continue
        if obj.budget is not None:
            budg = obj.budget
        else:
            budg = session.query(Budget).get(obj.budget_id)
        if budg.is_periodic:
            continue
        logger.debug(
            'Session has new Transaction referencing standing budget id=%s',
            budg.id)
        old_amt = float(budg.current_balance)
        budg.current_balance = old_amt - float(obj.actual_amount)
        logger.info(
            'New transaction (%s) for %s against standing budget id=%s; '
            'update budget current_balance from %s to %s', obj.description,
            fmt_currency(obj.actual_amount), budg.id, fmt_currency(old_amt),
            fmt_currency(budg.current_balance))
        session.add(budg)
        updated += 1
    logger.debug('Done handling new transactions; updated %d standing budgets',
                 updated)
示例#5
0
    def sort_trans_rows(self, rows):
        """
        Sort a list of transaction rows by date and then amount, to match up
        with the HTML in transactions table.

        :param rows: list of inner HTMLs, such as those returned by
          :py:meth:`~.inner_htmls`.
        :type rows: list
        :return: sorted rows
        :rtype: list
        """
        tmp_rows = []
        for row in rows:
            row[1] = float(row[1].replace('$', ''))
            tmp_rows.append(row)
        ret = []
        for row in sorted(tmp_rows, key=lambda x: (x[0], x[1])):
            row[1] = fmt_currency(row[1])
            ret.append(row)
        return ret