{-# LANGUAGE DataKinds #-}
module Haspara.Accounting.Journal where
import qualified Data.Aeson as Aeson
import qualified Data.Text as T
import Data.Time (Day)
import GHC.Generics (Generic)
import GHC.TypeLits (KnownNat, Nat)
import Haspara.Accounting.Account (Account(accountKind))
import Haspara.Accounting.Amount (Amount(..), amountFromQuantity, amountFromValue)
import Haspara.Accounting.Side (Side(..))
import Haspara.Internal.Aeson (commonAesonOptions)
import Haspara.Quantity (Quantity, UnsignedQuantity, sumUnsignedQuantity)
newtype Journal (precision :: Nat) account event = Journal
{ Journal precision account event
-> [JournalEntry precision account event]
journalEntries :: [JournalEntry precision account event]
}
deriving ((forall x.
Journal precision account event
-> Rep (Journal precision account event) x)
-> (forall x.
Rep (Journal precision account event) x
-> Journal precision account event)
-> Generic (Journal precision account event)
forall x.
Rep (Journal precision account event) x
-> Journal precision account event
forall x.
Journal precision account event
-> Rep (Journal precision account event) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (precision :: Nat) account event x.
Rep (Journal precision account event) x
-> Journal precision account event
forall (precision :: Nat) account event x.
Journal precision account event
-> Rep (Journal precision account event) x
$cto :: forall (precision :: Nat) account event x.
Rep (Journal precision account event) x
-> Journal precision account event
$cfrom :: forall (precision :: Nat) account event x.
Journal precision account event
-> Rep (Journal precision account event) x
Generic, Int -> Journal precision account event -> ShowS
[Journal precision account event] -> ShowS
Journal precision account event -> String
(Int -> Journal precision account event -> ShowS)
-> (Journal precision account event -> String)
-> ([Journal precision account event] -> ShowS)
-> Show (Journal precision account event)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> Journal precision account event -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[Journal precision account event] -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Journal precision account event -> String
showList :: [Journal precision account event] -> ShowS
$cshowList :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[Journal precision account event] -> ShowS
show :: Journal precision account event -> String
$cshow :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Journal precision account event -> String
showsPrec :: Int -> Journal precision account event -> ShowS
$cshowsPrec :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> Journal precision account event -> ShowS
Show)
instance (KnownNat precision, Aeson.FromJSON account, Aeson.FromJSON event) => Aeson.FromJSON (Journal precision account event) where
parseJSON :: Value -> Parser (Journal precision account event)
parseJSON = Options -> Value -> Parser (Journal precision account event)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON (Options -> Value -> Parser (Journal precision account event))
-> Options -> Value -> Parser (Journal precision account event)
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journal"
instance (KnownNat precision, Aeson.ToJSON account, Aeson.ToJSON event) => Aeson.ToJSON (Journal precision account event) where
toJSON :: Journal precision account event -> Value
toJSON = Options -> Journal precision account event -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON (Options -> Journal precision account event -> Value)
-> Options -> Journal precision account event -> Value
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journal"
data JournalEntry (precision :: Nat) account event = JournalEntry
{ JournalEntry precision account event -> Text
journalEntryId :: !T.Text
, JournalEntry precision account event -> Day
journalEntryDate :: !Day
, JournalEntry precision account event
-> [JournalEntryItem precision account event]
journalEntryItems :: ![JournalEntryItem precision account event]
, JournalEntry precision account event -> Text
journalEntryDescription :: !T.Text
}
deriving ((forall x.
JournalEntry precision account event
-> Rep (JournalEntry precision account event) x)
-> (forall x.
Rep (JournalEntry precision account event) x
-> JournalEntry precision account event)
-> Generic (JournalEntry precision account event)
forall x.
Rep (JournalEntry precision account event) x
-> JournalEntry precision account event
forall x.
JournalEntry precision account event
-> Rep (JournalEntry precision account event) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (precision :: Nat) account event x.
Rep (JournalEntry precision account event) x
-> JournalEntry precision account event
forall (precision :: Nat) account event x.
JournalEntry precision account event
-> Rep (JournalEntry precision account event) x
$cto :: forall (precision :: Nat) account event x.
Rep (JournalEntry precision account event) x
-> JournalEntry precision account event
$cfrom :: forall (precision :: Nat) account event x.
JournalEntry precision account event
-> Rep (JournalEntry precision account event) x
Generic, Int -> JournalEntry precision account event -> ShowS
[JournalEntry precision account event] -> ShowS
JournalEntry precision account event -> String
(Int -> JournalEntry precision account event -> ShowS)
-> (JournalEntry precision account event -> String)
-> ([JournalEntry precision account event] -> ShowS)
-> Show (JournalEntry precision account event)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> JournalEntry precision account event -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[JournalEntry precision account event] -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
JournalEntry precision account event -> String
showList :: [JournalEntry precision account event] -> ShowS
$cshowList :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[JournalEntry precision account event] -> ShowS
show :: JournalEntry precision account event -> String
$cshow :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
JournalEntry precision account event -> String
showsPrec :: Int -> JournalEntry precision account event -> ShowS
$cshowsPrec :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> JournalEntry precision account event -> ShowS
Show)
instance (KnownNat precision, Aeson.FromJSON account, Aeson.FromJSON event) => Aeson.FromJSON (JournalEntry precision account event) where
parseJSON :: Value -> Parser (JournalEntry precision account event)
parseJSON = Options -> Value -> Parser (JournalEntry precision account event)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON (Options -> Value -> Parser (JournalEntry precision account event))
-> Options
-> Value
-> Parser (JournalEntry precision account event)
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journalEntry"
instance (KnownNat precision, Aeson.ToJSON account, Aeson.ToJSON event) => Aeson.ToJSON (JournalEntry precision account event) where
toJSON :: JournalEntry precision account event -> Value
toJSON = Options -> JournalEntry precision account event -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON (Options -> JournalEntry precision account event -> Value)
-> Options -> JournalEntry precision account event -> Value
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journalEntry"
journalEntryTotalDebit
:: KnownNat precision
=> JournalEntry precision account event
-> UnsignedQuantity precision
journalEntryTotalDebit :: JournalEntry precision account event -> UnsignedQuantity precision
journalEntryTotalDebit =
[UnsignedQuantity precision] -> UnsignedQuantity precision
forall (s :: Nat).
KnownNat s =>
[UnsignedQuantity s] -> UnsignedQuantity s
sumUnsignedQuantity
([UnsignedQuantity precision] -> UnsignedQuantity precision)
-> (JournalEntry precision account event
-> [UnsignedQuantity precision])
-> JournalEntry precision account event
-> UnsignedQuantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JournalEntryItem precision account event
-> UnsignedQuantity precision)
-> [JournalEntryItem precision account event]
-> [UnsignedQuantity precision]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Amount precision -> UnsignedQuantity precision
forall (precision :: Nat).
Amount precision -> UnsignedQuantity precision
amountValue (Amount precision -> UnsignedQuantity precision)
-> (JournalEntryItem precision account event -> Amount precision)
-> JournalEntryItem precision account event
-> UnsignedQuantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntryItem precision account event -> Amount precision
forall (precision :: Nat) account event.
JournalEntryItem precision account event -> Amount precision
journalEntryItemAmount)
([JournalEntryItem precision account event]
-> [UnsignedQuantity precision])
-> (JournalEntry precision account event
-> [JournalEntryItem precision account event])
-> JournalEntry precision account event
-> [UnsignedQuantity precision]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JournalEntryItem precision account event -> Bool)
-> [JournalEntryItem precision account event]
-> [JournalEntryItem precision account event]
forall a. (a -> Bool) -> [a] -> [a]
filter (Side -> Side -> Bool
forall a. Eq a => a -> a -> Bool
(==) Side
SideDebit (Side -> Bool)
-> (JournalEntryItem precision account event -> Side)
-> JournalEntryItem precision account event
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount precision -> Side
forall (precision :: Nat). Amount precision -> Side
amountSide (Amount precision -> Side)
-> (JournalEntryItem precision account event -> Amount precision)
-> JournalEntryItem precision account event
-> Side
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntryItem precision account event -> Amount precision
forall (precision :: Nat) account event.
JournalEntryItem precision account event -> Amount precision
journalEntryItemAmount)
([JournalEntryItem precision account event]
-> [JournalEntryItem precision account event])
-> (JournalEntry precision account event
-> [JournalEntryItem precision account event])
-> JournalEntry precision account event
-> [JournalEntryItem precision account event]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntry precision account event
-> [JournalEntryItem precision account event]
forall (precision :: Nat) account event.
JournalEntry precision account event
-> [JournalEntryItem precision account event]
journalEntryItems
journalEntryTotalCredit
:: KnownNat precision
=> JournalEntry precision account event
-> UnsignedQuantity precision
journalEntryTotalCredit :: JournalEntry precision account event -> UnsignedQuantity precision
journalEntryTotalCredit =
[UnsignedQuantity precision] -> UnsignedQuantity precision
forall (s :: Nat).
KnownNat s =>
[UnsignedQuantity s] -> UnsignedQuantity s
sumUnsignedQuantity
([UnsignedQuantity precision] -> UnsignedQuantity precision)
-> (JournalEntry precision account event
-> [UnsignedQuantity precision])
-> JournalEntry precision account event
-> UnsignedQuantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JournalEntryItem precision account event
-> UnsignedQuantity precision)
-> [JournalEntryItem precision account event]
-> [UnsignedQuantity precision]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Amount precision -> UnsignedQuantity precision
forall (precision :: Nat).
Amount precision -> UnsignedQuantity precision
amountValue (Amount precision -> UnsignedQuantity precision)
-> (JournalEntryItem precision account event -> Amount precision)
-> JournalEntryItem precision account event
-> UnsignedQuantity precision
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntryItem precision account event -> Amount precision
forall (precision :: Nat) account event.
JournalEntryItem precision account event -> Amount precision
journalEntryItemAmount)
([JournalEntryItem precision account event]
-> [UnsignedQuantity precision])
-> (JournalEntry precision account event
-> [JournalEntryItem precision account event])
-> JournalEntry precision account event
-> [UnsignedQuantity precision]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JournalEntryItem precision account event -> Bool)
-> [JournalEntryItem precision account event]
-> [JournalEntryItem precision account event]
forall a. (a -> Bool) -> [a] -> [a]
filter (Side -> Side -> Bool
forall a. Eq a => a -> a -> Bool
(==) Side
SideCredit (Side -> Bool)
-> (JournalEntryItem precision account event -> Side)
-> JournalEntryItem precision account event
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount precision -> Side
forall (precision :: Nat). Amount precision -> Side
amountSide (Amount precision -> Side)
-> (JournalEntryItem precision account event -> Amount precision)
-> JournalEntryItem precision account event
-> Side
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntryItem precision account event -> Amount precision
forall (precision :: Nat) account event.
JournalEntryItem precision account event -> Amount precision
journalEntryItemAmount)
([JournalEntryItem precision account event]
-> [JournalEntryItem precision account event])
-> (JournalEntry precision account event
-> [JournalEntryItem precision account event])
-> JournalEntry precision account event
-> [JournalEntryItem precision account event]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JournalEntry precision account event
-> [JournalEntryItem precision account event]
forall (precision :: Nat) account event.
JournalEntry precision account event
-> [JournalEntryItem precision account event]
journalEntryItems
isJournalEntryBalanced
:: KnownNat precision
=> JournalEntry precision account event
-> Bool
isJournalEntryBalanced :: JournalEntry precision account event -> Bool
isJournalEntryBalanced = UnsignedQuantity precision -> UnsignedQuantity precision -> Bool
forall a. Eq a => a -> a -> Bool
(==)
(UnsignedQuantity precision -> UnsignedQuantity precision -> Bool)
-> (JournalEntry precision account event
-> UnsignedQuantity precision)
-> JournalEntry precision account event
-> UnsignedQuantity precision
-> Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JournalEntry precision account event -> UnsignedQuantity precision
forall (precision :: Nat) account event.
KnownNat precision =>
JournalEntry precision account event -> UnsignedQuantity precision
journalEntryTotalDebit
(JournalEntry precision account event
-> UnsignedQuantity precision -> Bool)
-> (JournalEntry precision account event
-> UnsignedQuantity precision)
-> JournalEntry precision account event
-> Bool
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> JournalEntry precision account event -> UnsignedQuantity precision
forall (precision :: Nat) account event.
KnownNat precision =>
JournalEntry precision account event -> UnsignedQuantity precision
journalEntryTotalCredit
data JournalEntryItem (precision :: Nat) account event = JournalEntryItem
{ JournalEntryItem precision account event -> Amount precision
journalEntryItemAmount :: !(Amount precision)
, JournalEntryItem precision account event -> Account account
journalEntryItemAccount :: !(Account account)
, JournalEntryItem precision account event -> event
journalEntryItemEvent :: !event
}
deriving (JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
(JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool)
-> (JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool)
-> Eq (JournalEntryItem precision account event)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (precision :: Nat) account event.
(Eq account, Eq event) =>
JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
/= :: JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
$c/= :: forall (precision :: Nat) account event.
(Eq account, Eq event) =>
JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
== :: JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
$c== :: forall (precision :: Nat) account event.
(Eq account, Eq event) =>
JournalEntryItem precision account event
-> JournalEntryItem precision account event -> Bool
Eq, (forall x.
JournalEntryItem precision account event
-> Rep (JournalEntryItem precision account event) x)
-> (forall x.
Rep (JournalEntryItem precision account event) x
-> JournalEntryItem precision account event)
-> Generic (JournalEntryItem precision account event)
forall x.
Rep (JournalEntryItem precision account event) x
-> JournalEntryItem precision account event
forall x.
JournalEntryItem precision account event
-> Rep (JournalEntryItem precision account event) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (precision :: Nat) account event x.
Rep (JournalEntryItem precision account event) x
-> JournalEntryItem precision account event
forall (precision :: Nat) account event x.
JournalEntryItem precision account event
-> Rep (JournalEntryItem precision account event) x
$cto :: forall (precision :: Nat) account event x.
Rep (JournalEntryItem precision account event) x
-> JournalEntryItem precision account event
$cfrom :: forall (precision :: Nat) account event x.
JournalEntryItem precision account event
-> Rep (JournalEntryItem precision account event) x
Generic, Int -> JournalEntryItem precision account event -> ShowS
[JournalEntryItem precision account event] -> ShowS
JournalEntryItem precision account event -> String
(Int -> JournalEntryItem precision account event -> ShowS)
-> (JournalEntryItem precision account event -> String)
-> ([JournalEntryItem precision account event] -> ShowS)
-> Show (JournalEntryItem precision account event)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> JournalEntryItem precision account event -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[JournalEntryItem precision account event] -> ShowS
forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
JournalEntryItem precision account event -> String
showList :: [JournalEntryItem precision account event] -> ShowS
$cshowList :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
[JournalEntryItem precision account event] -> ShowS
show :: JournalEntryItem precision account event -> String
$cshow :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
JournalEntryItem precision account event -> String
showsPrec :: Int -> JournalEntryItem precision account event -> ShowS
$cshowsPrec :: forall (precision :: Nat) account event.
(KnownNat precision, Show account, Show event) =>
Int -> JournalEntryItem precision account event -> ShowS
Show)
instance (KnownNat precision, Aeson.FromJSON account, Aeson.FromJSON event) => Aeson.FromJSON (JournalEntryItem precision account event) where
parseJSON :: Value -> Parser (JournalEntryItem precision account event)
parseJSON = Options
-> Value -> Parser (JournalEntryItem precision account event)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON (Options
-> Value -> Parser (JournalEntryItem precision account event))
-> Options
-> Value
-> Parser (JournalEntryItem precision account event)
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journalEntryItem"
instance (KnownNat precision, Aeson.ToJSON account, Aeson.ToJSON event) => Aeson.ToJSON (JournalEntryItem precision account event) where
toJSON :: JournalEntryItem precision account event -> Value
toJSON = Options -> JournalEntryItem precision account event -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON (Options -> JournalEntryItem precision account event -> Value)
-> Options -> JournalEntryItem precision account event -> Value
forall a b. (a -> b) -> a -> b
$ String -> Options
commonAesonOptions String
"journalEntryItem"
mkJournalEntryItemFromQuantity
:: KnownNat precision
=> Quantity precision
-> Account account
-> event
-> JournalEntryItem precision account event
mkJournalEntryItemFromQuantity :: Quantity precision
-> Account account
-> event
-> JournalEntryItem precision account event
mkJournalEntryItemFromQuantity Quantity precision
qty Account account
acc event
evt =
JournalEntryItem :: forall (precision :: Nat) account event.
Amount precision
-> Account account
-> event
-> JournalEntryItem precision account event
JournalEntryItem
{ journalEntryItemAmount :: Amount precision
journalEntryItemAmount = AccountKind -> Quantity precision -> Amount precision
forall (precision :: Nat).
KnownNat precision =>
AccountKind -> Quantity precision -> Amount precision
amountFromQuantity (Account account -> AccountKind
forall o. Account o -> AccountKind
accountKind Account account
acc) Quantity precision
qty
, journalEntryItemAccount :: Account account
journalEntryItemAccount = Account account
acc
, journalEntryItemEvent :: event
journalEntryItemEvent = event
evt
}
mkJournalEntryItemFromValue
:: KnownNat precision
=> Quantity precision
-> Account account
-> event
-> JournalEntryItem precision account event
mkJournalEntryItemFromValue :: Quantity precision
-> Account account
-> event
-> JournalEntryItem precision account event
mkJournalEntryItemFromValue Quantity precision
val Account account
acc event
evt =
JournalEntryItem :: forall (precision :: Nat) account event.
Amount precision
-> Account account
-> event
-> JournalEntryItem precision account event
JournalEntryItem
{ journalEntryItemAmount :: Amount precision
journalEntryItemAmount = AccountKind -> Quantity precision -> Amount precision
forall (precision :: Nat).
KnownNat precision =>
AccountKind -> Quantity precision -> Amount precision
amountFromValue (Account account -> AccountKind
forall o. Account o -> AccountKind
accountKind Account account
acc) Quantity precision
val
, journalEntryItemAccount :: Account account
journalEntryItemAccount = Account account
acc
, journalEntryItemEvent :: event
journalEntryItemEvent = event
evt
}