-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A library providing definitions to work with monetary values. -- -- Please see the README on GitHub at -- https://github.com/telostat/haspara#readme @package haspara @version 0.0.0.10 -- | This module provides helper definitions for Data.Aeson. module Haspara.Internal.Aeson -- | Common Aeson encoding/decoding options. commonAesonOptions :: String -> Options -- | Aeson encoding/decoding options for uppercase constructor tag -- modifiers aesonOptionsForSingleTag :: String -> Options -- | This module provides definitions for modeling and working with -- currencies. module Haspara.Currency -- | Type encoding for currency symbol values with a syntax of -- [A-Z]{3}[A-Z]*. -- -- Currency values can be constructed via mkCurrencyError -- that works in MonadError Text context: -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> mkCurrencyError "EUR" :: Either T.Text Currency
--   Right EUR
--   
-- -- ... or via mkCurrencyFail that works in MonadFail -- context: -- --
--   >>> mkCurrencyFail "EUR" :: Maybe Currency
--   Just EUR
--   
-- -- An IsString instance is provided as well which is unsafe but -- convenient: -- --
--   >>> "EUR" :: Currency
--   EUR
--   
newtype Currency MkCurrency :: Text -> Currency [currencyCode] :: Currency -> Text -- | Smart constructor for Currency values within MonadError -- context. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> mkCurrencyError "" :: Either T.Text Currency
--   Left "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: "
--   
--   >>> mkCurrencyError " " :: Either T.Text Currency
--   Left "Currency code error! Expecting at least 3 uppercase ASCII letters, but received:  "
--   
--   >>> mkCurrencyError "AB" :: Either T.Text Currency
--   Left "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: AB"
--   
--   >>> mkCurrencyError " ABC " :: Either T.Text Currency
--   Left "Currency code error! Expecting at least 3 uppercase ASCII letters, but received:  ABC "
--   
--   >>> mkCurrencyError "ABC" :: Either T.Text Currency
--   Right ABC
--   
mkCurrencyError :: MonadError Text m => Text -> m Currency -- | Smart constructor for Currency values within MonadFail -- context. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> mkCurrencyFail "" :: Maybe Currency
--   Nothing
--   
--   >>> mkCurrencyFail "US" :: Maybe Currency
--   Nothing
--   
--   >>> mkCurrencyFail "usd" :: Maybe Currency
--   Nothing
--   
--   >>> mkCurrencyFail "USD" :: Maybe Currency
--   Just USD
--   
mkCurrencyFail :: MonadFail m => Text -> m Currency -- | Parser that parses currency codes. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> MP.runParser currencyCodeParser "Example" ""
--   Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
--   >>> MP.runParser currencyCodeParser "Example" " "
--   Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens (' ' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = " ", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
--   >>> MP.runParser currencyCodeParser "Example" "a"
--   Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens ('a' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = "a", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
--   >>> MP.runParser currencyCodeParser "Example" "A"
--   Left (ParseErrorBundle {bundleErrors = TrivialError 1 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "A", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
--   >>> MP.runParser currencyCodeParser "Example" "AB"
--   Left (ParseErrorBundle {bundleErrors = TrivialError 2 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "AB", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
--   >>> MP.runParser currencyCodeParser "Example" "ABC"
--   Right "ABC"
--   
--   >>> MP.runParser currencyCodeParser "Example" "ABCD"
--   Right "ABCD"
--   
--   >>> MP.runParser currencyCodeParser "Example" " ABCD "
--   Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens (' ' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = " ABCD ", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})
--   
currencyCodeParser :: Parsec Void Text Text -- | Type encoding of a currency pair. -- -- CurrencyPair values are constructed via the data constructor: -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> CurrencyPair "EUR" "USD"
--   EUR/USD
--   
-- -- FromJSON and ToJSON instances are provided as well: -- --
--   >>> Aeson.decode "{\"base\": \"EUR\", \"quote\": \"EUR\"}" :: Maybe CurrencyPair
--   Just EUR/EUR
--   
--   >>> Aeson.encode (CurrencyPair "EUR" "USD")
--   "{\"base\":\"EUR\",\"quote\":\"USD\"}"
--   
data CurrencyPair CurrencyPair :: !Currency -> !Currency -> CurrencyPair -- | Base currency of the currency pair. Also referred to as -- counter currency. [currencyPairBase] :: CurrencyPair -> !Currency -- | Quote currency of the currency pair. Also referred to as -- transaction currency. [currencyPairQuote] :: CurrencyPair -> !Currency -- | Converts a CurrencyPair to a 2-tuple of Currency values. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> toCurrencyTuple (CurrencyPair "EUR" "USD")
--   (EUR,USD)
--   
toCurrencyTuple :: CurrencyPair -> (Currency, Currency) -- | Converts a 2-tuple of Currency values to a CurrencyPair. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> fromCurrencyTuple ("EUR", "USD")
--   EUR/USD
--   
fromCurrencyTuple :: (Currency, Currency) -> CurrencyPair instance Language.Haskell.TH.Syntax.Lift Haspara.Currency.Currency instance GHC.Classes.Ord Haspara.Currency.Currency instance Data.Hashable.Class.Hashable Haspara.Currency.Currency instance GHC.Classes.Eq Haspara.Currency.Currency instance Language.Haskell.TH.Syntax.Lift Haspara.Currency.CurrencyPair instance GHC.Classes.Ord Haspara.Currency.CurrencyPair instance GHC.Generics.Generic Haspara.Currency.CurrencyPair instance GHC.Classes.Eq Haspara.Currency.CurrencyPair instance Data.Aeson.Types.FromJSON.FromJSON Haspara.Currency.CurrencyPair instance Data.Aeson.Types.ToJSON.ToJSON Haspara.Currency.CurrencyPair instance GHC.Show.Show Haspara.Currency.CurrencyPair instance Data.String.IsString Haspara.Currency.Currency instance GHC.Show.Show Haspara.Currency.Currency instance Data.Aeson.Types.FromJSON.FromJSON Haspara.Currency.Currency instance Data.Aeson.Types.ToJSON.ToJSON Haspara.Currency.Currency -- | This module provides definitions for acccounts and types of accounts -- as they are used in accounting reporting. module Haspara.Accounting.Account -- | Type encoding for ledger account type. -- -- This type covers both balance sheet and income statement account -- types: -- --
    --
  1. For balance sheet accounts:
  2. --
  3. Asset (AccountKindAsset)
  4. --
  5. Liability (AccountKindLiability)
  6. --
  7. Equity (AccountKindEquity)
  8. --
  9. For income statement accounts:
  10. --
  11. Revenue (AccountKindRevenue)
  12. --
  13. Expense (AccountKindExpense)
  14. --
-- -- FromJSON and ToJSON instances, too: -- --
--   >>> :set -XTypeApplications
--   
--   >>> Data.Aeson.decode @AccountKind "\"ASSET\""
--   Just AccountKindAsset
--   
--   >>> Data.Aeson.decode @AccountKind "\"LIABILITY\""
--   Just AccountKindLiability
--   
--   >>> Data.Aeson.decode @AccountKind "\"EQUITY\""
--   Just AccountKindEquity
--   
--   >>> Data.Aeson.decode @AccountKind "\"REVENUE\""
--   Just AccountKindRevenue
--   
--   >>> Data.Aeson.decode @AccountKind "\"EXPENSE\""
--   Just AccountKindExpense
--   
--   >>> Data.Aeson.encode AccountKindAsset
--   "\"ASSET\""
--   
--   >>> Data.Aeson.encode AccountKindLiability
--   "\"LIABILITY\""
--   
--   >>> Data.Aeson.encode AccountKindEquity
--   "\"EQUITY\""
--   
--   >>> Data.Aeson.encode AccountKindRevenue
--   "\"REVENUE\""
--   
--   >>> Data.Aeson.encode AccountKindExpense
--   "\"EXPENSE\""
--   
data AccountKind AccountKindAsset :: AccountKind AccountKindLiability :: AccountKind AccountKindEquity :: AccountKind AccountKindRevenue :: AccountKind AccountKindExpense :: AccountKind -- | Provides textual representation of a given AccountKind. -- --
--   >>> accountKindText AccountKindAsset
--   "Asset"
--   
--   >>> accountKindText AccountKindLiability
--   "Liability"
--   
--   >>> accountKindText AccountKindEquity
--   "Equity"
--   
--   >>> accountKindText AccountKindRevenue
--   "Revenue"
--   
--   >>> accountKindText AccountKindExpense
--   "Expense"
--   
accountKindText :: AccountKind -> Text -- | Type encoding for account values. -- -- This definition provides both the AccountKind and an arbitrary -- object identifying the account. This arbitrary nature provides -- flexibility to use-site to use its own account identity and -- accompanying information when required. -- --
--   >>> :set -XTypeApplications
--   
--   >>> let acc = Account AccountKindAsset (1 ::Int)
--   
--   >>> Data.Aeson.encode acc
--   "{\"kind\":\"ASSET\",\"object\":1}"
--   
--   >>> Data.Aeson.decode @(Account Int) (Data.Aeson.encode acc)
--   Just (Account {accountKind = AccountKindAsset, accountObject = 1})
--   
--   >>> Data.Aeson.decode (Data.Aeson.encode acc) == Just acc
--   True
--   
data Account o Account :: !AccountKind -> !o -> Account o [accountKind] :: Account o -> !AccountKind [accountObject] :: Account o -> !o instance GHC.Show.Show Haspara.Accounting.Account.AccountKind instance GHC.Classes.Ord Haspara.Accounting.Account.AccountKind instance GHC.Generics.Generic Haspara.Accounting.Account.AccountKind instance GHC.Classes.Eq Haspara.Accounting.Account.AccountKind instance GHC.Enum.Enum Haspara.Accounting.Account.AccountKind instance GHC.Enum.Bounded Haspara.Accounting.Account.AccountKind instance GHC.Show.Show o => GHC.Show.Show (Haspara.Accounting.Account.Account o) instance GHC.Classes.Ord o => GHC.Classes.Ord (Haspara.Accounting.Account.Account o) instance GHC.Generics.Generic (Haspara.Accounting.Account.Account o) instance GHC.Classes.Eq o => GHC.Classes.Eq (Haspara.Accounting.Account.Account o) instance Data.Hashable.Class.Hashable o => Data.Hashable.Class.Hashable (Haspara.Accounting.Account.Account o) instance Data.Aeson.Types.FromJSON.FromJSON o => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Account.Account o) instance Data.Aeson.Types.ToJSON.ToJSON o => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Account.Account o) instance Data.Hashable.Class.Hashable Haspara.Accounting.Account.AccountKind instance Data.Aeson.Types.FromJSON.FromJSON Haspara.Accounting.Account.AccountKind instance Data.Aeson.Types.ToJSON.ToJSON Haspara.Accounting.Account.AccountKind -- | This module provides definitions for modeling and working with -- quantities with fixed decimal points. module Haspara.Quantity -- | Type encoding for quantity values with a given scaling (digits after -- the decimal point). -- --
--   >>> 42 :: Quantity 0
--   42
--   
--   >>> 42 :: Quantity 1
--   42.0
--   
--   >>> 42 :: Quantity 2
--   42.00
--   
--   >>> 41 + 1 :: Quantity 2
--   42.00
--   
--   >>> 43 - 1 :: Quantity 2
--   42.00
--   
--   >>> 2 * 3 * 7 :: Quantity 2
--   42.00
--   
--   >>> negate (-42) :: Quantity 2
--   42.00
--   
--   >>> abs (-42) :: Quantity 2
--   42.00
--   
--   >>> signum (-42) :: Quantity 2
--   -1.00
--   
--   >>> fromInteger 42 :: Quantity 2
--   42.00
--   
--   >>> mkQuantity 0.415 :: Quantity 2
--   0.42
--   
--   >>> mkQuantity 0.425 :: Quantity 2
--   0.42
--   
--   >>> mkQuantityLossless 0.42 :: Either String (Quantity 2)
--   Right 0.42
--   
--   >>> mkQuantityLossless 0.415 :: Either String (Quantity 2)
--   Left "Underflow while trying to create quantity: 0.415"
--   
newtype Quantity (s :: Nat) MkQuantity :: Decimal RoundHalfEven s Integer -> Quantity (s :: Nat) [unQuantity] :: Quantity (s :: Nat) -> Decimal RoundHalfEven s Integer -- | Type definition for unsigned Quantity values. type UnsignedQuantity s = Refined NonNegative (Quantity s) -- | Constructs Quantity values from Scientific values in a -- lossy way. -- -- This function uses mkQuantityAux in case that the lossless -- attempt fails. We could have used mkQuantityAux directly. -- However, mkQuantityAux is doing too much (see -- roundScientific). Therefore, we are first attempting a lossless -- construction (see mkQuantityLossless) and we fallback to -- mkQuantityAux in case the lossless construction fails. -- --
--   >>> mkQuantity 0 :: Quantity 0
--   0
--   
--   >>> mkQuantity 0 :: Quantity 1
--   0.0
--   
--   >>> mkQuantity 0 :: Quantity 2
--   0.00
--   
--   >>> mkQuantity 0.04 :: Quantity 1
--   0.0
--   
--   >>> mkQuantity 0.05 :: Quantity 1
--   0.0
--   
--   >>> mkQuantity 0.06 :: Quantity 1
--   0.1
--   
--   >>> mkQuantity 0.14 :: Quantity 1
--   0.1
--   
--   >>> mkQuantity 0.15 :: Quantity 1
--   0.2
--   
--   >>> mkQuantity 0.16 :: Quantity 1
--   0.2
--   
--   >>> mkQuantity 0.04 :: Quantity 2
--   0.04
--   
--   >>> mkQuantity 0.05 :: Quantity 2
--   0.05
--   
--   >>> mkQuantity 0.06 :: Quantity 2
--   0.06
--   
--   >>> mkQuantity 0.14 :: Quantity 2
--   0.14
--   
--   >>> mkQuantity 0.15 :: Quantity 2
--   0.15
--   
--   >>> mkQuantity 0.16 :: Quantity 2
--   0.16
--   
--   >>> mkQuantity 0.04 :: Quantity 3
--   0.040
--   
--   >>> mkQuantity 0.05 :: Quantity 3
--   0.050
--   
--   >>> mkQuantity 0.06 :: Quantity 3
--   0.060
--   
--   >>> mkQuantity 0.14 :: Quantity 3
--   0.140
--   
--   >>> mkQuantity 0.15 :: Quantity 3
--   0.150
--   
--   >>> mkQuantity 0.16 :: Quantity 3
--   0.160
--   
mkQuantity :: KnownNat s => Scientific -> Quantity s -- | Constructs Quantity values from Scientific values in a -- lossy way. -- --
--   >>> mkQuantityLossless 0 :: Either String (Quantity 0)
--   Right 0
--   
--   >>> mkQuantityLossless 0 :: Either String (Quantity 1)
--   Right 0.0
--   
--   >>> mkQuantityLossless 0 :: Either String (Quantity 2)
--   Right 0.00
--   
--   >>> mkQuantityLossless 0.04 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 4.0e-2"
--   
--   >>> mkQuantityLossless 0.05 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 5.0e-2"
--   
--   >>> mkQuantityLossless 0.06 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 6.0e-2"
--   
--   >>> mkQuantityLossless 0.14 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 0.14"
--   
--   >>> mkQuantityLossless 0.15 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 0.15"
--   
--   >>> mkQuantityLossless 0.16 :: Either String (Quantity 1)
--   Left "Underflow while trying to create quantity: 0.16"
--   
--   >>> mkQuantityLossless 0.04 :: Either String (Quantity 2)
--   Right 0.04
--   
--   >>> mkQuantityLossless 0.05 :: Either String (Quantity 2)
--   Right 0.05
--   
--   >>> mkQuantityLossless 0.06 :: Either String (Quantity 2)
--   Right 0.06
--   
--   >>> mkQuantityLossless 0.14 :: Either String (Quantity 2)
--   Right 0.14
--   
--   >>> mkQuantityLossless 0.15 :: Either String (Quantity 2)
--   Right 0.15
--   
--   >>> mkQuantityLossless 0.16 :: Either String (Quantity 2)
--   Right 0.16
--   
--   >>> mkQuantityLossless 0.04 :: Either String (Quantity 3)
--   Right 0.040
--   
--   >>> mkQuantityLossless 0.05 :: Either String (Quantity 3)
--   Right 0.050
--   
--   >>> mkQuantityLossless 0.06 :: Either String (Quantity 3)
--   Right 0.060
--   
--   >>> mkQuantityLossless 0.14 :: Either String (Quantity 3)
--   Right 0.140
--   
--   >>> mkQuantityLossless 0.15 :: Either String (Quantity 3)
--   Right 0.150
--   
--   >>> mkQuantityLossless 0.16 :: Either String (Quantity 3)
--   Right 0.160
--   
mkQuantityLossless :: (KnownNat s, MonadError String m) => Scientific -> m (Quantity s) -- | Rounds given quantity by k digits. -- --
--   >>> roundQuantity (mkQuantity 0.415 :: Quantity 3) :: Quantity 2
--   0.42
--   
--   >>> roundQuantity (mkQuantity 0.425 :: Quantity 3) :: Quantity 2
--   0.42
--   
roundQuantity :: KnownNat k => Quantity (n + k) -> Quantity n -- | Multiplies two quantities with different scales and rounds back to the -- scale of the frst operand. -- --
--   >>> times (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.42 :: Quantity 2)
--   0.18
--   
times :: (KnownNat s, KnownNat k) => Quantity s -> Quantity k -> Quantity s -- | Multiplies two quantities with different scales. -- --
--   >>> timesLossless (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.42 :: Quantity 2)
--   0.1764
--   
timesLossless :: (KnownNat s, KnownNat k) => Quantity s -> Quantity k -> Quantity (s + k) -- | Divides two quantities with same scales with possible loss. -- --
--   >>> divide (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.33
--   
--   >>> divide (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0 :: Quantity 2)
--   Nothing
--   
--   >>> divide (mkQuantity 0.42 :: Quantity 2) (mkQuantity 1 :: Quantity 2)
--   Just 0.42
--   
--   >>> divide (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.42 :: Quantity 2)
--   Just 1.00
--   
--   >>> divide (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.21 :: Quantity 2)
--   Just 2.00
--   
--   >>> divide (mkQuantity 0.42 :: Quantity 2) (mkQuantity (-0.21) :: Quantity 2)
--   Just -2.00
--   
divide :: KnownNat s => Quantity s -> Quantity s -> Maybe (Quantity s) -- | Divides two quantities with different scales with possible loss -- preserving dividend's precision. -- --
--   >>> divideL (mkQuantity 10 :: Quantity 1) (mkQuantity 3 :: Quantity 2)
--   Just 3.3
--   
--   >>> divideL (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.33
--   
--   >>> divideL (mkQuantity 10 :: Quantity 3) (mkQuantity 3 :: Quantity 2)
--   Just 3.333
--   
divideL :: (KnownNat s, KnownNat k) => Quantity s -> Quantity k -> Maybe (Quantity s) -- | Divides two quantities with different scales with possible loss -- preserving divisor's precision. -- --
--   >>> divideR (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 1)
--   Just 3.3
--   
--   >>> divideR (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.33
--   
--   >>> divideR (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 3)
--   Just 3.333
--   
divideR :: (KnownNat s, KnownNat k) => Quantity s -> Quantity k -> Maybe (Quantity k) -- | Divides two quantities with different scales with possible loss with a -- target precision of result. -- --
--   >>> :set -XTypeApplications
--   
--   >>> divideD @0 (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3
--   
--   >>> divideD @1 (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.3
--   
--   >>> divideD @2 (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.33
--   
--   >>> divideD @3 (mkQuantity 10 :: Quantity 2) (mkQuantity 3 :: Quantity 2)
--   Just 3.333
--   
--   >>> divideD @8 (mkQuantity 1111 :: Quantity 2) (mkQuantity 3333 :: Quantity 12)
--   Just 0.33333333
--   
divideD :: (KnownNat r, KnownNat s, KnownNat k) => Quantity s -> Quantity k -> Maybe (Quantity r) -- | Returns the total of a list of unsigned quantities. -- --
--   >>> sumUnsignedQuantity [] :: UnsignedQuantity 2
--   Refined 0.00
--   
sumUnsignedQuantity :: KnownNat s => [UnsignedQuantity s] -> UnsignedQuantity s -- | Returns the absolute value of the Quantity as -- UnsignedQuantity. -- --
--   >>> abs (mkQuantity 0.42 :: Quantity 2)
--   0.42
--   
--   >>> abs (mkQuantity 0 :: Quantity 2)
--   0.00
--   
--   >>> abs (mkQuantity (-0.42) :: Quantity 2)
--   0.42
--   
absQuantity :: KnownNat s => Quantity s -> UnsignedQuantity s -- | Auxiliary function for constructing Quantity values. -- -- See mkQuantity why we need this function and why we haven't -- used it as the direct implementation of mkQuantity. -- -- Call-sites should avoid using this function directly due to its -- performance characteristics. mkQuantityAux :: forall s. KnownNat s => Scientific -> Quantity s -- | Rounds a given scientific into a new scientific with given max digits -- after decimal point. -- -- This uses half-even rounding method. -- --
--   >>> roundScientific 0 0.4
--   0.0
--   
--   >>> roundScientific 0 0.5
--   0.0
--   
--   >>> roundScientific 0 0.6
--   1.0
--   
--   >>> roundScientific 0 1.4
--   1.0
--   
--   >>> roundScientific 0 1.5
--   2.0
--   
--   >>> roundScientific 0 1.6
--   2.0
--   
--   >>> roundScientific 1 0.04
--   0.0
--   
--   >>> roundScientific 1 0.05
--   0.0
--   
--   >>> roundScientific 1 0.06
--   0.1
--   
--   >>> roundScientific 1 0.14
--   0.1
--   
--   >>> roundScientific 1 0.15
--   0.2
--   
--   >>> roundScientific 1 0.16
--   0.2
--   
--   >>> roundScientific 1 3.650
--   3.6
--   
--   >>> roundScientific 1 3.740
--   3.7
--   
--   >>> roundScientific 1 3.749
--   3.7
--   
--   >>> roundScientific 1 3.750
--   3.8
--   
--   >>> roundScientific 1 3.751
--   3.8
--   
--   >>> roundScientific 1  3.760
--   3.8
--   
--   >>> roundScientific 1 (-3.650)
--   -3.6
--   
--   >>> roundScientific 1 (-3.740)
--   -3.7
--   
--   >>> roundScientific 1 (-3.749)
--   -3.7
--   
--   >>> roundScientific 1 (-3.750)
--   -3.8
--   
--   >>> roundScientific 1 (-3.751)
--   -3.8
--   
--   >>> roundScientific 1 (-3.760)
--   -3.8
--   
-- -- TODO: Refactor to improve the performance of this function. roundScientific :: Int -> Scientific -> Scientific instance GHC.TypeNats.KnownNat s => GHC.Num.Num (Haspara.Quantity.Quantity s) instance GHC.Generics.Generic (Haspara.Quantity.Quantity s) instance GHC.Classes.Ord (Haspara.Quantity.Quantity s) instance GHC.Classes.Eq (Haspara.Quantity.Quantity s) instance Language.Haskell.TH.Syntax.Lift (Numeric.Decimal.Internal.Decimal Numeric.Decimal.RoundHalfEven s GHC.Num.Integer.Integer) instance Language.Haskell.TH.Syntax.Lift (Haspara.Quantity.Quantity s) instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Quantity.Quantity s) instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Quantity.Quantity s) instance GHC.TypeNats.KnownNat s => GHC.Num.Num (Numeric.Decimal.BoundedArithmetic.Arith (Haspara.Quantity.Quantity s)) instance GHC.TypeNats.KnownNat s => GHC.Real.Fractional (Numeric.Decimal.BoundedArithmetic.Arith (Haspara.Quantity.Quantity s)) instance GHC.TypeNats.KnownNat s => GHC.Show.Show (Haspara.Quantity.Quantity s) -- | This module provides definitions for modeling and working with foreign -- exchange (FX) rate quotations. module Haspara.FxQuote -- | Type encoding for FX rate quotations with fixed precision. -- -- An FX rate quotation is a 3-tuple of: -- --
    --
  1. a currency pair the rate is quoted for, and
  2. --
  3. a date that the quotation is effective as of,
  4. --
  5. a (positive) rate as the value of the quotation.
  6. --
data FxQuote (s :: Nat) MkFxQuote :: !CurrencyPair -> !Day -> !Refined Positive (Quantity s) -> FxQuote (s :: Nat) -- | Currency pair of the FX rate. [fxQuotePair] :: FxQuote (s :: Nat) -> !CurrencyPair -- | Actual date of the FX rate. [fxQuoteDate] :: FxQuote (s :: Nat) -> !Day -- | (Positive) rate value of the FX rate. [fxQuoteRate] :: FxQuote (s :: Nat) -> !Refined Positive (Quantity s) -- | Smart constructor for FxQuote values within -- MonadError Text context. -- -- The rate is expected to be a positive value. If it is not, the -- function will throw an error. -- --
--   >>> :set -XTypeApplications
--   
--   >>> mkFxQuoteError @(Either _) @2 "EUR" "USD" (read "2021-12-31") 1.16
--   Right (MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16})
--   
--   >>> mkFxQuoteError @(Either _) @2 "EUR" "USD" (read "2021-12-31") (-1.16)
--   Left "Can not create FX Rate. Error was:   The predicate (GreaterThan 0) failed with the message: Value is not greater than 0\n"
--   
mkFxQuoteError :: MonadError Text m => KnownNat s => Currency -> Currency -> Day -> Scientific -> m (FxQuote s) -- | Smart constructor for FxQuote values within MonadFail -- context. -- -- The rate is expected to be a positive value. If it is not, the -- function will fail. -- --
--   >>> :set -XTypeApplications
--   
--   >>> mkFxQuoteFail @Maybe @2 "EUR" "USD" (read "2021-12-31") 1.16
--   Just (MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16})
--   
--   >>> mkFxQuoteFail @Maybe @2 "EUR" "USD" (read "2021-12-31") (-1.16)
--   Nothing
--   
mkFxQuoteFail :: MonadFail m => KnownNat s => Currency -> Currency -> Day -> Scientific -> m (FxQuote s) -- | Unsafe FxQuote constructor that errors if it fails. -- --
--   >>> :set -XTypeApplications
--   
--   >>> mkFxQuoteUnsafe @2 "EUR" "USD" (read "2021-12-31") 1.16
--   MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16}
--   
--   >>> mkFxQuoteUnsafe @2 "EUR" "USD" (read "2021-12-31") (-1.16)
--   ...
--   ...Can not create FX Rate. Error was:   The predicate (GreaterThan 0) failed with the message: Value is not greater than 0
--   ...
--   
mkFxQuoteUnsafe :: KnownNat s => Currency -> Currency -> Day -> Scientific -> FxQuote s -- | Type encoding for a dictionary-based FX rate quotation database for -- various CurrencyPair values. type FxQuoteDatabase (n :: Nat) = Map CurrencyPair (FxQuotePairDatabase n) -- | Type encoding for FX rate quotation database for a -- CurrencyPair. data FxQuotePairDatabase (n :: Nat) FxQuotePairDatabase :: !CurrencyPair -> !Map Day (FxQuote n) -> !Day -> !Day -> FxQuotePairDatabase (n :: Nat) [fxQuotePairDatabasePair] :: FxQuotePairDatabase (n :: Nat) -> !CurrencyPair [fxQuotePairDatabaseTable] :: FxQuotePairDatabase (n :: Nat) -> !Map Day (FxQuote n) [fxQuotePairDatabaseSince] :: FxQuotePairDatabase (n :: Nat) -> !Day [fxQuotePairDatabaseUntil] :: FxQuotePairDatabase (n :: Nat) -> !Day -- | Attempts to find and return the FX quotation for a given -- CurrencyPair as of a give Day in a given -- FxQuoteDatabase. findFxQuote :: KnownNat n => FxQuoteDatabase n -> CurrencyPair -> Day -> Maybe (FxQuote n) -- | Attempts to find and return the FX quotation as of a give Day -- in a given FxQuotePairDatabase. findFxQuoteAux :: KnownNat n => Day -> FxQuotePairDatabase n -> Maybe (FxQuote n) -- | Returns empty FX rate quotation database. -- --
--   >>> :set -XTypeApplications
--   
--   >>> emptyFxQuoteDatabase @8
--   fromList []
--   
emptyFxQuoteDatabase :: KnownNat n => FxQuoteDatabase n -- | Adds a list of FX rate quotations to the given database. -- --
--   >>> :set -XTypeApplications
--   
--   >>> let database = emptyFxQuoteDatabase @8
--   
--   >>> addFxQuotes [] database
--   fromList []
--   
--   >>> addFxQuotes [mkFxQuoteUnsafe @8 "EUR" "USD" (read "2021-01-31") 1.13] database
--   fromList [(EUR/USD,FxQuotePairDatabase {fxQuotePairDatabasePair = EUR/USD, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 1.13000000})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31})]
--   
--   >>> addFxQuotes [mkFxQuoteUnsafe @8 "EUR" "USD" (read "2021-01-31") 1.13, mkFxQuoteUnsafe @8 "USD" "EUR" (read "2021-01-31") 0.884956] database
--   fromList [(EUR/USD,FxQuotePairDatabase {fxQuotePairDatabasePair = EUR/USD, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 1.13000000})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31}),(USD/EUR,FxQuotePairDatabase {fxQuotePairDatabasePair = USD/EUR, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = USD/EUR, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 0.88495600})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31})]
--   
addFxQuotes :: KnownNat n => [FxQuote n] -> FxQuoteDatabase n -> FxQuoteDatabase n -- | Adds an FX rate quotation to the given database. addFxQuote :: KnownNat n => FxQuote n -> FxQuoteDatabase n -> FxQuoteDatabase n -- | Initializes FX quote pair database with the given FX quote. initFxQuotePairDatabase :: KnownNat n => FxQuote n -> FxQuotePairDatabase n -- | Updates an existing FX quote pair database with the given FX quote. updateFxQuotePairDatabase :: KnownNat n => FxQuote n -> FxQuotePairDatabase n -> FxQuotePairDatabase n instance GHC.TypeNats.KnownNat s => GHC.Show.Show (Haspara.FxQuote.FxQuote s) instance GHC.Classes.Ord (Haspara.FxQuote.FxQuote s) instance GHC.Generics.Generic (Haspara.FxQuote.FxQuote s) instance GHC.Classes.Eq (Haspara.FxQuote.FxQuote s) instance GHC.TypeNats.KnownNat n => GHC.Show.Show (Haspara.FxQuote.FxQuotePairDatabase n) instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.FromJSON.FromJSON (Haspara.FxQuote.FxQuote s) instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.ToJSON.ToJSON (Haspara.FxQuote.FxQuote s) -- | This module provides definitions for modeling and working with -- monetary values. module Haspara.Monetary -- | Type encoding for dated monetary values. -- -- A dated monetary value is a 3-tuple of: -- --
    --
  1. a date when the monetary value is effective as of,
  2. --
  3. the currency of the monetary value, and
  4. --
  5. the quantity of the monetary value.
  6. --
