diff --git a/conservancy_beancount/reports/fund.py b/conservancy_beancount/reports/fund.py index 2152cda..db2ef02 100644 --- a/conservancy_beancount/reports/fund.py +++ b/conservancy_beancount/reports/fund.py @@ -102,7 +102,7 @@ class ODSReport(core.BaseODS[FundPosts, None]): return None def start_spreadsheet(self) -> None: - self.use_sheet("Fund Report") + self.use_sheet("With Breakdowns") for width in [2.5, 1.5, 1.2, 1.2, 1.2, 1.5, 1.2, 1.3, 1.2, 1.3]: col_style = self.column_style(width) self.sheet.addElement(odf.table.TableColumn(stylename=col_style)) @@ -132,6 +132,14 @@ class ODSReport(core.BaseODS[FundPosts, None]): )) self.add_row() + def end_spreadsheet(self) -> None: + sheet = self.copy_element(self.sheet) + sheet.setAttribute('name', 'Fund Report') + for row in sheet.childNodes: + row.childNodes = row.childNodes[:6] + self.lock_first_row(sheet) + self.document.spreadsheet.insertBefore(sheet, self.sheet) + def _row_balances(self, accounts_map: AccountsMap) -> Iterable[core.Balance]: acct_order = ['Income', 'Expenses', 'Equity'] key_order = [core.OPENING_BALANCE_NAME, *acct_order, core.ENDING_BALANCE_NAME] diff --git a/tests/test_reports_fund.py b/tests/test_reports_fund.py index f5ddb38..079f78d 100644 --- a/tests/test_reports_fund.py +++ b/tests/test_reports_fund.py @@ -155,6 +155,34 @@ def check_cell_balance(cell, balance): else: assert not cell.value +def check_ods_sheet(sheet, account_balances, *, full): + account_bals = account_balances.copy() + unrestricted = account_bals.pop('Conservancy') + if full: + account_bals['Unrestricted'] = unrestricted + for row in sheet.getElementsByType(odf.table.TableRow): + cells = iter(testutil.ODSCell.from_row(row)) + try: + fund = next(cells).firstChild.text + except (AttributeError, StopIteration): + fund = None + if fund in account_bals: + balances = account_bals.pop(fund) + check_cell_balance(next(cells), balances['opening']) + check_cell_balance(next(cells), balances['Income']) + check_cell_balance(next(cells), -balances['Expenses']) + check_cell_balance(next(cells), balances['Equity:Realized']) + check_cell_balance(next(cells), sum(balances[key] for key in [ + 'opening', 'Income', 'Expenses', 'Equity:Realized', + ])) + if full: + check_cell_balance(next(cells), balances['Assets:Receivable']) + check_cell_balance(next(cells), balances['Assets:Prepaid']) + check_cell_balance(next(cells), balances['Liabilities:Payable']) + check_cell_balance(next(cells), balances['Liabilities']) + assert next(cells, None) is None + assert not account_bals, "did not see all funds in report" + def check_ods_report(ods, start_date, stop_date): account_bals = collections.OrderedDict((key, { 'opening': Decimal(amount), @@ -178,27 +206,10 @@ def check_ods_report(ods, start_date, stop_date): else: acct_key, _, _ = account.rpartition(':') account_bals[fund][acct_key] += amount - account_bals['Unrestricted'] = account_bals.pop('Conservancy') - for row in ods.getElementsByType(odf.table.TableRow): - cells = iter(testutil.ODSCell.from_row(row)) - try: - fund = next(cells).firstChild.text - except (AttributeError, StopIteration): - fund = None - if fund in account_bals: - balances = account_bals.pop(fund) - check_cell_balance(next(cells), balances['opening']) - check_cell_balance(next(cells), balances['Income']) - check_cell_balance(next(cells), -balances['Expenses']) - check_cell_balance(next(cells), balances['Equity:Realized']) - check_cell_balance(next(cells), sum(balances[key] for key in [ - 'opening', 'Income', 'Expenses', 'Equity:Realized', - ])) - check_cell_balance(next(cells), balances['Assets:Receivable']) - check_cell_balance(next(cells), balances['Assets:Prepaid']) - check_cell_balance(next(cells), balances['Liabilities:Payable']) - check_cell_balance(next(cells), balances['Liabilities']) - assert not account_bals, "did not see all funds in report" + sheets = iter(ods.getElementsByType(odf.table.Table)) + check_ods_sheet(next(sheets), account_bals, full=False) + check_ods_sheet(next(sheets), account_bals, full=True) + assert next(sheets, None) is None, "found unexpected sheet" def run_main(out_type, arglist, config=None): if config is None: