mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-08 07:09:28 +03:00
665fec83cd
Clean up valuation functions, and make clear which to use where.
109 lines
4.6 KiB
Haskell
109 lines
4.6 KiB
Haskell
{-# LANGUAGE FlexibleInstances #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-|
|
|
|
|
A transactions report. Like an EntriesReport, but with more
|
|
information such as a running balance.
|
|
|
|
-}
|
|
|
|
module Hledger.Reports.TransactionsReport (
|
|
TransactionsReport,
|
|
TransactionsReportItem,
|
|
transactionsReport,
|
|
transactionsReportByCommodity,
|
|
triOrigTransaction,
|
|
triDate,
|
|
triAmount,
|
|
triBalance,
|
|
triCommodityAmount,
|
|
triCommodityBalance,
|
|
tests_TransactionsReport
|
|
)
|
|
where
|
|
|
|
import Data.List (sortBy)
|
|
import Data.List.Extra (nubSort)
|
|
import Data.Ord (comparing)
|
|
import Data.Text (Text)
|
|
|
|
import Hledger.Data
|
|
import Hledger.Query
|
|
import Hledger.Reports.ReportOptions
|
|
import Hledger.Reports.AccountTransactionsReport
|
|
import Hledger.Utils
|
|
|
|
|
|
-- | A transactions report includes a list of transactions touching multiple accounts
|
|
-- (posting-filtered and unfiltered variants), a running balance, and some
|
|
-- other information helpful for rendering a register view with or without a notion
|
|
-- of current account(s). Two kinds of report use this data structure, see transactionsReport
|
|
-- and accountTransactionsReport below for details.
|
|
type TransactionsReport = [TransactionsReportItem] -- line items, one per transaction
|
|
type TransactionsReportItem = (Transaction -- the original journal transaction, unmodified
|
|
,Transaction -- the transaction as seen from a particular account, with postings maybe filtered
|
|
,Bool -- is this a split, ie more than one other account posting
|
|
,Text -- a display string describing the other account(s), if any
|
|
,MixedAmount -- the amount posted to the current account(s) by the filtered postings (or total amount posted)
|
|
,MixedAmount -- the running total of item amounts, starting from zero;
|
|
-- or with --historical, the running total including items
|
|
-- (matched by the report query) preceding the report period
|
|
)
|
|
|
|
triOrigTransaction (torig,_,_,_,_,_) = torig
|
|
triDate (_,tacct,_,_,_,_) = tdate tacct
|
|
triAmount (_,_,_,_,a,_) = a
|
|
triBalance (_,_,_,_,_,a) = a
|
|
triCommodityAmount c = filterMixedAmountByCommodity c . triAmount
|
|
triCommodityBalance c = filterMixedAmountByCommodity c . triBalance
|
|
|
|
-- | Select transactions from the whole journal. This is similar to a
|
|
-- "postingsReport" except with transaction-based report items which
|
|
-- are ordered most recent first. XXX Or an EntriesReport - use that instead ?
|
|
-- This is used by hledger-web's journal view.
|
|
transactionsReport :: ReportSpec -> Journal -> Query -> TransactionsReport
|
|
transactionsReport rspec j q = items
|
|
where
|
|
-- XXX items' first element should be the full transaction with all postings
|
|
items = reverse $ accountTransactionsReportItems q None nullmixedamt id ts
|
|
ts = sortBy (comparing date) $ filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j
|
|
date = transactionDateFn $ rsOpts rspec
|
|
|
|
-- | Split a transactions report whose items may involve several commodities,
|
|
-- into one or more single-commodity transactions reports.
|
|
transactionsReportByCommodity :: TransactionsReport -> [(CommoditySymbol, TransactionsReport)]
|
|
transactionsReportByCommodity tr =
|
|
[(c, filterTransactionsReportByCommodity c tr) | c <- transactionsReportCommodities tr]
|
|
where
|
|
transactionsReportCommodities = nubSort . map acommodity . concatMap (amounts . triAmount)
|
|
|
|
-- Remove transaction report items and item amount (and running
|
|
-- balance amount) components that don't involve the specified
|
|
-- commodity. Other item fields such as the transaction are left unchanged.
|
|
filterTransactionsReportByCommodity :: CommoditySymbol -> TransactionsReport -> TransactionsReport
|
|
filterTransactionsReportByCommodity c =
|
|
fixTransactionsReportItemBalances . concatMap (filterTransactionsReportItemByCommodity c)
|
|
where
|
|
filterTransactionsReportItemByCommodity c (t,t2,s,o,a,bal)
|
|
| c `elem` cs = [item']
|
|
| otherwise = []
|
|
where
|
|
cs = map acommodity $ amounts a
|
|
item' = (t,t2,s,o,a',bal)
|
|
a' = filterMixedAmountByCommodity c a
|
|
|
|
fixTransactionsReportItemBalances [] = []
|
|
fixTransactionsReportItemBalances [i] = [i]
|
|
fixTransactionsReportItemBalances items = reverse $ i:(go startbal is)
|
|
where
|
|
i:is = reverse items
|
|
startbal = filterMixedAmountByCommodity c $ triBalance i
|
|
go _ [] = []
|
|
go bal ((t,t2,s,o,amt,_):is) = (t,t2,s,o,amt,bal'):go bal' is
|
|
where bal' = bal `maPlus` amt
|
|
|
|
-- tests
|
|
|
|
tests_TransactionsReport = tests "TransactionsReport" [
|
|
]
|