data Money (s :: Nat) Money :: !Day -> !Currency -> !Quantity s -> Money (s :: Nat) [moneyDate] :: Money (s :: Nat) -> !Day [moneyCurrency] :: Money (s :: Nat) -> !Currency [moneyQuantity] :: Money (s :: Nat) -> !Quantity s -- | Type encoding of a monetary context. class MonadThrow m => Monetary m -- | Converts the given monetary value in one currency to another currency. -- -- Note that the conversion is performed with an FX rate quotation as of -- the date of the given monetary value. convertM :: (Monetary m, HasCallStack) => KnownNat s => Currency -> Money s -> m (Money s) -- | Converts the given monetary value in one currency to another currency -- as of the given date. -- -- The rule is: -- --
--   convertAsofM DATE2 CCY2 (Money DATE1 CCY1 QTY1) === convertM CCY2 (Money DATE2 CCY1 QTY1)
--   
convertAsofM :: (Monetary m, HasCallStack) => KnownNat s => Day -> Currency -> Money s -> m (Money s) -- | Attempts to convert the given Money to another using the given -- FxQuote value. -- -- This function runs some guards before attempting to do the conversion: -- --
    --
  1. Base currency of the FX rate quotation should be the same as the -- currency of the monetary value, throws -- IncompatibleCurrenciesException otherwise.
  2. --
  3. Date of the FX rate quotation should be equal to or greater than -- the date of the monetary value, throws -- IncompatibleDatesException otherwise.
  4. --
  5. Rate of the FX rate quotation should be 1 if the base and -- quote quotation are same, throws InconsistentFxQuoteException -- otherwise.
  6. --
