{-# LANGUAGE DataKinds #-}
module Haspara.Accounting.Balance where
import qualified Data.Aeson as Aeson
import GHC.Generics (Generic)
import GHC.TypeLits (KnownNat, Nat)
import Haspara.Accounting.Account (AccountKind)
import Haspara.Accounting.Amount (Amount(Amount), quantityFromAmount, valueFromAmount)
import Haspara.Accounting.Side (Side(..), otherSide)
import Haspara.Internal.Aeson (commonAesonOptions)
import Haspara.Quantity (Quantity, absQuantity)
import Refined (unrefine)
data Balance (precision :: Nat) = Balance
{ Balance precision -> Side
balanceSide :: !Side
, Balance precision -> Quantity precision
balanceValue :: !(Quantity precision)
}
deriving (Balance precision -> Balance precision -> Bool
(Balance precision -> Balance precision -> Bool)
-> (Balance precision -> Balance precision -> Bool)
-> Eq (Balance precision)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (precision :: Nat).
Balance precision -> Balance precision -> Bool
/= :: Balance precision -> Balance precision -> Bool
$c/= :: forall (precision :: Nat).
Balance precision -> Balance precision -> Bool
== :: Balance precision -> Balance precision -> Bool
$c== :: forall (precision :: Nat).
Balance precision -> Balance precision -> Bool
Eq, (forall x. Balance precision -> Rep (Balance precision) x)
-> (forall x. Rep (Balance precision) x -> Balance precision)
-> Generic (Balance precision)
forall x. Rep (Balance precision) x -> Balance precision
forall x. Balance precision -> Rep (Balance precision) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (precision :: Nat) x.
Rep (Balance precision) x -> Balance precision
forall (precision :: Nat) x.
Balance precision -> Rep (Balance precision) x
$cto :: forall (precision :: Nat) x.
Rep (Balance precision) x -> Balance precision
$cfrom :: forall (precision :: Nat) x.
Balance precision -> Rep (Balance precision) x
Generic, Int -> Balance precision -> ShowS
[Balance precision] -> ShowS
Balance precision -> String
(Int -> Balance precision -> ShowS)
-> (Balance precision -> String)
-> ([Balance precision] -> ShowS)
-> Show (Balance precision)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (precision :: Nat).
KnownNat precision =>
Int -> Balance precision -> ShowS
forall (precision :: Nat).
KnownNat precision =>
[Balance precision] -> ShowS
forall (precision :: Nat).
KnownNat precision =>
Balance precision -> String
showList :: [Balance precision] -> ShowS
$cshowList :: forall (precision :: Nat).
KnownNat precision =>
[Balance precision] -> ShowS
show :: Balance precision -> String
$cshow :: forall (precision :: Nat).
KnownNat precision =>
Balance precision -> String
showsPrec :: Int -> Balance precision -> ShowS
$cshowsPrec :: forall (precision :: Nat).
KnownNat precision =>
Int -> Balance precision -> ShowS
Show)
instance KnownNat precision => Aeson.FromJSON (Balance precision) where
parseJSON :: Value -> Parser (Balance precision)
parseJSON = Options -> Value -> Parser (Balance precision)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON (Options -> Value -> Parser (Balance precision))
-> Options -> Value -> Parser (Balance precision)
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"balance"
instance KnownNat precision => Aeson.ToJSON (Balance precision) where
toJSON :: Balance precision -> Value
toJSON = Options -> Balance precision -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON (Options -> Balance precision -> Value)
-> Options -> Balance precision -> Value
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"balance"
balanceDebit
:: KnownNat precision
=> Balance precision
-> Maybe (Quantity precision)
balanceDebit :: Balance precision -> Maybe (Quantity precision)
balanceDebit (Balance Side
SideDebit Quantity precision
v) = Quantity precision -> Maybe (Quantity precision)
forall a. a -> Maybe a
Just Quantity precision
v
balanceDebit Balance precision
_ = Maybe (Quantity precision)
forall a. Maybe a
Nothing
balanceCredit
:: KnownNat precision
=> Balance precision
-> Maybe (Quantity precision)
balanceCredit :: Balance precision -> Maybe (Quantity precision)
balanceCredit (Balance Side
SideCredit Quantity precision
v) = Quantity precision -> Maybe (Quantity precision)
forall a. a -> Maybe a
Just Quantity precision
v
balanceCredit Balance precision
_ = Maybe (Quantity precision)
forall a. Maybe a
Nothing
updateBalance
:: KnownNat precision
=> Balance precision
-> Amount precision
-> Balance precision
updateBalance :: Balance precision -> Amount precision -> Balance precision
updateBalance (Balance Side
bSide Quantity precision
bVal) (Amount Side
aSide UnsignedQuantity precision
aVal) =
Side -> Quantity precision -> Balance precision
forall (precision :: Nat).
Side -> Quantity precision -> Balance precision
Balance Side
bSide (Quantity precision
bVal Quantity precision -> Quantity precision -> Quantity precision
forall a. Num a => a -> a -> a
+ (UnsignedQuantity precision -> Quantity precision
forall p x. Refined p x -> x
unrefine UnsignedQuantity precision
aVal Quantity precision -> Quantity precision -> Quantity precision
forall a. Num a => a -> a -> a
* (if Side
bSide Side -> Side -> Bool
forall a. Eq a => a -> a -> Bool
== Side
aSide then Quantity precision
1 else (-Quantity precision
1))))
amountFromBalance
:: KnownNat precision
=> Balance precision
-> Amount precision
amountFromBalance :: Balance precision -> Amount precision
amountFromBalance (Balance Side
side Quantity precision
value) =
Side -> UnsignedQuantity precision -> Amount precision
forall (precision :: Nat).
Side -> UnsignedQuantity precision -> Amount precision
Amount (if Quantity precision
value Quantity precision -> Quantity precision -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity precision
0 then Side -> Side
otherSide Side
side else Side
side) (Quantity precision -> UnsignedQuantity precision
forall (s :: Nat). KnownNat s => Quantity s -> UnsignedQuantity s
absQuantity Quantity precision
value)
quantityFromBalance
:: KnownNat precision
=> AccountKind
-> Balance precision
-> Quantity precision
quantityFromBalance :: AccountKind -> Balance precision -> Quantity precision
quantityFromBalance AccountKind
k = AccountKind -> Amount precision -> Quantity precision
forall (precision :: Nat).
KnownNat precision =>
AccountKind -> Amount precision -> Quantity precision
quantityFromAmount AccountKind
k (Amount precision -> Quantity precision)
-> (Balance precision -> Amount precision)
-> Balance precision
-> Quantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Balance precision -> Amount precision
forall (precision :: Nat).
KnownNat precision =>
Balance precision -> Amount precision
amountFromBalance
valueFromBalance
:: KnownNat precision
=> AccountKind
-> Balance precision
-> Quantity precision
valueFromBalance :: AccountKind -> Balance precision -> Quantity precision
valueFromBalance AccountKind
k = AccountKind -> Amount precision -> Quantity precision
forall (precision :: Nat).
KnownNat precision =>
AccountKind -> Amount precision -> Quantity precision
valueFromAmount AccountKind
k (Amount precision -> Quantity precision)
-> (Balance precision -> Amount precision)
-> Balance precision
-> Quantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Balance precision -> Amount precision
forall (precision :: Nat).
KnownNat precision =>
Balance precision -> Amount precision
amountFromBalance