{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Hledger.Data.Journal (
JournalParser,
ErroringJournalParser,
addPriceDirective,
addTransactionModifier,
addPeriodicTransaction,
addTransaction,
journalInferMarketPricesFromTransactions,
journalApplyCommodityStyles,
commodityStylesFromAmounts,
journalCommodityStyles,
journalToCost,
journalAddInferredEquityPostings,
journalReverse,
journalSetLastReadTime,
journalPivot,
filterJournalTransactions,
filterJournalPostings,
filterJournalRelatedPostings,
filterJournalAmounts,
filterTransactionAmounts,
filterTransactionPostings,
filterTransactionRelatedPostings,
filterPostingAmount,
journalMapTransactions,
journalMapPostings,
journalMapPostingAmounts,
journalAccountNamesUsed,
journalAccountNamesImplied,
journalAccountNamesDeclared,
journalAccountNamesDeclaredOrUsed,
journalAccountNamesDeclaredOrImplied,
journalLeafAccountNamesDeclared,
journalAccountNames,
journalLeafAccountNames,
journalAccountNameTree,
journalAccountTags,
journalInheritedAccountTags,
journalPayeesDeclared,
journalPayeesUsed,
journalPayeesDeclaredOrUsed,
journalCommoditiesDeclared,
journalCommodities,
journalDateSpan,
journalDateSpanBothDates,
journalStartDate,
journalEndDate,
journalLastDay,
journalDescriptions,
journalFilePath,
journalFilePaths,
journalTransactionAt,
journalNextTransaction,
journalPrevTransaction,
journalPostings,
journalTransactionsSimilarTo,
journalAccountType,
journalAccountTypes,
journalAddAccountTypes,
journalPostingsAddAccountTags,
journalBalanceSheetAccountQuery,
journalProfitAndLossAccountQuery,
journalRevenueAccountQuery,
journalExpenseAccountQuery,
journalAssetAccountQuery,
journalLiabilityAccountQuery,
journalEquityAccountQuery,
journalCashAccountQuery,
journalConversionAccount,
canonicalStyleFrom,
nulljournal,
journalNumberTransactions,
journalNumberAndTieTransactions,
journalUntieTransactions,
journalModifyTransactions,
journalApplyAliases,
samplejournal,
samplejournalMaybeExplicit,
tests_Journal
)
where
import Control.Applicative ((<|>))
import Control.Monad.Except (ExceptT(..))
import Control.Monad.State.Strict (StateT)
import Data.Char (toUpper, isDigit)
import Data.Default (Default(..))
import Data.Foldable (toList)
import Data.List ((\\), find, foldl', sortBy, union)
import Data.List.Extra (nubSort)
import qualified Data.Map.Strict as M
import Data.Maybe (catMaybes, fromMaybe, mapMaybe, maybeToList)
import qualified Data.Set as S
import Data.Text (Text)
import qualified Data.Text as T
import Safe (headMay, headDef, maximumMay, minimumMay)
import Data.Time.Calendar (Day, addDays, fromGregorian)
import Data.Time.Clock.POSIX (POSIXTime)
import Data.Tree (Tree(..), flatten)
import Text.Printf (printf)
import Text.Megaparsec (ParsecT)
import Text.Megaparsec.Custom (FinalParseError)
import Hledger.Utils
import Hledger.Data.Types
import Hledger.Data.AccountName
import Hledger.Data.Amount
import Hledger.Data.Posting
import Hledger.Data.Transaction
import Hledger.Data.TransactionModifier
import Hledger.Data.Valuation
import Hledger.Query
type JournalParser m a = StateT Journal (ParsecT HledgerParseErrorData Text m) a
type ErroringJournalParser m a =
StateT Journal (ParsecT HledgerParseErrorData Text (ExceptT FinalParseError m)) a
instance Show Journal where
show :: Journal -> String
show Journal
j
| Int
debugLevel Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
3 = String -> String -> Int -> Int -> String
forall r. PrintfType r => String -> r
printf String
"Journal %s with %d transactions, %d accounts"
(Journal -> String
journalFilePath Journal
j)
([Transaction] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Transaction] -> Int) -> [Transaction] -> Int
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j)
([AccountName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [AccountName]
accounts)
| Int
debugLevel Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
6 = String -> String -> Int -> Int -> ShowS
forall r. PrintfType r => String -> r
printf String
"Journal %s with %d transactions, %d accounts: %s"
(Journal -> String
journalFilePath Journal
j)
([Transaction] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Transaction] -> Int) -> [Transaction] -> Int
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j)
([AccountName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [AccountName]
accounts)
([AccountName] -> String
forall a. Show a => a -> String
show [AccountName]
accounts)
| Bool
otherwise = String -> String -> Int -> Int -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"Journal %s with %d transactions, %d accounts: %s, commodity styles: %s"
(Journal -> String
journalFilePath Journal
j)
([Transaction] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Transaction] -> Int) -> [Transaction] -> Int
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j)
([AccountName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [AccountName]
accounts)
([AccountName] -> String
forall a. Show a => a -> String
show [AccountName]
accounts)
(Map AccountName AmountStyle -> String
forall a. Show a => a -> String
show (Map AccountName AmountStyle -> String)
-> Map AccountName AmountStyle -> String
forall a b. (a -> b) -> a -> b
$ Journal -> Map AccountName AmountStyle
jinferredcommodities Journal
j)
where accounts :: [AccountName]
accounts = (AccountName -> Bool) -> [AccountName] -> [AccountName]
forall a. (a -> Bool) -> [a] -> [a]
filter (AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
/= AccountName
"root") ([AccountName] -> [AccountName]) -> [AccountName] -> [AccountName]
forall a b. (a -> b) -> a -> b
$ Tree AccountName -> [AccountName]
forall a. Tree a -> [a]
flatten (Tree AccountName -> [AccountName])
-> Tree AccountName -> [AccountName]
forall a b. (a -> b) -> a -> b
$ Journal -> Tree AccountName
journalAccountNameTree Journal
j
instance Semigroup Journal where
Journal
j1 <> :: Journal -> Journal -> Journal
<> Journal
j2 = Journal :: Maybe Year
-> Maybe (AccountName, AmountStyle)
-> Maybe DecimalMark
-> [AccountName]
-> [AccountAlias]
-> [TimeclockEntry]
-> [String]
-> [(AccountName, PayeeDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
-> Map AccountName [Tag]
-> Map AccountType [AccountName]
-> Map AccountName AccountType
-> Map AccountName AmountStyle
-> Map AccountName Commodity
-> Map AccountName AmountStyle
-> [PriceDirective]
-> [MarketPrice]
-> [TransactionModifier]
-> [PeriodicTransaction]
-> [Transaction]
-> AccountName
-> [(String, AccountName)]
-> POSIXTime
-> Journal
Journal {
jparsedefaultyear :: Maybe Year
jparsedefaultyear = Journal -> Maybe Year
jparsedefaultyear Journal
j2
,jparsedefaultcommodity :: Maybe (AccountName, AmountStyle)
jparsedefaultcommodity = Journal -> Maybe (AccountName, AmountStyle)
jparsedefaultcommodity Journal
j2
,jparsedecimalmark :: Maybe DecimalMark
jparsedecimalmark = Journal -> Maybe DecimalMark
jparsedecimalmark Journal
j2
,jparseparentaccounts :: [AccountName]
jparseparentaccounts = Journal -> [AccountName]
jparseparentaccounts Journal
j2
,jparsealiases :: [AccountAlias]
jparsealiases = Journal -> [AccountAlias]
jparsealiases Journal
j2
,jparsetimeclockentries :: [TimeclockEntry]
jparsetimeclockentries = Journal -> [TimeclockEntry]
jparsetimeclockentries Journal
j1 [TimeclockEntry] -> [TimeclockEntry] -> [TimeclockEntry]
forall a. Semigroup a => a -> a -> a
<> Journal -> [TimeclockEntry]
jparsetimeclockentries Journal
j2
,jincludefilestack :: [String]
jincludefilestack = Journal -> [String]
jincludefilestack Journal
j2
,jdeclaredpayees :: [(AccountName, PayeeDeclarationInfo)]
jdeclaredpayees = Journal -> [(AccountName, PayeeDeclarationInfo)]
jdeclaredpayees Journal
j1 [(AccountName, PayeeDeclarationInfo)]
-> [(AccountName, PayeeDeclarationInfo)]
-> [(AccountName, PayeeDeclarationInfo)]
forall a. Semigroup a => a -> a -> a
<> Journal -> [(AccountName, PayeeDeclarationInfo)]
jdeclaredpayees Journal
j2
,jdeclaredaccounts :: [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts = Journal -> [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts Journal
j1 [(AccountName, AccountDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
forall a. Semigroup a => a -> a -> a
<> Journal -> [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts Journal
j2
,jdeclaredaccounttags :: Map AccountName [Tag]
jdeclaredaccounttags = Journal -> Map AccountName [Tag]
jdeclaredaccounttags Journal
j1 Map AccountName [Tag]
-> Map AccountName [Tag] -> Map AccountName [Tag]
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountName [Tag]
jdeclaredaccounttags Journal
j2
,jdeclaredaccounttypes :: Map AccountType [AccountName]
jdeclaredaccounttypes = Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes Journal
j1 Map AccountType [AccountName]
-> Map AccountType [AccountName] -> Map AccountType [AccountName]
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes Journal
j2
,jaccounttypes :: Map AccountName AccountType
jaccounttypes = Journal -> Map AccountName AccountType
jaccounttypes Journal
j1 Map AccountName AccountType
-> Map AccountName AccountType -> Map AccountName AccountType
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountName AccountType
jaccounttypes Journal
j2
,jglobalcommoditystyles :: Map AccountName AmountStyle
jglobalcommoditystyles = Journal -> Map AccountName AmountStyle
jglobalcommoditystyles Journal
j1 Map AccountName AmountStyle
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountName AmountStyle
jglobalcommoditystyles Journal
j2
,jcommodities :: Map AccountName Commodity
jcommodities = Journal -> Map AccountName Commodity
jcommodities Journal
j1 Map AccountName Commodity
-> Map AccountName Commodity -> Map AccountName Commodity
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountName Commodity
jcommodities Journal
j2
,jinferredcommodities :: Map AccountName AmountStyle
jinferredcommodities = Journal -> Map AccountName AmountStyle
jinferredcommodities Journal
j1 Map AccountName AmountStyle
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Semigroup a => a -> a -> a
<> Journal -> Map AccountName AmountStyle
jinferredcommodities Journal
j2
,jpricedirectives :: [PriceDirective]
jpricedirectives = Journal -> [PriceDirective]
jpricedirectives Journal
j1 [PriceDirective] -> [PriceDirective] -> [PriceDirective]
forall a. Semigroup a => a -> a -> a
<> Journal -> [PriceDirective]
jpricedirectives Journal
j2
,jinferredmarketprices :: [MarketPrice]
jinferredmarketprices = Journal -> [MarketPrice]
jinferredmarketprices Journal
j1 [MarketPrice] -> [MarketPrice] -> [MarketPrice]
forall a. Semigroup a => a -> a -> a
<> Journal -> [MarketPrice]
jinferredmarketprices Journal
j2
,jtxnmodifiers :: [TransactionModifier]
jtxnmodifiers = Journal -> [TransactionModifier]
jtxnmodifiers Journal
j1 [TransactionModifier]
-> [TransactionModifier] -> [TransactionModifier]
forall a. Semigroup a => a -> a -> a
<> Journal -> [TransactionModifier]
jtxnmodifiers Journal
j2
,jperiodictxns :: [PeriodicTransaction]
jperiodictxns = Journal -> [PeriodicTransaction]
jperiodictxns Journal
j1 [PeriodicTransaction]
-> [PeriodicTransaction] -> [PeriodicTransaction]
forall a. Semigroup a => a -> a -> a
<> Journal -> [PeriodicTransaction]
jperiodictxns Journal
j2
,jtxns :: [Transaction]
jtxns = Journal -> [Transaction]
jtxns Journal
j1 [Transaction] -> [Transaction] -> [Transaction]
forall a. Semigroup a => a -> a -> a
<> Journal -> [Transaction]
jtxns Journal
j2
,jfinalcommentlines :: AccountName
jfinalcommentlines = Journal -> AccountName
jfinalcommentlines Journal
j2
,jfiles :: [(String, AccountName)]
jfiles = Journal -> [(String, AccountName)]
jfiles Journal
j1 [(String, AccountName)]
-> [(String, AccountName)] -> [(String, AccountName)]
forall a. Semigroup a => a -> a -> a
<> Journal -> [(String, AccountName)]
jfiles Journal
j2
,jlastreadtime :: POSIXTime
jlastreadtime = POSIXTime -> POSIXTime -> POSIXTime
forall a. Ord a => a -> a -> a
max (Journal -> POSIXTime
jlastreadtime Journal
j1) (Journal -> POSIXTime
jlastreadtime Journal
j2)
}
instance Default Journal where
def :: Journal
def = Journal
nulljournal
nulljournal :: Journal
nulljournal :: Journal
nulljournal = Journal :: Maybe Year
-> Maybe (AccountName, AmountStyle)
-> Maybe DecimalMark
-> [AccountName]
-> [AccountAlias]
-> [TimeclockEntry]
-> [String]
-> [(AccountName, PayeeDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
-> Map AccountName [Tag]
-> Map AccountType [AccountName]
-> Map AccountName AccountType
-> Map AccountName AmountStyle
-> Map AccountName Commodity
-> Map AccountName AmountStyle
-> [PriceDirective]
-> [MarketPrice]
-> [TransactionModifier]
-> [PeriodicTransaction]
-> [Transaction]
-> AccountName
-> [(String, AccountName)]
-> POSIXTime
-> Journal
Journal {
jparsedefaultyear :: Maybe Year
jparsedefaultyear = Maybe Year
forall a. Maybe a
Nothing
,jparsedefaultcommodity :: Maybe (AccountName, AmountStyle)
jparsedefaultcommodity = Maybe (AccountName, AmountStyle)
forall a. Maybe a
Nothing
,jparsedecimalmark :: Maybe DecimalMark
jparsedecimalmark = Maybe DecimalMark
forall a. Maybe a
Nothing
,jparseparentaccounts :: [AccountName]
jparseparentaccounts = []
,jparsealiases :: [AccountAlias]
jparsealiases = []
,jparsetimeclockentries :: [TimeclockEntry]
jparsetimeclockentries = []
,jincludefilestack :: [String]
jincludefilestack = []
,jdeclaredpayees :: [(AccountName, PayeeDeclarationInfo)]
jdeclaredpayees = []
,jdeclaredaccounts :: [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts = []
,jdeclaredaccounttags :: Map AccountName [Tag]
jdeclaredaccounttags = Map AccountName [Tag]
forall k a. Map k a
M.empty
,jdeclaredaccounttypes :: Map AccountType [AccountName]
jdeclaredaccounttypes = Map AccountType [AccountName]
forall k a. Map k a
M.empty
,jaccounttypes :: Map AccountName AccountType
jaccounttypes = Map AccountName AccountType
forall k a. Map k a
M.empty
,jglobalcommoditystyles :: Map AccountName AmountStyle
jglobalcommoditystyles = Map AccountName AmountStyle
forall k a. Map k a
M.empty
,jcommodities :: Map AccountName Commodity
jcommodities = Map AccountName Commodity
forall k a. Map k a
M.empty
,jinferredcommodities :: Map AccountName AmountStyle
jinferredcommodities = Map AccountName AmountStyle
forall k a. Map k a
M.empty
,jpricedirectives :: [PriceDirective]
jpricedirectives = []
,jinferredmarketprices :: [MarketPrice]
jinferredmarketprices = []
,jtxnmodifiers :: [TransactionModifier]
jtxnmodifiers = []
,jperiodictxns :: [PeriodicTransaction]
jperiodictxns = []
,jtxns :: [Transaction]
jtxns = []
,jfinalcommentlines :: AccountName
jfinalcommentlines = AccountName
""
,jfiles :: [(String, AccountName)]
jfiles = []
,jlastreadtime :: POSIXTime
jlastreadtime = POSIXTime
0
}
journalFilePath :: Journal -> FilePath
journalFilePath :: Journal -> String
journalFilePath = (String, AccountName) -> String
forall a b. (a, b) -> a
fst ((String, AccountName) -> String)
-> (Journal -> (String, AccountName)) -> Journal -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> (String, AccountName)
mainfile
journalFilePaths :: Journal -> [FilePath]
journalFilePaths :: Journal -> [String]
journalFilePaths = ((String, AccountName) -> String)
-> [(String, AccountName)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, AccountName) -> String
forall a b. (a, b) -> a
fst ([(String, AccountName)] -> [String])
-> (Journal -> [(String, AccountName)]) -> Journal -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [(String, AccountName)]
jfiles
mainfile :: Journal -> (FilePath, Text)
mainfile :: Journal -> (String, AccountName)
mainfile = (String, AccountName)
-> [(String, AccountName)] -> (String, AccountName)
forall a. a -> [a] -> a
headDef (String
"", AccountName
"") ([(String, AccountName)] -> (String, AccountName))
-> (Journal -> [(String, AccountName)])
-> Journal
-> (String, AccountName)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [(String, AccountName)]
jfiles
addTransaction :: Transaction -> Journal -> Journal
addTransaction :: Transaction -> Journal -> Journal
addTransaction Transaction
t Journal
j = Journal
j { jtxns :: [Transaction]
jtxns = Transaction
t Transaction -> [Transaction] -> [Transaction]
forall a. a -> [a] -> [a]
: Journal -> [Transaction]
jtxns Journal
j }
addTransactionModifier :: TransactionModifier -> Journal -> Journal
addTransactionModifier :: TransactionModifier -> Journal -> Journal
addTransactionModifier TransactionModifier
mt Journal
j = Journal
j { jtxnmodifiers :: [TransactionModifier]
jtxnmodifiers = TransactionModifier
mt TransactionModifier
-> [TransactionModifier] -> [TransactionModifier]
forall a. a -> [a] -> [a]
: Journal -> [TransactionModifier]
jtxnmodifiers Journal
j }
addPeriodicTransaction :: PeriodicTransaction -> Journal -> Journal
addPeriodicTransaction :: PeriodicTransaction -> Journal -> Journal
addPeriodicTransaction PeriodicTransaction
pt Journal
j = Journal
j { jperiodictxns :: [PeriodicTransaction]
jperiodictxns = PeriodicTransaction
pt PeriodicTransaction
-> [PeriodicTransaction] -> [PeriodicTransaction]
forall a. a -> [a] -> [a]
: Journal -> [PeriodicTransaction]
jperiodictxns Journal
j }
addPriceDirective :: PriceDirective -> Journal -> Journal
addPriceDirective :: PriceDirective -> Journal -> Journal
addPriceDirective PriceDirective
h Journal
j = Journal
j { jpricedirectives :: [PriceDirective]
jpricedirectives = PriceDirective
h PriceDirective -> [PriceDirective] -> [PriceDirective]
forall a. a -> [a] -> [a]
: Journal -> [PriceDirective]
jpricedirectives Journal
j }
journalTransactionAt :: Journal -> Integer -> Maybe Transaction
journalTransactionAt :: Journal -> Year -> Maybe Transaction
journalTransactionAt Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} Year
i =
[Transaction] -> Maybe Transaction
forall a. [a] -> Maybe a
headMay [Transaction
t | Transaction
t <- [Transaction]
ts, Transaction -> Year
tindex Transaction
t Year -> Year -> Bool
forall a. Eq a => a -> a -> Bool
== Year
i]
journalNextTransaction :: Journal -> Transaction -> Maybe Transaction
journalNextTransaction :: Journal -> Transaction -> Maybe Transaction
journalNextTransaction Journal
j Transaction
t = Journal -> Year -> Maybe Transaction
journalTransactionAt Journal
j (Transaction -> Year
tindex Transaction
t Year -> Year -> Year
forall a. Num a => a -> a -> a
+ Year
1)
journalPrevTransaction :: Journal -> Transaction -> Maybe Transaction
journalPrevTransaction :: Journal -> Transaction -> Maybe Transaction
journalPrevTransaction Journal
j Transaction
t = Journal -> Year -> Maybe Transaction
journalTransactionAt Journal
j (Transaction -> Year
tindex Transaction
t Year -> Year -> Year
forall a. Num a => a -> a -> a
- Year
1)
journalPostings :: Journal -> [Posting]
journalPostings :: Journal -> [Posting]
journalPostings = (Transaction -> [Posting]) -> [Transaction] -> [Posting]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Transaction -> [Posting]
tpostings ([Transaction] -> [Posting])
-> (Journal -> [Transaction]) -> Journal -> [Posting]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [Transaction]
jtxns
journalCommoditiesDeclared :: Journal -> [CommoditySymbol]
journalCommoditiesDeclared :: Journal -> [AccountName]
journalCommoditiesDeclared = Map AccountName Commodity -> [AccountName]
forall k a. Map k a -> [k]
M.keys (Map AccountName Commodity -> [AccountName])
-> (Journal -> Map AccountName Commodity)
-> Journal
-> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Map AccountName Commodity
jcommodities
journalCommodities :: Journal -> S.Set CommoditySymbol
journalCommodities :: Journal -> Set AccountName
journalCommodities Journal
j = Map AccountName Commodity -> Set AccountName
forall k a. Map k a -> Set k
M.keysSet (Journal -> Map AccountName Commodity
jcommodities Journal
j) Set AccountName -> Set AccountName -> Set AccountName
forall a. Semigroup a => a -> a -> a
<> Map AccountName AmountStyle -> Set AccountName
forall k a. Map k a -> Set k
M.keysSet (Journal -> Map AccountName AmountStyle
jinferredcommodities Journal
j)
journalDescriptions :: Journal -> [Text]
journalDescriptions :: Journal -> [AccountName]
journalDescriptions = [AccountName] -> [AccountName]
forall a. Ord a => [a] -> [a]
nubSort ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Transaction -> AccountName) -> [Transaction] -> [AccountName]
forall a b. (a -> b) -> [a] -> [b]
map Transaction -> AccountName
tdescription ([Transaction] -> [AccountName])
-> (Journal -> [Transaction]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [Transaction]
jtxns
journalPayeesDeclared :: Journal -> [Payee]
journalPayeesDeclared :: Journal -> [AccountName]
journalPayeesDeclared = [AccountName] -> [AccountName]
forall a. Ord a => [a] -> [a]
nubSort ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((AccountName, PayeeDeclarationInfo) -> AccountName)
-> [(AccountName, PayeeDeclarationInfo)] -> [AccountName]
forall a b. (a -> b) -> [a] -> [b]
map (AccountName, PayeeDeclarationInfo) -> AccountName
forall a b. (a, b) -> a
fst ([(AccountName, PayeeDeclarationInfo)] -> [AccountName])
-> (Journal -> [(AccountName, PayeeDeclarationInfo)])
-> Journal
-> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [(AccountName, PayeeDeclarationInfo)]
jdeclaredpayees
journalPayeesUsed :: Journal -> [Payee]
journalPayeesUsed :: Journal -> [AccountName]
journalPayeesUsed = [AccountName] -> [AccountName]
forall a. Ord a => [a] -> [a]
nubSort ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Transaction -> AccountName) -> [Transaction] -> [AccountName]
forall a b. (a -> b) -> [a] -> [b]
map Transaction -> AccountName
transactionPayee ([Transaction] -> [AccountName])
-> (Journal -> [Transaction]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [Transaction]
jtxns
journalPayeesDeclaredOrUsed :: Journal -> [Payee]
journalPayeesDeclaredOrUsed :: Journal -> [AccountName]
journalPayeesDeclaredOrUsed Journal
j = Set AccountName -> [AccountName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Set AccountName -> [AccountName])
-> Set AccountName -> [AccountName]
forall a b. (a -> b) -> a -> b
$ ([AccountName] -> Set AccountName)
-> [[AccountName]] -> Set AccountName
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap [AccountName] -> Set AccountName
forall a. Ord a => [a] -> Set a
S.fromList
[Journal -> [AccountName]
journalPayeesDeclared Journal
j, Journal -> [AccountName]
journalPayeesUsed Journal
j]
journalAccountNamesUsed :: Journal -> [AccountName]
journalAccountNamesUsed :: Journal -> [AccountName]
journalAccountNamesUsed = [Posting] -> [AccountName]
accountNamesFromPostings ([Posting] -> [AccountName])
-> (Journal -> [Posting]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [Posting]
journalPostings
journalAccountNamesImplied :: Journal -> [AccountName]
journalAccountNamesImplied :: Journal -> [AccountName]
journalAccountNamesImplied = [AccountName] -> [AccountName]
expandAccountNames ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [AccountName]
journalAccountNamesUsed
journalAccountNamesDeclared :: Journal -> [AccountName]
journalAccountNamesDeclared :: Journal -> [AccountName]
journalAccountNamesDeclared = [AccountName] -> [AccountName]
forall a. Ord a => [a] -> [a]
nubSort ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((AccountName, AccountDeclarationInfo) -> AccountName)
-> [(AccountName, AccountDeclarationInfo)] -> [AccountName]
forall a b. (a -> b) -> [a] -> [b]
map (AccountName, AccountDeclarationInfo) -> AccountName
forall a b. (a, b) -> a
fst ([(AccountName, AccountDeclarationInfo)] -> [AccountName])
-> (Journal -> [(AccountName, AccountDeclarationInfo)])
-> Journal
-> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts
journalLeafAccountNamesDeclared :: Journal -> [AccountName]
journalLeafAccountNamesDeclared :: Journal -> [AccountName]
journalLeafAccountNamesDeclared = Tree AccountName -> [AccountName]
forall a. Show a => Tree a -> [a]
treeLeaves (Tree AccountName -> [AccountName])
-> (Journal -> Tree AccountName) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [AccountName] -> Tree AccountName
accountNameTreeFrom ([AccountName] -> Tree AccountName)
-> (Journal -> [AccountName]) -> Journal -> Tree AccountName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [AccountName]
journalAccountNamesDeclared
journalAccountNamesDeclaredOrUsed :: Journal -> [AccountName]
journalAccountNamesDeclaredOrUsed :: Journal -> [AccountName]
journalAccountNamesDeclaredOrUsed Journal
j = Set AccountName -> [AccountName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Set AccountName -> [AccountName])
-> Set AccountName -> [AccountName]
forall a b. (a -> b) -> a -> b
$ ([AccountName] -> Set AccountName)
-> [[AccountName]] -> Set AccountName
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap [AccountName] -> Set AccountName
forall a. Ord a => [a] -> Set a
S.fromList
[Journal -> [AccountName]
journalAccountNamesDeclared Journal
j, Journal -> [AccountName]
journalAccountNamesUsed Journal
j]
journalAccountNamesDeclaredOrImplied :: Journal -> [AccountName]
journalAccountNamesDeclaredOrImplied :: Journal -> [AccountName]
journalAccountNamesDeclaredOrImplied Journal
j = Set AccountName -> [AccountName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Set AccountName -> [AccountName])
-> Set AccountName -> [AccountName]
forall a b. (a -> b) -> a -> b
$ ([AccountName] -> Set AccountName)
-> [[AccountName]] -> Set AccountName
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap [AccountName] -> Set AccountName
forall a. Ord a => [a] -> Set a
S.fromList
[Journal -> [AccountName]
journalAccountNamesDeclared Journal
j, [AccountName] -> [AccountName]
expandAccountNames ([AccountName] -> [AccountName]) -> [AccountName] -> [AccountName]
forall a b. (a -> b) -> a -> b
$ Journal -> [AccountName]
journalAccountNamesUsed Journal
j]
journalAccountNames :: Journal -> [AccountName]
journalAccountNames :: Journal -> [AccountName]
journalAccountNames = Journal -> [AccountName]
journalAccountNamesDeclaredOrImplied
journalLeafAccountNames :: Journal -> [AccountName]
journalLeafAccountNames :: Journal -> [AccountName]
journalLeafAccountNames = Tree AccountName -> [AccountName]
forall a. Show a => Tree a -> [a]
treeLeaves (Tree AccountName -> [AccountName])
-> (Journal -> Tree AccountName) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Tree AccountName
journalAccountNameTree
journalAccountNameTree :: Journal -> Tree AccountName
journalAccountNameTree :: Journal -> Tree AccountName
journalAccountNameTree = [AccountName] -> Tree AccountName
accountNameTreeFrom ([AccountName] -> Tree AccountName)
-> (Journal -> [AccountName]) -> Journal -> Tree AccountName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [AccountName]
journalAccountNamesDeclaredOrImplied
journalAccountTags :: Journal -> AccountName -> [Tag]
journalAccountTags :: Journal -> AccountName -> [Tag]
journalAccountTags Journal{Map AccountName [Tag]
jdeclaredaccounttags :: Map AccountName [Tag]
jdeclaredaccounttags :: Journal -> Map AccountName [Tag]
jdeclaredaccounttags} AccountName
a = [Tag] -> AccountName -> Map AccountName [Tag] -> [Tag]
forall k a. Ord k => a -> k -> Map k a -> a
M.findWithDefault [] AccountName
a Map AccountName [Tag]
jdeclaredaccounttags
journalInheritedAccountTags :: Journal -> AccountName -> [Tag]
journalInheritedAccountTags :: Journal -> AccountName -> [Tag]
journalInheritedAccountTags Journal
j AccountName
a =
([Tag] -> AccountName -> [Tag]) -> [Tag] -> [AccountName] -> [Tag]
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\[Tag]
ts AccountName
a -> [Tag]
ts [Tag] -> [Tag] -> [Tag]
forall a. Eq a => [a] -> [a] -> [a]
`union` Journal -> AccountName -> [Tag]
journalAccountTags Journal
j AccountName
a) [] [AccountName]
as
where
as :: [AccountName]
as = AccountName
a AccountName -> [AccountName] -> [AccountName]
forall a. a -> [a] -> [a]
: AccountName -> [AccountName]
parentAccountNames AccountName
a
journalTransactionsSimilarTo :: Journal -> Query -> Text -> Int -> [(Double,Transaction)]
journalTransactionsSimilarTo :: Journal -> Query -> AccountName -> Int -> [(Double, Transaction)]
journalTransactionsSimilarTo Journal{[Transaction]
jtxns :: [Transaction]
jtxns :: Journal -> [Transaction]
jtxns} Query
q AccountName
desc Int
n =
Int -> [(Double, Transaction)] -> [(Double, Transaction)]
forall a. Int -> [a] -> [a]
take Int
n ([(Double, Transaction)] -> [(Double, Transaction)])
-> [(Double, Transaction)] -> [(Double, Transaction)]
forall a b. (a -> b) -> a -> b
$
((Double, Transaction) -> (Double, Transaction) -> Ordering)
-> [(Double, Transaction)] -> [(Double, Transaction)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (\(Double
s1,Transaction
t1) (Double
s2,Transaction
t2) -> (Double, Day) -> (Double, Day) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Double
s2,Transaction -> Day
tdate Transaction
t2) (Double
s1,Transaction -> Day
tdate Transaction
t1)) ([(Double, Transaction)] -> [(Double, Transaction)])
-> [(Double, Transaction)] -> [(Double, Transaction)]
forall a b. (a -> b) -> a -> b
$
((Double, Transaction) -> Bool)
-> [(Double, Transaction)] -> [(Double, Transaction)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
threshold)(Double -> Bool)
-> ((Double, Transaction) -> Double)
-> (Double, Transaction)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Double, Transaction) -> Double
forall a b. (a, b) -> a
fst)
[(AccountName -> AccountName -> Double
compareDescriptions AccountName
desc (AccountName -> Double) -> AccountName -> Double
forall a b. (a -> b) -> a -> b
$ Transaction -> AccountName
tdescription Transaction
t, Transaction
t) | Transaction
t <- [Transaction]
jtxns, Query
q Query -> Transaction -> Bool
`matchesTransaction` Transaction
t]
where
threshold :: Double
threshold = Double
0
compareDescriptions :: Text -> Text -> Double
compareDescriptions :: AccountName -> AccountName -> Double
compareDescriptions AccountName
a AccountName
b =
(if AccountName
a AccountName -> AccountName -> Bool
`T.isInfixOf` AccountName
b then (Double
0.5Double -> Double -> Double
forall a. Num a => a -> a -> a
+) else Double -> Double
forall a. a -> a
id) (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$
String -> String -> Double
compareStrings (AccountName -> String
simplify AccountName
a) (AccountName -> String
simplify AccountName
b)
where
simplify :: AccountName -> String
simplify = AccountName -> String
T.unpack (AccountName -> String)
-> (AccountName -> AccountName) -> AccountName -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DecimalMark -> Bool) -> AccountName -> AccountName
T.filter (Bool -> Bool
not(Bool -> Bool) -> (DecimalMark -> Bool) -> DecimalMark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.DecimalMark -> Bool
isDigit)
compareStrings :: String -> String -> Double
compareStrings :: String -> String -> Double
compareStrings String
"" String
"" = Double
1
compareStrings [DecimalMark
_] String
"" = Double
0
compareStrings String
"" [DecimalMark
_] = Double
0
compareStrings [DecimalMark
a] [DecimalMark
b] = if DecimalMark -> DecimalMark
toUpper DecimalMark
a DecimalMark -> DecimalMark -> Bool
forall a. Eq a => a -> a -> Bool
== DecimalMark -> DecimalMark
toUpper DecimalMark
b then Double
1 else Double
0
compareStrings String
s1 String
s2 = Double
2 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
commonpairs Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
totalpairs
where
pairs1 :: Set String
pairs1 = [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList ([String] -> Set String) -> [String] -> Set String
forall a b. (a -> b) -> a -> b
$ String -> [String]
wordLetterPairs (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ ShowS
uppercase String
s1
pairs2 :: Set String
pairs2 = [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList ([String] -> Set String) -> [String] -> Set String
forall a b. (a -> b) -> a -> b
$ String -> [String]
wordLetterPairs (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ ShowS
uppercase String
s2
commonpairs :: Double
commonpairs = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Int -> Double
forall a b. (a -> b) -> a -> b
$ Set String -> Int
forall a. Set a -> Int
S.size (Set String -> Int) -> Set String -> Int
forall a b. (a -> b) -> a -> b
$ Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
S.intersection Set String
pairs1 Set String
pairs2
totalpairs :: Double
totalpairs = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Int -> Double
forall a b. (a -> b) -> a -> b
$ Set String -> Int
forall a. Set a -> Int
S.size Set String
pairs1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Set String -> Int
forall a. Set a -> Int
S.size Set String
pairs2
wordLetterPairs :: String -> [String]
wordLetterPairs :: String -> [String]
wordLetterPairs = (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
letterPairs ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
words
letterPairs :: String -> [String]
letterPairs :: String -> [String]
letterPairs (DecimalMark
a:DecimalMark
b:String
rest) = [DecimalMark
a,DecimalMark
b] String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
letterPairs (DecimalMark
bDecimalMark -> ShowS
forall a. a -> [a] -> [a]
:String
rest)
letterPairs String
_ = []
journalAccountTypeQuery :: [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery :: [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType]
atypes Regexp
fallbackregex Journal{Map AccountType [AccountName]
jdeclaredaccounttypes :: Map AccountType [AccountName]
jdeclaredaccounttypes :: Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes} =
let
[AccountName]
declaredacctsoftype :: [AccountName] =
[[AccountName]] -> [AccountName]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[AccountName]] -> [AccountName])
-> [[AccountName]] -> [AccountName]
forall a b. (a -> b) -> a -> b
$ (AccountType -> Maybe [AccountName])
-> [AccountType] -> [[AccountName]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (AccountType -> Map AccountType [AccountName] -> Maybe [AccountName]
forall k a. Ord k => k -> Map k a -> Maybe a
`M.lookup` Map AccountType [AccountName]
jdeclaredaccounttypes) [AccountType]
atypes
in case [AccountName]
declaredacctsoftype of
[] -> Regexp -> Query
Acct Regexp
fallbackregex
[AccountName]
as -> [Query] -> Query
And ([Query] -> Query) -> [Query] -> Query
forall a b. (a -> b) -> a -> b
$ [Query] -> Query
Or [Query]
acctnameRegexes Query -> [Query] -> [Query]
forall a. a -> [a] -> [a]
: if [Query] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Query]
differentlyTypedRegexes then [] else [ Query -> Query
Not (Query -> Query) -> Query -> Query
forall a b. (a -> b) -> a -> b
$ [Query] -> Query
Or [Query]
differentlyTypedRegexes ]
where
acctnameRegexes :: [Query]
acctnameRegexes = (AccountName -> Query) -> [AccountName] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Regexp -> Query
Acct (Regexp -> Query)
-> (AccountName -> Regexp) -> AccountName -> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountName -> Regexp
accountNameToAccountRegex) [AccountName]
as
differentlyTypedRegexes :: [Query]
differentlyTypedRegexes = (AccountName -> Query) -> [AccountName] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Regexp -> Query
Acct (Regexp -> Query)
-> (AccountName -> Regexp) -> AccountName -> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountName -> Regexp
accountNameToAccountRegex) [AccountName]
differentlytypedsubs
differentlytypedsubs :: [AccountName]
differentlytypedsubs = [[AccountName]] -> [AccountName]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[[AccountName]
subs | (AccountType
t,[AccountName]
bs) <- Map AccountType [AccountName] -> [(AccountType, [AccountName])]
forall k a. Map k a -> [(k, a)]
M.toList Map AccountType [AccountName]
jdeclaredaccounttypes
, AccountType
t AccountType -> [AccountType] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [AccountType]
atypes
, let subs :: [AccountName]
subs = [AccountName
b | AccountName
b <- [AccountName]
bs, (AccountName -> Bool) -> [AccountName] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (AccountName -> AccountName -> Bool
`isAccountNamePrefixOf` AccountName
b) [AccountName]
as]
]
journalAssetAccountQuery :: Journal -> Query
journalAssetAccountQuery :: Journal -> Query
journalAssetAccountQuery Journal
j =
[Query] -> Query
Or [
[AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Asset] Regexp
assetAccountRegex Journal
j
,Journal -> Query
journalCashAccountOnlyQuery Journal
j
]
journalCashAccountQuery :: Journal -> Query
journalCashAccountQuery :: Journal -> Query
journalCashAccountQuery = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Cash] Regexp
cashAccountRegex
journalCashAccountOnlyQuery :: Journal -> Query
journalCashAccountOnlyQuery :: Journal -> Query
journalCashAccountOnlyQuery Journal
j
| AccountType
Cash AccountType -> Map AccountType [AccountName] -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`M.member` Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes Journal
j = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Cash] Regexp
forall a. a
notused Journal
j
| Bool
otherwise = Query
None
where notused :: a
notused = String -> a
forall a. String -> a
error' String
"journalCashAccountOnlyQuery: this should not have happened!"
journalLiabilityAccountQuery :: Journal -> Query
journalLiabilityAccountQuery :: Journal -> Query
journalLiabilityAccountQuery = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Liability] Regexp
liabilityAccountRegex
journalEquityAccountQuery :: Journal -> Query
journalEquityAccountQuery :: Journal -> Query
journalEquityAccountQuery = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Equity] Regexp
equityAccountRegex
journalRevenueAccountQuery :: Journal -> Query
journalRevenueAccountQuery :: Journal -> Query
journalRevenueAccountQuery = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Revenue] Regexp
revenueAccountRegex
journalExpenseAccountQuery :: Journal -> Query
journalExpenseAccountQuery :: Journal -> Query
journalExpenseAccountQuery = [AccountType] -> Regexp -> Journal -> Query
journalAccountTypeQuery [AccountType
Expense] Regexp
expenseAccountRegex
journalBalanceSheetAccountQuery :: Journal -> Query
journalBalanceSheetAccountQuery :: Journal -> Query
journalBalanceSheetAccountQuery Journal
j = [Query] -> Query
Or [Journal -> Query
journalAssetAccountQuery Journal
j
,Journal -> Query
journalLiabilityAccountQuery Journal
j
,Journal -> Query
journalEquityAccountQuery Journal
j
]
journalProfitAndLossAccountQuery :: Journal -> Query
journalProfitAndLossAccountQuery :: Journal -> Query
journalProfitAndLossAccountQuery Journal
j = [Query] -> Query
Or [Journal -> Query
journalRevenueAccountQuery Journal
j
,Journal -> Query
journalExpenseAccountQuery Journal
j
]
journalConversionAccount :: Journal -> AccountName
journalConversionAccount :: Journal -> AccountName
journalConversionAccount =
AccountName -> [AccountName] -> AccountName
forall a. a -> [a] -> a
headDef (String -> AccountName
T.pack String
"equity:conversion")
([AccountName] -> AccountName)
-> (Journal -> [AccountName]) -> Journal -> AccountName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [AccountName]
-> AccountType -> Map AccountType [AccountName] -> [AccountName]
forall k a. Ord k => a -> k -> Map k a -> a
M.findWithDefault [] AccountType
Conversion
(Map AccountType [AccountName] -> [AccountName])
-> (Journal -> Map AccountType [AccountName])
-> Journal
-> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes
journalAccountType :: Journal -> AccountName -> Maybe AccountType
journalAccountType :: Journal -> AccountName -> Maybe AccountType
journalAccountType Journal{Map AccountName AccountType
jaccounttypes :: Map AccountName AccountType
jaccounttypes :: Journal -> Map AccountName AccountType
jaccounttypes} = Map AccountName AccountType -> AccountName -> Maybe AccountType
accountNameType Map AccountName AccountType
jaccounttypes
journalAddAccountTypes :: Journal -> Journal
journalAddAccountTypes :: Journal -> Journal
journalAddAccountTypes Journal
j = Journal
j{jaccounttypes :: Map AccountName AccountType
jaccounttypes = Journal -> Map AccountName AccountType
journalAccountTypes Journal
j}
journalAccountTypes :: Journal -> M.Map AccountName AccountType
journalAccountTypes :: Journal -> Map AccountName AccountType
journalAccountTypes Journal
j = [(AccountName, AccountType)] -> Map AccountName AccountType
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(AccountName
a,AccountType
acctType) | (AccountName
a, Just (AccountType
acctType,Bool
_)) <- Tree (AccountName, Maybe (AccountType, Bool))
-> [(AccountName, Maybe (AccountType, Bool))]
forall a. Tree a -> [a]
flatten Tree (AccountName, Maybe (AccountType, Bool))
t']
where
t :: Tree AccountName
t = [AccountName] -> Tree AccountName
accountNameTreeFrom ([AccountName] -> Tree AccountName)
-> [AccountName] -> Tree AccountName
forall a b. (a -> b) -> a -> b
$ Journal -> [AccountName]
journalAccountNames Journal
j :: Tree AccountName
t' :: Tree (AccountName, Maybe (AccountType, Bool))
t' = Maybe (AccountType, Bool)
-> Tree AccountName
-> Tree (AccountName, Maybe (AccountType, Bool))
settypes Maybe (AccountType, Bool)
forall a. Maybe a
Nothing Tree AccountName
t :: Tree (AccountName, Maybe (AccountType, Bool))
where
settypes :: Maybe (AccountType, Bool) -> Tree AccountName -> Tree (AccountName, Maybe (AccountType, Bool))
settypes :: Maybe (AccountType, Bool)
-> Tree AccountName
-> Tree (AccountName, Maybe (AccountType, Bool))
settypes Maybe (AccountType, Bool)
mparenttype (Node AccountName
a Forest AccountName
subs) = (AccountName, Maybe (AccountType, Bool))
-> Forest (AccountName, Maybe (AccountType, Bool))
-> Tree (AccountName, Maybe (AccountType, Bool))
forall a. a -> Forest a -> Tree a
Node (AccountName
a, Maybe (AccountType, Bool)
mtype) ((Tree AccountName -> Tree (AccountName, Maybe (AccountType, Bool)))
-> Forest AccountName
-> Forest (AccountName, Maybe (AccountType, Bool))
forall a b. (a -> b) -> [a] -> [b]
map (Maybe (AccountType, Bool)
-> Tree AccountName
-> Tree (AccountName, Maybe (AccountType, Bool))
settypes Maybe (AccountType, Bool)
mtype) Forest AccountName
subs)
where
mtype :: Maybe (AccountType, Bool)
mtype = AccountName
-> Map AccountName (AccountType, Bool) -> Maybe (AccountType, Bool)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup AccountName
a Map AccountName (AccountType, Bool)
declaredtypes Maybe (AccountType, Bool)
-> Maybe (AccountType, Bool) -> Maybe (AccountType, Bool)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe (AccountType, Bool)
minferred
where
declaredtypes :: Map AccountName (AccountType, Bool)
declaredtypes = (,Bool
True) (AccountType -> (AccountType, Bool))
-> Map AccountName AccountType
-> Map AccountName (AccountType, Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Journal -> Map AccountName AccountType
journalDeclaredAccountTypes Journal
j
minferred :: Maybe (AccountType, Bool)
minferred = if Bool
-> ((AccountType, Bool) -> Bool)
-> Maybe (AccountType, Bool)
-> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (AccountType, Bool) -> Bool
forall a b. (a, b) -> b
snd Maybe (AccountType, Bool)
mparenttype
then Maybe (AccountType, Bool)
mparenttype
else (,Bool
False) (AccountType -> (AccountType, Bool))
-> Maybe AccountType -> Maybe (AccountType, Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AccountName -> Maybe AccountType
accountNameInferType AccountName
a Maybe (AccountType, Bool)
-> Maybe (AccountType, Bool) -> Maybe (AccountType, Bool)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe (AccountType, Bool)
mparenttype
journalDeclaredAccountTypes :: Journal -> M.Map AccountName AccountType
journalDeclaredAccountTypes :: Journal -> Map AccountName AccountType
journalDeclaredAccountTypes Journal{Map AccountType [AccountName]
jdeclaredaccounttypes :: Map AccountType [AccountName]
jdeclaredaccounttypes :: Journal -> Map AccountType [AccountName]
jdeclaredaccounttypes} =
[(AccountName, AccountType)] -> Map AccountName AccountType
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(AccountName, AccountType)] -> Map AccountName AccountType)
-> [(AccountName, AccountType)] -> Map AccountName AccountType
forall a b. (a -> b) -> a -> b
$ [[(AccountName, AccountType)]] -> [(AccountName, AccountType)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [(AccountName -> (AccountName, AccountType))
-> [AccountName] -> [(AccountName, AccountType)]
forall a b. (a -> b) -> [a] -> [b]
map (,AccountType
t) [AccountName]
as | (AccountType
t,[AccountName]
as) <- Map AccountType [AccountName] -> [(AccountType, [AccountName])]
forall k a. Map k a -> [(k, a)]
M.toList Map AccountType [AccountName]
jdeclaredaccounttypes]
journalPostingsAddAccountTags :: Journal -> Journal
journalPostingsAddAccountTags :: Journal -> Journal
journalPostingsAddAccountTags Journal
j = (Posting -> Posting) -> Journal -> Journal
journalMapPostings Posting -> Posting
addtags Journal
j
where addtags :: Posting -> Posting
addtags Posting
p = Posting
p Posting -> [Tag] -> Posting
`postingAddTags` (Journal -> AccountName -> [Tag]
journalInheritedAccountTags Journal
j (AccountName -> [Tag]) -> AccountName -> [Tag]
forall a b. (a -> b) -> a -> b
$ Posting -> AccountName
paccount Posting
p)
filterJournalTransactions :: Query -> Journal -> Journal
filterJournalTransactions :: Query -> Journal -> Journal
filterJournalTransactions Query
q j :: Journal
j@Journal{[Transaction]
jtxns :: [Transaction]
jtxns :: Journal -> [Transaction]
jtxns} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Bool) -> [Transaction] -> [Transaction]
forall a. (a -> Bool) -> [a] -> [a]
filter ((AccountName -> Maybe AccountType) -> Query -> Transaction -> Bool
matchesTransactionExtra (Journal -> AccountName -> Maybe AccountType
journalAccountType Journal
j) Query
q) [Transaction]
jtxns}
filterJournalPostings :: Query -> Journal -> Journal
filterJournalPostings :: Query -> Journal -> Journal
filterJournalPostings Query
q j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map ((AccountName -> Maybe AccountType)
-> Query -> Transaction -> Transaction
filterTransactionPostingsExtra (Journal -> AccountName -> Maybe AccountType
journalAccountType Journal
j) Query
q) [Transaction]
ts}
filterJournalRelatedPostings :: Query -> Journal -> Journal
filterJournalRelatedPostings :: Query -> Journal -> Journal
filterJournalRelatedPostings Query
q j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map (Query -> Transaction -> Transaction
filterTransactionRelatedPostings Query
q) [Transaction]
ts}
filterJournalAmounts :: Query -> Journal -> Journal
filterJournalAmounts :: Query -> Journal -> Journal
filterJournalAmounts Query
q j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map (Query -> Transaction -> Transaction
filterTransactionAmounts Query
q) [Transaction]
ts}
filterTransactionAmounts :: Query -> Transaction -> Transaction
filterTransactionAmounts :: Query -> Transaction -> Transaction
filterTransactionAmounts Query
q t :: Transaction
t@Transaction{tpostings :: Transaction -> [Posting]
tpostings=[Posting]
ps} = Transaction
t{tpostings :: [Posting]
tpostings=(Posting -> Maybe Posting) -> [Posting] -> [Posting]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (Query -> Posting -> Maybe Posting
filterPostingAmount Query
q) [Posting]
ps}
filterPostingAmount :: Query -> Posting -> Maybe Posting
filterPostingAmount :: Query -> Posting -> Maybe Posting
filterPostingAmount Query
q p :: Posting
p@Posting{pamount :: Posting -> MixedAmount
pamount=MixedAmount
as}
| Map MixedAmountKey Amount -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Map MixedAmountKey Amount
newamt = Maybe Posting
forall a. Maybe a
Nothing
| Bool
otherwise = Posting -> Maybe Posting
forall a. a -> Maybe a
Just Posting
p{pamount :: MixedAmount
pamount=Map MixedAmountKey Amount -> MixedAmount
Mixed Map MixedAmountKey Amount
newamt}
where
Mixed Map MixedAmountKey Amount
newamt = (Amount -> Bool) -> MixedAmount -> MixedAmount
filterMixedAmount (Query
q Query -> Amount -> Bool
`matchesAmount`) MixedAmount
as
filterTransactionPostings :: Query -> Transaction -> Transaction
filterTransactionPostings :: Query -> Transaction -> Transaction
filterTransactionPostings Query
q t :: Transaction
t@Transaction{tpostings :: Transaction -> [Posting]
tpostings=[Posting]
ps} = Transaction
t{tpostings :: [Posting]
tpostings=(Posting -> Bool) -> [Posting] -> [Posting]
forall a. (a -> Bool) -> [a] -> [a]
filter (Query
q Query -> Posting -> Bool
`matchesPosting`) [Posting]
ps}
filterTransactionPostingsExtra :: (AccountName -> Maybe AccountType) -> Query -> Transaction -> Transaction
AccountName -> Maybe AccountType
atypes Query
q t :: Transaction
t@Transaction{tpostings :: Transaction -> [Posting]
tpostings=[Posting]
ps} =
Transaction
t{tpostings :: [Posting]
tpostings=(Posting -> Bool) -> [Posting] -> [Posting]
forall a. (a -> Bool) -> [a] -> [a]
filter ((AccountName -> Maybe AccountType) -> Query -> Posting -> Bool
matchesPostingExtra AccountName -> Maybe AccountType
atypes Query
q) [Posting]
ps}
filterTransactionRelatedPostings :: Query -> Transaction -> Transaction
filterTransactionRelatedPostings :: Query -> Transaction -> Transaction
filterTransactionRelatedPostings Query
q t :: Transaction
t@Transaction{tpostings :: Transaction -> [Posting]
tpostings=[Posting]
ps} =
Transaction
t{tpostings :: [Posting]
tpostings=if [Posting] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Posting]
matches then [] else [Posting]
ps [Posting] -> [Posting] -> [Posting]
forall a. Eq a => [a] -> [a] -> [a]
\\ [Posting]
matches}
where matches :: [Posting]
matches = (Posting -> Bool) -> [Posting] -> [Posting]
forall a. (a -> Bool) -> [a] -> [a]
filter (Query -> Posting -> Bool
matchesPosting Query
q) [Posting]
ps
journalMapTransactions :: (Transaction -> Transaction) -> Journal -> Journal
journalMapTransactions :: (Transaction -> Transaction) -> Journal -> Journal
journalMapTransactions Transaction -> Transaction
f j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map Transaction -> Transaction
f [Transaction]
ts}
journalMapPostings :: (Posting -> Posting) -> Journal -> Journal
journalMapPostings :: (Posting -> Posting) -> Journal -> Journal
journalMapPostings Posting -> Posting
f j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map ((Posting -> Posting) -> Transaction -> Transaction
transactionMapPostings Posting -> Posting
f) [Transaction]
ts}
journalMapPostingAmounts :: (MixedAmount -> MixedAmount) -> Journal -> Journal
journalMapPostingAmounts :: (MixedAmount -> MixedAmount) -> Journal -> Journal
journalMapPostingAmounts MixedAmount -> MixedAmount
f = (Posting -> Posting) -> Journal -> Journal
journalMapPostings ((MixedAmount -> MixedAmount) -> Posting -> Posting
postingTransformAmount MixedAmount -> MixedAmount
f)
journalReverse :: Journal -> Journal
journalReverse :: Journal -> Journal
journalReverse Journal
j =
Journal
j {jfiles :: [(String, AccountName)]
jfiles = [(String, AccountName)] -> [(String, AccountName)]
forall a. [a] -> [a]
reverse ([(String, AccountName)] -> [(String, AccountName)])
-> [(String, AccountName)] -> [(String, AccountName)]
forall a b. (a -> b) -> a -> b
$ Journal -> [(String, AccountName)]
jfiles Journal
j
,jdeclaredaccounts :: [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts = [(AccountName, AccountDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
forall a. [a] -> [a]
reverse ([(AccountName, AccountDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)])
-> [(AccountName, AccountDeclarationInfo)]
-> [(AccountName, AccountDeclarationInfo)]
forall a b. (a -> b) -> a -> b
$ Journal -> [(AccountName, AccountDeclarationInfo)]
jdeclaredaccounts Journal
j
,jtxns :: [Transaction]
jtxns = [Transaction] -> [Transaction]
forall a. [a] -> [a]
reverse ([Transaction] -> [Transaction]) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j
,jtxnmodifiers :: [TransactionModifier]
jtxnmodifiers = [TransactionModifier] -> [TransactionModifier]
forall a. [a] -> [a]
reverse ([TransactionModifier] -> [TransactionModifier])
-> [TransactionModifier] -> [TransactionModifier]
forall a b. (a -> b) -> a -> b
$ Journal -> [TransactionModifier]
jtxnmodifiers Journal
j
,jperiodictxns :: [PeriodicTransaction]
jperiodictxns = [PeriodicTransaction] -> [PeriodicTransaction]
forall a. [a] -> [a]
reverse ([PeriodicTransaction] -> [PeriodicTransaction])
-> [PeriodicTransaction] -> [PeriodicTransaction]
forall a b. (a -> b) -> a -> b
$ Journal -> [PeriodicTransaction]
jperiodictxns Journal
j
,jpricedirectives :: [PriceDirective]
jpricedirectives = [PriceDirective] -> [PriceDirective]
forall a. [a] -> [a]
reverse ([PriceDirective] -> [PriceDirective])
-> [PriceDirective] -> [PriceDirective]
forall a b. (a -> b) -> a -> b
$ Journal -> [PriceDirective]
jpricedirectives Journal
j
}
journalSetLastReadTime :: POSIXTime -> Journal -> Journal
journalSetLastReadTime :: POSIXTime -> Journal -> Journal
journalSetLastReadTime POSIXTime
t Journal
j = Journal
j{ jlastreadtime :: POSIXTime
jlastreadtime = POSIXTime
t }
journalNumberAndTieTransactions :: Journal -> Journal
journalNumberAndTieTransactions = Journal -> Journal
journalTieTransactions (Journal -> Journal) -> (Journal -> Journal) -> Journal -> Journal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Journal
journalNumberTransactions
journalNumberTransactions :: Journal -> Journal
journalNumberTransactions :: Journal -> Journal
journalNumberTransactions j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Year -> Transaction -> Transaction)
-> [Year] -> [Transaction] -> [Transaction]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Year
i Transaction
t -> Transaction
t{tindex :: Year
tindex=Year
i}) [Year
1..] [Transaction]
ts}
journalTieTransactions :: Journal -> Journal
journalTieTransactions :: Journal -> Journal
journalTieTransactions j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map Transaction -> Transaction
txnTieKnot [Transaction]
ts}
journalUntieTransactions :: Transaction -> Transaction
journalUntieTransactions :: Transaction -> Transaction
journalUntieTransactions t :: Transaction
t@Transaction{tpostings :: Transaction -> [Posting]
tpostings=[Posting]
ps} = Transaction
t{tpostings :: [Posting]
tpostings=(Posting -> Posting) -> [Posting] -> [Posting]
forall a b. (a -> b) -> [a] -> [b]
map (\Posting
p -> Posting
p{ptransaction :: Maybe Transaction
ptransaction=Maybe Transaction
forall a. Maybe a
Nothing}) [Posting]
ps}
journalModifyTransactions :: Day -> Journal -> Either String Journal
journalModifyTransactions :: Day -> Journal -> Either String Journal
journalModifyTransactions Day
d Journal
j =
case (AccountName -> Maybe AccountType)
-> (AccountName -> [Tag])
-> Map AccountName AmountStyle
-> Day
-> [TransactionModifier]
-> [Transaction]
-> Either String [Transaction]
modifyTransactions (Journal -> AccountName -> Maybe AccountType
journalAccountType Journal
j) (Journal -> AccountName -> [Tag]
journalInheritedAccountTags Journal
j) (Journal -> Map AccountName AmountStyle
journalCommodityStyles Journal
j) Day
d (Journal -> [TransactionModifier]
jtxnmodifiers Journal
j) (Journal -> [Transaction]
jtxns Journal
j) of
Right [Transaction]
ts -> Journal -> Either String Journal
forall a b. b -> Either a b
Right Journal
j{jtxns :: [Transaction]
jtxns=[Transaction]
ts}
Left String
err -> String -> Either String Journal
forall a b. a -> Either a b
Left String
err
journalApplyCommodityStyles :: Journal -> Either String Journal
journalApplyCommodityStyles :: Journal -> Either String Journal
journalApplyCommodityStyles = (Journal -> Journal)
-> Either String Journal -> Either String Journal
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Journal -> Journal
fixjournal (Either String Journal -> Either String Journal)
-> (Journal -> Either String Journal)
-> Journal
-> Either String Journal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> Either String Journal
journalInferCommodityStyles
where
fixjournal :: Journal -> Journal
fixjournal j :: Journal
j@Journal{jpricedirectives :: Journal -> [PriceDirective]
jpricedirectives=[PriceDirective]
pds} =
(Posting -> Posting) -> Journal -> Journal
journalMapPostings (Map AccountName AmountStyle -> Posting -> Posting
postingApplyCommodityStyles Map AccountName AmountStyle
styles) Journal
j{jpricedirectives :: [PriceDirective]
jpricedirectives=(PriceDirective -> PriceDirective)
-> [PriceDirective] -> [PriceDirective]
forall a b. (a -> b) -> [a] -> [b]
map PriceDirective -> PriceDirective
fixpricedirective [PriceDirective]
pds}
where
styles :: Map AccountName AmountStyle
styles = Journal -> Map AccountName AmountStyle
journalCommodityStyles Journal
j
fixpricedirective :: PriceDirective -> PriceDirective
fixpricedirective pd :: PriceDirective
pd@PriceDirective{pdamount :: PriceDirective -> Amount
pdamount=Amount
a} = PriceDirective
pd{pdamount :: Amount
pdamount=Map AccountName AmountStyle -> Amount -> Amount
styleAmountExceptPrecision Map AccountName AmountStyle
styles Amount
a}
journalCommodityStyles :: Journal -> M.Map CommoditySymbol AmountStyle
journalCommodityStyles :: Journal -> Map AccountName AmountStyle
journalCommodityStyles Journal
j =
Map AccountName AmountStyle
globalstyles Map AccountName AmountStyle
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Semigroup a => a -> a -> a
<> Map AccountName AmountStyle
declaredstyles Map AccountName AmountStyle
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Semigroup a => a -> a -> a
<> Map AccountName AmountStyle
defaultcommoditystyle Map AccountName AmountStyle
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Semigroup a => a -> a -> a
<> Map AccountName AmountStyle
inferredstyles
where
globalstyles :: Map AccountName AmountStyle
globalstyles = Journal -> Map AccountName AmountStyle
jglobalcommoditystyles Journal
j
declaredstyles :: Map AccountName AmountStyle
declaredstyles = (Commodity -> Maybe AmountStyle)
-> Map AccountName Commodity -> Map AccountName AmountStyle
forall a b k. (a -> Maybe b) -> Map k a -> Map k b
M.mapMaybe Commodity -> Maybe AmountStyle
cformat (Map AccountName Commodity -> Map AccountName AmountStyle)
-> Map AccountName Commodity -> Map AccountName AmountStyle
forall a b. (a -> b) -> a -> b
$ Journal -> Map AccountName Commodity
jcommodities Journal
j
defaultcommoditystyle :: Map AccountName AmountStyle
defaultcommoditystyle = [(AccountName, AmountStyle)] -> Map AccountName AmountStyle
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(AccountName, AmountStyle)] -> Map AccountName AmountStyle)
-> [(AccountName, AmountStyle)] -> Map AccountName AmountStyle
forall a b. (a -> b) -> a -> b
$ [Maybe (AccountName, AmountStyle)] -> [(AccountName, AmountStyle)]
forall a. [Maybe a] -> [a]
catMaybes [Journal -> Maybe (AccountName, AmountStyle)
jparsedefaultcommodity Journal
j]
inferredstyles :: Map AccountName AmountStyle
inferredstyles = Journal -> Map AccountName AmountStyle
jinferredcommodities Journal
j
journalInferCommodityStyles :: Journal -> Either String Journal
journalInferCommodityStyles :: Journal -> Either String Journal
journalInferCommodityStyles Journal
j =
case [Amount] -> Either String (Map AccountName AmountStyle)
commodityStylesFromAmounts ([Amount] -> Either String (Map AccountName AmountStyle))
-> [Amount] -> Either String (Map AccountName AmountStyle)
forall a b. (a -> b) -> a -> b
$ Journal -> [Amount]
journalStyleInfluencingAmounts Journal
j of
Left String
e -> String -> Either String Journal
forall a b. a -> Either a b
Left String
e
Right Map AccountName AmountStyle
cs -> Journal -> Either String Journal
forall a b. b -> Either a b
Right Journal
j{jinferredcommodities :: Map AccountName AmountStyle
jinferredcommodities = String
-> Map AccountName AmountStyle -> Map AccountName AmountStyle
forall a. Show a => String -> a -> a
dbg7 String
"journalInferCommodityStyles" Map AccountName AmountStyle
cs}
commodityStylesFromAmounts :: [Amount] -> Either String (M.Map CommoditySymbol AmountStyle)
commodityStylesFromAmounts :: [Amount] -> Either String (Map AccountName AmountStyle)
commodityStylesFromAmounts =
Map AccountName AmountStyle
-> Either String (Map AccountName AmountStyle)
forall a b. b -> Either a b
Right (Map AccountName AmountStyle
-> Either String (Map AccountName AmountStyle))
-> ([Amount] -> Map AccountName AmountStyle)
-> [Amount]
-> Either String (Map AccountName AmountStyle)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Amount
-> Map AccountName AmountStyle -> Map AccountName AmountStyle)
-> Map AccountName AmountStyle
-> [Amount]
-> Map AccountName AmountStyle
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Amount
a -> (AmountStyle -> AmountStyle -> AmountStyle)
-> AccountName
-> AmountStyle
-> Map AccountName AmountStyle
-> Map AccountName AmountStyle
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith AmountStyle -> AmountStyle -> AmountStyle
canonicalStyle (Amount -> AccountName
acommodity Amount
a) (Amount -> AmountStyle
astyle Amount
a)) Map AccountName AmountStyle
forall a. Monoid a => a
mempty
canonicalStyleFrom :: [AmountStyle] -> AmountStyle
canonicalStyleFrom :: [AmountStyle] -> AmountStyle
canonicalStyleFrom = (AmountStyle -> AmountStyle -> AmountStyle)
-> AmountStyle -> [AmountStyle] -> AmountStyle
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' AmountStyle -> AmountStyle -> AmountStyle
canonicalStyle AmountStyle
amountstyle
canonicalStyle :: AmountStyle -> AmountStyle -> AmountStyle
canonicalStyle :: AmountStyle -> AmountStyle -> AmountStyle
canonicalStyle AmountStyle
a AmountStyle
b = AmountStyle
a{asprecision :: AmountPrecision
asprecision=AmountPrecision
prec, asdecimalpoint :: Maybe DecimalMark
asdecimalpoint=Maybe DecimalMark
decmark, asdigitgroups :: Maybe DigitGroupStyle
asdigitgroups=Maybe DigitGroupStyle
mgrps}
where
prec :: AmountPrecision
prec = AmountPrecision -> AmountPrecision -> AmountPrecision
forall a. Ord a => a -> a -> a
max (AmountStyle -> AmountPrecision
asprecision AmountStyle
a) (AmountStyle -> AmountPrecision
asprecision AmountStyle
b)
mgrps :: Maybe DigitGroupStyle
mgrps = AmountStyle -> Maybe DigitGroupStyle
asdigitgroups AmountStyle
a Maybe DigitGroupStyle
-> Maybe DigitGroupStyle -> Maybe DigitGroupStyle
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> AmountStyle -> Maybe DigitGroupStyle
asdigitgroups AmountStyle
b
defdecmark :: DecimalMark
defdecmark = case Maybe DigitGroupStyle
mgrps of
Just (DigitGroups DecimalMark
'.' [Word8]
_) -> DecimalMark
','
Maybe DigitGroupStyle
_ -> DecimalMark
'.'
decmark :: Maybe DecimalMark
decmark = case Maybe DigitGroupStyle
mgrps of
Just DigitGroupStyle
_ -> DecimalMark -> Maybe DecimalMark
forall a. a -> Maybe a
Just DecimalMark
defdecmark
Maybe DigitGroupStyle
Nothing -> AmountStyle -> Maybe DecimalMark
asdecimalpoint AmountStyle
a Maybe DecimalMark -> Maybe DecimalMark -> Maybe DecimalMark
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> AmountStyle -> Maybe DecimalMark
asdecimalpoint AmountStyle
b Maybe DecimalMark -> Maybe DecimalMark -> Maybe DecimalMark
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> DecimalMark -> Maybe DecimalMark
forall a. a -> Maybe a
Just DecimalMark
defdecmark
journalInferMarketPricesFromTransactions :: Journal -> Journal
journalInferMarketPricesFromTransactions :: Journal -> Journal
journalInferMarketPricesFromTransactions Journal
j =
Journal
j{jinferredmarketprices :: [MarketPrice]
jinferredmarketprices =
String -> [MarketPrice] -> [MarketPrice]
forall a. Show a => String -> a -> a
dbg4 String
"jinferredmarketprices" ([MarketPrice] -> [MarketPrice])
-> ([Posting] -> [MarketPrice]) -> [Posting] -> [MarketPrice]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
(PriceDirective -> MarketPrice)
-> [PriceDirective] -> [MarketPrice]
forall a b. (a -> b) -> [a] -> [b]
map PriceDirective -> MarketPrice
priceDirectiveToMarketPrice ([PriceDirective] -> [MarketPrice])
-> ([Posting] -> [PriceDirective]) -> [Posting] -> [MarketPrice]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
(Posting -> [PriceDirective]) -> [Posting] -> [PriceDirective]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Posting -> [PriceDirective]
postingPriceDirectivesFromCost ([Posting] -> [MarketPrice]) -> [Posting] -> [MarketPrice]
forall a b. (a -> b) -> a -> b
$
Journal -> [Posting]
journalPostings Journal
j
}
journalToCost :: ConversionOp -> Journal -> Journal
journalToCost :: ConversionOp -> Journal -> Journal
journalToCost ConversionOp
cost j :: Journal
j@Journal{jtxns :: Journal -> [Transaction]
jtxns=[Transaction]
ts} = Journal
j{jtxns :: [Transaction]
jtxns=(Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map (Map AccountName AmountStyle
-> ConversionOp -> Transaction -> Transaction
transactionToCost Map AccountName AmountStyle
styles ConversionOp
cost) [Transaction]
ts}
where
styles :: Map AccountName AmountStyle
styles = Journal -> Map AccountName AmountStyle
journalCommodityStyles Journal
j
journalAddInferredEquityPostings :: Journal -> Journal
journalAddInferredEquityPostings :: Journal -> Journal
journalAddInferredEquityPostings Journal
j = (Transaction -> Transaction) -> Journal -> Journal
journalMapTransactions (AccountName -> Transaction -> Transaction
transactionAddInferredEquityPostings AccountName
equityAcct) Journal
j
where
equityAcct :: AccountName
equityAcct = Journal -> AccountName
journalConversionAccount Journal
j
journalStyleInfluencingAmounts :: Journal -> [Amount]
journalStyleInfluencingAmounts :: Journal -> [Amount]
journalStyleInfluencingAmounts Journal
j =
String -> [Amount] -> [Amount]
forall a. Show a => String -> a -> a
dbg7 String
"journalStyleInfluencingAmounts" ([Amount] -> [Amount]) -> [Amount] -> [Amount]
forall a b. (a -> b) -> a -> b
$
[Maybe Amount] -> [Amount]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Amount] -> [Amount]) -> [Maybe Amount] -> [Amount]
forall a b. (a -> b) -> a -> b
$ [[Maybe Amount]] -> [Maybe Amount]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
[Maybe Amount
mdefaultcommodityamt]
,(PriceDirective -> Maybe Amount)
-> [PriceDirective] -> [Maybe Amount]
forall a b. (a -> b) -> [a] -> [b]
map (Amount -> Maybe Amount
forall a. a -> Maybe a
Just (Amount -> Maybe Amount)
-> (PriceDirective -> Amount) -> PriceDirective -> Maybe Amount
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PriceDirective -> Amount
pdamount) ([PriceDirective] -> [Maybe Amount])
-> [PriceDirective] -> [Maybe Amount]
forall a b. (a -> b) -> a -> b
$ Journal -> [PriceDirective]
jpricedirectives Journal
j
,(Amount -> Maybe Amount) -> [Amount] -> [Maybe Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Maybe Amount
forall a. a -> Maybe a
Just ([Amount] -> [Maybe Amount])
-> ([Posting] -> [Amount]) -> [Posting] -> [Maybe Amount]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Posting -> [Amount]) -> [Posting] -> [Amount]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (MixedAmount -> [Amount]
amountsRaw (MixedAmount -> [Amount])
-> (Posting -> MixedAmount) -> Posting -> [Amount]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Posting -> MixedAmount
pamount) ([Posting] -> [Maybe Amount]) -> [Posting] -> [Maybe Amount]
forall a b. (a -> b) -> a -> b
$ Journal -> [Posting]
journalPostings Journal
j
]
where
mdefaultcommodityamt :: Maybe Amount
mdefaultcommodityamt =
case Journal -> Maybe (AccountName, AmountStyle)
jparsedefaultcommodity Journal
j of
Just (AccountName
symbol,AmountStyle
style) -> Amount -> Maybe Amount
forall a. a -> Maybe a
Just Amount
nullamt{acommodity :: AccountName
acommodity=AccountName
symbol,astyle :: AmountStyle
astyle=AmountStyle
style}
Maybe (AccountName, AmountStyle)
Nothing -> Maybe Amount
forall a. Maybe a
Nothing
journalDateSpan :: Bool -> Journal -> DateSpan
journalDateSpan :: Bool -> Journal -> DateSpan
journalDateSpan Bool
False = Maybe WhichDate -> Journal -> DateSpan
journalDateSpanHelper (Maybe WhichDate -> Journal -> DateSpan)
-> Maybe WhichDate -> Journal -> DateSpan
forall a b. (a -> b) -> a -> b
$ WhichDate -> Maybe WhichDate
forall a. a -> Maybe a
Just WhichDate
PrimaryDate
journalDateSpan Bool
True = Maybe WhichDate -> Journal -> DateSpan
journalDateSpanHelper (Maybe WhichDate -> Journal -> DateSpan)
-> Maybe WhichDate -> Journal -> DateSpan
forall a b. (a -> b) -> a -> b
$ WhichDate -> Maybe WhichDate
forall a. a -> Maybe a
Just WhichDate
SecondaryDate
journalDateSpanBothDates :: Journal -> DateSpan
journalDateSpanBothDates :: Journal -> DateSpan
journalDateSpanBothDates = Maybe WhichDate -> Journal -> DateSpan
journalDateSpanHelper Maybe WhichDate
forall a. Maybe a
Nothing
journalDateSpanHelper :: Maybe WhichDate -> Journal -> DateSpan
journalDateSpanHelper :: Maybe WhichDate -> Journal -> DateSpan
journalDateSpanHelper Maybe WhichDate
whichdate Journal
j =
Maybe Day -> Maybe Day -> DateSpan
DateSpan ([Day] -> Maybe Day
forall a. Ord a => [a] -> Maybe a
minimumMay [Day]
dates) (Year -> Day -> Day
addDays Year
1 (Day -> Day) -> Maybe Day -> Maybe Day
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Day] -> Maybe Day
forall a. Ord a => [a] -> Maybe a
maximumMay [Day]
dates)
where
dates :: [Day]
dates = [Day]
pdates [Day] -> [Day] -> [Day]
forall a. [a] -> [a] -> [a]
++ [Day]
tdates
tdates :: [Day]
tdates = (Transaction -> [Day]) -> [Transaction] -> [Day]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Transaction -> [Day]
gettdate [Transaction]
ts
pdates :: [Day]
pdates = (Posting -> [Day]) -> [Posting] -> [Day]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Posting -> [Day]
getpdate ([Posting] -> [Day]) -> [Posting] -> [Day]
forall a b. (a -> b) -> a -> b
$ (Transaction -> [Posting]) -> [Transaction] -> [Posting]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Transaction -> [Posting]
tpostings [Transaction]
ts
ts :: [Transaction]
ts = Journal -> [Transaction]
jtxns Journal
j
gettdate :: Transaction -> [Day]
gettdate Transaction
t = case Maybe WhichDate
whichdate of
Just WhichDate
PrimaryDate -> [Transaction -> Day
tdate Transaction
t]
Just WhichDate
SecondaryDate -> [Day -> Maybe Day -> Day
forall a. a -> Maybe a -> a
fromMaybe (Transaction -> Day
tdate Transaction
t) (Maybe Day -> Day) -> Maybe Day -> Day
forall a b. (a -> b) -> a -> b
$ Transaction -> Maybe Day
tdate2 Transaction
t]
Maybe WhichDate
Nothing -> Transaction -> Day
tdate Transaction
t Day -> [Day] -> [Day]
forall a. a -> [a] -> [a]
: Maybe Day -> [Day]
forall a. Maybe a -> [a]
maybeToList (Transaction -> Maybe Day
tdate2 Transaction
t)
getpdate :: Posting -> [Day]
getpdate Posting
p = case Maybe WhichDate
whichdate of
Just WhichDate
PrimaryDate -> Maybe Day -> [Day]
forall a. Maybe a -> [a]
maybeToList (Maybe Day -> [Day]) -> Maybe Day -> [Day]
forall a b. (a -> b) -> a -> b
$ Posting -> Maybe Day
pdate Posting
p
Just WhichDate
SecondaryDate -> Maybe Day -> [Day]
forall a. Maybe a -> [a]
maybeToList (Maybe Day -> [Day]) -> Maybe Day -> [Day]
forall a b. (a -> b) -> a -> b
$ Posting -> Maybe Day
pdate2 Posting
p Maybe Day -> Maybe Day -> Maybe Day
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Posting -> Maybe Day
pdate Posting
p
Maybe WhichDate
Nothing -> [Maybe Day] -> [Day]
forall a. [Maybe a] -> [a]
catMaybes [Posting -> Maybe Day
pdate Posting
p, Posting -> Maybe Day
pdate2 Posting
p]
journalStartDate :: Bool -> Journal -> Maybe Day
journalStartDate :: Bool -> Journal -> Maybe Day
journalStartDate Bool
secondary Journal
j = Maybe Day
b where DateSpan Maybe Day
b Maybe Day
_ = Bool -> Journal -> DateSpan
journalDateSpan Bool
secondary Journal
j
journalEndDate :: Bool -> Journal -> Maybe Day
journalEndDate :: Bool -> Journal -> Maybe Day
journalEndDate Bool
secondary Journal
j = Maybe Day
e where DateSpan Maybe Day
_ Maybe Day
e = Bool -> Journal -> DateSpan
journalDateSpan Bool
secondary Journal
j
journalLastDay :: Bool -> Journal -> Maybe Day
journalLastDay :: Bool -> Journal -> Maybe Day
journalLastDay Bool
secondary Journal
j = Year -> Day -> Day
addDays (-Year
1) (Day -> Day) -> Maybe Day -> Maybe Day
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bool -> Journal -> Maybe Day
journalEndDate Bool
secondary Journal
j
journalPivot :: Text -> Journal -> Journal
journalPivot :: AccountName -> Journal -> Journal
journalPivot AccountName
fieldortagname Journal
j = Journal
j{jtxns :: [Transaction]
jtxns = (Transaction -> Transaction) -> [Transaction] -> [Transaction]
forall a b. (a -> b) -> [a] -> [b]
map (AccountName -> Transaction -> Transaction
transactionPivot AccountName
fieldortagname) ([Transaction] -> [Transaction])
-> (Journal -> [Transaction]) -> Journal -> [Transaction]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [Transaction]
jtxns (Journal -> [Transaction]) -> Journal -> [Transaction]
forall a b. (a -> b) -> a -> b
$ Journal
j}
transactionPivot :: Text -> Transaction -> Transaction
transactionPivot :: AccountName -> Transaction -> Transaction
transactionPivot AccountName
fieldortagname Transaction
t = Transaction
t{tpostings :: [Posting]
tpostings = (Posting -> Posting) -> [Posting] -> [Posting]
forall a b. (a -> b) -> [a] -> [b]
map (AccountName -> Posting -> Posting
postingPivot AccountName
fieldortagname) ([Posting] -> [Posting])
-> (Transaction -> [Posting]) -> Transaction -> [Posting]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Transaction -> [Posting]
tpostings (Transaction -> [Posting]) -> Transaction -> [Posting]
forall a b. (a -> b) -> a -> b
$ Transaction
t}
postingPivot :: Text -> Posting -> Posting
postingPivot :: AccountName -> Posting -> Posting
postingPivot AccountName
fieldortagname Posting
p = Posting
p{paccount :: AccountName
paccount = AccountName
pivotedacct, poriginal :: Maybe Posting
poriginal = Posting -> Maybe Posting
forall a. a -> Maybe a
Just (Posting -> Maybe Posting) -> Posting -> Maybe Posting
forall a b. (a -> b) -> a -> b
$ Posting -> Posting
originalPosting Posting
p}
where
pivotedacct :: AccountName
pivotedacct
| Just Transaction
t <- Posting -> Maybe Transaction
ptransaction Posting
p, AccountName
fieldortagname AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
== AccountName
"code" = Transaction -> AccountName
tcode Transaction
t
| Just Transaction
t <- Posting -> Maybe Transaction
ptransaction Posting
p, AccountName
fieldortagname AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
== AccountName
"description" = Transaction -> AccountName
tdescription Transaction
t
| Just Transaction
t <- Posting -> Maybe Transaction
ptransaction Posting
p, AccountName
fieldortagname AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
== AccountName
"payee" = Transaction -> AccountName
transactionPayee Transaction
t
| Just Transaction
t <- Posting -> Maybe Transaction
ptransaction Posting
p, AccountName
fieldortagname AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
== AccountName
"note" = Transaction -> AccountName
transactionNote Transaction
t
| Just Transaction
t <- Posting -> Maybe Transaction
ptransaction Posting
p, AccountName
fieldortagname AccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
== AccountName
"status" = String -> AccountName
T.pack (String -> AccountName)
-> (Transaction -> String) -> Transaction -> AccountName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Status -> String
forall a. Show a => a -> String
show (Status -> String)
-> (Transaction -> Status) -> Transaction -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Transaction -> Status
tstatus (Transaction -> AccountName) -> Transaction -> AccountName
forall a b. (a -> b) -> a -> b
$ Transaction
t
| Just (AccountName
_, AccountName
value) <- AccountName -> Posting -> Maybe Tag
postingFindTag AccountName
fieldortagname Posting
p = AccountName
value
| Bool
otherwise = AccountName
""
postingFindTag :: TagName -> Posting -> Maybe (TagName, TagValue)
postingFindTag :: AccountName -> Posting -> Maybe Tag
postingFindTag AccountName
tagname Posting
p = (Tag -> Bool) -> [Tag] -> Maybe Tag
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((AccountName
tagnameAccountName -> AccountName -> Bool
forall a. Eq a => a -> a -> Bool
==) (AccountName -> Bool) -> (Tag -> AccountName) -> Tag -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tag -> AccountName
forall a b. (a, b) -> a
fst) ([Tag] -> Maybe Tag) -> [Tag] -> Maybe Tag
forall a b. (a -> b) -> a -> b
$ Posting -> [Tag]
postingAllTags Posting
p
journalApplyAliases :: [AccountAlias] -> Journal -> Either RegexError Journal
journalApplyAliases :: [AccountAlias] -> Journal -> Either String Journal
journalApplyAliases [] Journal
j = Journal -> Either String Journal
forall a b. b -> Either a b
Right Journal
j
journalApplyAliases [AccountAlias]
aliases Journal
j =
case (Transaction -> Either String Transaction)
-> [Transaction] -> Either String [Transaction]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([AccountAlias] -> Transaction -> Either String Transaction
transactionApplyAliases [AccountAlias]
aliases) ([Transaction] -> Either String [Transaction])
-> [Transaction] -> Either String [Transaction]
forall a b. (a -> b) -> a -> b
$ Journal -> [Transaction]
jtxns Journal
j of
Right [Transaction]
ts -> Journal -> Either String Journal
forall a b. b -> Either a b
Right Journal
j{jtxns :: [Transaction]
jtxns = [Transaction]
ts}
Left String
err -> String -> Either String Journal
forall a b. a -> Either a b
Left String
err
samplejournal :: Journal
samplejournal = Bool -> Journal
samplejournalMaybeExplicit Bool
True
samplejournalMaybeExplicit :: Bool -> Journal
samplejournalMaybeExplicit :: Bool -> Journal
samplejournalMaybeExplicit Bool
explicit = Journal
nulljournal
{jtxns :: [Transaction]
jtxns = [
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
01 Int
01,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"income",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[AccountName
"assets:bank:checking" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"income:salary" AccountName -> Amount -> Posting
`post` if Bool
explicit then DecimalRaw Year -> Amount
usd (-DecimalRaw Year
1) else Amount
missingamt
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
,
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
06 Int
01,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"gift",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[AccountName
"assets:bank:checking" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"income:gifts" AccountName -> Amount -> Posting
`post` if Bool
explicit then DecimalRaw Year -> Amount
usd (-DecimalRaw Year
1) else Amount
missingamt
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
,
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
06 Int
02,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"save",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=
[AccountName
"assets:bank:saving" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"assets:bank:checking" AccountName -> Amount -> Posting
`post` if Bool
explicit then DecimalRaw Year -> Amount
usd (-DecimalRaw Year
1) else Amount
missingamt
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
,
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
06 Int
03,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Cleared,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"eat & shop",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=[AccountName
"expenses:food" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"expenses:supplies" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"assets:cash" AccountName -> Amount -> Posting
`post` if Bool
explicit then DecimalRaw Year -> Amount
usd (-DecimalRaw Year
2) else Amount
missingamt
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
,
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
10 Int
01,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"take a loan",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=[AccountName
"assets:bank:checking" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"liabilities:debts" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd (-DecimalRaw Year
1)
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
,
Transaction -> Transaction
txnTieKnot (Transaction -> Transaction) -> Transaction -> Transaction
forall a b. (a -> b) -> a -> b
$ Transaction :: Year
-> AccountName
-> (SourcePos, SourcePos)
-> Day
-> Maybe Day
-> Status
-> AccountName
-> AccountName
-> AccountName
-> [Tag]
-> [Posting]
-> Transaction
Transaction {
tindex :: Year
tindex=Year
0,
tsourcepos :: (SourcePos, SourcePos)
tsourcepos=(SourcePos, SourcePos)
nullsourcepos,
tdate :: Day
tdate=Year -> Int -> Int -> Day
fromGregorian Year
2008 Int
12 Int
31,
tdate2 :: Maybe Day
tdate2=Maybe Day
forall a. Maybe a
Nothing,
tstatus :: Status
tstatus=Status
Unmarked,
tcode :: AccountName
tcode=AccountName
"",
tdescription :: AccountName
tdescription=AccountName
"pay off",
tcomment :: AccountName
tcomment=AccountName
"",
ttags :: [Tag]
ttags=[],
tpostings :: [Posting]
tpostings=[AccountName
"liabilities:debts" AccountName -> Amount -> Posting
`post` DecimalRaw Year -> Amount
usd DecimalRaw Year
1
,AccountName
"assets:bank:checking" AccountName -> Amount -> Posting
`post` if Bool
explicit then DecimalRaw Year -> Amount
usd (-DecimalRaw Year
1) else Amount
missingamt
],
tprecedingcomment :: AccountName
tprecedingcomment=AccountName
""
}
]
}
tests_Journal :: TestTree
tests_Journal = String -> [TestTree] -> TestTree
testGroup String
"Journal" [
String -> Assertion -> TestTree
testCase String
"journalDateSpan" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
Bool -> Journal -> DateSpan
journalDateSpan Bool
True Journal
nulljournal{
jtxns :: [Transaction]
jtxns = [Transaction
nulltransaction{tdate :: Day
tdate = Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
02 Int
01
,tpostings :: [Posting]
tpostings = [Posting
posting{pdate :: Maybe Day
pdate=Day -> Maybe Day
forall a. a -> Maybe a
Just (Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
01 Int
10)}]
}
,Transaction
nulltransaction{tdate :: Day
tdate = Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
09 Int
01
,tpostings :: [Posting]
tpostings = [Posting
posting{pdate2 :: Maybe Day
pdate2=Day -> Maybe Day
forall a. a -> Maybe a
Just (Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
10 Int
10)}]
}
]
}
DateSpan -> DateSpan -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= (Maybe Day -> Maybe Day -> DateSpan
DateSpan (Day -> Maybe Day
forall a. a -> Maybe a
Just (Day -> Maybe Day) -> Day -> Maybe Day
forall a b. (a -> b) -> a -> b
$ Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
1 Int
10) (Day -> Maybe Day
forall a. a -> Maybe a
Just (Day -> Maybe Day) -> Day -> Maybe Day
forall a b. (a -> b) -> a -> b
$ Year -> Int -> Int -> Day
fromGregorian Year
2014 Int
10 Int
11))
,String -> [TestTree] -> TestTree
testGroup String
"standard account type queries" ([TestTree] -> TestTree) -> [TestTree] -> TestTree
forall a b. (a -> b) -> a -> b
$
let
j :: Journal
j = Journal
samplejournal
journalAccountNamesMatching :: Query -> Journal -> [AccountName]
journalAccountNamesMatching :: Query -> Journal -> [AccountName]
journalAccountNamesMatching Query
q = (AccountName -> Bool) -> [AccountName] -> [AccountName]
forall a. (a -> Bool) -> [a] -> [a]
filter (Query
q Query -> AccountName -> Bool
`matchesAccount`) ([AccountName] -> [AccountName])
-> (Journal -> [AccountName]) -> Journal -> [AccountName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Journal -> [AccountName]
journalAccountNames
namesfrom :: (Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
qfunc = Query -> Journal -> [AccountName]
journalAccountNamesMatching (Journal -> Query
qfunc Journal
j) Journal
j
in [String -> Assertion -> TestTree
testCase String
"assets" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" [AccountName
"assets",AccountName
"assets:bank",AccountName
"assets:bank:checking",AccountName
"assets:bank:saving",AccountName
"assets:cash"]
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalAssetAccountQuery)
,String -> Assertion -> TestTree
testCase String
"cash" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" [AccountName
"assets:bank",AccountName
"assets:bank:checking",AccountName
"assets:bank:saving",AccountName
"assets:cash"]
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalCashAccountQuery)
,String -> Assertion -> TestTree
testCase String
"liabilities" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" [AccountName
"liabilities",AccountName
"liabilities:debts"]
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalLiabilityAccountQuery)
,String -> Assertion -> TestTree
testCase String
"equity" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" []
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalEquityAccountQuery)
,String -> Assertion -> TestTree
testCase String
"income" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" [AccountName
"income",AccountName
"income:gifts",AccountName
"income:salary"]
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalRevenueAccountQuery)
,String -> Assertion -> TestTree
testCase String
"expenses" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ String -> [AccountName] -> [AccountName] -> Assertion
forall a.
(Eq a, Show a, HasCallStack) =>
String -> a -> a -> Assertion
assertEqual String
"" [AccountName
"expenses",AccountName
"expenses:food",AccountName
"expenses:supplies"]
((Journal -> Query) -> [AccountName]
namesfrom Journal -> Query
journalExpenseAccountQuery)
]
]