convert :: HasCallStack => MonadThrow m => KnownNat s => KnownNat k => Money s -> FxQuote k -> m (Money s) -- | Type encoding of exceptions thrown by the Monetary module. data MonetaryException -- | Indicates that we received a currency other than the expected -- currency. [IncompatibleCurrenciesException] :: HasCallStack => Currency -> Currency -> MonetaryException -- | Indicates that we received a currency other than the expected -- currency. [IncompatibleDatesException] :: HasCallStack => Day -> Day -> MonetaryException -- | Indicates that we received a currency other than the expected -- currency. [InconsistentFxQuoteException] :: forall (s :: Nat). (HasCallStack, KnownNat s) => FxQuote s -> MonetaryException instance GHC.TypeNats.KnownNat s => GHC.Show.Show (Haspara.Monetary.Money s) instance GHC.Classes.Ord (Haspara.Monetary.Money s) instance GHC.Generics.Generic (Haspara.Monetary.Money s) instance GHC.Classes.Eq (Haspara.Monetary.Money s) instance GHC.Show.Show Haspara.Monetary.MonetaryException instance GHC.Exception.Type.Exception Haspara.Monetary.MonetaryException instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Monetary.Money s) instance GHC.TypeNats.KnownNat s => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Monetary.Money s) -- | This module provides definitions for and functions to work with -- Debit/Credit dichotomy which is essential to double-entry bookkeeping. -- -- In our concept, we refer to this dichotomy as Side -- (materialized via Side sum-type) which is either Debit -- (materialized via SideDebit nullary data constructor) or -- Dredit (materialized via SideCredit nullary data -- constructor). -- -- This module provides FromJSON and ToJSON instances for -- Side as well. Following accounting conventions, we chose the -- JSON value for Debit as "db", and for Credit as -- "cr". module Haspara.Accounting.Side -- | Data definition for encoding the debit/credit indicator. data Side SideDebit :: Side SideCredit :: Side -- | Gives the other side. -- --
--   >>> otherSide SideDebit
--   SideCredit
--   
--   >>> otherSide SideCredit
--   SideDebit
--   
otherSide :: Side -> Side -- | Computes the Side by the given AccountKind and the sign -- of the given Quantity. -- -- The sign of the Quantity is indeed a proxy for whether the -- event of the Quantity is an increment (+1) or -- decrement (-1) event. -- -- 0 quantities are considered to originate from an increment -- event. So far, this seems to be a safe assumption that gives us -- totality in the context of this function. -- -- Note the following mapping as a guide: -- -- TODO: table -- --
--   >>> :set -XDataKinds
--   
--   >>> import Haspara.Quantity
--   
--   >>> let decrement = mkQuantity (-0.42) :: Quantity 2
--   
--   >>> let nocrement = mkQuantity 0 :: Quantity 2
--   
--   >>> let increment = mkQuantity 0.42 :: Quantity 2
--   
--   >>> fmap (sideByAccountKind AccountKindAsset) [decrement, nocrement, increment]
--   [SideCredit,SideDebit,SideDebit]
--   
--   >>> fmap (sideByAccountKind AccountKindLiability) [decrement, nocrement, increment]
--   [SideDebit,SideCredit,SideCredit]
--   
--   >>> fmap (sideByAccountKind AccountKindEquity) [decrement, nocrement, increment]
--   [SideDebit,SideCredit,SideCredit]
--   
--   >>> fmap (sideByAccountKind AccountKindRevenue) [decrement, nocrement, increment]
--   [SideDebit,SideCredit,SideCredit]
--   
--   >>> fmap (sideByAccountKind AccountKindExpense) [decrement, nocrement, increment]
--   [SideCredit,SideDebit,SideDebit]
--   
sideByAccountKind :: KnownNat precision => AccountKind -> Quantity precision -> Side -- | Returns the "normal" side for a given AccountKind. -- -- Note the following mapping as a guide: -- -- TODO: table normalSideByAccountKind :: AccountKind -> Side instance GHC.Show.Show Haspara.Accounting.Side.Side instance GHC.Classes.Ord Haspara.Accounting.Side.Side instance GHC.Classes.Eq Haspara.Accounting.Side.Side instance Data.Aeson.Types.FromJSON.FromJSON Haspara.Accounting.Side.Side instance Data.Aeson.Types.ToJSON.ToJSON Haspara.Accounting.Side.Side -- | This module provides FIFO machinery for inventory accounting. module Haspara.Accounting.Inventory -- | Data definition that keeps track of inventory for an economic -- resource. -- -- This data definition is polymorphic over the precision for, -- respectively: -- --
    --
  1. pprec precision of the price values,
  2. --
  3. sprec precision of the inventory event quantities, -- and
  4. --
  5. vprec precision of the monetary values such as PnL.
  6. --
