示例#1
0
 def test_dump(self, entries, _, __):
     """
     2012-01-01 open Assets:Bank1:Checking
     2012-01-01 open Assets:Bank1:Savings
     2012-01-01 open Assets:Bank2:Checking
     2012-01-01 open Expenses:Restaurant
     2012-01-01 open Expenses:Movie
     2012-01-01 open Liabilities:CreditCard
     2012-01-01 open Equity:Opening-Balances
     """
     real_account = realization.realize(entries)
     lines = realization.dump(real_account)
     self.assertEqual([
         ('|-- Assets              ', '|   |                   '),
         ('|   |-- Bank1           ', '|   |   |               '),
         ('|   |   |-- Checking    ', '|   |   |               '),
         ('|   |   `-- Savings     ', '|   |                   '),
         ('|   `-- Bank2           ', '|       |               '),
         ('|       `-- Checking    ', '|                       '),
         ('|-- Equity              ', '|   |                   '),
         ('|   `-- Opening-Balances', '|                       '),
         ('|-- Expenses            ', '|   |                   '),
         ('|   |-- Movie           ', '|   |                   '),
         ('|   `-- Restaurant      ', '|                       '),
         ('`-- Liabilities         ', '    |                   '),
         ('    `-- CreditCard      ', '                        '),
     ], [(first_line, cont_line) for first_line, cont_line, _1 in lines])
示例#2
0
    def render_real_text(self, real_root, price_map, price_date, options_map,
                         file):
        rows = []
        account_types = options.get_account_types(options_map)
        for root in (account_types.assets, account_types.liabilities):
            for unused_first_line, unused_cont_line, real_account in realization.dump(
                    realization.get(real_root, root)):

                last_posting = realization.find_last_active_posting(
                    real_account.txn_postings)

                # Don't render updates to accounts that have been closed.
                # Note: this is O(N), maybe we can store this at realization.
                if last_posting is None or isinstance(last_posting,
                                                      data.Close):
                    continue

                last_date = data.get_entry(last_posting).date
                # Skip this posting if a cutoff date has been specified and the
                # account has been updated to at least the cutoff date.
                if self.args.cutoff and self.args.cutoff <= last_date:
                    continue

                rows.append((real_account.account, last_date))

        table_ = table.create_table(rows, [(0, 'Account'),
                                           (1, 'Last Date', '{}'.format)])
        table.render_table(table_, file, 'text')
示例#3
0
def tree_table(oss, real_account, formatter, header=None, classes=None):
    """Generator to a tree of accounts as an HTML table.

    This yields each real_account object in turn and a list object used to
    provide the values for the various columns to render.

    Args:
      oss: a io.StringIO instance, into which we will render the HTML.
      real_account: an instance of a RealAccount node.
      formatter: A object used to render account names and other links.
      header: a list of header columns to render. The first column is special,
              and is used for the account name.
      classes: a list of CSS class strings to apply to the table element.
    Returns:
      A generator of tuples of
        real_account: An instance of RealAccount to render as a row
        cells: A mutable list object to accumulate values for each column you
          want to render.
        row_classes: A mutable list object to accumulate css classes that you
          want to add for the row.

      You need to append to the given 'cells' object; if you don't append
      anything, this tells this routine to skip rendering the row. On the very
      last line, the 'real_account' object will be a special sentinel value to
      indicate that it is meant to render the totals line: TOTALS_LINE.
    """
    write = lambda data: (oss.write(data), oss.write('\n'))

    classes = list(classes) if classes else []
    classes.append('tree-table')
    write('<table class="{}">'.format(' '.join(classes) if classes else ''))

    if header:
        write('<thead>')
        write('<tr>')
        header_iter = iter(header)
        write('<th class="first">{}</th>'.format(next(header_iter)))
        for column in header_iter:
            write('<th>{}</th>'.format(column))
        write('</tr>')
        write('</thead>')

    # Note: This code eventually should be reworked to be agnostic regarding
    # text or HTML output rendering.
    lines = realization.dump(real_account)

    # Yield with a None for the final line.
    lines.append((None, None, TOTALS_LINE))

    for first_line, unused_cont_line, real_acc in lines:
        # Let the caller fill in the data to be rendered by adding it to a list
        # objects. The caller may return multiple cell values; this will create
        # multiple columns.
        cells = []
        row_classes = []
        yield real_acc, cells, row_classes

        # If no cells were added, skip the line. If you want to render empty
        # cells, append empty strings.
        if not cells:
            continue

        # Render the row
        write('<tr class="{}">'.format(' '.join(row_classes)))

        if real_acc is TOTALS_LINE:
            label = '<span class="totals-label"></span>'
        else:
            label = (formatter.render_account(real_acc.account)
                     if formatter else real_acc.account)

        write('<td class="tree-node-name">{}</td>'.format(label))

        # Add columns for each value rendered.
        for cell in cells:
            write('<td class="num">{}</td>'.format(cell))

        write('</tr>')

    write('</table>')