fund: Text output readability improvements.
Make it look more like the spreadsheets: * Don't normalize Expenses negative. * Consistent account order: Income, then Expenses, then Equity. * Include a bottom line divider for each fund.
This commit is contained in:
parent
cc1767a09d
commit
58954aab23
2 changed files with 21 additions and 11 deletions
|
@ -82,7 +82,7 @@ from .. import data
|
||||||
AccountsMap = Mapping[data.Account, core.PeriodPostings]
|
AccountsMap = Mapping[data.Account, core.PeriodPostings]
|
||||||
FundPosts = Tuple[MetaValue, AccountsMap]
|
FundPosts = Tuple[MetaValue, AccountsMap]
|
||||||
|
|
||||||
EQUITY_ACCOUNTS = ['Equity', 'Income', 'Expenses']
|
EQUITY_ACCOUNTS = ['Income', 'Expenses', 'Equity']
|
||||||
INFO_ACCOUNTS = [
|
INFO_ACCOUNTS = [
|
||||||
'Assets:Receivable',
|
'Assets:Receivable',
|
||||||
'Assets:Prepaid',
|
'Assets:Prepaid',
|
||||||
|
@ -106,7 +106,7 @@ class ODSReport(core.BaseODS[FundPosts, None]):
|
||||||
headers = [["Fund"], ["Balance as of", self.start_date.isoformat()]]
|
headers = [["Fund"], ["Balance as of", self.start_date.isoformat()]]
|
||||||
if expanded:
|
if expanded:
|
||||||
sheet_name = "With Breakdowns"
|
sheet_name = "With Breakdowns"
|
||||||
headers += [["Income"], ["Expenses"], ["Equity"]]
|
headers.extend([acct] for acct in EQUITY_ACCOUNTS)
|
||||||
else:
|
else:
|
||||||
sheet_name = "Fund Report"
|
sheet_name = "Fund Report"
|
||||||
headers += [["Additions"], ["Releases from", "Restrictions"]]
|
headers += [["Additions"], ["Releases from", "Restrictions"]]
|
||||||
|
@ -176,10 +176,9 @@ class ODSReport(core.BaseODS[FundPosts, None]):
|
||||||
self.sheet = start_sheet
|
self.sheet = start_sheet
|
||||||
|
|
||||||
def _row_balances(self, accounts_map: AccountsMap) -> Iterator[core.Balance]:
|
def _row_balances(self, accounts_map: AccountsMap) -> Iterator[core.Balance]:
|
||||||
acct_order = ['Income', 'Expenses', 'Equity']
|
key_order = [core.OPENING_BALANCE_NAME, *EQUITY_ACCOUNTS, core.ENDING_BALANCE_NAME]
|
||||||
key_order = [core.OPENING_BALANCE_NAME, *acct_order, core.ENDING_BALANCE_NAME]
|
|
||||||
balances: Dict[str, core.Balance] = {key: core.MutableBalance() for key in key_order}
|
balances: Dict[str, core.Balance] = {key: core.MutableBalance() for key in key_order}
|
||||||
for acct_s, balance in core.account_balances(accounts_map, acct_order):
|
for acct_s, balance in core.account_balances(accounts_map, EQUITY_ACCOUNTS):
|
||||||
if acct_s in balances:
|
if acct_s in balances:
|
||||||
balances[acct_s] = balance
|
balances[acct_s] = balance
|
||||||
else:
|
else:
|
||||||
|
@ -242,7 +241,9 @@ class TextReport:
|
||||||
acct_s = total_fmt.format(self.start_date.isoformat())
|
acct_s = total_fmt.format(self.start_date.isoformat())
|
||||||
elif acct_s is core.ENDING_BALANCE_NAME:
|
elif acct_s is core.ENDING_BALANCE_NAME:
|
||||||
acct_s = total_fmt.format(self.stop_date.isoformat())
|
acct_s = total_fmt.format(self.stop_date.isoformat())
|
||||||
yield acct_s, (-balance).format(None, sep='\0').split('\0')
|
if not acct_s.startswith('Expenses:'):
|
||||||
|
balance = -balance
|
||||||
|
yield acct_s, balance.format(None, sep='\0').split('\0')
|
||||||
for _, account in core.sort_and_filter_accounts(account_map, INFO_ACCOUNTS):
|
for _, account in core.sort_and_filter_accounts(account_map, INFO_ACCOUNTS):
|
||||||
balance = account_map[account].stop_bal
|
balance = account_map[account].stop_bal
|
||||||
if not balance.is_zero():
|
if not balance.is_zero():
|
||||||
|
@ -262,14 +263,19 @@ class TextReport:
|
||||||
print(line_fmt.replace('{:>', '{:^').format("ACCOUNT", "BALANCE"),
|
print(line_fmt.replace('{:>', '{:^').format("ACCOUNT", "BALANCE"),
|
||||||
file=self.out_file)
|
file=self.out_file)
|
||||||
fund_start = f' balance as of {self.start_date.isoformat()}'
|
fund_start = f' balance as of {self.start_date.isoformat()}'
|
||||||
|
fund_end = f' balance as of {self.stop_date.isoformat()}'
|
||||||
for acct_s, bal_seq in output:
|
for acct_s, bal_seq in output:
|
||||||
if acct_s.endswith(fund_start):
|
is_end_bal = acct_s.endswith(fund_end)
|
||||||
print(line_fmt.format('―' * acct_width, '―' * bal_width),
|
if is_end_bal or acct_s.endswith(fund_start):
|
||||||
|
print(line_fmt.format('─' * acct_width, '─' * bal_width),
|
||||||
file=self.out_file)
|
file=self.out_file)
|
||||||
bal_iter = iter(bal_seq)
|
bal_iter = iter(bal_seq)
|
||||||
print(line_fmt.format(acct_s, next(bal_iter)), file=self.out_file)
|
print(line_fmt.format(acct_s, next(bal_iter)), file=self.out_file)
|
||||||
for bal_s in bal_iter:
|
for bal_s in bal_iter:
|
||||||
print(line_fmt.format('', bal_s), file=self.out_file)
|
print(line_fmt.format('', bal_s), file=self.out_file)
|
||||||
|
if is_end_bal:
|
||||||
|
print(line_fmt.format('═' * acct_width, '═' * bal_width),
|
||||||
|
file=self.out_file)
|
||||||
|
|
||||||
|
|
||||||
class ReportType(enum.Enum):
|
class ReportType(enum.Enum):
|
||||||
|
|
|
@ -111,11 +111,13 @@ def check_text_balances(actual, expected, *expect_accounts):
|
||||||
balance = Decimal()
|
balance = Decimal()
|
||||||
for expect_account in expect_accounts:
|
for expect_account in expect_accounts:
|
||||||
expect_amount = expected[expect_account]
|
expect_amount = expected[expect_account]
|
||||||
|
balance += expect_amount
|
||||||
|
if expect_account.startswith('Expenses:'):
|
||||||
|
expect_amount *= -1
|
||||||
if expect_amount:
|
if expect_amount:
|
||||||
actual_account, actual_amount = next(actual)
|
actual_account, actual_amount = next(actual)
|
||||||
assert actual_account == expect_account
|
assert actual_account == expect_account
|
||||||
assert actual_amount == format_amount(expect_amount)
|
assert actual_amount == format_amount(expect_amount)
|
||||||
balance += expect_amount
|
|
||||||
return balance
|
return balance
|
||||||
|
|
||||||
def check_text_report(output, project, start_date, stop_date):
|
def check_text_report(output, project, start_date, stop_date):
|
||||||
|
@ -142,17 +144,19 @@ def check_text_report(output, project, start_date, stop_date):
|
||||||
assert open_amt == format_amount(balance_amount)
|
assert open_amt == format_amount(balance_amount)
|
||||||
balance_amount += check_text_balances(
|
balance_amount += check_text_balances(
|
||||||
actual, expected,
|
actual, expected,
|
||||||
|
'Income:Other',
|
||||||
|
'Expenses:Other',
|
||||||
'Equity:Funds:Restricted',
|
'Equity:Funds:Restricted',
|
||||||
'Equity:Funds:Unrestricted',
|
'Equity:Funds:Unrestricted',
|
||||||
'Equity:Realized:CurrencyConversion',
|
'Equity:Realized:CurrencyConversion',
|
||||||
'Income:Other',
|
|
||||||
'Expenses:Other',
|
|
||||||
)
|
)
|
||||||
|
next(actual)
|
||||||
end_acct, end_amt = next(actual)
|
end_acct, end_amt = next(actual)
|
||||||
assert end_acct == "{} balance as of {}".format(
|
assert end_acct == "{} balance as of {}".format(
|
||||||
project, stop_date.isoformat(),
|
project, stop_date.isoformat(),
|
||||||
)
|
)
|
||||||
assert end_amt == format_amount(balance_amount)
|
assert end_amt == format_amount(balance_amount)
|
||||||
|
next(actual)
|
||||||
balance_amount += check_text_balances(
|
balance_amount += check_text_balances(
|
||||||
actual, expected,
|
actual, expected,
|
||||||
'Assets:Receivable:Accounts',
|
'Assets:Receivable:Accounts',
|
||||||
|
|
Loading…
Add table
Reference in a new issue