-- -- Values of this type should not be directly manipulated. Instead, -- def is to be used for initializing an empty inventory and -- updateInventory method (and convenience wrappers) should be -- used to update the inventory with new inventory events. data Inventory (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) MkInventory :: !Quantity sprec -> !Seq (InventoryEvent pprec sprec) -> !Seq (InventoryHistoryItem pprec sprec vprec) -> Inventory (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) [inventoryTotal] :: Inventory (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !Quantity sprec [inventoryCurrent] :: Inventory (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !Seq (InventoryEvent pprec sprec) [inventoryHistory] :: Inventory (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !Seq (InventoryHistoryItem pprec sprec vprec) -- | Data definition for inventory events. -- -- This data definition is polymorphic over the precision for, -- respectively: -- --
    --
  1. pprec precision of the price values, and
  2. --
  3. sprec precision of the inventory event quantities.
  4. --
data InventoryEvent (pprec :: Nat) (sprec :: Nat) InventoryEvent :: !Day -> !Quantity pprec -> !Quantity sprec -> InventoryEvent (pprec :: Nat) (sprec :: Nat) [inventoryEventDate] :: InventoryEvent (pprec :: Nat) (sprec :: Nat) -> !Day [inventoryEventPrice] :: InventoryEvent (pprec :: Nat) (sprec :: Nat) -> !Quantity pprec [inventoryEventQuantity] :: InventoryEvent (pprec :: Nat) (sprec :: Nat) -> !Quantity sprec -- | Data definition for PnL-taking inventory history items. -- -- Essentially, values of this type represent a pnl-taking for a -- long/short inventory event and a matching short/long inventory event -- of the same quantity. Date refers to the date of the later event. If -- prices are different, PnL is non-zero. -- -- This data definition is polymorphic over the precision for, -- respectively: -- --
    --
  1. pprec precision of the price values,
  2. --
  3. sprec precision of the inventory event quantities, -- and
  4. --
  5. vprec precision of the monetary values such as PnL.
  6. --
-- -- Values of this type should not be directly manipulated. -- updateInventory method (and convenience wrappers) are in charge -- of creating values of this data type. data InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) MkInventoryHistoryItem :: !Day -> !Quantity vprec -> !InventoryEvent pprec sprec -> !InventoryEvent pprec sprec -> InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) [inventoryHistoryItemDate] :: InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !Day [inventoryHistoryItemPnl] :: InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !Quantity vprec [inventoryHistoryItemFst] :: InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !InventoryEvent pprec sprec [inventoryHistoryItemSnd] :: InventoryHistoryItem (pprec :: Nat) (sprec :: Nat) (vprec :: Nat) -> !InventoryEvent pprec sprec -- | Processes a new inventory event onto the inventory. -- -- Any event with 0 quantity is disregarded. updateInventory :: KnownNat pprec => KnownNat sprec => KnownNat vprec => InventoryEvent pprec sprec -> Inventory pprec sprec vprec -> (Seq (InventoryHistoryItem pprec sprec vprec), Inventory pprec sprec vprec) -- | Convenience wrapper for updateInventory which works with date, -- price and quantity. updateInventoryVP :: KnownNat pprec => KnownNat sprec => KnownNat vprec => Day -> Quantity pprec -> Quantity sprec -> Inventory pprec sprec vprec -> (Seq (InventoryHistoryItem pprec sprec vprec), Inventory pprec sprec vprec) -- | Convenience wrapper for updateInventory which works with date, -- price and quantity. updateInventoryVV :: KnownNat pprec => KnownNat sprec => KnownNat vprec => Day -> Quantity vprec -> Quantity sprec -> Inventory pprec sprec vprec -> (Seq (InventoryHistoryItem pprec sprec vprec), Inventory pprec sprec vprec) -- | Work-horse function for updating inventory. -- -- This is where the whole trick happens in this module. updateInventoryAux :: KnownNat pprec => KnownNat sprec => KnownNat vprec => Seq (InventoryHistoryItem pprec sprec vprec) -> InventoryEvent pprec sprec -> Inventory pprec sprec vprec -> (Seq (InventoryHistoryItem pprec sprec vprec), Inventory pprec sprec vprec) -- | Splits the event into two events as per the given quantity. -- -- If the event has a quantity of 100 and the desired quantity -- is 10, this function spits out two event with same -- information except that the first has a quantity of 10 and -- the second has a quantity of 90. splitEvent :: KnownNat pprec => KnownNat sprec => Quantity sprec -> InventoryEvent pprec sprec -> (InventoryEvent pprec sprec, InventoryEvent pprec sprec) -- | Pushes a new inventory event to the inventory. -- -- This function is to be called by the internal machinery that handles -- most of the critical tasks. Direct calls to this function will bypass -- the entire machinery. addInventoryEvent :: KnownNat pprec => KnownNat sprec => KnownNat vprec => InventoryEvent pprec sprec -> Inventory pprec sprec vprec -> Inventory pprec sprec vprec -- | Captures two events of same absolute quantities with different -- directions into a profit-taking inventory history item and updates the -- inventory. munchAll :: KnownNat pprec => KnownNat sprec => KnownNat vprec => InventoryEvent pprec sprec -> InventoryEvent pprec sprec -> Seq (InventoryEvent pprec sprec) -> Inventory pprec sprec vprec -> (InventoryHistoryItem pprec sprec vprec, Inventory pprec sprec vprec) -- | Data definition representing how two inventory events should be -- processed. data Munch (sprec :: Nat) MunchNo :: Munch (sprec :: Nat) MunchAll :: Munch (sprec :: Nat) MunchLeft :: Quantity sprec -> Munch (sprec :: Nat) MunchRight :: Quantity sprec -> Munch (sprec :: Nat) -- | Figures out how two inventory events should be processed. whatMunch :: KnownNat pprec => KnownNat sprec => InventoryEvent pprec sprec -> InventoryEvent pprec sprec -> Munch sprec instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec) => GHC.Show.Show (Haspara.Accounting.Inventory.InventoryEvent pprec sprec) instance GHC.Generics.Generic (Haspara.Accounting.Inventory.InventoryEvent pprec sprec) instance GHC.Classes.Eq (Haspara.Accounting.Inventory.InventoryEvent pprec sprec) instance (GHC.TypeNats.KnownNat vprec, GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec) => GHC.Show.Show (Haspara.Accounting.Inventory.InventoryHistoryItem pprec sprec vprec) instance GHC.Generics.Generic (Haspara.Accounting.Inventory.InventoryHistoryItem pprec sprec vprec) instance GHC.Classes.Eq (Haspara.Accounting.Inventory.InventoryHistoryItem pprec sprec vprec) instance (GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat vprec) => GHC.Show.Show (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance GHC.Generics.Generic (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance GHC.Classes.Eq (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance GHC.TypeNats.KnownNat sprec => GHC.Show.Show (Haspara.Accounting.Inventory.Munch sprec) instance GHC.Classes.Eq (Haspara.Accounting.Inventory.Munch sprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat vprec) => Data.Default.Class.Default (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat vprec) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat vprec) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Inventory.Inventory pprec sprec vprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat vprec) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Inventory.InventoryHistoryItem pprec sprec vprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec, GHC.TypeNats.KnownNat vprec) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Inventory.InventoryHistoryItem pprec sprec vprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Inventory.InventoryEvent pprec sprec) instance (GHC.TypeNats.KnownNat pprec, GHC.TypeNats.KnownNat sprec) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Inventory.InventoryEvent pprec sprec) -- | This module provides definitions for amounts used as in accounting. -- -- For balance definition that allows "Negative Balance" phenomenon, see -- Balance. module Haspara.Accounting.Amount -- | Data definition for amounts. data Amount (precision :: Nat) Amount :: !Side -> !UnsignedQuantity precision -> Amount (precision :: Nat) [amountSide] :: Amount (precision :: Nat) -> !Side [amountValue] :: Amount (precision :: Nat) -> !UnsignedQuantity precision -- | Returns the debit value of the Amount, if any. amountDebit :: KnownNat precision => Amount precision -> Maybe (UnsignedQuantity precision) -- | Returns the credit value of the Amount, if any. amountCredit :: KnownNat precision => Amount precision -> Maybe (UnsignedQuantity precision) -- | Builds the Amount for the given value for the given -- AccountKind. -- -- The value concept here refers to the value of a particular -- economic event as in the contribution of that event to the net-worth -- of the entity. -- -- This definition of the value is different than what we refer to in -- amountFromQuantity. In amountFromQuantity the -- quantity is simply reflecting the increment or decrement in a -- particular account of a particular AccountKind. -- -- For example, consider getting a loan: There are two immediate events -- due to this exchange: -- --
    --
  1. Inflow of cash of some quantity to an AccountKindAsset -- account.
  2. --
  3. Inflow of loan contract with some notional value of the same -- quantity to a 'AccountKindLiability acount.
  4. --
