diff --git a/conservancy_beancount/reports/balance_sheet.py b/conservancy_beancount/reports/balance_sheet.py index 55e2964e5cfa4c163d1ec68f8e2fee8ac11daaf1..92f540ac96bb91157c7e5b91ade08d4956cff552 100644 --- a/conservancy_beancount/reports/balance_sheet.py +++ b/conservancy_beancount/reports/balance_sheet.py @@ -198,6 +198,7 @@ class Report(core.BaseODS[Sequence[None], None]): ) -> None: super().__init__() self.balances = balances + self.date_fmt = date_fmt one_day = datetime.timedelta(days=1) date = balances.period_range.stop - one_day self.period_name = date.strftime(date_fmt) @@ -248,23 +249,37 @@ class Report(core.BaseODS[Sequence[None], None]): account, sort_period, )) - def write_financial_position(self) -> None: - self.use_sheet("Financial Position") - for width in [3, 1.5, 1.5]: - col_style = self.column_style(width) + def start_sheet(self, + sheet_name: str, + *headers: Iterable[str], + totals_prefix: Sequence[str]=(), + first_width: Union[float, str]=3, + width: Union[float, str]=1.5, + ) -> None: + header_cells: Sequence[odf.table.TableCell] = [ + odf.table.TableCell(), + *(self.multiline_cell(header_lines, stylename=self.style_huline) + for header_lines in headers), + *(self.multiline_cell([*totals_prefix, date_s], stylename=self.style_huline) + for date_s in [self.period_name, self.opening_name]), + ] + self.col_count = len(header_cells) + self.use_sheet(sheet_name) + for index in range(self.col_count): + col_style = self.column_style(width if index else first_width) self.sheet.addElement(odf.table.TableColumn(stylename=col_style)) + start_date = self.balances.period_range.start.strftime(self.date_fmt) self.add_row( self.multiline_cell([ - "DRAFT Statement of Financial Position", - self.period_name, - ], numbercolumnsspanned=3, stylename=self.style_header) + f"DRAFT Statement of {sheet_name}", + f"{start_date}—{self.period_name}", + ], numbercolumnsspanned=self.col_count, stylename=self.style_header) ) self.add_row() - self.add_row( - odf.table.TableCell(), - self.string_cell(self.period_name, stylename=self.style_huline), - self.string_cell(self.opening_name, stylename=self.style_huline), - ) + self.add_row(*header_cells) + + def write_financial_position(self) -> None: + self.start_sheet("Financial Position") prior_assets = core.MutableBalance() period_assets = core.MutableBalance() @@ -358,35 +373,18 @@ class Report(core.BaseODS[Sequence[None], None]): ) def write_activities(self) -> None: - self.use_sheet("Activities") + self.start_sheet( + "Activities", + ["Without Donor", "Restrictions"], + ["With Donor", "Restrictions"], + totals_prefix=["Total Year Ended"], + ) bal_kwargs: Sequence[Dict[str, Any]] = [ {'period': Period.PERIOD, 'fund': Fund.UNRESTRICTED}, {'period': Period.PERIOD, 'fund': Fund.RESTRICTED}, {'period': Period.PERIOD}, {'period': Period.PRIOR}, ] - col_count = len(bal_kwargs) + 1 - for index in range(col_count): - col_style = self.column_style(1.5 if index else 3) - self.sheet.addElement(odf.table.TableColumn(stylename=col_style)) - self.add_row( - self.multiline_cell([ - "DRAFT Statement of Activities", - self.period_name, - ], numbercolumnsspanned=col_count, stylename=self.style_header) - ) - self.add_row() - self.add_row( - odf.table.TableCell(), - self.multiline_cell(["Without Donor", "Restrictions"], - stylename=self.style_huline), - self.multiline_cell(["With Donor", "Restrictions"], - stylename=self.style_huline), - self.multiline_cell(["Total Year Ended", self.period_name], - stylename=self.style_huline), - self.multiline_cell(["Total Year Ended", self.opening_name], - stylename=self.style_huline), - ) totals = [core.MutableBalance() for _ in bal_kwargs] self.add_row(self.string_cell("Support and Revenue", stylename=self.style_bold)) @@ -513,7 +511,13 @@ class Report(core.BaseODS[Sequence[None], None]): ) def write_functional_expenses(self) -> None: - self.use_sheet("Functional Expenses") + self.start_sheet( + "Functional Expenses", + ["Program", "Services"], + ["Management and", "Administrative"], + ["Fundraising"], + totals_prefix=["Total Year Ended"], + ) bal_kwargs: Sequence[Dict[str, Any]] = [ {'period': Period.PERIOD, 'post_type': 'program'}, {'period': Period.PERIOD, 'post_type': 'management'}, @@ -521,30 +525,6 @@ class Report(core.BaseODS[Sequence[None], None]): {'period': Period.PERIOD}, {'period': Period.PRIOR}, ] - col_count = len(bal_kwargs) + 1 - for index in range(col_count): - col_style = self.column_style(1.5 if index else 3) - self.sheet.addElement(odf.table.TableColumn(stylename=col_style)) - self.add_row( - self.multiline_cell([ - "DRAFT Statement of Functional Expenses", - self.period_name, - ], numbercolumnsspanned=col_count, stylename=self.style_header) - ) - self.add_row() - self.add_row( - odf.table.TableCell(), - self.multiline_cell(["Program", "Services"], - stylename=self.style_huline), - self.multiline_cell(["Management and", "Administrative"], - stylename=self.style_huline), - self.multiline_cell(["Fundraising"], - stylename=self.style_huline), - self.multiline_cell(["Total Year Ended", self.period_name], - stylename=self.style_huline), - self.multiline_cell(["Total Year Ended", self.opening_name], - stylename=self.style_huline), - ) totals = [core.MutableBalance() for _ in bal_kwargs] for text, classification in self.walk_classifications_by_account('Expenses'): @@ -566,7 +546,7 @@ class Report(core.BaseODS[Sequence[None], None]): if not (break_bal - balances[3]).clean_copy(1).is_zero(): logger.warning( "Functional expenses breakdown does not match total on row %s", - len(self.sheet.childNodes) - col_count, + len(self.sheet.childNodes) - self.col_count, ) for total, bal in zip(totals, balances): total += bal @@ -578,27 +558,12 @@ class Report(core.BaseODS[Sequence[None], None]): ) def write_cash_flows(self) -> None: - self.use_sheet("Cash Flows") + self.start_sheet("Cash Flows") bal_kwargs: Sequence[Dict[str, Any]] = [ {'period': Period.PERIOD}, {'period': Period.PRIOR}, ] - col_count = len(bal_kwargs) + 1 - for index in range(col_count): - col_style = self.column_style(1.5 if index else 3) - self.sheet.addElement(odf.table.TableColumn(stylename=col_style)) - self.add_row( - self.multiline_cell([ - "DRAFT Statement of Cash Flows", - self.period_name, - ], numbercolumnsspanned=col_count, stylename=self.style_header) - ) - self.add_row() - self.add_row( - odf.table.TableCell(), - self.string_cell(self.period_name, stylename=self.style_huline), - self.string_cell(self.opening_name, stylename=self.style_huline), - ) + self.add_row(self.string_cell( "Cash Flows from Operating Activities", stylename=self.style_bold,