@@ -69,6 +69,7 @@ from pathlib import Path
import odf.table # type:ignore[import]
from beancount.core import data as bc_data
from beancount.parser import printer as bc_printer
from . import core
@@ -84,6 +85,20 @@ PostTally = List[Tuple[int, data.Account]]
PROGNAME = 'ledger-report'
logger = logging.getLogger('conservancy_beancount.reports.ledger')
class AccountPostings(core.RelatedPostings):
START_DATE: datetime.date
def __init__(self,
source: Iterable[data.Posting]=(),
*,
_can_own: bool=False,
) -> None:
super().__init__(source, _can_own=_can_own)
self.start_bal = self.balance_at_cost_by_date(self.START_DATE)
self.stop_bal = self.balance_at_cost()
self.period_bal = self.stop_bal - self.start_bal
class LedgerODS(core.BaseODS[data.Posting, data.Account]):
CORE_COLUMNS: Sequence[str] = [
'Date',
@@ -268,17 +283,21 @@ class LedgerODS(core.BaseODS[data.Posting, data.Account]):
def _report_section_balance(self, key: data.Account, date_key: str) -> None:
uses_opening = key.is_under('Assets', 'Equity', 'Liabilities')
related = self.account_groups[key]
if date_key == 'start':
if not uses_opening:
return
date = self.date_range.start
balance = related.start_bal
description = "Opening Balance"
else:
date = self.date_range.stop
description = "Ending Balance" if uses_opening else "Period Total"
balance = self.norm_func(
self.account_groups[key].balance_at_cost_by_date(date)
)
if uses_opening:
balance = related.stop_bal
description = "Ending Balance"
balance = related.period_bal
description = "Period Total"
self.add_row(
self.date_cell(date, stylename=self.merge_styles(
self.style_bold, self.style_date,
@@ -286,7 +305,7 @@ class LedgerODS(core.BaseODS[data.Posting, data.Account]):
odf.table.TableCell(),
self.string_cell(description, stylename=self.style_bold),
self.balance_cell(balance, stylename=self.style_bold),
self.balance_cell(self.norm_func(balance), stylename=self.style_bold),
def start_section(self, key: data.Account) -> None:
@@ -327,11 +346,13 @@ class LedgerODS(core.BaseODS[data.Posting, data.Account]):
def _combined_balance_row(self,
date: datetime.date,
balance_accounts: Sequence[str],
attr_name: str,
date = getattr(self.date_range, attr_name)
balance_attrname = f'{attr_name}_bal'
balance = -sum((
related.balance_at_cost_by_date(date)
getattr(related, balance_attrname)
for account, related in self.account_groups.items()
if account.is_under(*balance_accounts)
), core.MutableBalance())
@@ -365,23 +386,23 @@ class LedgerODS(core.BaseODS[data.Posting, data.Account]):
numbercolumnsspanned=2,
))
self.add_row()
self._combined_balance_row(self.date_range.start, balance_accounts)
self._combined_balance_row(balance_accounts, 'start')
for _, account in self._sort_and_filter_accounts(
self.account_groups, balance_accounts,
):
related = self.account_groups[account]
# start_bal - stop_bal == -(stop_bal - start_bal)
balance = related.balance_at_cost_by_date(self.date_range.start)
balance -= related.balance_at_cost_by_date(self.date_range.stop)
balance = self.account_groups[account].period_bal
if not balance.is_zero():
self.string_cell(account, stylename=self.style_endtext),
self.balance_cell(balance),
self.balance_cell(-balance),
self._combined_balance_row(self.date_range.stop, balance_accounts)
self._combined_balance_row(balance_accounts, 'stop')
def write(self, rows: Iterable[data.Posting]) -> None:
self.account_groups = dict(core.RelatedPostings.group_by_account(rows))
AccountPostings.START_DATE = self.date_range.start
self.account_groups = dict(AccountPostings.group_by_account(
post for post in rows if post.meta.date < self.date_range.stop
self.write_balance_sheet()
tally_by_account_iter = (
(account, sum(1 for post in related if post.meta.date in self.date_range))