def setUp(self): self.gl_structure = GeneralLedgerStructure("NameA", description="DescriptionA") self.sales_acc = self.gl_structure._acci_sales_.create_account( "sales_default", "0000") self.cos_acc = self.gl_structure._acci_cos_.create_account( "cos_default", "0000") self.reva_acc = self.gl_structure["Other Income"].create_account( "RevA", number="011") self.expa_acc = self.gl_structure["Expense"].create_account( "ExpenseA", number="011") self.object = Entity("EntityA", gl_structure=self.gl_structure, description="DescriptionA") # Set up the needed objects self.comp1 = self.object.create_component("ComponentA1", description="ca1") basic_activity = BasicActivity("BasicActivityA", description="DescriptionA", dt_account="Bank", cr_account="Sales", amount=5000, start=datetime(2016, 2, 1), end=datetime(2017, 2, 1), interval=1) self.comp1.add_activity(basic_activity) self.clock = Clock("NameA", start_datetime=datetime(2016, 1, 1))
def __init__(self, name, description=None, start_datetime=datetime.now(), period_duration=TimePeriod.year, period_count=1): self.clock = Clock( "Clock", start_datetime=get_date(start_datetime), timestep_period_duration=period_duration) self.period_count = period_count self.entities = [] super(TimeBasedModel, self).__init__(name, description=description)
def test_run(self): """ Test that the activity run method creates a transaction with an amount of 5000. """ structure = GeneralLedgerStructure("NameA", description="DescriptionA") gl = GeneralLedger("NameA", structure, description="DescriptionA") clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) clock.tick() clock.tick() self.object.prepare_to_run(clock, 20) self.object.run(clock, gl) self.assertEqual(len(gl.transactions), 1) self.assertEqual(gl.transactions[0].amount, 5000)
def setUp(self): self.gl_structure = GeneralLedgerStructure( "GL Structure", description="General Ledger Structure") self.gl_structure["Account Payable"].create_account( "Capital Loan", "0000") self.gl_structure["Expense"].create_account( "Interest Expense", "0000") self.gl = GeneralLedger( "GL", self.gl_structure, description="General Ledger") self.clock = Clock("NameA", start_datetime=datetime(2016, 2, 1)) self.object = BasicLoanActivity( "Capital Loan", bank_account="Bank/Default", loan_account="Account Payable/Capital Loan", interest_account="Expense/Interest Expense", amount=180000, interest_rate=0.15, start=datetime(2016, 2, 1), duration=36, interval=1, description="Loan for Capital")
def setUp(self): self.gl_structure = GeneralLedgerStructure( "NameA", description="DescriptionA") self.sales_acc = self.gl_structure._acci_sales_.create_account( "sales_default", "0000") self.cos_acc = self.gl_structure._acci_cos_.create_account( "cos_default", "0000") self.reva_acc = self.gl_structure["Other Income"].create_account( "RevA", number="011") self.expa_acc = self.gl_structure["Expense"].create_account( "ExpenseA", number="011") self.object = Entity("EntityA", gl_structure=self.gl_structure, description="DescriptionA") # Set up the needed objects self.comp1 = self.object.create_component("ComponentA1", description="ca1") basic_activity = BasicActivity("BasicActivityA", description="DescriptionA", dt_account="Bank", cr_account="Sales", amount=5000, start=datetime(2016, 2, 1), end=datetime(2017, 2, 1), interval=1) self.comp1.add_activity(basic_activity) self.clock = Clock("NameA", start_datetime=datetime(2016, 1, 1))
def test_run(self): """ Test that the component runs its activities. """ # Set up the general ledger so that an activity can create a # transaction. structure = GeneralLedgerStructure("NameA", description="DescriptionA") gl = GeneralLedger("NameA", structure, description="DescriptionA") # Prepare the component for a run. Tick the clock to the correct place # for the activity to create a transaction. clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) clock.tick() clock.tick() self.object.prepare_to_run(clock, 20) self.object.run(clock, gl) # If the activity has been run, then a transaction should have # been generated. self.assertEqual(len(gl.transactions), 1)
def test_prepare_to_run(self): """ Test that the component run's its activities' prepare_to_run methods. """ clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) self.object.prepare_to_run(clock, 18) # The activity's start and end period indexes should be changed. self.assertEqual( self.object.components[0].activities[0].start_period_ix, 2) self.assertEqual(self.object.components[0].activities[0].end_period_ix, 14)
def test__meet_execution_criteria(self): """ Test that the activity only meets the execution criteria when it's amount is greater than 0. """ clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) self.object.prepare_to_run(clock, 13) self.assertEqual(self.object._meet_execution_criteria(5), True) self.object.amount = 0 self.assertEqual(self.object._meet_execution_criteria(5), False)
def setUp(self): self.gl_structure = GeneralLedgerStructure( "GL Structure", description="General Ledger Structure") self.gl_structure["Account Payable"].create_account( "Capital Loan", "0000") self.gl_structure["Expense"].create_account("Interest Expense", "0000") self.gl = GeneralLedger("GL", self.gl_structure, description="General Ledger") self.clock = Clock("NameA", start_datetime=datetime(2016, 2, 1)) self.object = BasicLoanActivity( "Capital Loan", bank_account="Bank/Default", loan_account="Account Payable/Capital Loan", interest_account="Expense/Interest Expense", amount=180000, interest_rate=0.15, start=datetime(2016, 2, 1), duration=36, interval=1, description="Loan for Capital")
class ClockUnitTester(unittest.TestCase): """ Tester for the auxi.core.time.Clock class. """ def setUp(self): self.object = Clock("NameA", description="DescriptionA", start_datetime=datetime(2016, 2, 1), timestep_period_duration=TimePeriod.year, timestep_period_count=3) def test_constructor(self): self.assertEqual(self.object.name, "NameA") self.assertEqual(self.object.description, "DescriptionA") self.assertEqual(self.object.start_datetime, datetime(2016, 2, 1)) self.assertEqual(self.object.timestep_period_duration, TimePeriod.year) self.assertEqual(self.object.timestep_period_count, 3) def test_tick(self): self.assertEqual(self.object.timestep_ix, 0) self.object.tick() self.assertEqual(self.object.timestep_ix, 1) def test_reset(self): self.object.tick() self.object.reset() self.assertEqual(self.object.timestep_ix, 0) def test_get_datetime_at_period_ix(self): self.assertEqual(self.object.get_datetime_at_period_ix(3), datetime(2019, 2, 1)) def test_get_datetime(self): self.object.tick() self.assertEqual(self.object.get_datetime(), datetime(2017, 2, 1))
class EntityUnitTester(unittest.TestCase): """ Tester for the auxi.modelling.entity.component class. """ def setUp(self): self.gl_structure = GeneralLedgerStructure( "NameA", description="DescriptionA") self.sales_acc = self.gl_structure._acci_sales_.create_account( "sales_default", "0000") self.cos_acc = self.gl_structure._acci_cos_.create_account( "cos_default", "0000") self.reva_acc = self.gl_structure["Other Income"].create_account( "RevA", number="011") self.expa_acc = self.gl_structure["Expense"].create_account( "ExpenseA", number="011") self.object = Entity("EntityA", gl_structure=self.gl_structure, description="DescriptionA") # Set up the needed objects self.comp1 = self.object.create_component("ComponentA1", description="ca1") basic_activity = BasicActivity("BasicActivityA", description="DescriptionA", dt_account="Bank", cr_account="Sales", amount=5000, start=datetime(2016, 2, 1), end=datetime(2017, 2, 1), interval=1) self.comp1.add_activity(basic_activity) self.clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) def test_constructor(self): self.assertEqual(self.object.name, "EntityA") self.assertEqual(self.object.description, "DescriptionA") self.assertEqual(self.object.gl.structure.name, self.gl_structure.name) self.assertEqual(self.object.period_count, -1) def test_set_parent_path(self): self.object.set_parent_path("/modelA") self.assertEqual(self.object.path, "/modelA/EntityA") def test_set_name(self): """ Test wether the name changes when it is set, that the entity's name changes and that the component's children's paths are updated correctly. """ self.object.set_parent_path("modelA") self.object.name = "NameAt" self.assertEqual(self.object.name, "NameAt") self.assertEqual(self.object.components[0].path, "modelA/NameAt/ComponentA1") self.assertEqual(self.object.components[0].activities[0].path, "modelA/NameAt/ComponentA1/BasicActivityA") def test_getitem_exists(self): self.assertEqual( self.comp1, self.object["ComponentA1"]) def test_getitem_not_exists(self): self.assertRaises(IndexError, self.object.__getitem__, "ComponentA3") def test_create_component(self): new_comp = self.object.create_component("ComponentA2", description="ca2") self.assertEqual(new_comp.name, "ComponentA2") self.assertEqual(new_comp.description, "ca2") self.assertEqual(new_comp, self.object.components[1]) def test_remove_component(self): self.object.create_component("ComponentA2", description="ca2") self.object.remove_component("ComponentA2") self.assertEqual(len(self.object.components), 1) def test_prepare_to_run(self): """ Test that the entity run's its component' prepare_to_run methods. """ # Test the prepare to run method before any run has been performed self.object.gl.create_transaction( "TestA", description="TestA_Desc", tx_date=datetime(2016, 2, 1).date(), dt_account="Bank", cr_account="Sales", source="Peanut Sales", amount=20.00) self.object.negative_income_tax_total = 99 self.object.prepare_to_run(self.clock, 18) # Was the component's prepare to run executed? self.assertEqual( self.object.components[0].activities[0].start_period_ix, 2) self.assertEqual( self.object.components[0].activities[0].end_period_ix, 14) # Was the datetime's set correctly? self.assertEqual( self.object._exec_year_end_datetime, self.clock.get_datetime_at_period_ix(18)) self.assertEqual( self.object._prev_year_end_datetime, self.clock.start_datetime) self.assertEqual( self.object._curr_year_end_datetime, self.clock.start_datetime + relativedelta(years=1)) # Was the transactions cleared? self.assertEqual(len(self.object.gl.transactions), 0) # Was the negative tax income reset to 0? self.assertEqual(self.object.negative_income_tax_total, 0) def test_run(self): """ Test that the entity runs its components. """ self.object.prepare_to_run(self.clock, 20) self.clock.tick() self.clock.tick() self.object.run(self.clock) self.assertEqual(len(self.object.gl.transactions), 1) self.assertEqual(self.object.gl.transactions[0].amount, 5000) def test__perform_year_end_gross_profit_and_income_summary(self): """ Test that the year end gross profit and income summary accounts are summed up correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Create the accounts to write of dict income_summary_write_off_accounts = collections.OrderedDict([ (self.cos_acc, 700), (gls._acci_inc_tax_exp_acc_, -300), (self.sales_acc, 70), (gls._accb_bank_["Default"], -30)]) gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, 70), (gls._accb_bank_["Default"], -30)]) # Test when there the gross profit is 0. # The gross profit account should not be settled: inc = self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, {}, income_summary_write_off_accounts) # The gross profit account should not be settled. # Only the 4 transactions from the income summary year end calcs # should be there self.assertEqual(len(self.object.gl.transactions), 4) # The income summary should be that of the income summary year end calc # method: -360 (See the income summary year end calc, in this case, # gross profit starts at 0 instead of 5000, thus -360 instead of 4640) self.assertEqual(inc, -360) # Test when there is gross profit. # The gross profit account should not be settled: del self.object.gl.transactions[:] # Clear the tx list self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, gross_profit_write_off_accounts, {}) # The gross profit account should be settled. # Only the 2 transactions from the income summary year end calcs # should be there as well as the gross profit settle transaction self.assertEqual(len(self.object.gl.transactions), 3) # Make sure the gross profit settle transaction appears correct # When gross profit is positive: self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 40) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) # When gross profit is negative: gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, -70), (gls._accb_bank_["Default"], 30)]) del self.object.gl.transactions[:] # Clear the tx list self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, gross_profit_write_off_accounts, {}) self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 40) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) def test__perform_year_end_gross_profit(self): """ Test that the year end gross profit account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Create the accounts to write of dict gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, 70), (gls._accb_bank_["Default"], -30)]) gross_profit = self.object._perform_year_end_gross_profit( year_end_datetime, gross_profit_write_off_accounts) self.assertEqual(len(self.object.gl.transactions), 2) # Expenses: 700-300 = 400 # Other: 70-30 = 40 # Total: gross_profit + Other - expenses: 5000 + 40 - 400 = 4640 self.assertEqual(gross_profit, 40) # Test the "self.sales_acc: 70" transaction self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, 70) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test the "gls._accb_bank_["Default"]: -30" transaction self.assertEqual(self.object.gl.transactions[1].dt_account, gls._accb_bank_["Default"].path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, 30) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) def test__perform_year_end_income_summary(self): """ Test that the year end income summary account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) gross_profit = 5000 # Create the accounts to write of dict income_summary_write_off_accounts = collections.OrderedDict([ (self.cos_acc, 700), (gls._acci_inc_tax_exp_acc_, -300), (self.sales_acc, 70), (gls._accb_bank_["Default"], -30)]) income_summary_amount = self.object._perform_year_end_income_summary( year_end_datetime, gross_profit, income_summary_write_off_accounts) self.assertEqual(len(self.object.gl.transactions), 4) # Expenses: 700-300 = 400 # Other: 70-30 = 40 # Total: gross_profit + Other - expenses: 5000 + 40 - 400 = 4640 self.assertEqual(income_summary_amount, 4640) # Test the "self.cos_acc: 700" transaction self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, 700) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test the "gls._acci_inc_tax_exp_acc_: -300" transaction self.assertEqual(self.object.gl.transactions[1].dt_account, gls._acci_inc_tax_exp_acc_.path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, 300) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) # Test the "self.sales_acc: 70" transaction self.assertEqual(self.object.gl.transactions[2].dt_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 70) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) # Test the "gls._accb_bank_["Default"]: -30" transaction self.assertEqual(self.object.gl.transactions[3].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[3].cr_account, gls._accb_bank_["Default"].path) self.assertEqual(self.object.gl.transactions[3].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[3].amount, 30) self.assertEqual(self.object.gl.transactions[3].is_closing_cr_account, True) def test__perform_year_end_income_tax(self): # TODO pass def test__perform_year_end_retained_earnings(self): """ Test that the year end retained earnings account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Test for == 0 case income_summary = 0 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 0) # Test for > 0 case income_summary = 1000 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 1) self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, gls._accb_ret_earnings_acc_.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, income_summary) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test for < 0 case income_summary = -300 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 2) self.assertEqual(self.object.gl.transactions[1].dt_account, gls._accb_ret_earnings_acc_.path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, income_summary) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) def test__perform_year_end_procedure(self): """ Test that all the year end accounts has been closed of correctly. """ gls = self.object.gl.structure # Test when that no year end transactions are created in the # middle of a year self.object.prepare_to_run(self.clock, 28) self.clock.timestep_ix = 6 # create the transactions self.object.gl.create_transaction( "Sales_tx", description="Sales tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=70) # create the transactions self.object.gl.create_transaction( "Cost_of_Sales_tx", description="Cost of Sales tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=30) self.object._perform_year_end_procedure(self.clock) # Only one transaction should have been created and no # year end transactions. self.assertEqual(len(self.object.gl.transactions), 2) # Test that the year end procedure, at the year end, creates # - two gross profit transactions with values of 70 and 40 # - one gross profit and income summary settle transaction # with a value of 70 - 30 # - one retained earnings transaction with a value of 70 - 30 # Only the 2 transaction (sales tx, and cost of sales tx) and the # 4 'year end' transactions should have been created.) self.clock.timestep_ix = 12 self.object._perform_year_end_procedure(self.clock) self.assertEqual(len(self.object.gl.transactions), 6) self.assertEqual(self.object.gl.transactions[2].amount, 70) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[3].amount, 30) self.assertEqual(self.object.gl.transactions[3].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[3].dt_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[3].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[4].amount, 40) self.assertEqual(self.object.gl.transactions[4].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[4].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[4].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[5].amount, 40) self.assertEqual(self.object.gl.transactions[5].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[5].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[5].cr_account, gls._accb_ret_earnings_acc_.path) # Test for a new year self.clock.timestep_ix = 18 # Test for when other revenue and expense accounts transactions # exists as well. # create a sales transactions self.object.gl.create_transaction( "SalesTx2", description="Sales tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=45) self.object.gl.create_transaction( "SalesTx3", description="Sales tx3", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=35) self.object.gl.create_transaction( "Cost_of_Sales_tx2", description="Cost of Sales tx 2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=15) self.object.gl.create_transaction( "Cost_of_Sales_tx3", description="Cost of Sales tx 3", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=5) # create the transactions self.object.gl.create_transaction( "revenueATx", description="revenue a tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.reva_acc.path, source=self.object.path, amount=450) self.object.gl.create_transaction( "revenueATx2", description="revenue a tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.reva_acc.path, source=self.object.path, amount=350) # create the transactions self.object.gl.create_transaction( "expenseAtx", description="expense a tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.expa_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=320) self.object.gl.create_transaction( "expenseAtx2", description="expense a tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.expa_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=180) # Test that the year end procedure, at the year end, creates # - two gross profit transactions with values of 80 and 20 # - two income summary transactions with values of 800 and 500 # - one gross profit and income summary settle transaction # with a value of 80 - 20 # - one retained earnings transaction with a value of # 800 - 500 + 80 - 20 # Only the 6 transactions (2 sales tx, 2 cost of sales, # 2 revenue a and 2 expense a) and the 5 'year end' transactions # should have been created.) self.clock.timestep_ix = 24 self.object._perform_year_end_procedure(self.clock) self.assertEqual(len(self.object.gl.transactions), 20) self.assertEqual(self.object.gl.transactions[14].amount, 80) self.assertEqual(self.object.gl.transactions[14].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[14].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[14].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[15].amount, 20) self.assertEqual(self.object.gl.transactions[15].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[15].dt_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[15].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[16].amount, 800) self.assertEqual(self.object.gl.transactions[16].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[16].dt_account, self.reva_acc.path) self.assertEqual(self.object.gl.transactions[16].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[17].amount, 500) self.assertEqual(self.object.gl.transactions[17].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[17].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[17].cr_account, self.expa_acc.path) self.assertEqual(self.object.gl.transactions[18].amount, 60) self.assertEqual(self.object.gl.transactions[18].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[18].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[18].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[19].amount, 360) self.assertEqual(self.object.gl.transactions[19].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[19].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[19].cr_account, gls._accb_ret_earnings_acc_.path)
class BasicLoanActivityUnitTester(unittest.TestCase): """ Tester for the auxi.modelling.business.basic.BasicLoanActivity class. """ def setUp(self): self.gl_structure = GeneralLedgerStructure( "GL Structure", description="General Ledger Structure") self.gl_structure["Account Payable"].create_account( "Capital Loan", "0000") self.gl_structure["Expense"].create_account( "Interest Expense", "0000") self.gl = GeneralLedger( "GL", self.gl_structure, description="General Ledger") self.clock = Clock("NameA", start_datetime=datetime(2016, 2, 1)) self.object = BasicLoanActivity( "Capital Loan", bank_account="Bank/Default", loan_account="Account Payable/Capital Loan", interest_account="Expense/Interest Expense", amount=180000, interest_rate=0.15, start=datetime(2016, 2, 1), duration=36, interval=1, description="Loan for Capital") def test_constructor(self): self.assertEqual(self.object.name, "Capital Loan") self.assertEqual(self.object.bank_account, "Bank/Default") self.assertEqual( self.object.loan_account, "Account Payable/Capital Loan") self.assertEqual( self.object.interest_account, "Expense/Interest Expense") self.assertEqual(self.object.amount, 180000) self.assertEqual(self.object.interest_rate, 0.15) self.assertEqual(self.object.start_datetime, datetime(2016, 2, 1)) self.assertEqual(self.object.end_datetime, datetime(2019, 3, 1)) self.assertEqual(self.object.duration, 36) self.assertEqual(self.object.interval, 1) self.assertEqual(self.object.description, "Loan for Capital") def test__meet_exection_criteria(self): """ Test that the activity only meets the execution criteria when it's amount is greater than 0 and its duration is greater than 0. """ self.object.prepare_to_run(self.clock, 13) self.assertEqual(self.object._meet_execution_criteria(5), True) self.object.amount = 0 self.assertEqual(self.object._meet_execution_criteria(5), False) self.object.amount = 180000 self.object.duration = 0 self.assertEqual(self.object._meet_execution_criteria(5), False) def test_run_first_month(self): """ Test that the activity run method creates a transaction with an amount of 180000 on the first month. No other transactions """ self.object.prepare_to_run(self.clock, 1) self.object.run(self.clock, self.gl) self.assertEqual(len(self.gl.transactions), 1) self.assertEqual(self.gl.transactions[0].amount, 180000) def test_run_third_month(self): """ Test that the activity run method accrued the interest correctly. """ self.clock.tick() self.object.prepare_to_run(self.clock, 61) self.clock.tick() self.object.run(self.clock, self.gl) self.clock.tick() self.object.run(self.clock, self.gl) self.clock.tick() self.object.run(self.clock, self.gl) self.assertEqual(len(self.gl.transactions), 5) # Test the intreset rate for the first month # loan amount = 180000 # First month's interest should be (180000 * 0.15) / 12 = 2250 self.assertEqual(self.gl.transactions[1].amount, 2250) # Principle payment is 6239.76 (see below) # The interest payed the previous month is 2250 # Making the total amount payed to the loan 6239.76 - 2250 = 3,989.76 # New amount to calculate interest from: 180000 - 3,989.76 = 176,010.24 # 2nd month's interest should be 176,010.24 * 0.15) / 12 = 2,200.13 self.assertEqual("%.2f" % self.gl.transactions[3].amount, "2200.13") # Test the monthly principle payment # interest rate = 0.15: per month 0.0125. # loan amount = 180000 # duration of the loan = 36 # payment = (180000*0.0125) / (1-(1/pow((1+0.0125), 36))) = 6239.76 self.assertEqual("%.2f" % self.gl.transactions[2].amount, "6239.76") self.assertEqual("%.2f" % self.gl.transactions[4].amount, "6239.76") def test_run_last_month(self): """ Test that the activity run method creates settled the loan on the loans' last month and that the transactions """ self.clock.tick() self.object.prepare_to_run(self.clock, 61) for i in range(0, 60): self.object.run(self.clock, self.gl) self.clock.tick() # Test the number of transaction that was created during the # loan's lifetime. # 2 transactions per months should be created + the initial loan amount # transaction. 36*2 + 1 = 73 last_tx_ix = len(self.gl.transactions) self.assertEqual(len(self.gl.transactions), 73) # The transactions should have run only run for 36 months # (the duration of the loan) r = relativedelta.relativedelta( self.gl.transactions[last_tx_ix-1].tx_date, self.gl.transactions[0].tx_date) self.assertEqual(r.years * 12 + r.months, 36) def test_get_referenced_accounts(self): """ Test that the activity run method get_referenced_accounts accounts matches the debit and credit accounts self.object was initialised with. """ result = self.object.get_referenced_accounts() self.assertEqual(self.object.bank_account, result[0]) self.assertEqual(self.object.loan_account, result[1]) self.assertEqual(self.object.interest_account, result[2])
class EntityUnitTester(unittest.TestCase): """ Tester for the auxi.modelling.entity.component class. """ def setUp(self): self.gl_structure = GeneralLedgerStructure("NameA", description="DescriptionA") self.sales_acc = self.gl_structure._acci_sales_.create_account( "sales_default", "0000") self.cos_acc = self.gl_structure._acci_cos_.create_account( "cos_default", "0000") self.reva_acc = self.gl_structure["Other Income"].create_account( "RevA", number="011") self.expa_acc = self.gl_structure["Expense"].create_account( "ExpenseA", number="011") self.object = Entity("EntityA", gl_structure=self.gl_structure, description="DescriptionA") # Set up the needed objects self.comp1 = self.object.create_component("ComponentA1", description="ca1") basic_activity = BasicActivity("BasicActivityA", description="DescriptionA", dt_account="Bank", cr_account="Sales", amount=5000, start=datetime(2016, 2, 1), end=datetime(2017, 2, 1), interval=1) self.comp1.add_activity(basic_activity) self.clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) def test_constructor(self): self.assertEqual(self.object.name, "EntityA") self.assertEqual(self.object.description, "DescriptionA") self.assertEqual(self.object.gl.structure.name, self.gl_structure.name) self.assertEqual(self.object.period_count, -1) def test_set_parent_path(self): self.object.set_parent_path("/modelA") self.assertEqual(self.object.path, "/modelA/EntityA") def test_set_name(self): """ Test whether the name changes when it is set, that the entity's name changes and that the component's children's paths are updated correctly. """ self.object.set_parent_path("modelA") self.object.name = "NameAt" self.assertEqual(self.object.name, "NameAt") self.assertEqual(self.object.components[0].path, "modelA/NameAt/ComponentA1") self.assertEqual(self.object.components[0].activities[0].path, "modelA/NameAt/ComponentA1/BasicActivityA") def test_getitem_exists(self): self.assertEqual(self.comp1, self.object["ComponentA1"]) def test_getitem_not_exists(self): self.assertRaises(IndexError, self.object.__getitem__, "ComponentA3") def test_create_component(self): new_comp = self.object.create_component("ComponentA2", description="ca2") self.assertEqual(new_comp.name, "ComponentA2") self.assertEqual(new_comp.description, "ca2") self.assertEqual(new_comp, self.object.components[1]) def test_remove_component(self): self.object.create_component("ComponentA2", description="ca2") self.object.remove_component("ComponentA2") self.assertEqual(len(self.object.components), 1) def test_prepare_to_run(self): """ Test that the entity run's its component' prepare_to_run methods. """ # Test the prepare to run method before any run has been performed self.object.gl.create_transaction("TestA", description="TestA_Desc", tx_date=datetime(2016, 2, 1).date(), dt_account="Bank", cr_account="Sales", source="Peanut Sales", amount=20.00) self.object.negative_income_tax_total = 99 self.object.prepare_to_run(self.clock, 18) # Was the component's prepare to run executed? self.assertEqual( self.object.components[0].activities[0].start_period_ix, 2) self.assertEqual(self.object.components[0].activities[0].end_period_ix, 14) # Was the datetime's set correctly? self.assertEqual(self.object._exec_year_end_datetime, self.clock.get_datetime_at_period_ix(18)) self.assertEqual(self.object._prev_year_end_datetime, self.clock.start_datetime) self.assertEqual(self.object._curr_year_end_datetime, self.clock.start_datetime + relativedelta(years=1)) # Was the transactions cleared? self.assertEqual(len(self.object.gl.transactions), 0) # Was the negative tax income reset to 0? self.assertEqual(self.object.negative_income_tax_total, 0) def test_run(self): """ Test that the entity runs its components. """ self.object.prepare_to_run(self.clock, 20) self.clock.tick() self.clock.tick() self.object.run(self.clock) self.assertEqual(len(self.object.gl.transactions), 1) self.assertEqual(self.object.gl.transactions[0].amount, 5000) def test__perform_year_end_gross_profit_and_income_summary(self): """ Test that the year end gross profit and income summary accounts are summed up correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Create the accounts to write of dict income_summary_write_off_accounts = collections.OrderedDict([ (self.cos_acc, 700), (gls._acci_inc_tax_exp_acc_, -300), (self.sales_acc, 70), (gls._accb_bank_["Default"], -30) ]) gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, 70), (gls._accb_bank_["Default"], -30) ]) # Test when there the gross profit is 0. # The gross profit account should not be settled: inc = self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, {}, income_summary_write_off_accounts) # The gross profit account should not be settled. # Only the 4 transactions from the income summary year end calcs # should be there self.assertEqual(len(self.object.gl.transactions), 4) # The income summary should be that of the income summary year end calc # method: -360 (See the income summary year end calc, in this case, # gross profit starts at 0 instead of 5000, thus -360 instead of 4640) self.assertEqual(inc, -360) # Test when there is gross profit. # The gross profit account should not be settled: del self.object.gl.transactions[:] # Clear the tx list self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, gross_profit_write_off_accounts, {}) # The gross profit account should be settled. # Only the 2 transactions from the income summary year end calcs # should be there as well as the gross profit settle transaction self.assertEqual(len(self.object.gl.transactions), 3) # Make sure the gross profit settle transaction appears correct # When gross profit is positive: self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 40) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) # When gross profit is negative: gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, -70), (gls._accb_bank_["Default"], 30) ]) del self.object.gl.transactions[:] # Clear the tx list self.object._perform_year_end_gross_profit_and_income_summary( year_end_datetime, gross_profit_write_off_accounts, {}) self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 40) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) def test__perform_year_end_gross_profit(self): """ Test that the year end gross profit account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Create the accounts to write of dict gross_profit_write_off_accounts = collections.OrderedDict([ (self.sales_acc, 70), (gls._accb_bank_["Default"], -30) ]) gross_profit = self.object._perform_year_end_gross_profit( year_end_datetime, gross_profit_write_off_accounts) self.assertEqual(len(self.object.gl.transactions), 2) # Expenses: 700-300 = 400 # Other: 70-30 = 40 # Total: gross_profit + Other - expenses: 5000 + 40 - 400 = 4640 self.assertEqual(gross_profit, 40) # Test the "self.sales_acc: 70" transaction self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, 70) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test the "gls._accb_bank_["Default"]: -30" transaction self.assertEqual(self.object.gl.transactions[1].dt_account, gls._accb_bank_["Default"].path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, 30) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) def test__perform_year_end_income_summary(self): """ Test that the year end income summary account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) gross_profit = 5000 # Create the accounts to write of dict income_summary_write_off_accounts = collections.OrderedDict([ (self.cos_acc, 700), (gls._acci_inc_tax_exp_acc_, -300), (self.sales_acc, 70), (gls._accb_bank_["Default"], -30) ]) income_summary_amount = self.object._perform_year_end_income_summary( year_end_datetime, gross_profit, income_summary_write_off_accounts) self.assertEqual(len(self.object.gl.transactions), 4) # Expenses: 700-300 = 400 # Other: 70-30 = 40 # Total: gross_profit + Other - expenses: 5000 + 40 - 400 = 4640 self.assertEqual(income_summary_amount, 4640) # Test the "self.cos_acc: 700" transaction self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, 700) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test the "gls._acci_inc_tax_exp_acc_: -300" transaction self.assertEqual(self.object.gl.transactions[1].dt_account, gls._acci_inc_tax_exp_acc_.path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, 300) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) # Test the "self.sales_acc: 70" transaction self.assertEqual(self.object.gl.transactions[2].dt_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[2].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[2].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[2].amount, 70) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) # Test the "gls._accb_bank_["Default"]: -30" transaction self.assertEqual(self.object.gl.transactions[3].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[3].cr_account, gls._accb_bank_["Default"].path) self.assertEqual(self.object.gl.transactions[3].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[3].amount, 30) self.assertEqual(self.object.gl.transactions[3].is_closing_cr_account, True) def test__perform_year_end_income_tax(self): # TODO pass def test__perform_year_end_retained_earnings(self): """ Test that the year end retained earnings account is closed correctly. """ gls = self.object.gl.structure year_end_datetime = datetime(2017, 2, 1) # Test for == 0 case income_summary = 0 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 0) # Test for > 0 case income_summary = 1000 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 1) self.assertEqual(self.object.gl.transactions[0].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[0].cr_account, gls._accb_ret_earnings_acc_.path) self.assertEqual(self.object.gl.transactions[0].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[0].amount, income_summary) self.assertEqual(self.object.gl.transactions[0].is_closing_cr_account, True) # Test for < 0 case income_summary = -300 self.object._perform_year_end_retained_earnings( year_end_datetime, income_summary) self.assertEqual(len(self.object.gl.transactions), 2) self.assertEqual(self.object.gl.transactions[1].dt_account, gls._accb_ret_earnings_acc_.path) self.assertEqual(self.object.gl.transactions[1].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[1].tx_date, year_end_datetime) self.assertEqual(self.object.gl.transactions[1].amount, income_summary) self.assertEqual(self.object.gl.transactions[1].is_closing_cr_account, True) def test__perform_year_end_procedure(self): """ Test that all the year end accounts has been closed of correctly. """ gls = self.object.gl.structure # Test when that no year end transactions are created in the # middle of a year self.object.prepare_to_run(self.clock, 28) self.clock.timestep_ix = 6 # create the transactions self.object.gl.create_transaction( "Sales_tx", description="Sales tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=70) # create the transactions self.object.gl.create_transaction( "Cost_of_Sales_tx", description="Cost of Sales tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=30) self.object._perform_year_end_procedure(self.clock) # Only one transaction should have been created and no # year end transactions. self.assertEqual(len(self.object.gl.transactions), 2) # Test that the year end procedure, at the year end, creates # - two gross profit transactions with values of 70 and 40 # - one gross profit and income summary settle transaction # with a value of 70 - 30 # - one retained earnings transaction with a value of 70 - 30 # Only the 2 transaction (sales tx, and cost of sales tx) and the # 4 'year end' transactions should have been created.) self.clock.timestep_ix = 12 self.object._perform_year_end_procedure(self.clock) self.assertEqual(len(self.object.gl.transactions), 6) self.assertEqual(self.object.gl.transactions[2].amount, 70) self.assertEqual(self.object.gl.transactions[2].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[2].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[2].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[3].amount, 30) self.assertEqual(self.object.gl.transactions[3].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[3].dt_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[3].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[4].amount, 40) self.assertEqual(self.object.gl.transactions[4].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[4].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[4].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[5].amount, 40) self.assertEqual(self.object.gl.transactions[5].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[5].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[5].cr_account, gls._accb_ret_earnings_acc_.path) # Test for a new year self.clock.timestep_ix = 18 # Test for when other revenue and expense accounts transactions # exists as well. # create a sales transactions self.object.gl.create_transaction( "SalesTx2", description="Sales tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=45) self.object.gl.create_transaction( "SalesTx3", description="Sales tx3", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.sales_acc.path, source=self.object.path, amount=35) self.object.gl.create_transaction( "Cost_of_Sales_tx2", description="Cost of Sales tx 2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=15) self.object.gl.create_transaction( "Cost_of_Sales_tx3", description="Cost of Sales tx 3", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.cos_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=5) # create the transactions self.object.gl.create_transaction( "revenueATx", description="revenue a tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.reva_acc.path, source=self.object.path, amount=450) self.object.gl.create_transaction( "revenueATx2", description="revenue a tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=gls._accb_bank_["Default"].path, # Bank account cr_account=self.reva_acc.path, source=self.object.path, amount=350) # create the transactions self.object.gl.create_transaction( "expenseAtx", description="expense a tx", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.expa_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=320) self.object.gl.create_transaction( "expenseAtx2", description="expense a tx2", tx_date=self.clock.get_datetime_at_period_ix( self.clock.timestep_ix), dt_account=self.expa_acc.path, cr_account=gls._accb_bank_["Default"].path, # Bank account source=self.object.path, amount=180) # Test that the year end procedure, at the year end, creates # - two gross profit transactions with values of 80 and 20 # - two income summary transactions with values of 800 and 500 # - one gross profit and income summary settle transaction # with a value of 80 - 20 # - one retained earnings transaction with a value of # 800 - 500 + 80 - 20 # Only the 6 transactions (2 sales tx, 2 cost of sales, # 2 revenue a and 2 expense a) and the 5 'year end' transactions # should have been created.) self.clock.timestep_ix = 24 self.object._perform_year_end_procedure(self.clock) self.assertEqual(len(self.object.gl.transactions), 20) self.assertEqual(self.object.gl.transactions[14].amount, 80) self.assertEqual(self.object.gl.transactions[14].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[14].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[14].cr_account, self.sales_acc.path) self.assertEqual(self.object.gl.transactions[15].amount, 20) self.assertEqual(self.object.gl.transactions[15].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[15].dt_account, self.cos_acc.path) self.assertEqual(self.object.gl.transactions[15].cr_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[16].amount, 800) self.assertEqual(self.object.gl.transactions[16].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[16].dt_account, self.reva_acc.path) self.assertEqual(self.object.gl.transactions[16].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[17].amount, 500) self.assertEqual(self.object.gl.transactions[17].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[17].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[17].cr_account, self.expa_acc.path) self.assertEqual(self.object.gl.transactions[18].amount, 60) self.assertEqual(self.object.gl.transactions[18].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[18].dt_account, gls._acci_gross_prof_.path) self.assertEqual(self.object.gl.transactions[18].cr_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[19].amount, 360) self.assertEqual(self.object.gl.transactions[19].is_closing_cr_account, True) self.assertEqual(self.object.gl.transactions[19].dt_account, gls._acci_inc_sum_.path) self.assertEqual(self.object.gl.transactions[19].cr_account, gls._accb_ret_earnings_acc_.path)
def setUp(self): self.object = Clock("NameA", description="DescriptionA", start_datetime=datetime(2016, 2, 1), timestep_period_duration=TimePeriod.year, timestep_period_count=3)
class TimeBasedModel(NamedObject): """ Represents an time based model class. An instance of this class is by default configured to run only once, thus functioning as a steady state model. The instance's time based parameters must be configured for it to function as a time based model. :param name: The name. :param description: The description. :param start_datetime: The start datetime of the model. :param period_duration: The duration of the model's time period. e.g. month, day etc. :param period_count: The number of periods to execute the model for. """ def __init__(self, name, description=None, start_datetime=datetime.now(), period_duration=TimePeriod.year, period_count=1): self.clock = Clock( "Clock", start_datetime=get_date(start_datetime), timestep_period_duration=period_duration) self.period_count = period_count self.entities = [] super(TimeBasedModel, self).__init__(name, description=description) def _update_childrens_parent_path(self): for e in self.entities: e.set_parent_path(self.name) @property def name(self): return self._name @name.setter def name(self, value): self._name = value self._update_childrens_parent_path() def create_entity(self, name, gl_structure, description=None): """ Create an entity and add it to the model. :param name: The entity name. :param gl_structure: The entity's general ledger structure. :param description: The entity description. :returns: The created entity. """ new_entity = Entity(name, gl_structure, description=description) self.entities.append(new_entity) return new_entity def remove_entity(self, name): """ Remove an entity from the model. :param name: The name of the entity to remove. """ entity_to_remove = None for e in self.entities: if e.name == name: entity_to_remove = e if entity_to_remove is not None: self.entities.remove(entity_to_remove) def prepare_to_run(self): """ Prepare the model for execution. """ self.clock.reset() for e in self.entities: e.prepare_to_run(self.clock, self.period_count) def run(self): """ Execute the model. """ self.prepare_to_run() for i in range(0, self.period_count): for e in self.entities: e.run(self.clock) self.clock.tick() def __getitem__(self, key): return [e for e in self.entities if e.name == key][0]
class BasicLoanActivityUnitTester(unittest.TestCase): """ Tester for the auxi.modelling.business.basic.BasicLoanActivity class. """ def setUp(self): self.gl_structure = GeneralLedgerStructure( "GL Structure", description="General Ledger Structure") self.gl_structure["Account Payable"].create_account( "Capital Loan", "0000") self.gl_structure["Expense"].create_account("Interest Expense", "0000") self.gl = GeneralLedger("GL", self.gl_structure, description="General Ledger") self.clock = Clock("NameA", start_datetime=datetime(2016, 2, 1)) self.object = BasicLoanActivity( "Capital Loan", bank_account="Bank/Default", loan_account="Account Payable/Capital Loan", interest_account="Expense/Interest Expense", amount=180000, interest_rate=0.15, start=datetime(2016, 2, 1), duration=36, interval=1, description="Loan for Capital") def test_constructor(self): self.assertEqual(self.object.name, "Capital Loan") self.assertEqual(self.object.bank_account, "Bank/Default") self.assertEqual(self.object.loan_account, "Account Payable/Capital Loan") self.assertEqual(self.object.interest_account, "Expense/Interest Expense") self.assertEqual(self.object.amount, 180000) self.assertEqual(self.object.interest_rate, 0.15) self.assertEqual(self.object.start_datetime, datetime(2016, 2, 1)) self.assertEqual(self.object.end_datetime, datetime(2019, 3, 1)) self.assertEqual(self.object.duration, 36) self.assertEqual(self.object.interval, 1) self.assertEqual(self.object.description, "Loan for Capital") def test__meet_execution_criteria(self): """ Test that the activity only meets the execution criteria when it's amount is greater than 0 and its duration is greater than 0. """ self.object.prepare_to_run(self.clock, 13) self.assertEqual(self.object._meet_execution_criteria(5), True) self.object.amount = 0 self.assertEqual(self.object._meet_execution_criteria(5), False) self.object.amount = 180000 self.object.duration = 0 self.assertEqual(self.object._meet_execution_criteria(5), False) def test_run_first_month(self): """ Test that the activity run method creates a transaction with an amount of 180000 on the first month. No other transactions """ self.object.prepare_to_run(self.clock, 1) self.object.run(self.clock, self.gl) self.assertEqual(len(self.gl.transactions), 1) self.assertEqual(self.gl.transactions[0].amount, 180000) def test_run_third_month(self): """ Test that the activity run method accrued the interest correctly. """ self.clock.tick() self.object.prepare_to_run(self.clock, 61) self.clock.tick() self.object.run(self.clock, self.gl) self.clock.tick() self.object.run(self.clock, self.gl) self.clock.tick() self.object.run(self.clock, self.gl) self.assertEqual(len(self.gl.transactions), 5) # Test the interest rate for the first month # loan amount = 180000 # First month's interest should be (180000 * 0.15) / 12 = 2250 self.assertEqual(self.gl.transactions[1].amount, 2250) # Principle payment is 6239.76 (see below) # The interest payed the previous month is 2250 # Making the total amount payed to the loan 6239.76 - 2250 = 3,989.76 # New amount to calculate interest from: 180000 - 3,989.76 = 176,010.24 # 2nd month's interest should be 176,010.24 * 0.15) / 12 = 2,200.13 self.assertEqual("%.2f" % self.gl.transactions[3].amount, "2200.13") # Test the monthly principle payment # interest rate = 0.15: per month 0.0125. # loan amount = 180000 # duration of the loan = 36 # payment = (180000*0.0125) / (1-(1/pow((1+0.0125), 36))) = 6239.76 self.assertEqual("%.2f" % self.gl.transactions[2].amount, "6239.76") self.assertEqual("%.2f" % self.gl.transactions[4].amount, "6239.76") def test_run_last_month(self): """ Test that the activity run method creates settled the loan on the loans' last month and that the transactions """ self.clock.tick() self.object.prepare_to_run(self.clock, 61) for i in range(0, 60): self.object.run(self.clock, self.gl) self.clock.tick() # Test the number of transaction that was created during the # loan's lifetime. # 2 transactions per months should be created + the initial loan amount # transaction. 36*2 + 1 = 73 last_tx_ix = len(self.gl.transactions) self.assertEqual(len(self.gl.transactions), 73) # The transactions should have run only run for 36 months # (the duration of the loan) r = relativedelta.relativedelta( self.gl.transactions[last_tx_ix - 1].tx_date, self.gl.transactions[0].tx_date) self.assertEqual(r.years * 12 + r.months, 36) def test_get_referenced_accounts(self): """ Test that the activity run method get_referenced_accounts accounts matches the debit and credit accounts self.object was initialised with. """ result = self.object.get_referenced_accounts() self.assertEqual(self.object.bank_account, result[0]) self.assertEqual(self.object.loan_account, result[1]) self.assertEqual(self.object.interest_account, result[2])
def test_prepare_to_run(self): clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) self.object.prepare_to_run(clock, 18) self.assertEqual(self.object.start_period_ix, 2) self.assertEqual(self.object.end_period_ix, 14)
def test__meet_execution_criteria(self): clock = Clock("NameA", start_datetime=datetime(2016, 1, 1)) self.object.prepare_to_run(clock, 13) self.assertEqual(self.object._meet_execution_criteria(3), False) self.assertEqual(self.object._meet_execution_criteria(5), True) self.assertEqual(self.object._meet_execution_criteria(40), False)