def test_highest_interest_first(current_date):
    """
  If there are 2+ loans, the loan with highest interest 
  receives the payment.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    init_loans = []
    init_loan_balance = Money(100.00)
    bill_info = BillInfo(
        day=10, amount=Money(1.00))  # days after dates covered in this test
    loan_info = LoanInfo(init_loan_balance, interest=1.00)
    init_loans.append(Loan(loan_info, bill_info))

    loan_info = LoanInfo(init_loan_balance, interest=loan_info.interest + 1.00)
    init_loans.append(Loan(loan_info, bill_info))

    loans = copy.deepcopy(init_loans)

    payer = HighestInterestFirstPayer(loans, account,
                                      next_day(current_date.date),
                                      Money(100.00))

    current_date.register(payer)
    current_date.increment_day()

    # second loan, the higher interest one, should have a different balance
    assert init_loans[1].balance != loans[1].balance

    # but lower interest one should be unchanged in this test
    assert init_loans[0].balance == loans[0].balance
def test_highest_interest_accruing(current_date):
    """
  If there are multiple loans, it's the highest interest loans who
  are accruing that are addressed first.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    init_loans = []
    init_loan_balance = Money(100.00)
    bill_info = BillInfo(
        day=10, amount=Money(1.00))  # days after dates covered in this test
    accrue_start_date = current_date.date + datetime.timedelta(days=100)
    loan_info = LoanInfo(init_loan_balance, 1.00, accrue_start_date)
    init_loans.append(Loan(loan_info, bill_info))

    loan_info = LoanInfo(init_loan_balance, 1.00)
    init_loans.append(Loan(loan_info, bill_info))

    loans = copy.deepcopy(init_loans)

    payer = HighestInterestFirstPayer(loans, account,
                                      next_day(current_date.date),
                                      Money(50.00))

    current_date.register(payer)
    current_date.increment_day()

    # first loan, nonaccruing, should not have a changed balance
    assert loans[0].balance == init_loans[0].balance

    # second loan should have a decreased balance
    assert loans[1].balance + Money(50.00) == init_loans[1].balance
def test_account_loan_balance_adjusts(current_date):
    """
  The total_owed on a loan and change in account balance should 
  be changed in a specific way.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    init_loan_balance = Money(100.00)
    bill_info = BillInfo(
        day=10, amount=Money(1.00))  # days after dates covered in this test
    loan_info = LoanInfo(init_loan_balance, interest=1.00)

    loans = [Loan(loan_info, bill_info)]

    # pay day after current_date (5)
    pay_amount = Money(10.00)
    payer = HighestInterestFirstPayer(loans, account,
                                      next_day(current_date.date), pay_amount)
    init_total_owed = payer.total_owed

    current_date.register(payer)
    current_date.increment_day()

    assert account.balance + pay_amount == init_account_balance
    assert loans[0].total_owed + pay_amount == init_loan_balance
def test_dont_overpay_small_balance_loan(current_date):
    """
  If a loan has only a small balance left, and the
  HighestInterestFirstPayer's amount is greater than that balance
  do not overpay.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    init_loan_balance = Money(100.00)
    bill_info = BillInfo(
        day=10, amount=Money(1.00))  # days after dates covered in this test
    loan_info = LoanInfo(init_loan_balance, interest=1.00)

    loans = [Loan(loan_info, bill_info)]

    # pay day after current_date (5)
    pay_amount = Money(200.00)
    payer = HighestInterestFirstPayer(loans, account,
                                      next_day(current_date.date), pay_amount)
    init_total_owed = payer.total_owed

    current_date.register(payer)
    current_date.increment_day()

    assert account.balance + init_loan_balance == init_account_balance
    assert loans[0].total_owed == Money(0.00)
Exemplo n.º 5
0
def test_order_observers_regiester():
    """
  The order in which two observers are registered should not affect
  the update cycle.
  """
    start = datetime.date(2020, 7, 4)
    date = DateSubject(start)
    end = date.date + datetime.timedelta(days=10)
    bill_info = BillInfo(day=end.day, amount=Money(10.00))
    loan_info = LoanInfo(Money(1000.00), interest=1.00)

    loan = Loan(loan_info, bill_info)
    loan_copy = copy.deepcopy(loan)

    account = Account(Money(10000.00))  # a reserve of money

    date.register(MinPaymentPayer(loan, account))
    date.register(InterestAccruer(loan))

    date.register(InterestAccruer(loan_copy))
    date.register(MinPaymentPayer(loan_copy, account))

    for d in date_range(start, end):
        date.increment_day()

    # \todo These are off by a penny. Is that acceptable?
    assert almost_equal(loan.balance, loan_copy.balance, 0.01)
    assert almost_equal(loan.total_owed, loan_copy.total_owed, 0.01)
Exemplo n.º 6
0
    def test_create_from_string(self):
        """
    For user's convenience we wish to be able to construct a Money instance
    from a string.
    """
        result = Money.from_string("10.00")
        self.assertEqual(result.amount, Decimal("10.00"))

        result = Money.from_string("-15.34")
        self.assertEqual(result.amount, Decimal("-15.34"))
Exemplo n.º 7
0
    def test_create_from_float(self):
        """
    For user's convenience we expect to be able to construct a Money instance
    from a float or int.
    """
        result = Money(10)
        self.assertEqual(result.amount, 10)

        result = Money(-10)
        self.assertEqual(result.amount, -10)

        result = Money(1.23)
        self.assertEqual(result.amount, 1.23)
Exemplo n.º 8
0
def test_payment_reduces_balance(current_date, min_payment):
    """
  When bill day is hit, loan total_owed reduces to zero
  when minimum payment exceed amount owed on loan.
  """
    initial_balance = Money(100.00)
    loan = create_loan(initial_balance, min_payment)

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance == initial_amount - initial_balance
    assert loan.total_owed == Money(0.00)
Exemplo n.º 9
0
def test_in_progress(current_date):
    """
  If min payments are in progress account balance should change, and
  loan balance should change.
  """
    initial_balance = Money(100.00)
    loan = create_loan(initial_balance, Money(10.00))

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance != initial_amount
    assert loan.total_owed != initial_balance
Exemplo n.º 10
0
def test_payment_reduces_balance(current_date, min_payment):
    """
  When bill day is hit, loan total_owed reduces 
  by the minimum payment amount. Same with account balance.
  """
    initial_balance = Money(100.00)
    loan = create_loan(initial_balance, min_payment)

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance == initial_amount - min_payment
    assert loan.total_owed == initial_balance - min_payment
Exemplo n.º 11
0
def test_not_in_progress(current_date):
    """
  If min payments are not in progress hitting bill date should
  not change account balance or total owed on loan.
  """
    initial_balance = Money(100.00)
    bill_start_date = current_date.date + datetime.timedelta(days=100)
    loan = create_loan(initial_balance, Money(10.00), bill_start_date)

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance == initial_amount
    assert loan.total_owed == initial_balance
Exemplo n.º 12
0
def test_daily_accrued(zero_accured_loan, num_days):
    """
  If you have a 1% APR and accrue the daily interest rate 365 times 
  on a $100 balance loan, the accured interest should be $1.
  """
    date = datetime.date(2011, 1, 1)
    for i in range(num_days):
        zero_accured_loan.accrue_daily(date.timetuple().tm_year)
    assert almost_equal(zero_accured_loan.total_owed,
                        Money(100.00 + num_days / 365))
Exemplo n.º 13
0
def test_loan_accrues_multiple_days(current_date):
  loan = create_loan()
  initial_principal = loan.balance
  accruer = InterestAccruer(loan)
  current_date.register(accruer)

  for i in range(10):
    current_date.increment_day()

  expected_interest = 10 * 1.00 * Money(10000.00) / 366. / 100 

  assert almost_equal(loan.total_owed, initial_principal + expected_interest)
