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])
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')
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>')