haspara-0.0.0.8: A library providing definitions to work with monetary values.
Safe HaskellSafe-Inferred
LanguageHaskell2010

Haspara.Accounting.Balance

Description

This module provides definitions for balances used as in accounting.

Synopsis

Documentation

data Balance (precision :: Nat) Source #

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

Constructors

Balance 

Fields

Instances

Instances details
KnownNat precision => FromJSON (Balance precision) Source #

FromJSON instance for Balance.

For normal balances:

>>> :set -XDataKinds
>>> :set -XOverloadedStrings
>>> Aeson.eitherDecode "{\"side\": \"db\", \"value\": 42, \"inventory\": {\"current\": [], \"history\": [], \"total\": 0.0}}" :: Either String (Balance 2)
Right (Balance {balanceSide = SideDebit, balanceValue = 42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
>>> Aeson.eitherDecode "{\"side\": \"cr\", \"value\": 42, \"inventory\": {\"current\": [], \"history\": [], \"total\": 0.0}}" :: Either String (Balance 2)
Right (Balance {balanceSide = SideCredit, balanceValue = 42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})

For negative balances:

>>> Aeson.eitherDecode "{\"side\": \"db\", \"value\": -42, \"inventory\": {\"current\": [], \"history\": [], \"total\": 0.0}}" :: Either String (Balance 2)
Right (Balance {balanceSide = SideDebit, balanceValue = -42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
>>> Aeson.eitherDecode "{\"side\": \"cr\", \"value\": -42, \"inventory\": {\"current\": [], \"history\": [], \"total\": 0.0}}" :: Either String (Balance 2)
Right (Balance {balanceSide = SideCredit, balanceValue = -42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
Instance details

Defined in Haspara.Accounting.Balance

Methods

parseJSON :: Value -> Parser (Balance precision) #

parseJSONList :: Value -> Parser [Balance precision] #

KnownNat precision => ToJSON (Balance precision) Source #

ToJSON instance for Balance.

For normal balances:

>>> :set -XDataKinds
>>> import Data.Default (def)
>>> import Haspara.Accounting.Side
>>> import Haspara.Quantity
>>> Aeson.encode (Balance SideDebit (mkQuantity 42 :: Quantity 2) def)
"{\"side\":\"db\",\"value\":42.0,\"inventory\":{\"total\":0.0,\"current\":[],\"history\":[]}}"
>>> Aeson.encode (Balance SideCredit (mkQuantity 42 :: Quantity 2) def)
"{\"side\":\"cr\",\"value\":42.0,\"inventory\":{\"total\":0.0,\"current\":[],\"history\":[]}}"
>>> Aeson.eitherDecode (Aeson.encode (Balance SideDebit (mkQuantity 42 :: Quantity 2) def)) :: Either String (Balance 2)
Right (Balance {balanceSide = SideDebit, balanceValue = 42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
>>> Aeson.eitherDecode (Aeson.encode (Balance SideCredit (mkQuantity 42 :: Quantity 2) def)) :: Either String (Balance 2)
Right (Balance {balanceSide = SideCredit, balanceValue = 42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})

For negative balances:

>>> Aeson.encode (Balance SideDebit (mkQuantity (-42) :: Quantity 2) def)
"{\"side\":\"db\",\"value\":-42.0,\"inventory\":{\"total\":0.0,\"current\":[],\"history\":[]}}"
>>> Aeson.encode (Balance SideCredit (mkQuantity (-42) :: Quantity 2) def)
"{\"side\":\"cr\",\"value\":-42.0,\"inventory\":{\"total\":0.0,\"current\":[],\"history\":[]}}"
>>> Aeson.eitherDecode (Aeson.encode (Balance SideDebit (mkQuantity (-42) :: Quantity 2) def)) :: Either String (Balance 2)
Right (Balance {balanceSide = SideDebit, balanceValue = -42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
>>> Aeson.eitherDecode (Aeson.encode (Balance SideCredit (mkQuantity (-42) :: Quantity 2) def)) :: Either String (Balance 2)
Right (Balance {balanceSide = SideCredit, balanceValue = -42.00, balanceInventory = MkInventory {inventoryTotal = 0.000000000000, inventoryCurrent = fromList [], inventoryHistory = fromList []}})
Instance details

Defined in Haspara.Accounting.Balance

Methods

toJSON :: Balance precision -> Value #

toEncoding :: Balance precision -> Encoding #

toJSONList :: [Balance precision] -> Value #

toEncodingList :: [Balance precision] -> Encoding #

Generic (Balance precision) Source # 
Instance details

Defined in Haspara.Accounting.Balance

Associated Types

type Rep (Balance precision) :: Type -> Type #

Methods

from :: Balance precision -> Rep (Balance precision) x #

to :: Rep (Balance precision) x -> Balance precision #

KnownNat precision => Show (Balance precision) Source # 
Instance details

Defined in Haspara.Accounting.Balance

Methods

showsPrec :: Int -> Balance precision -> ShowS #

show :: Balance precision -> String #

showList :: [Balance precision] -> ShowS #

Eq (Balance precision) Source # 
Instance details

Defined in Haspara.Accounting.Balance

Methods

(==) :: Balance precision -> Balance precision -> Bool #

(/=) :: Balance precision -> Balance precision -> Bool #

type Rep (Balance precision) Source # 
Instance details

Defined in Haspara.Accounting.Balance

type Rep (Balance precision) = D1 ('MetaData "Balance" "Haspara.Accounting.Balance" "haspara-0.0.0.8-83lIPqySeX32MZXT98KoZ2" 'False) (C1 ('MetaCons "Balance" 'PrefixI 'True) (S1 ('MetaSel ('Just "balanceSide") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Side) :*: (S1 ('MetaSel ('Just "balanceValue") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Quantity precision)) :*: S1 ('MetaSel ('Just "balanceInventory") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Inventory 8 12 precision)))))

balanceDebit :: KnownNat precision => Balance precision -> Maybe (Quantity precision) Source #

Returns the debit quantity, if any.

balanceCredit :: KnownNat precision => Balance precision -> Maybe (Quantity precision) Source #

Returns the credit quantity, if any.

updateBalance :: KnownNat precision => Balance precision -> Amount precision -> Balance precision Source #

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 []}}

updateBalanceWithInventory :: KnownNat precision => Day -> Balance precision -> Amount precision -> Quantity 12 -> ([InventoryHistoryItem 8 12 precision], Balance precision) Source #

Updates the balance with additional inventory event.

amountFromBalance :: KnownNat precision => Balance precision -> Amount precision Source #

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}

quantityFromBalance :: KnownNat precision => AccountKind -> Balance precision -> Quantity precision Source #

Returns the quantity of the balance given the account kind.

See quantityFromAmount for the meaning of quantity.

valueFromBalance :: KnownNat precision => AccountKind -> Balance precision -> Quantity precision Source #

Returns the value of the balance given the account kind.

See valueFromAmount for the meaning of quantity.