Skip to content

Commit

Permalink
test added for Report
Browse files Browse the repository at this point in the history
  • Loading branch information
epogrebnyak committed Dec 23, 2023
1 parent 02c9a00 commit 3f9e292
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 99 deletions.
97 changes: 48 additions & 49 deletions x/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ def subset(self, cls):
}
)

def balance_sheet(self):
from report import balance_sheet

return balance_sheet(self)

def income_statement(self):
from report import income_statement

return income_statement(self)


class Pipeline:
"""A pipeline to accumulate ledger transformations."""
Expand Down Expand Up @@ -365,33 +375,49 @@ def close_last(self):
self.close_contra(accounts.ContraCapital)
return self

def balance_sheet(self):
from report import balance_sheet

return balance_sheet(self.ledger)

def income_statement(self):
from report import income_statement

return income_statement(self.ledger)
class TrialBalance(UserDict[str, tuple[int, int]]):
def column_1(self):
names = [
name.replace("_", " ").strip().capitalize() for name in self.data.keys()
]
return Column(names).align_left(".").add_space(1).header("Account")

def column_2(self):
return (
Column([str(d) for (d, _) in self.data.values()])
.align_right()
.add_space_left(2)
.header("Debit")
.add_space(2)
)

def column_3(self):
return (
Column([str(c) for (_, c) in self.data.values()])
.align_right()
.add_space_left(2)
.header("Credit")
)

def view_trial_balance(chart, ledger) -> str:
data = list(yield_tuples_for_trial_balance(chart, ledger))
def table(self):
return self.column_1() + self.column_2() + self.column_3()

col_1 = Column([d[0] for d in data]).align_left(".").add_space(1).header("Account")
col_2 = nth(data, 1).align_right().add_space_left(2).header("Debit").add_space(2)
col_3 = nth(data, 2).align_right().add_space_left(2).header("Credit")
return (col_1 + col_2 + col_3).printable()
def view(self):
return self.table().printable()


class TB(UserDict[str, tuple[int, int]]):
...
def yield_tuples(ledger):
for name, taccount in ledger.subset(accounts.DebitAccount).data.items():
yield name, taccount.balance(), 0
for name, taccount in ledger.subset(accounts.CreditAccount).data.items():
yield name, 0, taccount.balance()


def make_trial_balance(chart, ledger):
return TB(
{name: (a, b) for name, a, b in yield_tuples_for_trial_balance(chart, ledger)}
def trial_balance(chart, ledger):
ignore = [chart.null_account, chart.income_summary_account]
return TrialBalance(
{name: (a, b) for name, a, b in yield_tuples(ledger) if name not in ignore}
)


Expand All @@ -407,38 +433,11 @@ def pipeline(self):

def income_statement(self, header="Income Statement"):
p = self.pipeline.close_first()
return p.income_statement().viewer(self.titles, header)
return p.ledger.income_statement().viewer(self.titles, header)

def balance_sheet(self, header="Balance Sheet"):
p = self.pipeline.close_first().close_second().close_last()
return p.balance_sheet().viewer(self.titles, header)
return p.ledger.balance_sheet().viewer(self.titles, header)

def trial_balance(self, header="Trial Balance"):
return view_trial_balance(self.chart, self.ledger)

def tb(self):
return make_trial_balance(self.chart, self.ledger)


def yield_tuples_for_trial_balance(chart, ledger):
def must_exclude(t_account):
return any(
[
isinstance(t_account, e)
for e in [accounts.NullAccount, accounts.IncomeSummaryAccount]
]
)

for account_name, t_account in ledger.data.items():
if isinstance(t_account, accounts.DebitAccount) and not must_exclude(t_account):
yield account_name, t_account.balance(), 0
for account_name, t_account in ledger.data.items():
if isinstance(t_account, accounts.CreditAccount) and not must_exclude(
t_account
):
yield account_name, 0, t_account.balance()


def nth(data, n: int, f=str) -> Column:
"""Make a column from nth element of each tuple or list in `data`."""
return Column([f(d[n]) for d in data])
return trial_balance(self.chart, self.ledger)
34 changes: 33 additions & 1 deletion x/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ContraLabel,
Pipeline,
make_chart,
Reporter,
)


Expand Down Expand Up @@ -127,8 +128,39 @@ def test_ledger0_initial_values(ledger0):
assert ledger0.data["refunds"].debit_and_credit() == (499, 0)


def test_chaining_in_pipeline_must_not_corrupt_the_argument(chart0, ledger0):
def test_chaining_in_pipeline_must_not_corrupt_input_argument(chart0, ledger0):
Pipeline(chart0, ledger0).close_first().close_second().close_last()
assert ledger0.data["salaries"].debit_and_credit() == (2001, 0)
assert ledger0.data["sales"].debit_and_credit() == (0, 3499)
assert ledger0.data["refunds"].debit_and_credit() == (499, 0)


