diff --git a/conservancy_beancount/reports/accrual.py b/conservancy_beancount/reports/accrual.py index 57a21bb74bdee76800abc4704f407a6f63c467a4..54c12a2cf2fbe958c98c7944b566c5c6c7d4d68d 100644 --- a/conservancy_beancount/reports/accrual.py +++ b/conservancy_beancount/reports/accrual.py @@ -400,9 +400,11 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]): def end_section(self, key: Optional[data.Account]) -> None: if key is None: return - self.add_row() + total_balance = core.MutableBalance() text_style = self.merge_styles(self.style_bold, self.style_endtext) text_span = self.COL_COUNT - 1 + last_age_text: Optional[str] = None + self.add_row() for threshold, balance in zip(self.age_thresholds, self.age_balances): years, days = divmod(threshold, 365) years_text = f"{years} {'Year' if years == 1 else 'Years'}" @@ -413,15 +415,30 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]): age_text = years_text else: age_text = days_text + if last_age_text is None: + age_range = f"Over {age_text}" + else: + age_range = f"{age_text}–{last_age_text}" self.add_row( self.string_cell( - f"Total Aged Over {age_text}: ", + f"Total Aged {age_range}: ", stylename=text_style, numbercolumnsspanned=text_span, ), *(odf.table.TableCell() for _ in range(1, text_span)), self.balance_cell(balance), ) + last_age_text = age_text + total_balance += balance + self.add_row( + self.string_cell( + "Total Unpaid: ", + stylename=text_style, + numbercolumnsspanned=text_span, + ), + *(odf.table.TableCell() for _ in range(1, text_span)), + self.balance_cell(total_balance), + ) def _link_seq(self, row: AccrualPostings, key: MetaKey) -> Iterator[Tuple[str, str]]: for href in row.all_meta_links(key): diff --git a/tests/test_reports_accrual.py b/tests/test_reports_accrual.py index 1ab79019b83710686e906784561a87be8fc9e9f6..d6f894dd4237351a1c39436334971c1d9a04fe65 100644 --- a/tests/test_reports_accrual.py +++ b/tests/test_reports_accrual.py @@ -182,13 +182,13 @@ def check_aging_sheet(sheet, aging_rows, date, accrue_date): for actual, expected in zip(rows, expect_rows): expected.check_row_match(actual) for row in rows: - if row.text.startswith("Total Aged Over "): + if row.text.startswith("Total Aged "): break else: assert None, "Totals rows not found" actual_sum = Decimal(row.childNodes[-1].value) for row in rows: - if row.text.startswith("Total Aged Over "): + if row.text.startswith("Total Aged "): actual_sum += Decimal(row.childNodes[-1].value) else: break