-- -- Let's say, the notional is USD 1,000. Therefore: -- --
    --
  1. Inflow of USD 1,000 to the cash account.
  2. --
  3. Inflow of a Loan Contract of USD 1,000 to the liability -- account.
  4. --
-- -- Conventionally, the latter is reflected as follow: -- --
--   >>> :set -XDataKinds
--   
--   >>> import Haspara.Quantity
--   
--   >>> amountFromQuantity AccountKindLiability (mkQuantity 1000 :: Quantity 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 1000.00}
--   
-- -- However, if the call-site is referring to values as in the net effect -- of the event to the net-worth of the entity, then: -- --
--   >>> amountFromValue AccountKindLiability (mkQuantity (-1000) :: Quantity 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 1000.00}
--   
-- -- For reference, given: -- --
--   >>> let valPos = mkQuantity 42 :: Quantity 2
--   
--   >>> let valNeg = mkQuantity (-42) :: Quantity 2
--   
-- -- ..., let's consider following events: -- -- We have an inflow and outflow of some assets, respectively: -- --
--   >>> amountFromValue AccountKindAsset valPos
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
--   >>> amountFromValue AccountKindAsset valNeg
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
-- -- We have some decrease and increase in our liabilities, respectively: -- --
--   >>> amountFromValue AccountKindLiability valPos
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
--   >>> amountFromValue AccountKindLiability valNeg
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
-- -- We have some increase and decrease in our equity, respectively: -- --
--   >>> amountFromValue AccountKindEquity valPos
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
--   >>> amountFromValue AccountKindEquity valNeg
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
-- -- We have some profit and loss in our PnL, respectively: -- --
--   >>> amountFromValue AccountKindRevenue valPos
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
--   >>> amountFromValue AccountKindRevenue valNeg
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
-- -- We have some decrease and increase in our expenses, respectively: -- --
--   >>> amountFromValue AccountKindExpense valPos
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
--   >>> amountFromValue AccountKindExpense valNeg
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
amountFromValue :: KnownNat precision => AccountKind -> Quantity precision -> Amount precision -- | Returns the value for the given Amount for the given -- AccountKind. -- -- This is dual to amountFromValue. -- -- For values of positive and negative net-effect on the net-worth of the -- entity, respectively: -- --
--   >>> :set -XDataKinds
--   
--   >>> import Haspara.Quantity
--   
--   >>> let valPos = mkQuantity 42 :: Quantity 2
--   
--   >>> let valNeg = mkQuantity (-42) :: Quantity 2
--   
-- -- ..., for a check function that checks if the roundtrip to a -- value is successful for a given AccountKind: -- --
--   >>> let check = \k v -> v == valueFromAmount k (amountFromValue k v)
--   
-- -- ..., and for the list of AccountKinds. -- --
--   >>> let kinds = [minBound .. maxBound] :: [AccountKind]
--   
--   >>> kinds
--   [AccountKindAsset,AccountKindLiability,AccountKindEquity,AccountKindRevenue,AccountKindExpense]
--   
-- -- All checks should pass: -- --
--   >>> all (\k -> check k valPos && check k valNeg) kinds
--   True
--   
valueFromAmount :: KnownNat precision => AccountKind -> Amount precision -> Quantity precision -- | Builds the Amount value for the given account kind and -- quantity. -- -- The concept of quantity here refers to the conventional concept -- of what it means for an Account of a given AccountKind. -- -- For example, a loan of USD 1,000 has an increase in our liabilities. -- Therefore, the quantity is expected to be positive: -- --
--   >>> :set -XDataKinds
--   
--   >>> import Haspara.Quantity
--   
--   >>> amountFromQuantity AccountKindLiability (mkQuantity 1000 :: Quantity 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 1000.00}
--   
-- -- Note amountFromValue function if you are rather working with -- values that are conceptually different than the quantity here -- whereby a value refers to the value of a particular economic -- event as in the contribution of that event to the net-worth of the -- entity. Therefore, above example would be reflected as follows to get -- the same Amount value: -- --
--   >>> amountFromValue AccountKindLiability (mkQuantity (-1000) :: Quantity 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 1000.00}
--   
-- -- Check amountFromValue documentation for further information. amountFromQuantity :: KnownNat precision => AccountKind -> Quantity precision -> Amount precision -- | Returns the quantity for the given amount. -- -- This is dual to amountFromQuantity. quantityFromAmount :: KnownNat precision => AccountKind -> Amount precision -> Quantity precision instance GHC.TypeNats.KnownNat precision => GHC.Show.Show (Haspara.Accounting.Amount.Amount precision) instance GHC.Classes.Ord (Haspara.Accounting.Amount.Amount precision) instance GHC.Generics.Generic (Haspara.Accounting.Amount.Amount precision) instance GHC.Classes.Eq (Haspara.Accounting.Amount.Amount precision) instance GHC.TypeNats.KnownNat precision => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Amount.Amount precision) instance GHC.TypeNats.KnownNat precision => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Amount.Amount precision) -- | This module provides data definitions and functions to work with -- journal entries. module Haspara.Accounting.Journal -- | Data definition for the journal entries of interest (like a general -- ledger.) -- -- A Journal is a list of JournalEntry records which are -- polymorphic over the precision of the monetary quantities, the account -- and event objects. newtype Journal (precision :: Nat) account event Journal :: [JournalEntry precision account event] -> Journal (precision :: Nat) account event [journalEntries] :: Journal (precision :: Nat) account event -> [JournalEntry precision account event] -- | Data definition for a journal entry. -- -- A journal entry has a (unique) identifier, date and description, and a -- list of JournalEntryItems. Journal entry definition is -- polymorphic over the precision of the monetary quantities, the account -- and event objects. data JournalEntry (precision :: Nat) account event JournalEntry :: !Text -> !Day -> ![JournalEntryItem precision account event] -> !Text -> JournalEntry (precision :: Nat) account event [journalEntryId] :: JournalEntry (precision :: Nat) account event -> !Text [journalEntryDate] :: JournalEntry (precision :: Nat) account event -> !Day [journalEntryItems] :: JournalEntry (precision :: Nat) account event -> ![JournalEntryItem precision account event] [journalEntryDescription] :: JournalEntry (precision :: Nat) account event -> !Text -- | Returns the total debit amount of a journal entry. journalEntryTotalDebit :: KnownNat precision => JournalEntry precision account event -> UnsignedQuantity precision -- | Returns the total credit amount of a journal entry. journalEntryTotalCredit :: KnownNat precision => JournalEntry precision account event -> UnsignedQuantity precision -- | Predicate to check if a journal entry is balanced or not. -- -- The logical check is indeed whether the total debit amount is equal to -- the total credit amount or not. isJournalEntryBalanced :: KnownNat precision => JournalEntry precision account event -> Bool -- | Data definition for a journal entry item. -- -- A journal entry item has a Side, an unsigned quantity as -- amount, an account that it belongs to and the event the item is -- originating from. Journal entry item definition is polymorphic over -- the precision of the monetary quantities, the account and event -- objects. data JournalEntryItem (precision :: Nat) account event JournalEntryItem :: !Amount precision -> !Account account -> !event -> !Maybe (JournalEntryItemInventoryEvent account event) -> JournalEntryItem (precision :: Nat) account event [journalEntryItemAmount] :: JournalEntryItem (precision :: Nat) account event -> !Amount precision [journalEntryItemAccount] :: JournalEntryItem (precision :: Nat) account event -> !Account account [journalEntryItemEvent] :: JournalEntryItem (precision :: Nat) account event -> !event [journalEntryItemInventoryEvent] :: JournalEntryItem (precision :: Nat) account event -> !Maybe (JournalEntryItemInventoryEvent account event) -- | Data definition for inventory event. data JournalEntryItemInventoryEvent account event JournalEntryItemInventoryEvent :: !Account account -> !event -> !Quantity 12 -> JournalEntryItemInventoryEvent account event [journalEntryItemInventoryEventPnlAccount] :: JournalEntryItemInventoryEvent account event -> !Account account [journalEntryItemInventoryEventEvent] :: JournalEntryItemInventoryEvent account event -> !event [journalEntryItemInventoryEventQuantity] :: JournalEntryItemInventoryEvent account event -> !Quantity 12 -- | Creates a JournalEntryItem from the given signed value, -- the account it belongs to and the event it is originating from. -- -- The value is defined as in amountFromValue function. mkJournalEntryItemFromValue :: KnownNat precision => Quantity precision -> Account account -> event -> JournalEntryItem precision account event -- | Creates a JournalEntryItem with inventory event informationfrom -- the given signed value, the account it belongs to and the event -- it is originating from. -- -- The value is defined as in amountFromValue function. mkInventoryJournalEntryItemFromValue :: KnownNat precision => Quantity precision -> Account account -> event -> Account account -> event -> Quantity 12 -> JournalEntryItem precision account event instance (GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Journal.JournalEntryItemInventoryEvent account event) instance GHC.Generics.Generic (Haspara.Accounting.Journal.JournalEntryItemInventoryEvent account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.Journal.JournalEntryItemInventoryEvent account event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Journal.JournalEntryItem precision account event) instance GHC.Generics.Generic (Haspara.Accounting.Journal.JournalEntryItem precision account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.Journal.JournalEntryItem precision account event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Journal.JournalEntry precision account event) instance GHC.Generics.Generic (Haspara.Accounting.Journal.JournalEntry precision account event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Journal.Journal precision account event) instance GHC.Generics.Generic (Haspara.Accounting.Journal.Journal precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Journal.Journal precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Journal.Journal precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Journal.JournalEntry precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Journal.JournalEntry precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Journal.JournalEntryItem precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Journal.JournalEntryItem precision account event) instance (Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Journal.JournalEntryItemInventoryEvent account event) instance (Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Journal.JournalEntryItemInventoryEvent account event) -- | This module provides definitions for balances used as in accounting. module Haspara.Accounting.Balance -- | Data definition for balances. -- -- This definition is similar to Amount, however, the value is -- allowed to be negative to reflect "Negative Balance" phenomenon. -- -- See -- https://www.accountingtools.com/articles/what-is-a-negative-balance.html data Balance (precision :: Nat) Balance :: !Side -> !Quantity precision -> !Inventory 8 12 precision -> Balance (precision :: Nat) [balanceSide] :: Balance (precision :: Nat) -> !Side [balanceValue] :: Balance (precision :: Nat) -> !Quantity precision [balanceInventory] :: Balance (precision :: Nat) -> !Inventory 8 12 precision -- | Returns the debit quantity, if any. balanceDebit :: KnownNat precision => Balance precision -> Maybe (Quantity precision) -- | Returns the credit quantity, if any. balanceCredit :: KnownNat precision => Balance precision -> Maybe (Quantity precision) -- | Updates the balance with the given amount. -- --
--   >>> :set -XDataKinds
--   
--   >>> import Data.Default (def)
--   
--   >>> import Haspara.Accounting.Amount
--   
--   >>> import Haspara.Accounting.Side
--   
--   >>> import Refined.Unsafe
--   
--   >>> let balance = Balance SideDebit 42 def :: Balance 2
--   
--   >>> balance
--   Balance {balanceSide = SideDebit, balanceValue = 42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}}
--   
--   >>> let amountDebit = Amount SideDebit (unsafeRefine 10) :: Amount 2
--   
--   >>> amountDebit
--   Amount {amountSide = SideDebit, amountValue = Refined 10.00}
--   
--   >>> let amountCredit = Amount SideCredit (unsafeRefine 10) :: Amount 2
--   
--   >>> amountCredit
--   Amount {amountSide = SideCredit, amountValue = Refined 10.00}
--   
--   >>> updateBalance balance amountDebit
--   Balance {balanceSide = SideDebit, balanceValue = 52.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}}
--   
--   >>> updateBalance balance amountCredit
--   Balance {balanceSide = SideDebit, balanceValue = 32.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}}
--   
updateBalance :: KnownNat precision => Balance precision -> Amount precision -> Balance precision -- | Updates the balance with additional inventory event. updateBalanceWithInventory :: KnownNat precision => Day -> Balance precision -> Amount precision -> Quantity 12 -> ([InventoryHistoryItem 8 12 precision], Balance precision) -- | Converts the balance to amount. -- --
--   >>> :set -XDataKinds
--   
--   >>> import Data.Default (def)
--   
--   >>> import Haspara.Accounting.Side
--   
--   >>> amountFromBalance (Balance SideDebit 42 def :: Balance 2)
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
--   >>> amountFromBalance (Balance SideDebit (-42) def :: Balance 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
--   >>> amountFromBalance (Balance SideCredit 42 def :: Balance 2)
--   Amount {amountSide = SideCredit, amountValue = Refined 42.00}
--   
--   >>> amountFromBalance (Balance SideCredit (-42) def :: Balance 2)
--   Amount {amountSide = SideDebit, amountValue = Refined 42.00}
--   
amountFromBalance :: KnownNat precision => Balance precision -> Amount precision -- | Returns the quantity of the balance given the account kind. -- -- See quantityFromAmount for the meaning of quantity. quantityFromBalance :: KnownNat precision => AccountKind -> Balance precision -> Quantity precision -- | Returns the value of the balance given the account kind. -- -- See valueFromAmount for the meaning of quantity. valueFromBalance :: KnownNat precision => AccountKind -> Balance precision -> Quantity precision instance GHC.TypeNats.KnownNat precision => GHC.Show.Show (Haspara.Accounting.Balance.Balance precision) instance GHC.Generics.Generic (Haspara.Accounting.Balance.Balance precision) instance GHC.Classes.Eq (Haspara.Accounting.Balance.Balance precision) instance GHC.TypeNats.KnownNat precision => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Balance.Balance precision) instance GHC.TypeNats.KnownNat precision => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Balance.Balance precision) -- | This module provides data definitions and functions for ledgers and -- postings. module Haspara.Accounting.Ledger -- | Data definition for a general ledger. newtype GeneralLedger (precision :: Nat) account event GeneralLedger :: [Ledger precision account event] -> GeneralLedger (precision :: Nat) account event [generalLedgerLedgers] :: GeneralLedger (precision :: Nat) account event -> [Ledger precision account event] -- | Data definition for a ledger. data Ledger (precision :: Nat) account event Ledger :: !Account account -> !Balance precision -> ![LedgerEntry precision event] -> Ledger (precision :: Nat) account event [ledgerAccount] :: Ledger (precision :: Nat) account event -> !Account account [ledgerOpening] :: Ledger (precision :: Nat) account event -> !Balance precision [ledgerRunning] :: Ledger (precision :: Nat) account event -> ![LedgerEntry precision event] -- | Returns the closing balance of a ledger. ledgerClosing :: KnownNat precision => Ledger precision account event -> Balance precision -- | Type encoding of a ledger item. data LedgerEntry (precision :: Nat) event LedgerEntry :: !Day -> !Amount precision -> !Text -> !event -> !Text -> !Balance precision -> LedgerEntry (precision :: Nat) event [ledgerEntryDate] :: LedgerEntry (precision :: Nat) event -> !Day [ledgerEntryAmount] :: LedgerEntry (precision :: Nat) event -> !Amount precision [ledgerEntryDescription] :: LedgerEntry (precision :: Nat) event -> !Text [ledgerEntryEvent] :: LedgerEntry (precision :: Nat) event -> !event [ledgerEntryPostingId] :: LedgerEntry (precision :: Nat) event -> !Text [ledgerEntryBalance] :: LedgerEntry (precision :: Nat) event -> !Balance precision -- | Initializes an empty ledger for a given account. initLedger :: KnownNat precision => Account account -> Ledger precision account event -- | Initializes a ledger with the given opening balance. initLedgerWithOpeningBalance :: KnownNat precision => Account account -> Balance precision -> Ledger precision account event -- | Initializes a ledger with the given opening value. -- -- See amountFromValue for the meaning of the concept of value. initLedgerWithOpeningValue :: KnownNat precision => Account account -> (Maybe (Quantity 12), Quantity precision) -> Ledger precision account event -- | Initializes a ledger with the given opening quantity. -- -- See amountFromQuantity for the meaning of the concept of -- quantity. initLedgerWithOpeningQuantity :: KnownNat precision => Account account -> (Maybe (Quantity 12), Quantity precision) -> Ledger precision account event -- | Posts a given list of journal entries to the given general ledger and -- returns the new general ledger. postEntries :: KnownNat precision => Eq account => Ord account => GeneralLedger precision account event -> [JournalEntry precision account event] -> GeneralLedger precision account event -- | Posts a given journal entry to the given general ledger and returns -- the new general ledger. postEntry :: KnownNat precision => Eq account => Ord account => GeneralLedger precision account event -> JournalEntry precision account event -> GeneralLedger precision account event -- | Posts a given journal entry item of a given journal entry to the given -- general ledger and returns the new general ledger. postEntryItem :: KnownNat precision => Eq account => Ord account => GeneralLedger precision account event -> JournalEntry precision account event -> JournalEntryItem precision account event -> GeneralLedger precision account event -- | Performs a posting to the given ledger. postItem :: KnownNat precision => Ledger precision account event -> Day -> Amount precision -> Text -> event -> Text -> Maybe (JournalEntryItemInventoryEvent account event) -> (Maybe (JournalEntry precision account event), Ledger precision account event) -- | Creates 2 journal entry items for the captured non-zero PnL. histItemToJournalEntryItem :: KnownNat precision => event -> Account account -> Account account -> InventoryHistoryItem 8 12 precision -> [JournalEntryItem precision account event] instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Ledger.LedgerEntry precision event) instance GHC.Generics.Generic (Haspara.Accounting.Ledger.LedgerEntry precision event) instance GHC.Classes.Eq event => GHC.Classes.Eq (Haspara.Accounting.Ledger.LedgerEntry precision event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Ledger.Ledger precision account event) instance GHC.Generics.Generic (Haspara.Accounting.Ledger.Ledger precision account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.Ledger.Ledger precision account event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.Ledger.GeneralLedger precision account event) instance GHC.Generics.Generic (Haspara.Accounting.Ledger.GeneralLedger precision account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.Ledger.GeneralLedger precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Ledger.GeneralLedger precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Ledger.GeneralLedger precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Ledger.Ledger precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Ledger.Ledger precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.Ledger.LedgerEntry precision event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.Ledger.LedgerEntry precision event) -- | This module provides data definitions and functions for trial -- balances. module Haspara.Accounting.TrialBalance -- | Data definition for a trial balance. newtype TrialBalance (precision :: Nat) account event TrialBalance :: [TrialBalanceItem precision account event] -> TrialBalance (precision :: Nat) account event [trialBalanceItems] :: TrialBalance (precision :: Nat) account event -> [TrialBalanceItem precision account event] -- | Data definition for a trial balance item. data TrialBalanceItem (precision :: Nat) account event TrialBalanceItem :: !Ledger precision account event -> !Balance precision -> TrialBalanceItem (precision :: Nat) account event [trialBalanceItemLedger] :: TrialBalanceItem (precision :: Nat) account event -> !Ledger precision account event [trialBalanceItemBalance] :: TrialBalanceItem (precision :: Nat) account event -> !Balance precision -- | Returns the amount of the trial balance item. This is a simple -- conversion from Balance to Amount. trialBalanceItemAmount :: KnownNat precision => TrialBalanceItem precision account event -> Amount precision -- | Given a general ledger, prepares the trial balance. prepareTrialBalance :: KnownNat precision => GeneralLedger precision account event -> TrialBalance precision account event -- | Converts a Ledger to a TrialBalanceItem. mkTrialBalanceItem :: KnownNat precision => Ledger precision account event -> TrialBalanceItem precision account event -- | Computes the trial balance totals as a 2-tuple of total debits and -- total credits. trialBalanceTotals :: KnownNat precision => TrialBalance precision account event -> (Balance precision, Balance precision) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.TrialBalance.TrialBalanceItem precision account event) instance GHC.Generics.Generic (Haspara.Accounting.TrialBalance.TrialBalanceItem precision account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.TrialBalance.TrialBalanceItem precision account event) instance (GHC.TypeNats.KnownNat precision, GHC.Show.Show account, GHC.Show.Show event) => GHC.Show.Show (Haspara.Accounting.TrialBalance.TrialBalance precision account event) instance GHC.Generics.Generic (Haspara.Accounting.TrialBalance.TrialBalance precision account event) instance (GHC.Classes.Eq account, GHC.Classes.Eq event) => GHC.Classes.Eq (Haspara.Accounting.TrialBalance.TrialBalance precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.TrialBalance.TrialBalance precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.TrialBalance.TrialBalance precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.FromJSON.FromJSON account, Data.Aeson.Types.FromJSON.FromJSON event) => Data.Aeson.Types.FromJSON.FromJSON (Haspara.Accounting.TrialBalance.TrialBalanceItem precision account event) instance (GHC.TypeNats.KnownNat precision, Data.Aeson.Types.ToJSON.ToJSON account, Data.Aeson.Types.ToJSON.ToJSON event) => Data.Aeson.Types.ToJSON.ToJSON (Haspara.Accounting.TrialBalance.TrialBalanceItem precision account event) -- | This module provides a collection of definitions for a rudimentary -- accounting functionality. module Haspara.Accounting -- | This module provides high-level definitions of haspara -- library. -- -- haspara provides rudimentary (and experimental) accounting -- functionality, too. These definitions can be found under -- Haspara.Accounting module. module Haspara -- | This module provides template-haskell functions for various -- Haspara definitions. module Haspara.TH -- | Constructs a Quantity value at compile-time using -- -XTemplateHaskell. -- --
--   >>> :set -XDataKinds
--   
--   >>> :set -XOverloadedStrings
--   
--   >>> :set -XTemplateHaskell
--   
--   >>> $$(quantityTH 0.00) :: Quantity 2
--   0.00
--   
--   >>> $$(quantityTH 0.09) :: Quantity 2
--   0.09
--   
--   >>> $$(quantityTH 0.009) :: Quantity 2
--   ...
--   ..."Underflow while trying to create quantity: 9.0e-3"
--   ...
--   
--   >>> $$(quantityTH 0.009) :: Quantity 3
--   0.009
--   
quantityTH :: KnownNat s => Scientific -> Code Q (Quantity s) -- | Constructs a Currency value at compile-time using -- -XTemplateHaskell. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> :set -XTemplateHaskell
--   
--   >>> $$(currencyTH "USD")
--   USD
--   
--   >>> $$(currencyTH "usd")
--   ...
--   ...Currency code error! Expecting at least 3 uppercase ASCII letters, but received: usd
--   ...
--   
currencyTH :: Text -> Code Q Currency -- | Constructs a CurrencyPair value at compile-time using -- -XTemplateHaskell. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> :set -XTemplateHaskell
--   
--   >>> $$(currencyPairTH "EUR" "USD")
--   EUR/USD
--   
--   >>> $$(currencyPairTH "USD" "USD")
--   USD/USD
--   
--   >>> $$(currencyPairTH "USD" "eur")
--   ...
--   ... Currency code error! Expecting at least 3 uppercase ASCII letters, but received: eur
--   ...
--   
currencyPairTH :: Text -> Text -> Code Q CurrencyPair