#|

Money Stuff

Storing Floating Point values in an SQL database is *BAD*!:

    CL-DECK-BUILDER2> (with-connection (db)
                        (mito:retrieve-by-sql
                        (sxql:select ((:as 0.005 :real)))))
    ((:REAL 0.004999999888241291d0))

So I'm taking expert's advice and storing money as a fixed point integer with 100 divisions (cents).

Deflate: Mito -> RDBMS

Now with test suite!

|#

(in-package #:cl-deck-builder2.toolkit.money)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defgeneric currency-deflate (obj)
  (:documentation "CURRENCY-DEFLATE takes a NUMBER or a STRING and converts it into a fixed point number.

    ;; One Half Dollar / $0.50 / 50 Cents / These are all the same thing
    (CURRENCY-DEFLATE 1/2)    => 50
    (CURRENCY-DEFLATE 0.50)   => 50
    (CURRENCY-DEFLATE 0.5d0)  => 50
    (CURRENCY-DEFLATE \"1/2\")    => 50
    (CURRENCY-DEFLATE \"0.50\")   => 50
    (CURRENCY-DEFLATE \"0.5d0\")  => 50

    ;; One Dollar / $1.00 /     100 Cents / These are all the same thing
    (CURRENCY-DEFLATE 1)     => 100
    (CURRENCY-DEFLATE 1.00)  => 100
    (CURRENCY-DEFLATE 1.0d0) => 100
    (CURRENCY-DEFLATE \"1\")     => 100
    (CURRENCY-DEFLATE \"1.00\")  => 100
    (CURRENCY-DEFLATE \"1.0d0\") => 100

    ;; Ten Dollars / $10.00 /    1000 Cents / These are all the same thing
    (CURRENCY-DEFLATE 10)     => 1000
    (CURRENCY-DEFLATE 10.00)  => 1000
    (CURRENCY-DEFLATE 10.0d0) => 1000
    (CURRENCY-DEFLATE \"10\")     => 1000
    (CURRENCY-DEFLATE \"10.00\")  => 1000
    (CURRENCY-DEFLATE \"10.0d0\") => 1000")
  (:method ((number number))
    ;; CEILING or FLOOR?
    (ceiling (* 100 number)))
  (:method ((string string))
    (currency-deflate
     (read-from-string
      (if (eq (char string 0) #\$)
          (subseq string 1)
          string)))))

(defgeneric currency-inflate (obj)
  (:documentation "CURRENCY-INFLATE takes a NUMBER and converts it into a STRING representation of the fixed point amount of cents (100 cents per dollar) into \"$DD.CC\" format.")
  (:method ((number number))
    (format nil "~$" (float (/ number 100)))))