Exemplo n.º 14
0
def test_nonzero_balance_loan(current_date):
    """
  If there is a nonzero balance loan total owed of highinterestpayer
  should change, and account amount should change.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    bill_info = BillInfo(day=10, amount=Money(1.00))
    loan_info = LoanInfo(Money(100.00), interest=1.00)

    loans = [Loan(loan_info, bill_info)]

    payer = HighestInterestFirstPayer(loans, account, 8, Money(10.00))
    init_total_owed = payer.total_owed

    current_date.register(payer)
    for i in range(31):
        current_date.increment_day()

    assert init_account_balance != account.balance
    assert init_total_owed != payer.total_owed
Exemplo n.º 15
0
def test_multiple_loans_highest_interest_first(current_date):
    """
  If there are 2+ loans, where payer's amount covers at least one of the
  loan's remaining balance, and then some, the second highest interest
  loan is the loan whose balance gets paid down.
  """
    init_account_balance = Money(10000.00)
    account = Account(init_account_balance)

    init_loans = []
    init_loan_balance = Money(100.00)
    bill_info = BillInfo(
        day=10, amount=Money(1.00))  # days after dates covered in this test
    loan_info = LoanInfo(init_loan_balance, interest=1.00)
    init_loans.append(Loan(loan_info, bill_info))

    loan_info = LoanInfo(init_loan_balance, interest=loan_info.interest + 1.00)
    init_loans.append(Loan(loan_info, bill_info))

    loan_info = LoanInfo(init_loan_balance, interest=loan_info.interest - 0.50)
    init_loans.append(Loan(loan_info, bill_info))

    loans = copy.deepcopy(init_loans)

    payer = HighestInterestFirstPayer(loans, account,
                                      next_day(current_date.date),
                                      init_loan_balance + Money(50.00))

    current_date.register(payer)
    current_date.increment_day()

    # first loan in this test should remain unchanged.
    assert loans[0].balance == init_loans[0].balance

    # Second loan should have zero money left
    assert loans[1].balance == Money(0.00)

    # Third loan should have a reduced balance
    assert loans[2].balance == init_loans[2].balance - Money(50.00)
Exemplo n.º 16
0
 def test_neg(self):
     self.assertAlmostEqual(-Money(3.67), Money(-3.67))
Exemplo n.º 17
0
 def test_abs(self):
     self.assertAlmostEqual(Money(1.23), abs(Money(-1.23)))
Exemplo n.º 18
0
def zero_accured_loan():
    """Return a loan with zero accrued interest with 1% interest rate (APR)"""
    bill_info = BillInfo(day=1, amount=Money())
    loan_info = LoanInfo(Money(100.00), interest=1.00)
    return Loan(loan_info, bill_info)
Exemplo n.º 19
0
 def test_eq(self):
     a = Money(1.45)
     b = Money(1.45)
     self.assertEqual(a, b)
Exemplo n.º 20
0
 def test_add(self):
     a = Money(1.30)
     b = Money(2.60)
     self.assertAlmostEqual(a + b, Money(3.90))
Exemplo n.º 21
0
 def test_mul(self):
     a = Money(2.20)
     b = 4 * a
     self.assertAlmostEqual(b, Money(8.80))
     c = 0.1 * a
     self.assertAlmostEqual(c, Money(0.22))
Exemplo n.º 22
0
    initial_balance = Money(100.00)
    loan = create_loan(initial_balance, Money(10.00))

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance != initial_amount
    assert loan.total_owed != initial_balance


@pytest.mark.parametrize(
    "min_payment",
    [Money(1.00), Money(5.34), Money(25.00)])
def test_payment_reduces_balance(current_date, min_payment):
    """
  When bill day is hit, loan total_owed reduces 
  by the minimum payment amount. Same with account balance.
  """
    initial_balance = Money(100.00)
    loan = create_loan(initial_balance, min_payment)

    initial_amount = Money(1000.00)
    account = Account(initial_amount)  # a reserve of money
    payer = MinPaymentPayer(loan, account)

    current_date.register(payer)
    current_date.increment_day()
    assert account.balance == initial_amount - min_payment
Exemplo n.º 23
0
 def test_bool_false(self):
     self.assertFalse(Money(0))
Exemplo n.º 24
0
 def test_bool_true(self):
     self.assertTrue(Money(1))
Exemplo n.º 25
0
 def test_sub(self):
     a = Money(3.45)
     b = Money(4.60)
     self.assertAlmostEqual(a - b, Money(-1.15))
Exemplo n.º 26
0
 def test_lt(self):
     one = Money(1)
     two = Money(2)
     self.assertTrue(one < two)
Exemplo n.º 27
0
def create_loan(accrue_start_date=None):
  # create loan where minimum payment is the day after ptest fixture's date.
  bill_info = BillInfo(day=20, amount=Money(1.00)) 
  loan_info = LoanInfo(Money(10000.00), interest=1.00, start_date=accrue_start_date)

  return Loan(loan_info, bill_info)  
Exemplo n.º 28
0
 def test_gt(self):
     one = Money(1)
     two = Money(2)
     self.assertTrue(two > one)
Exemplo n.º 29
0
from finance.finance.billinfo import BillInfo
from finance.finance.loaninfo import LoanInfo
from finance.finance.money import Money, almost_equal
from finance.finance.loan import Loan


@pytest.fixture
def zero_accured_loan():
    """Return a loan with zero accrued interest with 1% interest rate (APR)"""
    bill_info = BillInfo(day=1, amount=Money())
    loan_info = LoanInfo(Money(100.00), interest=1.00)
    return Loan(loan_info, bill_info)


@pytest.mark.parametrize("amount, expected", [(Money(1.00), Money(99.00)),
                                              (Money(5.00), Money(95.00)),
                                              (Money(67), Money(33))])
def test_make_payment(zero_accured_loan, amount, expected):
    """If you apply $1 to a loan, its balance should descrease by $1"""
    zero_accured_loan.make_payment(amount)
    assert zero_accured_loan.balance == expected


@pytest.mark.parametrize("num_days", [randint(0, 1000) for i in range(10)])
def test_daily_accrued(zero_accured_loan, num_days):
    """
  If you have a 1% APR and accrue the daily interest rate 365 times 
  on a $100 balance loan, the accured interest should be $1.
  """
    date = datetime.date(2011, 1, 1)
Exemplo n.º 30
0
 def test_div(self):
     a = Money(3.33)
     b = a / 3
     self.assertAlmostEqual(b, Money(1.11))