def test_balance_sheet(chart0, ledger0):
assert Reporter(chart0, ledger0).balance_sheet().statement.dict() == {
"assets": {"cash": 10999},
"capital": {"equity": 10000, "retained_earnings": 999},
"liabilities": {},
}


def test_income_statement(chart0, ledger0):
assert Reporter(chart0, ledger0).income_statement().statement.dict() == {
"income": {"sales": 3000},
"expenses": {"salaries": 2001},
}


def test_trial_balance_view(chart0, ledger0):
assert Reporter(chart0, ledger0).trial_balance() == {
"cash": (10999, 0),
"ts": (2000, 0),
"refunds": (499, 0),
"salaries": (2001, 0),
"equity": (0, 12000),
"sales": (0, 3499),
"retained_earnings": (0, 0),
}


def test_trial_balance_view(chart0, ledger0):
assert isinstance(Reporter(chart0, ledger0).trial_balance().view(), str)
82 changes: 33 additions & 49 deletions x/using.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,40 @@
from compose import BaseChart, BaseLedger, Pipeline, Reporter, make_chart
from compose import Reporter, make_chart


def ledger0(x: BaseChart) -> BaseLedger:
ledger = x.ledger()
ledger.post("cash", "equity", 12_000)
ledger.post("ts", "cash", 2_000)
ledger.post("cash", "sales", 3_499)
ledger.post("refunds", "cash", 499)
ledger.post("salaries", "cash", 2_001)
return ledger


# created chart
x = make_chart( # type: ignore
chart = make_chart( # type: ignore
"asset:cash", # type: ignore
"capital:equity", # type: ignore
"contra:equity:ts", # type: ignore
"income:sales", # type: ignore
"contra:sales:refunds", # type: ignore
"expense:salaries", # type: ignore
) # type: ignore
# created ledger
# THIS LEDGER IS EXPECTED TO BE UNCHANGED
ledger = ledger0(x)
assert ledger.data["salaries"].debit_and_credit() == (2001, 0)
assert ledger.data["sales"].debit_and_credit() == (0, 3499)
assert ledger.data["refunds"].debit_and_credit() == (499, 0)

# BUT THE ledger variable get altered by the chain() function
# all of below should print true
Pipeline(x, ledger).close_first().close_second().close_last()
print(ledger.data["salaries"].debit_and_credit() == (2001, 0))
print(ledger.data["sales"].debit_and_credit() == (0, 3499))
print(ledger.data["refunds"].debit_and_credit() == (499, 0))


r = Reporter(x, ledger=ledger0(x))
print(r.tb())
# this should not change
assert r.tb()["salaries"] == (2001, 0)
assert r.tb()["sales"] == (0, 3499)
assert r.tb()["refunds"] == (499, 0)

# income statement calculation corrupts r.ledger
print(r.income_statement())
print(r.tb()["salaries"] == (2001, 0))
print(r.tb()["sales"] == (0, 3499)) # must be True, now it is False
print(r.tb()["refunds"] == (499, 0)) # must be True, now it is False


# balance sheet calculation corrupts initial ledger further
print(r.balance_sheet())
print(r.tb()["salaries"] == (2001, 0)) # must be True, now it is False
print(r.tb()["sales"] == (0, 3499)) # must be True, now it is False
print(r.tb()["refunds"] == (499, 0)) # must be True, now it is False
print(r.tb())
ledger = chart.ledger()
ledger.post("cash", "equity", 12_000)
ledger.post("ts", "cash", 2_000)
ledger.post("cash", "sales", 3_499)
ledger.post("refunds", "cash", 499)
ledger.post("salaries", "cash", 2_001)
r = Reporter(chart, ledger)

assert r.trial_balance() == {
"cash": (10999, 0),
"ts": (2000, 0),
"refunds": (499, 0),
"salaries": (2001, 0),
"equity": (0, 12000),
"sales": (0, 3499),
"retained_earnings": (0, 0),
}
assert r.income_statement().statement.dict() == {
"income": {"sales": 3000},
"expenses": {"salaries": 2001},
}
assert r.balance_sheet().statement.dict() == {
"assets": {"cash": 10999},
"capital": {"equity": 10000, "retained_earnings": 999},
"liabilities": {},
}
print(r.trial_balance().column_1())
print(r.trial_balance().column_2())
print(r.trial_balance().column_3())
print(r.trial_balance().view())

0 comments on commit 3f9e292

Please sign in to comment.