h$!      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                                                                                                               None& %(-.0235678;>?haspara'Common Aeson encoding/decoding options.hasparaAeson encoding/decoding options for uppercase constructor tag modifiersNone) %(-./0235678;<=>?thaspara!Type encoding of a currency pair.1 values are constructed via the data constructor:CurrencyPair "EUR" "USD"EUR/USD and  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\"}"haspara Base currency+ of the currency pair. Also referred to as counter currency.hasparaQuote currency+ of the currency pair. Also referred to as transaction currency.haspara:Type encoding for currency symbol values with a syntax of [A-Z]{3}[A-Z]*. values can be constructed via   that works in   context:/mkCurrencyError "EUR" :: Either T.Text Currency Right EUR ... or via   that works in  context:&mkCurrencyFail "EUR" :: Maybe CurrencyJust EURAn = instance is provided as well which is unsafe but convenient:"EUR" :: CurrencyEUR hasparaSmart constructor for  values within  context.,mkCurrencyError "" :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: "-mkCurrencyError " " :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: ".mkCurrencyError "AB" :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: AB"1mkCurrencyError " ABC " :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: ABC "/mkCurrencyError "ABC" :: Either T.Text Currency Right ABC hasparaSmart constructor for  values within  context.#mkCurrencyFail "" :: Maybe CurrencyNothing%mkCurrencyFail "US" :: Maybe CurrencyNothing&mkCurrencyFail "usd" :: Maybe CurrencyNothing&mkCurrencyFail "USD" :: Maybe CurrencyJust USD haspara"Parser that parses currency codes.,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"0MP.runParser currencyCodeParser "Example" "ABCD" Right "ABCD"2MP.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 = ""}}) haspara Converts a  to a 2-tuple of  values.*toCurrencyTuple (CurrencyPair "EUR" "USD") (EUR,USD) hasparaConverts a 2-tuple of  values to a . fromCurrencyTuple ("EUR", "USD")EUR/USDhaspara instance for . Aeson.encode ("USD" :: Currency) "\"USD\""haspara instance for .3Aeson.eitherDecode "\"\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: "4Aeson.eitherDecode "\"A\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: A"5Aeson.eitherDecode "\"AB\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: AB"6Aeson.eitherDecode "\"ABC\"" :: Either String Currency Right ABC7Aeson.eitherDecode "\"ABCD\"" :: Either String Currency Right ABCDhaspara instance for ."USD" :: CurrencyUSDhaspara instance for ."USD" :: CurrencyUSDhaspara instance for .CurrencyPair "EUR" "USD"EUR/USD    None) %(-./0235678;<=>?"haspara!Type encoding for account values."This definition provides both the ! 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.,let acc = Account AccountKindAsset (1 ::Int)Data.Aeson.encode acc#"{\"kind\":\"ASSET\",\"object\":1}"8Data.Aeson.decode @(Account Int) (Data.Aeson.encode acc)Just (Account {accountKind = AccountKindAsset, accountObject = 1})5Data.Aeson.decode (Data.Aeson.encode acc) == Just accTrue!haspara&Type encoding for ledger account type.This type covers both balance sheet and income statement account types: For balance sheet accounts:Asset (") Liability (#)Equity ($)For income statement accounts: Revenue (%) Expense (&) and  instances, too: *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\""'haspara+Provides textual representation of a given !. accountKindText AccountKindAsset"Asset"$accountKindText AccountKindLiability "Liability"!accountKindText AccountKindEquity"Equity""accountKindText AccountKindRevenue "Revenue""accountKindText AccountKindExpense "Expense"  !&%$#"' !&%$#"' None' %(-./0235678;>?A:8hasparaType definition for unsigned 9 values.9hasparaType encoding for quantity values with a given scaling (digits after the decimal point).42 :: Quantity 04242 :: Quantity 142.042 :: Quantity 242.0041 + 1 :: Quantity 242.0043 - 1 :: Quantity 242.002 * 3 * 7 :: Quantity 242.00negate (-42) :: Quantity 242.00abs (-42) :: Quantity 242.00signum (-42) :: Quantity 2-1.00fromInteger 42 :: Quantity 242.00mkQuantity 0.415 :: Quantity 20.42mkQuantity 0.425 :: Quantity 20.425mkQuantityLossless 0.42 :: Either String (Quantity 2) Right 0.426mkQuantityLossless 0.415 :: Either String (Quantity 2)7Left "Underflow while trying to create quantity: 0.415"<haspara Constructs 9 values from  values in a lossy way.This function uses C> in case that the lossless attempt fails. We could have used C directly. However, C is doing too much (see D). Therefore, we are first attempting a lossless construction (see =) and we fallback to C) in case the lossless construction fails.mkQuantity 0 :: Quantity 00mkQuantity 0 :: Quantity 10.0mkQuantity 0 :: Quantity 20.00mkQuantity 0.04 :: Quantity 10.0mkQuantity 0.05 :: Quantity 10.0mkQuantity 0.06 :: Quantity 10.1mkQuantity 0.14 :: Quantity 10.1mkQuantity 0.15 :: Quantity 10.2mkQuantity 0.16 :: Quantity 10.2mkQuantity 0.04 :: Quantity 20.04mkQuantity 0.05 :: Quantity 20.05mkQuantity 0.06 :: Quantity 20.06mkQuantity 0.14 :: Quantity 20.14mkQuantity 0.15 :: Quantity 20.15mkQuantity 0.16 :: Quantity 20.16mkQuantity 0.04 :: Quantity 30.040mkQuantity 0.05 :: Quantity 30.050mkQuantity 0.06 :: Quantity 30.060mkQuantity 0.14 :: Quantity 30.140mkQuantity 0.15 :: Quantity 30.150mkQuantity 0.16 :: Quantity 30.160=haspara Constructs 9 values from  values in a lossy way.2mkQuantityLossless 0 :: Either String (Quantity 0)Right 02mkQuantityLossless 0 :: Either String (Quantity 1) Right 0.02mkQuantityLossless 0 :: Either String (Quantity 2) Right 0.005mkQuantityLossless 0.04 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 4.0e-2"5mkQuantityLossless 0.05 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 5.0e-2"5mkQuantityLossless 0.06 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 6.0e-2"5mkQuantityLossless 0.14 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.14"5mkQuantityLossless 0.15 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.15"5mkQuantityLossless 0.16 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.16"5mkQuantityLossless 0.04 :: Either String (Quantity 2) Right 0.045mkQuantityLossless 0.05 :: Either String (Quantity 2) Right 0.055mkQuantityLossless 0.06 :: Either String (Quantity 2) Right 0.065mkQuantityLossless 0.14 :: Either String (Quantity 2) Right 0.145mkQuantityLossless 0.15 :: Either String (Quantity 2) Right 0.155mkQuantityLossless 0.16 :: Either String (Quantity 2) Right 0.165mkQuantityLossless 0.04 :: Either String (Quantity 3) Right 0.0405mkQuantityLossless 0.05 :: Either String (Quantity 3) Right 0.0505mkQuantityLossless 0.06 :: Either String (Quantity 3) Right 0.0605mkQuantityLossless 0.14 :: Either String (Quantity 3) Right 0.1405mkQuantityLossless 0.15 :: Either String (Quantity 3) Right 0.1505mkQuantityLossless 0.16 :: Either String (Quantity 3) Right 0.160>hasparaRounds given quantity by k digits.?@ABCD 9:;8<=>?@ABCDNone) %(-./0235678;<=>?SPhaspara3Type encoding for FX rate quotation database for a .VhasparaType encoding for a dictionary-based FX rate quotation database for various  values.Whaspara:Type encoding for FX rate quotations with fixed precision.%An FX rate quotation is a 3-tuple of: +a currency pair the rate is quoted for, and-a date that the quotation is effective as of,0a (positive) rate as the value of the quotation.YhasparaCurrency pair of the FX rate.ZhasparaActual date of the FX rate.[haspara%(Positive) rate value of the FX rate.\hasparaSmart constructor for W values within   context.The rate is expected to be a positive value. If it is not, the function will throw an error.mkFxQuoteError @(Either _) @2 "EUR" "USD" (read "2021-12-31") 1.16Right (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"]hasparaSmart constructor for W values within  context.The rate is expected to be a positive value. If it is not, the function will fail. >>> 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^hasparaUnsafe W constructor that s if it fails.7mkFxQuoteUnsafe @2 "EUR" "USD" (read "2021-12-31") 1.16MkFxQuote {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..._haspara9Attempts to find and return the FX quotation for a given  as of a give  in a given V.`haspara:Attempts to find and return the FX quotation as of a give  in a given P.ahaspara)Returns empty FX rate quotation database.emptyFxQuoteDatabase @8 fromList []bhaspara8Adds a list of FX rate quotations to the given database.&let database = emptyFxQuoteDatabase @8addFxQuotes [] database fromList []addFxQuotes [mkFxQuoteUnsafe @8 "EUR" "USD" (read "2021-01-31") 1.13] databasefromList [(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] databasefromList [(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})]chaspara0Adds an FX rate quotation to the given database.dhaspara;Initializes FX quote pair database with the given FX quote.ehasparaUpdates an existing FX quote pair database with the given FX quote.\haspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive.]haspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive.^haspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive._haspara/FX quotation database to perform the lookup on.haspara3Currency pair we are looking for the quotation for.haspara.Date the quotation we look for is valid as of.PQUTSRVWX[ZY\]^_`abcdeWX[ZY\]^VPQUTSR_`abcdeNone) %(-./0235678;<=>?[Y mhaspara*Type encoding of exceptions thrown by the  module.nhasparaIndicates that we received a currency other than the expected currency.ohasparaIndicates that we received a currency other than the expected currency.phasparaIndicates that we received a currency other than the expected currency.qhaspara$Type encoding of a monetary context.rhasparaConverts 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.shasparaConverts 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) thaspara(Type encoding for dated monetary values.'A dated monetary value is a 3-tuple of: 2a date when the monetary value is effective as of,'the currency of the monetary value, and#the quantity of the monetary value.yhasparaAttempts to convert the given t to another using the given W value.This function runs some guards before attempting to do the conversion: Base currency of the FX rate quotation should be the same as the currency of the monetary value, throws n otherwise.Date of the FX rate quotation should be equal to or greater than the date of the monetary value, throws o otherwise.(Rate of the FX rate quotation should be 16 if the base and quote quotation are same, throws p otherwise.nhasparaExpected currencyhasparaReceived currencyohasparaDate on and onwards of interesthaspara Date receivedphaspara6FX rate quotation that is interpreted as inconsistent. mponqsrtuxwvy tuxwvqsrymponNone& %(-.0235678;>?ehaspara8Data definition for encoding the debit/credit indicator.hasparaGives the other side.otherSide SideDebit SideCreditotherSide SideCredit SideDebithaspara Computes the  by the given ! and the sign of the given 9.The sign of the 91 is indeed a proxy for whether the event of the 9 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:Kind of accountDebitCreditAssetIncreaseDecrease LiabilityDecreaseIncreaseEquity/CapitalDecreaseIncreaseIncome/RevenueDecreaseIncreaseExpenseCostDividendIncreaseDecrease :set -XDataKindsimport Haspara.Quantity0let decrement = mkQuantity (-0.42) :: Quantity 2*let nocrement = mkQuantity 0 :: Quantity 2-let increment = mkQuantity 0.42 :: Quantity 2fmap (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]haspara&Returns the "normal" side for a given !.&Note the following mapping as a guide:Kind of AccountNormal BalanceNegative BalanceAssetDebitCredit LiabilityCreditDebitEquityCreditDebitRevenueCreditDebitExpenseDebitCredithaspara instance for .Aeson.encode SideDebit"\"db\""Aeson.encode SideCredit"\"cr\""7Aeson.decode (Aeson.encode SideDebit) == Just SideDebitTrue9Aeson.decode (Aeson.encode SideCredit) == Just SideCreditTruehaspara instance for .1Aeson.eitherDecode "\"db\"" :: Either String SideRight SideDebit1Aeson.eitherDecode "\"cr\"" :: Either String SideRight SideCredit5Aeson.eitherDecode "\"hebele\"" :: Either String SideLeft "Error in $: Unkown side indicator: \"hebele\". Expecting one of \"db\" or \"cr\""None' %(-./0235678;>?~ hasparaData definition for amounts.hasparaReturns the debit value of the  , if any.haspara Returns the credit value of the  , if any.haspara Builds the  for the given value for the given !.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 . In  the quantity is simply reflecting the increment or decrement in a particular account of a particular !.For example, consider getting a loan: There are two immediate events due to this exchange: &Inflow of cash of some quantity to an " account.Inflow of loan contract with some notional value of the same quantity to a 'AccountKindLiability acount.0Let's say, the notional is USD 1,000. Therefore: (Inflow of USD 1,000 to the cash account.Inflow of a Loan Contract of USD 1,000 to the liability account.2Conventionally, the latter is reflected as follow:import Haspara.QuantityamountFromQuantity 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 v == valueFromAmount k (amountFromValue k v)..., and for the list of !s.3let kinds = [minBound .. maxBound] :: [AccountKind]kinds[AccountKindAsset,AccountKindLiability,AccountKindEquity,AccountKindRevenue,AccountKindExpense]All checks should pass:2all (\k -> check k valPos && check k valNeg) kindsTruehaspara Builds the / value for the given account kind and quantity.The concept of quantity here refers to the conventional concept of what it means for an  of a given !.For example, a loan of USD 1,000 has an increase in our liabilities. Therefore, the quantity is expected to be positive:import Haspara.QuantityamountFromQuantity AccountKindLiability (mkQuantity 1000 :: Quantity 2)?Amount {amountSide = SideCredit, amountValue = Refined 1000.00}Note  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  value:amountFromValue AccountKindLiability (mkQuantity (-1000) :: Quantity 2)?Amount {amountSide = SideCredit, amountValue = Refined 1000.00}Check ' documentation for further information.haspara*Returns the quantity for the given amount.This is dual to .haspara instance for .import Haspara.Accounting.Sideimport Haspara.Quantityimport Refined.UnsafeAeson.encode (Amount SideDebit (unsafeRefine (mkQuantity 42 :: Quantity 2)))""{\"side\":\"db\",\"value\":42.0}"Aeson.encode (Amount SideCredit (unsafeRefine (mkQuantity 42 :: Quantity 2)))""{\"side\":\"cr\",\"value\":42.0}"Aeson.eitherDecode (Aeson.encode (Amount SideDebit (unsafeRefine (mkQuantity 42 :: Quantity 2)))) :: Either String (Amount 2)Right (Amount {amountSide = SideDebit, amountValue = Refined 42.00})Aeson.eitherDecode (Aeson.encode (Amount SideCredit (unsafeRefine (mkQuantity 42 :: Quantity 2)))) :: Either String (Amount 2)Right (Amount {amountSide = SideCredit, amountValue = Refined 42.00})haspara instance for .Aeson.eitherDecode "{\"side\": \"db\", \"value\": 42}" :: Either String (Amount 2)Right (Amount {amountSide = SideDebit, amountValue = Refined 42.00})Aeson.eitherDecode "{\"side\": \"cr\", \"value\": 42}" :: Either String (Amount 2)Right (Amount {amountSide = SideCredit, amountValue = Refined 42.00})   None' %(-./0235678;>?haspara)Data definition for a journal entry item.A journal entry item has a , 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.haspara$Data definition for a journal entry.A journal entry has a (unique) identifier, date and description, and a list of s. Journal entry definition is polymorphic over the precision of the monetary quantities, the account and event objects.hasparaData definition for the journal entries of interest (like a general ledger.)A  is a list of  records which are polymorphic over the precision of the monetary quantities, the account and event objects.haspara2Returns the total debit amount of a journal entry.haspara3Returns the total credit amount of a journal entry.haspara9Predicate 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.haspara Creates a  from the given signed quantity, the account it belongs to and the event it is originating from.The quantity is defined as in  function.haspara Creates a  from the given signed value, the account it belongs to and the event it is originating from.The value is defined as in  function. None' %(-./0235678;>?^ hasparaData definition for balances.This definition is similar to , however, the value is allowed to be negative to reflect "Negative Balance" phenomenon.See https://www.accountingtools.com/articles/what-is-a-negative-balance.htmlhaspara#Returns the debit quantity, if any.haspara$Returns the credit quantity, if any.haspara*Updates the balance with the given amount. import Haspara.Accounting.Amountimport Haspara.Accounting.Sideimport Refined.Unsafe/let balance = Balance SideDebit 42 :: Balance 2balance7Balance {balanceSide = SideDebit, balanceValue = 42.00}let amountDebit = Amount SideDebit (unsafeRefine 10) :: Amount 2 amountDebitAeson.encode (Balance SideDebit (mkQuantity 42 :: Quantity 2))""{\"side\":\"db\",\"value\":42.0}"?Aeson.encode (Balance SideCredit (mkQuantity 42 :: Quantity 2))""{\"side\":\"cr\",\"value\":42.0}"Aeson.eitherDecode (Aeson.encode (Balance SideDebit (mkQuantity 42 :: Quantity 2))) :: Either String (Balance 2)?Right (Balance {balanceSide = SideDebit, balanceValue = 42.00})Aeson.eitherDecode (Aeson.encode (Balance SideCredit (mkQuantity 42 :: Quantity 2))) :: Either String (Balance 2)Right (Balance {balanceSide = SideCredit, balanceValue = 42.00})For negative balances:Aeson.encode (Balance SideDebit (mkQuantity (-42) :: Quantity 2))#"{\"side\":\"db\",\"value\":-42.0}"Aeson.encode (Balance SideCredit (mkQuantity (-42) :: Quantity 2))#"{\"side\":\"cr\",\"value\":-42.0}"Aeson.eitherDecode (Aeson.encode (Balance SideDebit (mkQuantity (-42) :: Quantity 2))) :: Either String (Balance 2)Right (Balance {balanceSide = SideDebit, balanceValue = -42.00})Aeson.eitherDecode (Aeson.encode (Balance SideCredit (mkQuantity (-42) :: Quantity 2))) :: Either String (Balance 2)Right (Balance {balanceSide = SideCredit, balanceValue = -42.00})haspara instance for .For normal balances:Aeson.eitherDecode "{\"side\": \"db\", \"value\": 42}" :: Either String (Balance 2)?Right (Balance {balanceSide = SideDebit, balanceValue = 42.00})Aeson.eitherDecode "{\"side\": \"cr\", \"value\": 42}" :: Either String (Balance 2)Right (Balance {balanceSide = SideCredit, balanceValue = 42.00})For negative balances:Aeson.eitherDecode "{\"side\": \"db\", \"value\": -42}" :: Either String (Balance 2)Right (Balance {balanceSide = SideDebit, balanceValue = -42.00})Aeson.eitherDecode "{\"side\": \"cr\", \"value\": -42}" :: Either String (Balance 2)Right (Balance {balanceSide = SideCredit, balanceValue = -42.00})   None) %(-./0235678;<=>? hasparaType encoding of a ledger item.hasparaData definition for a ledger.haspara%Data definition for a general ledger.haspara(Returns the closing balance of a ledger.haspara0Initializes an empty ledger for a given account.haspara4Initializes a ledger with the given opening balance.haspara2Initializes a ledger with the given opening value.See ) for the meaning of the concept of value.haspara5Initializes a ledger with the given opening quantity.See , for the meaning of the concept of quantity.hasparaPosts a given list of journal entries to the given general ledger and returns the new general ledger.hasparaPosts a given journal entry to the given general ledger and returns the new general ledger.hasparaPosts a given journal entry item of a given journal entry to the given general ledger and returns the new general ledger.haspara'Performs a posting to the given ledger. None' %(-./0235678;>?6haspara)Data definition for a trial balance item.haspara$Data definition for a trial balance.hasparaReturns the amount of the trial balance item. This is a simple conversion from  to .haspara3Given a general ledger, prepares the trial balance.haspara Converts a  to a .hasparaComputes the trial balance totals as a 2-tuple of total debits and total credits.  None& %(-.0235678;>? !&%$"#'None& %(-.0235678;>?< 89:;<=>?@ABCDPQUTRSVWX[YZ\]^_`abcdempnoqrstuxvwy None& %(-.0235678;>?haspara Constructs a 9 value at compile-time using -XTemplateHaskell.!$$(quantityTH 0.00) :: Quantity 20.00!$$(quantityTH 0.09) :: Quantity 20.09"$$(quantityTH 0.009) :: Quantity 2...6..."Underflow while trying to create quantity: 9.0e-3"..."$$(quantityTH 0.009) :: Quantity 30.009haspara Constructs a  value at compile-time using -XTemplateHaskell.$$(currencyTH "USD")USD$$(currencyTH "usd")......Currency code error! Expecting at least 3 uppercase ASCII letters, but received: usd...haspara Constructs a  value at compile-time using -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...None' %(-.0235678;>?  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abccdefghijklmnopqrstuvwxyz{|}~                                                                                                               &haspara-0.0.0.5-EkkfyzMRwPgIJNppmBSdYMHaspara.Internal.AesonHaspara.CurrencyHaspara.Accounting.AccountHaspara.QuantityHaspara.FxQuoteHaspara.MonetaryHaspara.Accounting.SideHaspara.Accounting.AmountHaspara.Accounting.JournalHaspara.Accounting.BalanceHaspara.Accounting.LedgerHaspara.Accounting.TrialBalance Haspara.TH Data.AesonFromJSONToJSONHasparaMonetaryAccountHaspara.Accounting Paths_hasparacommonAesonOptionsaesonOptionsForSingleTag CurrencyPaircurrencyPairBasecurrencyPairQuoteCurrency MkCurrency currencyCodemkCurrencyErrormkCurrencyFailcurrencyCodeParsertoCurrencyTuplefromCurrencyTuple$fToJSONCurrency$fFromJSONCurrency$fShowCurrency$fIsStringCurrency$fShowCurrencyPair$fToJSONCurrencyPair$fFromJSONCurrencyPair$fEqCurrencyPair$fGenericCurrencyPair$fOrdCurrencyPair$fLiftLiftedRepCurrencyPair $fEqCurrency$fHashableCurrency $fOrdCurrency$fLiftLiftedRepCurrency accountKind accountObject AccountKindAccountKindAssetAccountKindLiabilityAccountKindEquityAccountKindRevenueAccountKindExpenseaccountKindText$fToJSONAccountKind$fFromJSONAccountKind$fHashableAccountKind$fToJSONAccount$fFromJSONAccount$fHashableAccount $fEqAccount$fGenericAccount $fOrdAccount $fShowAccount$fBoundedAccountKind$fEnumAccountKind$fEqAccountKind$fGenericAccountKind$fOrdAccountKind$fShowAccountKindUnsignedQuantityQuantity MkQuantity unQuantity mkQuantitymkQuantityLossless roundQuantitytimes timesLosslesssumUnsignedQuantity absQuantity mkQuantityAuxroundScientific$fShowQuantity$fFractionalArith $fNumArith$fToJSONQuantity$fFromJSONQuantity $fEqQuantity $fOrdQuantity$fGenericQuantity $fNumQuantity$fLiftLiftedRepQuantity$fLiftLiftedRepDecimalFxQuotePairDatabasefxQuotePairDatabasePairfxQuotePairDatabaseTablefxQuotePairDatabaseSincefxQuotePairDatabaseUntilFxQuoteDatabaseFxQuote MkFxQuote fxQuotePair fxQuoteDate fxQuoteRatemkFxQuoteError mkFxQuoteFailmkFxQuoteUnsafe findFxQuotefindFxQuoteAuxemptyFxQuoteDatabase addFxQuotes addFxQuoteinitFxQuotePairDatabaseupdateFxQuotePairDatabase$fToJSONFxQuote$fFromJSONFxQuote$fShowFxQuotePairDatabase $fEqFxQuote$fGenericFxQuote $fOrdFxQuote $fShowFxQuoteMonetaryExceptionIncompatibleCurrenciesExceptionIncompatibleDatesExceptionInconsistentFxQuoteExceptionconvertM convertAsofMMoney moneyDate moneyCurrency moneyQuantityconvert $fToJSONMoney$fFromJSONMoney$fExceptionMonetaryException $fEqMoney$fGenericMoney $fOrdMoney $fShowMoney$fShowMonetaryExceptionSide SideDebit SideCredit otherSidesideByAccountKindnormalSideByAccountKind $fToJSONSide$fFromJSONSide$fEqSide $fOrdSide $fShowSideAmount amountSide amountValue amountDebit amountCreditamountFromValuevalueFromAmountamountFromQuantityquantityFromAmount$fToJSONAmount$fFromJSONAmount $fEqAmount$fGenericAmount $fOrdAmount $fShowAmountJournalEntryItemjournalEntryItemAmountjournalEntryItemAccountjournalEntryItemEvent JournalEntryjournalEntryIdjournalEntryDatejournalEntryItemsjournalEntryDescriptionJournaljournalEntriesjournalEntryTotalDebitjournalEntryTotalCreditisJournalEntryBalancedmkJournalEntryItemFromQuantitymkJournalEntryItemFromValue$fToJSONJournalEntryItem$fFromJSONJournalEntryItem$fToJSONJournalEntry$fFromJSONJournalEntry$fToJSONJournal$fFromJSONJournal$fGenericJournal $fShowJournal$fGenericJournalEntry$fShowJournalEntry$fEqJournalEntryItem$fGenericJournalEntryItem$fShowJournalEntryItemBalance balanceSide balanceValue balanceDebit balanceCredit updateBalanceamountFromBalancequantityFromBalancevalueFromBalance$fToJSONBalance$fFromJSONBalance $fEqBalance$fGenericBalance $fShowBalance LedgerEntryledgerEntryDateledgerEntryAmountledgerEntryDescriptionledgerEntryEventledgerEntryPostingIdledgerEntryBalanceLedger ledgerAccount ledgerOpening ledgerRunning GeneralLedgergeneralLedgerLedgers ledgerClosing initLedgerinitLedgerWithOpeningBalanceinitLedgerWithOpeningValueinitLedgerWithOpeningQuantity postEntries postEntry postEntryItempostItem$fToJSONLedgerEntry$fFromJSONLedgerEntry$fToJSONLedger$fFromJSONLedger$fToJSONGeneralLedger$fFromJSONGeneralLedger$fEqGeneralLedger$fGenericGeneralLedger$fShowGeneralLedger $fEqLedger$fGenericLedger $fShowLedger$fEqLedgerEntry$fGenericLedgerEntry$fShowLedgerEntryTrialBalanceItemtrialBalanceItemLedgertrialBalanceItemBalance TrialBalancetrialBalanceItemstrialBalanceItemAmountprepareTrialBalancemkTrialBalanceItemtrialBalanceTotals$fToJSONTrialBalanceItem$fFromJSONTrialBalanceItem$fToJSONTrialBalance$fFromJSONTrialBalance$fEqTrialBalance$fGenericTrialBalance$fShowTrialBalance$fEqTrialBalanceItem$fGenericTrialBalanceItem$fShowTrialBalanceItem quantityTH currencyTHcurrencyPairTH$aeson-2.0.3.0-2OVHsUhPzTcLotCtpJ9DT0Data.Aeson.Types.FromJSONData.Aeson.Types.ToJSON mtl-2.2.2Control.Monad.Error.Class MonadError#text-1.2.5.0-IEal7YJCEpPE23BnjRa8JhData.Text.InternalTextbaseControl.Monad.Fail MonadFail Data.StringIsStringGHC.ShowShow)scientific-0.3.7.0-1cuz7K99vCtLQ884HOpguaData.Scientific Scientifictemplate-haskellLanguage.Haskell.TH.SyntaxLiftGHC.Errerror time-1.9.3Data.Time.Calendar.DaysDayversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName