Skip to content

Instantly share code, notes, and snippets.

@renanreismartins
Created February 16, 2023 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renanreismartins/e517def40182900e843b55b7a39ae3c1 to your computer and use it in GitHub Desktop.
Save renanreismartins/e517def40182900e843b55b7a39ae3c1 to your computer and use it in GitHub Desktop.
(ns griffin.spec.journal-entry
(:require [clojure.spec.alpha :as s]))
(s/def ::id uuid?)
(s/def ::account-id uuid?)
(s/def ::type #{:credit :debit})
(s/def ::amount pos-int?)
(s/def ::line-item (s/keys :req-un [::account-id ::amount ::type]))
(s/def ::line-items (s/coll-of ::line-item :min-count 2))
(s/def ::journal-entry (s/keys :req-un [::id ::line-items]))
(def line-item-cred {
:account-id (java.util.UUID/fromString "f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
:amount 100
:type :credit})
(def line-item-deb {
:account-id (java.util.UUID/fromString "f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
:amount 100
:type :debit})
(def unbalanced-entry {
:id (java.util.UUID/fromString "4fe5d828-6444-11e8-8222-720007e40350")
:line-items [line-item-cred, line-item-cred, line-item-deb]})
(def balanced-entry {
:id (java.util.UUID/fromString "4fe5d828-6444-11e8-8222-720007e40350")
:line-items [line-item-cred, line-item-deb]})
;;
;; I'm assuming the following:
;; Each line-item we need to have a 'counter' line-item. Example: credit 100, debit 100.
;; Works only with :type is always credit or debit
;; I'm not correlating the account-id inside the items, but it would not be hard to do so
;; Could increase the test coverage for corner cases (empty collections, etc)
;; Could use a test framework :)
;; Probably this is not idiomatic, has been years since I wrote any Clojure
(defn total-amount [items] (reduce + (map :amount items)))
(defn credits-and-debits [entry] (partition-by :type (:line-items entry)))
(defn is-balanced [entry]
(let [[credits debits] (credits-and-debits entry)]
(and (= (count credits) (count debits))
(= 0 (- (total-amount credits) (total-amount debits))))))
(println "Balanced entry should return true: ")
(println (is-balanced balanced-entry))
(println)
(println "Unbalanced entry should return false: ")
(println (is-balanced unbalanced-entry))
@rmartinsdepaula
Copy link

Does not matter for this solution but better to check:

When partitioning, what is the criteria of ordering of the partitions? For example, the collection (partition) of credits is the first returned. (Maybe based on order of the possible values on :type?)

@renanreismartins
Copy link
Author

;; Each line-item we need to have one or more 'counter' line-items. Example: credit 100, debit 100 or credit 100, debit 50, debit 50

Reviewing I found that for a ledger we must have the same number of counter transactions. So this is a bug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment