{-# LANGUAGE DataKinds #-}
module Haspara.Accounting.Amount where
import qualified Data.Aeson as Aeson
import GHC.Generics (Generic)
import GHC.TypeLits (KnownNat, Nat)
import Haspara.Accounting.Account (AccountKind(..))
import Haspara.Accounting.Side (Side(..), sideByAccountKind)
import Haspara.Internal.Aeson (commonAesonOptions)
import Haspara.Quantity (Quantity, UnsignedQuantity, absQuantity)
import Refined (unrefine)
data Amount (precision :: Nat) = Amount
{ Amount precision -> Side
amountSide :: !Side
, Amount precision -> UnsignedQuantity precision
amountValue :: !(UnsignedQuantity precision)
}
deriving (Amount precision -> Amount precision -> Bool
(Amount precision -> Amount precision -> Bool)
-> (Amount precision -> Amount precision -> Bool)
-> Eq (Amount precision)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
/= :: Amount precision -> Amount precision -> Bool
$c/= :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
== :: Amount precision -> Amount precision -> Bool
$c== :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
Eq, (forall x. Amount precision -> Rep (Amount precision) x)
-> (forall x. Rep (Amount precision) x -> Amount precision)
-> Generic (Amount precision)
forall x. Rep (Amount precision) x -> Amount precision
forall x. Amount precision -> Rep (Amount precision) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (precision :: Nat) x.
Rep (Amount precision) x -> Amount precision
forall (precision :: Nat) x.
Amount precision -> Rep (Amount precision) x
$cto :: forall (precision :: Nat) x.
Rep (Amount precision) x -> Amount precision
$cfrom :: forall (precision :: Nat) x.
Amount precision -> Rep (Amount precision) x
Generic, Eq (Amount precision)
Eq (Amount precision)
-> (Amount precision -> Amount precision -> Ordering)
-> (Amount precision -> Amount precision -> Bool)
-> (Amount precision -> Amount precision -> Bool)
-> (Amount precision -> Amount precision -> Bool)
-> (Amount precision -> Amount precision -> Bool)
-> (Amount precision -> Amount precision -> Amount precision)
-> (Amount precision -> Amount precision -> Amount precision)
-> Ord (Amount precision)
Amount precision -> Amount precision -> Bool
Amount precision -> Amount precision -> Ordering
Amount precision -> Amount precision -> Amount precision
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (precision :: Nat). Eq (Amount precision)
forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
forall (precision :: Nat).
Amount precision -> Amount precision -> Ordering
forall (precision :: Nat).
Amount precision -> Amount precision -> Amount precision
min :: Amount precision -> Amount precision -> Amount precision
$cmin :: forall (precision :: Nat).
Amount precision -> Amount precision -> Amount precision
max :: Amount precision -> Amount precision -> Amount precision
$cmax :: forall (precision :: Nat).
Amount precision -> Amount precision -> Amount precision
>= :: Amount precision -> Amount precision -> Bool
$c>= :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
> :: Amount precision -> Amount precision -> Bool
$c> :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
<= :: Amount precision -> Amount precision -> Bool
$c<= :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
< :: Amount precision -> Amount precision -> Bool
$c< :: forall (precision :: Nat).
Amount precision -> Amount precision -> Bool
compare :: Amount precision -> Amount precision -> Ordering
$ccompare :: forall (precision :: Nat).
Amount precision -> Amount precision -> Ordering
$cp1Ord :: forall (precision :: Nat). Eq (Amount precision)
Ord, Int -> Amount precision -> ShowS
[Amount precision] -> ShowS
Amount precision -> String
(Int -> Amount precision -> ShowS)
-> (Amount precision -> String)
-> ([Amount precision] -> ShowS)
-> Show (Amount precision)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (precision :: Nat).
KnownNat precision =>
Int -> Amount precision -> ShowS
forall (precision :: Nat).
KnownNat precision =>
[Amount precision] -> ShowS
forall (precision :: Nat).
KnownNat precision =>
Amount precision -> String
showList :: [Amount precision] -> ShowS
$cshowList :: forall (precision :: Nat).
KnownNat precision =>
[Amount precision] -> ShowS
show :: Amount precision -> String
$cshow :: forall (precision :: Nat).
KnownNat precision =>
Amount precision -> String
showsPrec :: Int -> Amount precision -> ShowS
$cshowsPrec :: forall (precision :: Nat).
KnownNat precision =>
Int -> Amount precision -> ShowS
Show)
instance KnownNat precision => Aeson.FromJSON (Amount precision) where
parseJSON :: Value -> Parser (Amount precision)
parseJSON = Options -> Value -> Parser (Amount precision)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON (Options -> Value -> Parser (Amount precision))
-> Options -> Value -> Parser (Amount precision)
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"amount"
instance KnownNat precision => Aeson.ToJSON (Amount precision) where
toJSON :: Amount precision -> Value
toJSON = Options -> Amount precision -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON (Options -> Amount precision -> Value)
-> Options -> Amount precision -> Value
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"amount"
amountDebit :: KnownNat precision => Amount precision -> Maybe (UnsignedQuantity precision)
amountDebit :: Amount precision -> Maybe (UnsignedQuantity precision)
amountDebit (Amount Side
SideDebit UnsignedQuantity precision
value) = UnsignedQuantity precision -> Maybe (UnsignedQuantity precision)
forall a. a -> Maybe a
Just UnsignedQuantity precision
value
amountDebit Amount precision
_ = Maybe (UnsignedQuantity precision)
forall a. Maybe a
Nothing
amountCredit :: KnownNat precision => Amount precision -> Maybe (UnsignedQuantity precision)
amountCredit :: Amount precision -> Maybe (UnsignedQuantity precision)
amountCredit (Amount Side
SideCredit UnsignedQuantity precision
value) = UnsignedQuantity precision -> Maybe (UnsignedQuantity precision)
forall a. a -> Maybe a
Just UnsignedQuantity precision
value
amountCredit Amount precision
_ = Maybe (UnsignedQuantity precision)
forall a. Maybe a
Nothing
amountFromValue
:: KnownNat precision
=> AccountKind
-> Quantity precision
-> Amount precision
amountFromValue :: AccountKind -> Quantity precision -> Amount precision
amountFromValue AccountKind
k Quantity precision
q = case AccountKind
k of
AccountKind
AccountKindAsset -> Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount { amountSide :: Side
amountSide = if Quantity precision
q Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity precision
0 then Side
SideDebit else Side
SideCredit, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q }
AccountKind
AccountKindLiability -> Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount { amountSide :: Side
amountSide = if Quantity precision
q Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity precision
0 then Side
SideDebit else Side
SideCredit, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q }
AccountKind
AccountKindEquity -> Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount { amountSide :: Side
amountSide = if Quantity precision
q Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity precision
0 then Side
SideCredit else Side
SideDebit, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q }
AccountKind
AccountKindRevenue -> Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount { amountSide :: Side
amountSide = if Quantity precision
q Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity precision
0 then Side
SideCredit else Side
SideDebit, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q }
AccountKind
AccountKindExpense -> Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount { amountSide :: Side
amountSide = if Quantity precision
q Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity precision
0 then Side
SideCredit else Side
SideDebit, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q }
valueFromAmount
:: KnownNat precision
=> AccountKind
-> Amount precision
-> Quantity precision
valueFromAmount :: AccountKind -> Amount precision -> Quantity precision
valueFromAmount AccountKind
k (Amount Side
s UnsignedQuantity precision
v) = case (AccountKind
k, Side
s, UnsignedQuantity precision -> Quantity precision
forall p x. Refined p x -> x
unrefine UnsignedQuantity precision
v) of
(AccountKind
AccountKindAsset, Side
SideDebit, Quantity precision
q) -> Quantity precision
q
(AccountKind
AccountKindAsset, Side
SideCredit, Quantity precision
q) -> -Quantity precision
q
(AccountKind
AccountKindLiability, Side
SideDebit, Quantity precision
q) -> Quantity precision
q
(AccountKind
AccountKindLiability, Side
SideCredit, Quantity precision
q) -> -Quantity precision
q
(AccountKind
AccountKindEquity, Side
SideDebit, Quantity precision
q) -> -Quantity precision
q
(AccountKind
AccountKindEquity, Side
SideCredit, Quantity precision
q) -> Quantity precision
q
(AccountKind
AccountKindRevenue, Side
SideDebit, Quantity precision
q) -> -Quantity precision
q
(AccountKind
AccountKindRevenue, Side
SideCredit, Quantity precision
q) -> Quantity precision
q
(AccountKind
AccountKindExpense, Side
SideDebit, Quantity precision
q) -> -Quantity precision
q
(AccountKind
AccountKindExpense, Side
SideCredit, Quantity precision
q) -> Quantity precision
q
amountFromQuantity
:: KnownNat precision
=> AccountKind
-> Quantity precision
-> Amount precision
amountFromQuantity :: AccountKind -> Quantity precision -> Amount precision
amountFromQuantity AccountKind
k Quantity precision
q =
Amount :: forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount
{ amountSide :: Side
amountSide = AccountKind -> Quantity precision -> Side
forall (precision :: Nat).
KnownNat precision =>
AccountKind -> Quantity precision -> Side
sideByAccountKind AccountKind
k Quantity precision
q
, amountValue :: UnsignedQuantity precision
amountValue = Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
q
}
quantityFromAmount
:: KnownNat precision
=> AccountKind
-> Amount precision
-> Quantity precision
quantityFromAmount :: AccountKind -> Amount precision -> Quantity precision
quantityFromAmount AccountKind
k (Amount Side
side UnsignedQuantity precision
absValue) =
let
value :: Quantity precision
value = UnsignedQuantity precision -> Quantity precision
forall p x. Refined p x -> x
unrefine UnsignedQuantity precision
absValue
in
case (AccountKind
k, Side
side) of
(AccountKind
AccountKindAsset, Side
SideDebit) -> Quantity precision
value
(AccountKind
AccountKindAsset, Side
SideCredit) -> -Quantity precision
value
(AccountKind
AccountKindLiability, Side
SideDebit) -> -Quantity precision
value
(AccountKind
AccountKindLiability, Side
SideCredit) -> Quantity precision
value
(AccountKind
AccountKindEquity, Side
SideDebit) -> -Quantity precision
value
(AccountKind
AccountKindEquity, Side
SideCredit) -> Quantity precision
value
(AccountKind
AccountKindRevenue, Side
SideDebit) -> -Quantity precision
value
(AccountKind
AccountKindRevenue, Side
SideCredit) -> Quantity precision
value
(AccountKind
AccountKindExpense, Side
SideDebit) -> Quantity precision
value
(AccountKind
AccountKindExpense, Side
SideCredit) -> -Quantity precision
value