 (s/def ::per-page validation/positive-integer?)
 (s/def ::select-options (s/keys :req-un [::page ::per-page]))
 
-(defmulti ^:private parse-date-range
-  type)
-
-(defmethod ^:private parse-date-range :default
-  [value]
-  value)
-
-(defmethod ^:private parse-date-range String
-  [value]
-  (let [[year month day] (->> (re-matches #"(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?"
-                                          value)
-                              rest
-                              (map #(when % (Integer. %))))]
-    (cond
-
-      day
-      (t/local-date year month day)
-
-      month
-      [:between
-       (t/first-day-of-the-month year month)
-       (t/last-day-of-the-month year month)]
-
-      :else
-      [:between
-       (t/local-date year 1 1)
-       (t/local-date year 12 31)])))
-
-(defn- ensure-transaction-date-type
-  [criteria]
-  (if-let [transaction-date (:transaction-date criteria)]
-    (assoc criteria :transaction-date (parse-date-range transaction-date))
-    criteria))
-
-(defn- ensure-id-type
-  [criteria]
-  (if-let [id (:id criteria)]
-    (if (string? id)
-      (assoc criteria :id (java.util.UUID/fromString id))
-      criteria)
-    criteria))
-
-(defn- prepare-criteria
-  [criteria]
-  (-> criteria
-      ensure-transaction-date-type
-      ensure-id-type))
-
 (defn search
   "Returns the transactions that belong to the specified entity"
   ([storage-spec criteria]

(defn- after-item-read
  "Makes adjustments to a transaction item in prepartion for return
  from the data store"
  ([item] (after-item-read item nil))
  ([{:keys [quantity negative reconciliation-status] :as item} account]
   (if (map? item)
     (-> item
         (update-in [:action] keyword)
         (assoc :reconciled? (= "completed" reconciliation-status)
                :polarized-quantity (if negative
                                      (* -1 quantity)
                                      quantity)))
     item)))

(defn- item-value-sum
  "Returns the sum of values of the items in the transaction having

  [storage transaction-id]
  (select-lots-transactions-by-transaction-id storage transaction-id))

; TODO move this to a util namespace
(defmulti ^:private parse-date-range
  type)

(defmethod ^:private parse-date-range :default
  [value]
  value)

(defmethod ^:private parse-date-range String
  [value]
  (let [[year month day] (->> (re-matches #"(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?"
                                          value)
                              rest
                              (map #(when % (Integer. %))))]
    (cond

      day
      (t/local-date year month day)

      month
      [:between
       (t/first-day-of-the-month year month)
       (t/last-day-of-the-month year month)]

      :else
      [:between
       (t/local-date year 1 1)
       (t/local-date year 12 31)])))

; TODO Replace these with coercion rules?
(defn- ensure-id-type
  [criteria]
  (if-let [id (:id criteria)]
    (if (string? id)
      (assoc criteria :id (java.util.UUID/fromString id))
      criteria)
    criteria))

(defn- ensure-transaction-date-type
  [criteria]
  (if-let [transaction-date (:transaction-date criteria)]
    (assoc criteria :transaction-date (parse-date-range transaction-date))
    criteria))

(defn- prepare-criteria
  [criteria]
  (-> criteria
      ensure-transaction-date-type
      ensure-id-type))

(defn search-items
  "Returns transaction items matching the specified criteria"
  ([storage-spec criteria]
   (search-items storage-spec criteria {}))
  ([storage-spec criteria options]
   (with-storage [s storage-spec]
     (map after-item-read
          (select-transaction-items s
                                    (prepare-criteria criteria)
                                    options)))))

(defn- append-items
  [{:keys [id transaction-date] :as transaction} storage]
  (when transaction
    (assoc transaction
           :items
           (vec (search-items storage {:transaction-id id
                                       :transaction-date transaction-date}
                              {:sort [[:action :desc] [:quantity :desc]]})))))

(defn- append-lot-items
  [transaction storage]
