(ns bank (:use [account] :reload-all)) (defn add-random-account [bank] {:accounts (conj (:accounts bank) (create-random-account)) :overdraft-fund (:overdraft-fund bank)}) ;; assuming this interpretation of the overdraft conditions: (defn overdraft-allowed [bank account transaction] (cond (< (- (balance account) (:amount transaction)) -1000) false (zero? (:overdraft-fund bank)) false :else true)) (defn apply-simple-transaction [bank account transaction] (let [updated-transaction (assoc transaction :balance (+ (balance account) (:amount transaction))) updated-account (assoc account :transaction-history (conj (:transaction-history account) updated-transaction))] (assoc-in bank [:accounts (.indexOf (bank :accounts) account)] updated-account))) (defn apply-overdraft [bank account transaction] (let [overdraft-amount (- (:amount transaction) (balance account)) charge (* overdraft-amount (overdraft-charge (:type account))) updated-transaction (assoc transaction :balance (- (+ overdraft-amount charge))) updated-account (assoc account :transaction-history (conj (:transaction-history account) updated-transaction)) updated-overdraft-fund (- (:overdraft-fund bank) overdraft-amount)] (assoc-in bank [:accounts (.indexOf (bank :accounts) account)] updated-account) (assoc bank :overdraft-fund updated-overdraft-fund))) (def failed-overdraft-charge 10) (defn apply-failed-overdraft [bank account transaction] (let [updated-transaction (assoc transaction :balance (- (balance account) failed-overdraft-charge)) updated-account (assoc account :transaction-history (conj (:transaction-history account) updated-transaction))] (assoc-in bank [:accounts (.indexOf (bank :accounts) account)] updated-account))) ;; current balance of account is defined by the balance field of the last transaction. ;; apply-bonus and apply-interest are not considered transactions themselves. (defn apply-extras [bank account amount] (let [transaction (last (:transaction-history account)) updated-transaction (assoc transaction :balance (+ (:balance transaction) amount)) updated-account (assoc-in account [:transaction-history (.indexOf (account :transaction-history) transaction)] updated-transaction)] (assoc-in bank [:accounts (.indexOf (bank :accounts) account)] updated-account))) (defn apply-interest [bank account] (apply-extras bank account (interest-amount account))) (defn apply-bonus [bank account] (apply-extras bank account (bonus-amount account))) (defn extra-applies? [transaction-number interval] (cond (zero? transaction-number) false (zero? (mod transaction-number interval)) true :else false)) (defn apply-transaction [bank account transaction] (let [account-index (.indexOf (bank :accounts) account) bank (cond (>= (:amount transaction) 0) (apply-simple-transaction bank account transaction) (>= (- (balance account) (:amount transaction)) 0) (apply-simple-transaction bank account transaction) (true? (overdraft-allowed bank account transaction)) (apply-overdraft bank account transaction)) transaction-number (.size (:transaction-history account)) updated-account ((bank :accounts) account-index) bank (if (extra-applies? transaction-number bonus-interval) (apply-bonus bank updated-account) bank) updated-account ((bank :accounts) account-index) bank (if (extra-applies? transaction-number interest-interval) (apply-interest bank updated-account) bank)] bank))