(ns ex.money
"Provides functions to parse bank statement JSON account data and
calculate current balances."
(:require [cheshire.core :as json]
[clojure.string :as str]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn as-currency
"Money amounts are transmitted as \\"$2.44\\".
Parse this and return a numeric type."
[currency-amount]
;; strip off the leading "$"
(-> (subs currency-amount 1)
(bigdec)))
(defn sum-transactions [transactions]
(let [amounts (map :amount transactions)
currencies (map as-currency amounts)]
(reduce + currencies)))
(defn current-balance [accounts]
;; Recursively loop over all accounts,
(loop [balance 0
accounts accounts]
(if (first accounts) ;; test to know when to end looping
(let [[account transactions] (first accounts)]
(recur (+ balance (sum-transactions transactions))
accounts))
balance)))
(defn convert-accounts [accounts-json]
(json/parse-string accounts-json true))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(comment
;; A collection of accounts, each with a list of transactions.
;; Formatted as a JSON string e.g. to mimic an API call response.
(def account-data-json
"{\\"savings\\":
[{\\"day\\":0,\\"amount\\":\\"$1200.20\\"},
{\\"day\\":22,\\"amount\\":\\"$0.03\\"}],
\\"checking\\":
[{\\"day\\":0,\\"amount\\":\\"$120.00\\"},
{\\"day\\":2,\\"amount\\":\\"$5.99\\"},
{\\"day\\":3,\\"amount\\":\\"$20\\"},
{\\"day\\":3,\\"amount\\":\\"$12.33\\"},
{\\"day\\":3,\\"amount\\":\\"-$4.50\\"},
{\\"day\\":5,\\"amount\\":\\"$30\\"}]}")
;; Exercise the code using this test data:
(-> account-data-json
convert-accounts
current-balance)
;; Code never completes...
)