diff --git a/lib/account.rb b/lib/account.rb index e69de29b..107c963f 100644 --- a/lib/account.rb +++ b/lib/account.rb @@ -0,0 +1,94 @@ +require 'csv' + +module Bank + + class Account + + def self.all(file) + + all_accounts = [] + + CSV.open(file).each do | line | + + id = line[0].to_i + balance = line[1].to_i + date_opened = line[2] + + account = Account.new(id, balance, date_opened) + + all_accounts << account + end + + all_accounts + end + + def self.find(file, id) + + all_accounts = Bank::Account.all(file) + + all_accounts.each do | account | + + if account.id == id + + return account + + end + + end + + raise ArgumentError.new "Account #{id} does not exist." + + end + + def self.find_with_index(file, index) + + all_accounts = Bank::Account.all(file) + + all_accounts.fetch(index) + + end + + + attr_accessor :id, :balance, :date_opened + + def initialize(id, balance, date_opened = nil) + + raise ArgumentError.new "Can't create an account with a negative balance." unless balance >= 0 + + @id = id + @balance = balance + @date_opened = date_opened + + end + + def withdraw(withdrawal_amount) + + raise ArgumentError.new "Please enter a withdrawal amount greater than 0." unless withdrawal_amount > 0 + + if @balance >= withdrawal_amount + @balance -= withdrawal_amount + + else + puts "You haven't sufficient funds for withdrawal." + @balance + + end + + end + + def deposit(deposit_amount) + + raise ArgumentError.new "Please enter a deposit amount greater than 0." unless deposit_amount > 0 + + @balance += deposit_amount + + end + + + end + +end + +find_account = Bank::Account.find("../support/accounts.csv", 1213) +puts find_account +puts find_account.class diff --git a/lib/checking_account.rb b/lib/checking_account.rb new file mode 100644 index 00000000..0c4492ee --- /dev/null +++ b/lib/checking_account.rb @@ -0,0 +1,98 @@ +require 'csv' +require_relative 'account' + +module Bank + + class CheckingAccount < Account + + attr_reader :counter, :check_withdrawal_fee + + def initialize(id, balance, date_opened = nil) + + super + @counter = 0 + @check_withdrawal_fee + + end + + def withdraw(withdrawal_amount) + + raise ArgumentError.new "Please enter a withdrawal amount greater than 0." unless withdrawal_amount > 0 + + withdrawal_fee = 1 + + if @balance >= withdrawal_amount + withdrawal_fee + @balance -= (withdrawal_amount + withdrawal_fee) + + else + puts "You haven't sufficient funds for withdrawal." + @balance + + end + + end + + def withdraw_with_check(withdrawal_amount) + + raise ArgumentError.new "Please enter a withdrawal amount greater than 0." unless withdrawal_amount > 0 + + @counter += 1 + deficit_limit = 10 + + if (1..3) === @counter then @check_withdrawal_fee = 0; end + if (4..10000) === @counter then @check_withdrawal_fee = 2; end + + if @balance - (withdrawal_amount + @check_withdrawal_fee) >= -deficit_limit + @balance -= (withdrawal_amount + @check_withdrawal_fee) + + else + puts "You haven't sufficient funds for withdrawal." + @balance + + end + + end + + def reset_checks + + @counter = 0 + + end + + end + +end + + + +#The user is allowed three free check uses in one month, but any subsequent use adds a $2 transaction fee + +#reset_checks: Resets the number of checks used to zero +# +janice = Bank::CheckingAccount.new(333, 300) + +withdrawal_amount = 3 + +# 2.times do +# +# janice.withdraw_with_check(withdrawal_amount) +# puts janice.counter +# puts janice.balance +# puts janice.check_withdrawal_fee +# +# end +# +# janice.reset_checks +# +# puts janice.reset_checks.class +# +# puts "Reset: #{janice.reset_checks}" +# +# 2.times do +# +# janice.withdraw_with_check(withdrawal_amount) +# puts janice.counter +# puts janice.balance +# puts janice.check_withdrawal_fee +# +# end diff --git a/lib/savings_account.rb b/lib/savings_account.rb new file mode 100644 index 00000000..df40b182 --- /dev/null +++ b/lib/savings_account.rb @@ -0,0 +1,59 @@ +require 'csv' +require_relative 'account' + +module Bank + + class SavingsAccount < Account + + def initialize(id, balance) + + raise ArgumentError.new "Starting balance must be $10 or more." until balance >= 10 + super + + + end + + def withdraw(withdrawal_amount) + + raise ArgumentError.new "Please enter a withdrawal amount greater than 0." unless withdrawal_amount > 0 + + fee = 2 + + if @balance - (withdrawal_amount + fee) >= 12 + @balance -= (withdrawal_amount + fee) + + else + puts "You haven't sufficient funds for withdrawal." + return @balance + + end + + end + + def add_interest(rate) + + raise ArgumentError.new "Please enter an interest rate greater than 0.00." unless rate > 0.00 + + start_balance = @balance + @balance *= 1 + (rate/100) + interest_earned = start_balance * (rate/100) + + end + + + end + +end + + +#It should include the following new method: + +#add_interest(rate): Calculate the interest on the balance and add the interest to the balance. Return the interest that was calculated and added to the balance (not the updated balance). +#Input rate is assumed to be a percentage (i.e. 0.25). +#The formula for calculating interest is balance * rate/100 +#Example: If the interest rate is 0.25 and the balance is $10,000, then the interest that is returned is $25 and the new balance becomes $10,025. + +# janice = Bank::SavingsAccount.new(333, 10) +# +# puts janice.add_interest(0.25) +# puts janice.balance diff --git a/specs/account_spec.rb b/specs/account_spec.rb index 6c399139..e726d1be 100644 --- a/specs/account_spec.rb +++ b/specs/account_spec.rb @@ -3,6 +3,8 @@ require 'minitest/skip_dsl' require_relative '../lib/account' +Minitest::Reporters.use! + describe "Wave 1" do describe "Account#initialize" do it "Takes an ID and an initial balance" do @@ -137,35 +139,85 @@ end # TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "Wave 2" do - describe "Account.all" do - it "Returns an array of all accounts" do - # TODO: Your test code here! - # Useful checks might include: - # - Account.all returns an array - # - Everything in the array is an Account - # - The number of accounts is correct - # - The ID and balance of the first and last - # accounts match what's in the CSV file - # Feel free to split this into multiple tests if needed - end - end +describe "Wave 2" do - describe "Account.find" do - it "Returns an account that exists" do - # TODO: Your test code here! - end + before do - it "Can find the first account from the CSV" do - # TODO: Your test code here! - end + @all_accounts = Bank::Account.all("../support/accounts.csv") - it "Can find the last account from the CSV" do - # TODO: Your test code here! - end + end + + describe "Account.all" do + + it "Returns an array of all accounts" do + + @all_accounts.must_be_kind_of Array + + end + + it "The number of accounts is correct" do + + @all_accounts.length.must_equal 12 + + end + + + it "Everything in the array is an Account" do + + @all_accounts.each do | account | + + account.must_be_kind_of Bank::Account + + end + + end + + + it "The ID and balance of the first and last accounts match what's in the CSV file" do + + @all_accounts[0].id.must_equal 1212 + @all_accounts[-1].id.must_equal 15156 + @all_accounts[0].balance.must_equal 1235667 + @all_accounts[-1].balance.must_equal 4356772 + + end + + end + + describe "Account.find" do + + it "Returns an account that exists" do + + find_account = Bank::Account.find("../support/accounts.csv", 1213) + find_account.must_be_kind_of Bank::Account + find_account.id.must_equal 1213 + + end + + it "Can find the first account from the CSV" do + + find_account = Bank::Account.find_with_index("../support/accounts.csv", 0) + find_account.must_be_kind_of Bank::Account + find_account.id.must_equal 1212 + + end + + it "Can find the last account from the CSV" do + + find_account = Bank::Account.find_with_index("../support/accounts.csv", -1) + find_account.must_be_kind_of Bank::Account + find_account.id.must_equal 15156 + + end + + it "Raises an error for an account that doesn't exist" do + + proc {find_account = Bank::Account.find("../support/accounts.csv", 3333)}.must_raise ArgumentError + + proc {find_account = Bank::Account.find_with_index("../support/accounts.csv", 13)}.must_raise IndexError + + end + + end - it "Raises an error for an account that doesn't exist" do - # TODO: Your test code here! - end - end end diff --git a/specs/checking_account_spec.rb b/specs/checking_account_spec.rb index 7f95339e..f8a7817e 100644 --- a/specs/checking_account_spec.rb +++ b/specs/checking_account_spec.rb @@ -1,80 +1,215 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require_relative '../lib/checking_account' -# TODO: uncomment the next line once you start wave 3 and add lib/checking_account.rb -# require_relative '../lib/checking_account' - -# Because a CheckingAccount is a kind -# of Account, and we've already tested a bunch of functionality -# on Account, we effectively get all that testing for free! -# Here we'll only test things that are different. - -# TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "CheckingAccount" do - describe "#initialize" do - # Check that a CheckingAccount is in fact a kind of account - it "Is a kind of Account" do - account = Bank::CheckingAccount.new(12345, 100.0) - account.must_be_kind_of Bank::Account - end - end +Minitest::Reporters.use! - describe "#withdraw" do - it "Applies a $1 fee each time" do - # TODO: Your test code here! - end +describe "CheckingAccount" do - it "Doesn't modify the balance if the fee would put it negative" do - # TODO: Your test code here! - end - end + describe "#initialize" do - describe "#withdraw_using_check" do - it "Reduces the balance" do - # TODO: Your test code here! - end + it "Is a kind of Account" do - it "Returns the modified balance" do - # TODO: Your test code here! - end + account = Bank::CheckingAccount.new(12345, 100.0) + account.must_be_kind_of Bank::Account - it "Allows the balance to go down to -$10" do - # TODO: Your test code here! - end + end + end - it "Outputs a warning if the account would go below -$10" do - # TODO: Your test code here! - end + describe "#withdraw" do - it "Doesn't modify the balance if the account would go below -$10" do - # TODO: Your test code here! - end + it "Applies a $1 fee each time" do - it "Requires a positive withdrawal amount" do - # TODO: Your test code here! - end + start_balance = 300 + withdrawal_amount = 298 + withdrawal_fee = 1 + account = Bank::CheckingAccount.new(12345, start_balance) - it "Allows 3 free uses" do - # TODO: Your test code here! - end + account.withdraw(withdrawal_amount).must_equal start_balance - (withdrawal_amount +withdrawal_fee) - it "Applies a $2 fee after the third use" do - # TODO: Your test code here! - end - end + end + + it "Doesn't modify the balance if the fee would put it negative" do + + start_balance = 300 + withdrawal_amount = 300 + withdrawal_fee = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + account.withdraw(withdrawal_amount) + + account.withdraw(withdrawal_amount).must_equal start_balance + + end + + end + + describe "#withdraw_with_check" do + + it "Reduces the balance" do + + start_balance = 300 + withdrawal_amount = 100 + account = Bank::CheckingAccount.new(12345, start_balance) + account.withdraw_with_check(withdrawal_amount) + + account.balance.must_equal start_balance - withdrawal_amount + + end + + it "Returns the modified balance" do + + start_balance = 300 + withdrawal_amount = 100 + account = Bank::CheckingAccount.new(12345, start_balance) + + account.withdraw_with_check(withdrawal_amount).must_equal start_balance - withdrawal_amount + + end + + it "Allows the balance to go down to -$10" do + + start_balance = 300 + withdrawal_amount = 310 + deficit_limit = -10 + account = Bank::CheckingAccount.new(12345, start_balance) + + account.withdraw_with_check(withdrawal_amount).must_equal deficit_limit + + end + + it "Outputs a warning if the account would go below -$10" do + + start_balance = 300 + withdrawal_amount = 311 + account = Bank::CheckingAccount.new(12345, start_balance) + + proc {account.withdraw_with_check(withdrawal_amount)}.must_output /.+/ + + end + + it "Doesn't modify the balance if the account would go below -$10" do + + start_balance = 300 + withdrawal_amount = 311 + account = Bank::CheckingAccount.new(12345, start_balance) + + account.withdraw_with_check(withdrawal_amount).must_equal start_balance + + end + + it "Requires a positive withdrawal amount" do + + start_balance = 300 + withdrawal_amount = -1 + account = Bank::CheckingAccount.new(12345, start_balance) + + proc {account.withdraw_with_check(withdrawal_amount)}.must_raise ArgumentError + + end + + it "Allows 3 free uses" do + + start_balance = 300 + withdrawal_amount = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + + 3.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.check_withdrawal_fee.must_equal 0 - describe "#reset_checks" do - it "Can be called without error" do - # TODO: Your test code here! - end - it "Makes the next three checks free if less than 3 checks had been used" do - # TODO: Your test code here! - end + end - it "Makes the next three checks free if more than 3 checks had been used" do - # TODO: Your test code here! - end + it "Applies a $2 fee after the third use" do + + start_balance = 300 + withdrawal_amount = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + + 4.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.check_withdrawal_fee.must_equal 2 + + + + end end + + describe "#reset_checks" do + + it "Can be called without error" do + + start_balance = 300 + withdrawal_amount = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + + 4.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.reset_checks.must_equal 0 + end + + it "Makes the next three checks free if less than 3 checks had been used" do + + start_balance = 300 + withdrawal_amount = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + + 2.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.reset_checks + + 3.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.check_withdrawal_fee.must_equal 0 + + end + + it "Makes the next three checks free if more than 3 checks had been used" do + + + start_balance = 300 + withdrawal_amount = 1 + account = Bank::CheckingAccount.new(12345, start_balance) + + 5.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.reset_checks + + 3.times do + + account.withdraw_with_check(withdrawal_amount) + + end + + account.check_withdrawal_fee.must_equal 0 + + end + + end + end diff --git a/specs/savings_account_spec.rb b/specs/savings_account_spec.rb index 3f4d1e4a..dc3b5a3d 100644 --- a/specs/savings_account_spec.rb +++ b/specs/savings_account_spec.rb @@ -1,58 +1,117 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require_relative '../lib/savings_account' + +Minitest::Reporters.use! + +describe "SavingsAccount" do + + describe "#initialize" do + + it "Is a kind of Account" do + + account = Bank::SavingsAccount.new(12345, 100.0) + account.must_be_kind_of Bank::Account + + end + + it "Requires an initial balance of at least $10" do + + proc {Bank::SavingsAccount.new(1337, -100.0)}.must_raise ArgumentError + + proc {Bank::SavingsAccount.new(1337, -0.0)}.must_raise ArgumentError + + proc {Bank::SavingsAccount.new(1337, 9.0)}.must_raise ArgumentError + + end + end + + describe "#withdraw" do + + it "Outputs a warning if the balance would go below $10" do + + start_balance = 50.0 + withdrawal_amount = 48.0 + account = Bank::SavingsAccount.new(1337, start_balance) + + proc {account.withdraw(withdrawal_amount)}.must_output /.+/ + + end + + it "Doesn't modify the balance if it would go below $10" do + + start_balance = 50.0 + withdrawal_amount = 41.0 + account = Bank::SavingsAccount.new(1337, start_balance) + + updated_balance = account.withdraw(withdrawal_amount) + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + end + + it "Doesn't modify the balance if it would go below $10" do + + start_balance = 50.0 + withdrawal_amount = 41.0 + account = Bank::SavingsAccount.new(1337, start_balance) + + updated_balance = account.withdraw(withdrawal_amount) + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + end + + + it "Doesn't modify the balance if it would go below $10 due to the $2 fee" do + + start_balance = 11 + withdrawal_amount = 1 + account = Bank::SavingsAccount.new(1337, start_balance) + + updated_balance = account.withdraw(withdrawal_amount) + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + + end + + + end + + describe "#add_interest" do + + it "Returns the interest calculated" do + + start_balance = 10000 + rate = 0.25 + account = Bank::SavingsAccount.new(1337, start_balance) + calculated_interest = start_balance * (rate/100) + + calculated_interest.must_equal account.add_interest(rate) + + end + + it "Updates the balance with calculated interest" do + + start_balance = 12000 + rate = 0.13 + account = Bank::SavingsAccount.new(1337, start_balance) + account.add_interest(rate) + new_balance = start_balance * (1 + (rate/100)) + + new_balance.must_equal account.balance + + end + + it "Requires a positive rate" do + + start_balance = 12000 + rate = -0.1 + account = Bank::SavingsAccount.new(1337, start_balance) + + proc {account.add_interest(rate)}.must_raise ArgumentError + + end + + end -# TODO: uncomment the next line once you start wave 3 and add lib/savings_account.rb -# require_relative '../lib/savings_account' - -# Because a SavingsAccount is a kind -# of Account, and we've already tested a bunch of functionality -# on Account, we effectively get all that testing for free! -# Here we'll only test things that are different. - -# TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "SavingsAccount" do - describe "#initialize" do - it "Is a kind of Account" do - # Check that a SavingsAccount is in fact a kind of account - account = Bank::SavingsAccount.new(12345, 100.0) - account.must_be_kind_of Bank::Account - end - - it "Requires an initial balance of at least $10" do - # TODO: Your test code here! - end - end - - describe "#withdraw" do - it "Applies a $2 fee each time" do - # TODO: Your test code here! - end - - it "Outputs a warning if the balance would go below $10" do - # TODO: Your test code here! - end - - it "Doesn't modify the balance if it would go below $10" do - # TODO: Your test code here! - end - - it "Doesn't modify the balance if the fee would put it below $10" do - # TODO: Your test code here! - end - end - - describe "#add_interest" do - it "Returns the interest calculated" do - # TODO: Your test code here! - end - - it "Updates the balance with calculated interest" do - # TODO: Your test code here! - end - - it "Requires a positive rate" do - # TODO: Your test code here! - end - end end