{- |
New common report types, used by the BudgetReport for now, perhaps all reports later.
-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor  #-}
{-# LANGUAGE DeriveGeneric  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NamedFieldPuns #-}

module Hledger.Reports.ReportTypes
( PeriodicReport(..)
, PeriodicReportRow(..)

, Percentage
, Change
, Balance
, Total
, Average

, periodicReportSpan
, prMapName
, prMapMaybeName

, CompoundPeriodicReport(..)
, CBCSubreportSpec(..)

, DisplayName(..)
, flatDisplayName
, treeDisplayName

, prrFullName
, prrDisplayName
, prrDepth
, prrAdd
) where

import Data.Aeson (ToJSON(..))
import Data.Bifunctor (Bifunctor(..))
import Data.Decimal (Decimal)
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import GHC.Generics (Generic)

import Hledger.Data
import Hledger.Query (Query)
import Hledger.Reports.ReportOptions (ReportOpts)

type Percentage = Decimal

type Change  = MixedAmount  -- ^ A change in balance during a certain period.
type Balance = MixedAmount  -- ^ An ending balance as of some date.
type Total   = MixedAmount  -- ^ The sum of 'Change's in a report or a report row. Does not make sense for 'Balance's.
type Average = MixedAmount  -- ^ The average of 'Change's or 'Balance's in a report or report row.

-- | A periodic report is a generic tabular report, where each row corresponds
-- to some label (usually an account name) and each column to a date period.
-- The column periods are usually consecutive subperiods formed by splitting
-- the overall report period by some report interval (daily, weekly, etc.).
-- It has:
--
-- 1. a list of each column's period (date span)
--
-- 2. a list of rows, each containing:
--
--   * an account label
--
--   * the account's depth
--
--   * A list of amounts, one for each column. Depending on the value type,
--     these can represent balance changes, ending balances, budget
--     performance, etc. (for example, see 'BalanceAccumulation' and
--     "Hledger.Cli.Commands.Balance").
--
--   * the total of the row's amounts for a periodic report,
--     or zero for cumulative/historical reports (since summing
--     end balances generally doesn't make sense).
--
--   * the average of the row's amounts
--
-- 3. the column totals, and the overall grand total (or zero for
-- cumulative/historical reports) and grand average.

data PeriodicReport a b =
  PeriodicReport
  { forall a b. PeriodicReport a b -> [DateSpan]
prDates  :: [DateSpan]               -- The subperiods formed by splitting the overall
                                         -- report period by the report interval. For
                                         -- ending-balance reports, only the end date is
                                         -- significant. Usually displayed as report columns.
  , forall a b. PeriodicReport a b -> [PeriodicReportRow a b]
prRows   :: [PeriodicReportRow a b]  -- One row per account in the report.
  , forall a b. PeriodicReport a b -> PeriodicReportRow () b
prTotals :: PeriodicReportRow () b   -- The grand totals row.
  } deriving (Int -> PeriodicReport a b -> ShowS
[PeriodicReport a b] -> ShowS
PeriodicReport a b -> String
(Int -> PeriodicReport a b -> ShowS)
-> (PeriodicReport a b -> String)
-> ([PeriodicReport a b] -> ShowS)
-> Show (PeriodicReport a b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall a b. (Show a, Show b) => Int -> PeriodicReport a b -> ShowS
forall a b. (Show a, Show b) => [PeriodicReport a b] -> ShowS
forall a b. (Show a, Show b) => PeriodicReport a b -> String
$cshowsPrec :: forall a b. (Show a, Show b) => Int -> PeriodicReport a b -> ShowS
showsPrec :: Int -> PeriodicReport a b -> ShowS
$cshow :: forall a b. (Show a, Show b) => PeriodicReport a b -> String
show :: PeriodicReport a b -> String
$cshowList :: forall a b. (Show a, Show b) => [PeriodicReport a b] -> ShowS
showList :: [PeriodicReport a b] -> ShowS
Show, (forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b)
-> (forall a b. a -> PeriodicReport a b -> PeriodicReport a a)
-> Functor (PeriodicReport a)
forall a b. a -> PeriodicReport a b -> PeriodicReport a a
forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
forall a a b. a -> PeriodicReport a b -> PeriodicReport a a
forall a a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
fmap :: forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
$c<$ :: forall a a b. a -> PeriodicReport a b -> PeriodicReport a a
<$ :: forall a b. a -> PeriodicReport a b -> PeriodicReport a a
Functor, (forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x)
-> (forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b)
-> Generic (PeriodicReport a b)
forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b
forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a b x. Rep (PeriodicReport a b) x -> PeriodicReport a b
forall a b x. PeriodicReport a b -> Rep (PeriodicReport a b) x
$cfrom :: forall a b x. PeriodicReport a b -> Rep (PeriodicReport a b) x
from :: forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x
$cto :: forall a b x. Rep (PeriodicReport a b) x -> PeriodicReport a b
to :: forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b
Generic, [PeriodicReport a b] -> Value
[PeriodicReport a b] -> Encoding
PeriodicReport a b -> Bool
PeriodicReport a b -> Value
PeriodicReport a b -> Encoding
(PeriodicReport a b -> Value)
-> (PeriodicReport a b -> Encoding)
-> ([PeriodicReport a b] -> Value)
-> ([PeriodicReport a b] -> Encoding)
-> (PeriodicReport a b -> Bool)
-> ToJSON (PeriodicReport a b)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
forall a b. (ToJSON a, ToJSON b) => [PeriodicReport a b] -> Value
forall a b.
(ToJSON a, ToJSON b) =>
[PeriodicReport a b] -> Encoding
forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Bool
forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Value
forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Encoding
$ctoJSON :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Value
toJSON :: PeriodicReport a b -> Value
$ctoEncoding :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Encoding
toEncoding :: PeriodicReport a b -> Encoding
$ctoJSONList :: forall a b. (ToJSON a, ToJSON b) => [PeriodicReport a b] -> Value
toJSONList :: [PeriodicReport a b] -> Value
$ctoEncodingList :: forall a b.
(ToJSON a, ToJSON b) =>
[PeriodicReport a b] -> Encoding
toEncodingList :: [PeriodicReport a b] -> Encoding
$comitField :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Bool
omitField :: PeriodicReport a b -> Bool
ToJSON)

instance Bifunctor PeriodicReport where
  bimap :: forall a b c d.
(a -> b) -> (c -> d) -> PeriodicReport a c -> PeriodicReport b d
bimap a -> b
f c -> d
g PeriodicReport a c
pr = PeriodicReport a c
pr{prRows = map (bimap f g) $ prRows pr, prTotals = g <$> prTotals pr}

instance HasAmounts b => HasAmounts (PeriodicReport a b) where
  styleAmounts :: Map CommoditySymbol AmountStyle
-> PeriodicReport a b -> PeriodicReport a b
styleAmounts Map CommoditySymbol AmountStyle
styles r :: PeriodicReport a b
r@PeriodicReport{[PeriodicReportRow a b]
prRows :: forall a b. PeriodicReport a b -> [PeriodicReportRow a b]
prRows :: [PeriodicReportRow a b]
prRows,PeriodicReportRow () b
prTotals :: forall a b. PeriodicReport a b -> PeriodicReportRow () b
prTotals :: PeriodicReportRow () b
prTotals} =
    PeriodicReport a b
r{prRows=styleAmounts styles prRows, prTotals=styleAmounts styles prTotals}

data PeriodicReportRow a b =
  PeriodicReportRow
  { forall a b. PeriodicReportRow a b -> a
prrName    :: a    -- An account name.
  , forall a b. PeriodicReportRow a b -> [b]
prrAmounts :: [b]  -- The data value for each subperiod.
  , forall a b. PeriodicReportRow a b -> b
prrTotal   :: b    -- The total of this row's values.
  , forall a b. PeriodicReportRow a b -> b
prrAverage :: b    -- The average of this row's values.
  } deriving (Int -> PeriodicReportRow a b -> ShowS
[PeriodicReportRow a b] -> ShowS
PeriodicReportRow a b -> String
(Int -> PeriodicReportRow a b -> ShowS)
-> (PeriodicReportRow a b -> String)
-> ([PeriodicReportRow a b] -> ShowS)
-> Show (PeriodicReportRow a b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall a b.
(Show a, Show b) =>
Int -> PeriodicReportRow a b -> ShowS
forall a b. (Show a, Show b) => [PeriodicReportRow a b] -> ShowS
forall a b. (Show a, Show b) => PeriodicReportRow a b -> String
$cshowsPrec :: forall a b.
(Show a, Show b) =>
Int -> PeriodicReportRow a b -> ShowS
showsPrec :: Int -> PeriodicReportRow a b -> ShowS
$cshow :: forall a b. (Show a, Show b) => PeriodicReportRow a b -> String
show :: PeriodicReportRow a b -> String
$cshowList :: forall a b. (Show a, Show b) => [PeriodicReportRow a b] -> ShowS
showList :: [PeriodicReportRow a b] -> ShowS
Show, (forall a b.
 (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b)
-> (forall a b.
    a -> PeriodicReportRow a b -> PeriodicReportRow a a)
-> Functor (PeriodicReportRow a)
forall a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
forall a b.
(a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
forall a a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
forall a a b.
(a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a a b.
(a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
fmap :: forall a b.
(a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
$c<$ :: forall a a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
<$ :: forall a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
Functor, (forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x)
-> (forall x.
    Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b)
-> Generic (PeriodicReportRow a b)
forall x. Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a b x.
Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
forall a b x.
PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
$cfrom :: forall a b x.
PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
from :: forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
$cto :: forall a b x.
Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
to :: forall x. Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
Generic, [PeriodicReportRow a b] -> Value
[PeriodicReportRow a b] -> Encoding
PeriodicReportRow a b -> Bool
PeriodicReportRow a b -> Value
PeriodicReportRow a b -> Encoding
(PeriodicReportRow a b -> Value)
-> (PeriodicReportRow a b -> Encoding)
-> ([PeriodicReportRow a b] -> Value)
-> ([PeriodicReportRow a b] -> Encoding)
-> (PeriodicReportRow a b -> Bool)
-> ToJSON (PeriodicReportRow a b)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
forall a b.
(ToJSON b, ToJSON a) =>
[PeriodicReportRow a b] -> Value
forall a b.
(ToJSON b, ToJSON a) =>
[PeriodicReportRow a b] -> Encoding
forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Bool
forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Value
forall a b.
(ToJSON b, ToJSON a) =>
PeriodicReportRow a b -> Encoding
$ctoJSON :: forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Value
toJSON :: PeriodicReportRow a b -> Value
$ctoEncoding :: forall a b.
(ToJSON b, ToJSON a) =>
PeriodicReportRow a b -> Encoding
toEncoding :: PeriodicReportRow a b -> Encoding
$ctoJSONList :: forall a b.
(ToJSON b, ToJSON a) =>
[PeriodicReportRow a b] -> Value
toJSONList :: [PeriodicReportRow a b] -> Value
$ctoEncodingList :: forall a b.
(ToJSON b, ToJSON a) =>
[PeriodicReportRow a b] -> Encoding
toEncodingList :: [PeriodicReportRow a b] -> Encoding
$comitField :: forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Bool
omitField :: PeriodicReportRow a b -> Bool
ToJSON)

instance Bifunctor PeriodicReportRow where
  first :: forall a b c.
(a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
first a -> b
f PeriodicReportRow a c
prr = PeriodicReportRow a c
prr{prrName = f $ prrName prr}
  second :: forall b c a.
(b -> c) -> PeriodicReportRow a b -> PeriodicReportRow a c
second = (b -> c) -> PeriodicReportRow a b -> PeriodicReportRow a c
forall a b.
(a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap

instance Semigroup b => Semigroup (PeriodicReportRow a b) where
  <> :: PeriodicReportRow a b
-> PeriodicReportRow a b -> PeriodicReportRow a b
(<>) = PeriodicReportRow a b
-> PeriodicReportRow a b -> PeriodicReportRow a b
forall b a.
Semigroup b =>
PeriodicReportRow a b
-> PeriodicReportRow a b -> PeriodicReportRow a b
prrAdd

instance HasAmounts b => HasAmounts (PeriodicReportRow a b) where
  styleAmounts :: Map CommoditySymbol AmountStyle
-> PeriodicReportRow a b -> PeriodicReportRow a b
styleAmounts Map CommoditySymbol AmountStyle
styles PeriodicReportRow a b
r =
    PeriodicReportRow a b
r{prrAmounts=styleAmounts styles $ prrAmounts r
     ,prrTotal  =styleAmounts styles $ prrTotal r
     ,prrAverage=styleAmounts styles $ prrAverage r
     }

-- | Add two 'PeriodicReportRows', preserving the name of the first.
prrAdd :: Semigroup b => PeriodicReportRow a b -> PeriodicReportRow a b -> PeriodicReportRow a b
prrAdd :: forall b a.
Semigroup b =>
PeriodicReportRow a b
-> PeriodicReportRow a b -> PeriodicReportRow a b
prrAdd (PeriodicReportRow a
n1 [b]
amts1 b
t1 b
a1) (PeriodicReportRow a
_ [b]
amts2 b
t2 b
a2) =
    a -> [b] -> b -> b -> PeriodicReportRow a b
forall a b. a -> [b] -> b -> b -> PeriodicReportRow a b
PeriodicReportRow a
n1 ((b -> b -> b) -> [b] -> [b] -> [b]
forall a. (a -> a -> a) -> [a] -> [a] -> [a]
zipWithPadded b -> b -> b
forall a. Semigroup a => a -> a -> a
(<>) [b]
amts1 [b]
amts2) (b
t1 b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
t2) (b
a1 b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
a2)

-- | Version of 'zipWith' which will not end on the shortest list, but will copy the rest of the longer list.
zipWithPadded :: (a -> a -> a) -> [a] -> [a] -> [a]
zipWithPadded :: forall a. (a -> a -> a) -> [a] -> [a] -> [a]
zipWithPadded a -> a -> a
f (a
a:[a]
as) (a
b:[a]
bs) = a -> a -> a
f a
a a
b a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (a -> a -> a) -> [a] -> [a] -> [a]
forall a. (a -> a -> a) -> [a] -> [a] -> [a]
zipWithPadded a -> a -> a
f [a]
as [a]
bs
zipWithPadded a -> a -> a
_ [a]
as     []     = [a]
as
zipWithPadded a -> a -> a
_ []     [a]
bs     = [a]
bs

-- | Figure out the overall date span of a PeriodicReport
periodicReportSpan :: PeriodicReport a b -> DateSpan
periodicReportSpan :: forall a b. PeriodicReport a b -> DateSpan
periodicReportSpan (PeriodicReport [] [PeriodicReportRow a b]
_ PeriodicReportRow () b
_)       = Maybe EFDay -> Maybe EFDay -> DateSpan
DateSpan Maybe EFDay
forall a. Maybe a
Nothing Maybe EFDay
forall a. Maybe a
Nothing
periodicReportSpan (PeriodicReport [DateSpan]
colspans [PeriodicReportRow a b]
_ PeriodicReportRow () b
_) = Maybe EFDay -> Maybe EFDay -> DateSpan
DateSpan ((Day -> EFDay) -> Maybe Day -> Maybe EFDay
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Day -> EFDay
Exact (Maybe Day -> Maybe EFDay)
-> (DateSpan -> Maybe Day) -> DateSpan -> Maybe EFDay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DateSpan -> Maybe Day
spanStart (DateSpan -> Maybe EFDay) -> DateSpan -> Maybe EFDay
forall a b. (a -> b) -> a -> b
$ [DateSpan] -> DateSpan
forall a. HasCallStack => [a] -> a
head [DateSpan]
colspans) ((Day -> EFDay) -> Maybe Day -> Maybe EFDay
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Day -> EFDay
Exact (Maybe Day -> Maybe EFDay)
-> (DateSpan -> Maybe Day) -> DateSpan -> Maybe EFDay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DateSpan -> Maybe Day
spanEnd (DateSpan -> Maybe EFDay) -> DateSpan -> Maybe EFDay
forall a b. (a -> b) -> a -> b
$ [DateSpan] -> DateSpan
forall a. HasCallStack => [a] -> a
last [DateSpan]
colspans)

-- | Map a function over the row names.
prMapName :: (a -> b) -> PeriodicReport a c -> PeriodicReport b c
prMapName :: forall a b c. (a -> b) -> PeriodicReport a c -> PeriodicReport b c
prMapName a -> b
f PeriodicReport a c
report = PeriodicReport a c
report{prRows = map (prrMapName f) $ prRows report}

-- | Map a function over the row names, possibly discarding some.
prMapMaybeName :: (a -> Maybe b) -> PeriodicReport a c -> PeriodicReport b c
prMapMaybeName :: forall a b c.
(a -> Maybe b) -> PeriodicReport a c -> PeriodicReport b c
prMapMaybeName a -> Maybe b
f PeriodicReport a c
report = PeriodicReport a c
report{prRows = mapMaybe (prrMapMaybeName f) $ prRows report}

-- | Map a function over the row names of the PeriodicReportRow.
prrMapName :: (a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
prrMapName :: forall a b c.
(a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
prrMapName a -> b
f PeriodicReportRow a c
row = PeriodicReportRow a c
row{prrName = f $ prrName row}

-- | Map maybe a function over the row names of the PeriodicReportRow.
prrMapMaybeName :: (a -> Maybe b) -> PeriodicReportRow a c -> Maybe (PeriodicReportRow b c)
prrMapMaybeName :: forall a b c.
(a -> Maybe b)
-> PeriodicReportRow a c -> Maybe (PeriodicReportRow b c)
prrMapMaybeName a -> Maybe b
f PeriodicReportRow a c
row = case a -> Maybe b
f (a -> Maybe b) -> a -> Maybe b
forall a b. (a -> b) -> a -> b
$ PeriodicReportRow a c -> a
forall a b. PeriodicReportRow a b -> a
prrName PeriodicReportRow a c
row of
    Maybe b
Nothing -> Maybe (PeriodicReportRow b c)
forall a. Maybe a
Nothing
    Just b
a  -> PeriodicReportRow b c -> Maybe (PeriodicReportRow b c)
forall a. a -> Maybe a
Just PeriodicReportRow a c
row{prrName = a}


-- | A compound balance report has:
--
-- * an overall title
--
-- * the period (date span) of each column
--
-- * one or more named, normal-positive multi balance reports,
--   with columns corresponding to the above, and a flag indicating
--   whether they increased or decreased the overall totals
--
-- * a list of overall totals for each column, and their grand total and average
--
-- It is used in compound balance report commands like balancesheet,
-- cashflow and incomestatement.
data CompoundPeriodicReport a b = CompoundPeriodicReport
  { forall a b. CompoundPeriodicReport a b -> CommoditySymbol
cbrTitle      :: Text
  , forall a b. CompoundPeriodicReport a b -> [DateSpan]
cbrDates      :: [DateSpan]
  , forall a b.
CompoundPeriodicReport a b
-> [(CommoditySymbol, PeriodicReport a b, Bool)]
cbrSubreports :: [(Text, PeriodicReport a b, Bool)]
  , forall a b. CompoundPeriodicReport a b -> PeriodicReportRow () b
cbrTotals     :: PeriodicReportRow () b
  } deriving (Int -> CompoundPeriodicReport a b -> ShowS
[CompoundPeriodicReport a b] -> ShowS
CompoundPeriodicReport a b -> String
(Int -> CompoundPeriodicReport a b -> ShowS)
-> (CompoundPeriodicReport a b -> String)
-> ([CompoundPeriodicReport a b] -> ShowS)
-> Show (CompoundPeriodicReport a b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall a b.
(Show a, Show b) =>
Int -> CompoundPeriodicReport a b -> ShowS
forall a b.
(Show a, Show b) =>
[CompoundPeriodicReport a b] -> ShowS
forall a b.
(Show a, Show b) =>
CompoundPeriodicReport a b -> String
$cshowsPrec :: forall a b.
(Show a, Show b) =>
Int -> CompoundPeriodicReport a b -> ShowS
showsPrec :: Int -> CompoundPeriodicReport a b -> ShowS
$cshow :: forall a b.
(Show a, Show b) =>
CompoundPeriodicReport a b -> String
show :: CompoundPeriodicReport a b -> String
$cshowList :: forall a b.
(Show a, Show b) =>
[CompoundPeriodicReport a b] -> ShowS
showList :: [CompoundPeriodicReport a b] -> ShowS
Show, (forall a b.
 (a -> b)
 -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b)
-> (forall a b.
    a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a)
-> Functor (CompoundPeriodicReport a)
forall a b.
a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
forall a b.
(a -> b)
-> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
forall a a b.
a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
forall a a b.
(a -> b)
-> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a a b.
(a -> b)
-> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
fmap :: forall a b.
(a -> b)
-> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
$c<$ :: forall a a b.
a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
<$ :: forall a b.
a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
Functor, (forall x.
 CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x)
-> (forall x.
    Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b)
-> Generic (CompoundPeriodicReport a b)
forall x.
Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
forall x.
CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a b x.
Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
forall a b x.
CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
$cfrom :: forall a b x.
CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
from :: forall x.
CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
$cto :: forall a b x.
Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
to :: forall x.
Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
Generic, [CompoundPeriodicReport a b] -> Value
[CompoundPeriodicReport a b] -> Encoding
CompoundPeriodicReport a b -> Bool
CompoundPeriodicReport a b -> Value
CompoundPeriodicReport a b -> Encoding
(CompoundPeriodicReport a b -> Value)
-> (CompoundPeriodicReport a b -> Encoding)
-> ([CompoundPeriodicReport a b] -> Value)
-> ([CompoundPeriodicReport a b] -> Encoding)
-> (CompoundPeriodicReport a b -> Bool)
-> ToJSON (CompoundPeriodicReport a b)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
forall a b.
(ToJSON b, ToJSON a) =>
[CompoundPeriodicReport a b] -> Value
forall a b.
(ToJSON b, ToJSON a) =>
[CompoundPeriodicReport a b] -> Encoding
forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Bool
forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Value
forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Encoding
$ctoJSON :: forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Value
toJSON :: CompoundPeriodicReport a b -> Value
$ctoEncoding :: forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Encoding
toEncoding :: CompoundPeriodicReport a b -> Encoding
$ctoJSONList :: forall a b.
(ToJSON b, ToJSON a) =>
[CompoundPeriodicReport a b] -> Value
toJSONList :: [CompoundPeriodicReport a b] -> Value
$ctoEncodingList :: forall a b.
(ToJSON b, ToJSON a) =>
[CompoundPeriodicReport a b] -> Encoding
toEncodingList :: [CompoundPeriodicReport a b] -> Encoding
$comitField :: forall a b.
(ToJSON b, ToJSON a) =>
CompoundPeriodicReport a b -> Bool
omitField :: CompoundPeriodicReport a b -> Bool
ToJSON)

instance HasAmounts b => HasAmounts (CompoundPeriodicReport a b) where
  styleAmounts :: Map CommoditySymbol AmountStyle
-> CompoundPeriodicReport a b -> CompoundPeriodicReport a b
styleAmounts Map CommoditySymbol AmountStyle
styles cpr :: CompoundPeriodicReport a b
cpr@CompoundPeriodicReport{[(CommoditySymbol, PeriodicReport a b, Bool)]
cbrSubreports :: forall a b.
CompoundPeriodicReport a b
-> [(CommoditySymbol, PeriodicReport a b, Bool)]
cbrSubreports :: [(CommoditySymbol, PeriodicReport a b, Bool)]
cbrSubreports, PeriodicReportRow () b
cbrTotals :: forall a b. CompoundPeriodicReport a b -> PeriodicReportRow () b
cbrTotals :: PeriodicReportRow () b
cbrTotals} =
    CompoundPeriodicReport a b
cpr{
        cbrSubreports = styleAmounts styles cbrSubreports
      , cbrTotals     = styleAmounts styles cbrTotals
      }

instance HasAmounts b => HasAmounts (Text, PeriodicReport a b, Bool) where
  styleAmounts :: Map CommoditySymbol AmountStyle
-> (CommoditySymbol, PeriodicReport a b, Bool)
-> (CommoditySymbol, PeriodicReport a b, Bool)
styleAmounts Map CommoditySymbol AmountStyle
styles (CommoditySymbol
a,PeriodicReport a b
b,Bool
c) = (CommoditySymbol
a,Map CommoditySymbol AmountStyle
-> PeriodicReport a b -> PeriodicReport a b
forall a. HasAmounts a => Map CommoditySymbol AmountStyle -> a -> a
styleAmounts Map CommoditySymbol AmountStyle
styles PeriodicReport a b
b,Bool
c)

-- | Description of one subreport within a compound balance report.
-- Part of a "CompoundBalanceCommandSpec", but also used in hledger-lib.
data CBCSubreportSpec a = CBCSubreportSpec
  { forall a. CBCSubreportSpec a -> CommoditySymbol
cbcsubreporttitle          :: Text                      -- ^ The title to use for the subreport
  , forall a. CBCSubreportSpec a -> Query
cbcsubreportquery          :: Query                     -- ^ The Query to use for the subreport
  , forall a. CBCSubreportSpec a -> ReportOpts -> ReportOpts
cbcsubreportoptions        :: ReportOpts -> ReportOpts  -- ^ A function to transform the ReportOpts used to produce the subreport
  , forall a.
CBCSubreportSpec a
-> PeriodicReport DisplayName MixedAmount
-> PeriodicReport a MixedAmount
cbcsubreporttransform      :: PeriodicReport DisplayName MixedAmount -> PeriodicReport a MixedAmount  -- ^ A function to transform the result of the subreport
  , forall a. CBCSubreportSpec a -> Bool
cbcsubreportincreasestotal :: Bool                      -- ^ Whether the subreport and overall report total are of the same sign (e.g. Assets are normally
                                                            --   positive in a balance sheet report, as is the overall total. Liabilities are normally of the
                                                            --   opposite sign.)
  }


-- | A full name, display name, and depth for an account.
data DisplayName = DisplayName
    { DisplayName -> CommoditySymbol
displayFull :: AccountName
    , DisplayName -> CommoditySymbol
displayName :: AccountName
    , DisplayName -> Int
displayDepth :: Int
    } deriving (Int -> DisplayName -> ShowS
[DisplayName] -> ShowS
DisplayName -> String
(Int -> DisplayName -> ShowS)
-> (DisplayName -> String)
-> ([DisplayName] -> ShowS)
-> Show DisplayName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DisplayName -> ShowS
showsPrec :: Int -> DisplayName -> ShowS
$cshow :: DisplayName -> String
show :: DisplayName -> String
$cshowList :: [DisplayName] -> ShowS
showList :: [DisplayName] -> ShowS
Show, DisplayName -> DisplayName -> Bool
(DisplayName -> DisplayName -> Bool)
-> (DisplayName -> DisplayName -> Bool) -> Eq DisplayName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DisplayName -> DisplayName -> Bool
== :: DisplayName -> DisplayName -> Bool
$c/= :: DisplayName -> DisplayName -> Bool
/= :: DisplayName -> DisplayName -> Bool
Eq, Eq DisplayName
Eq DisplayName =>
(DisplayName -> DisplayName -> Ordering)
-> (DisplayName -> DisplayName -> Bool)
-> (DisplayName -> DisplayName -> Bool)
-> (DisplayName -> DisplayName -> Bool)
-> (DisplayName -> DisplayName -> Bool)
-> (DisplayName -> DisplayName -> DisplayName)
-> (DisplayName -> DisplayName -> DisplayName)
-> Ord DisplayName
DisplayName -> DisplayName -> Bool
DisplayName -> DisplayName -> Ordering
DisplayName -> DisplayName -> DisplayName
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: DisplayName -> DisplayName -> Ordering
compare :: DisplayName -> DisplayName -> Ordering
$c< :: DisplayName -> DisplayName -> Bool
< :: DisplayName -> DisplayName -> Bool
$c<= :: DisplayName -> DisplayName -> Bool
<= :: DisplayName -> DisplayName -> Bool
$c> :: DisplayName -> DisplayName -> Bool
> :: DisplayName -> DisplayName -> Bool
$c>= :: DisplayName -> DisplayName -> Bool
>= :: DisplayName -> DisplayName -> Bool
$cmax :: DisplayName -> DisplayName -> DisplayName
max :: DisplayName -> DisplayName -> DisplayName
$cmin :: DisplayName -> DisplayName -> DisplayName
min :: DisplayName -> DisplayName -> DisplayName
Ord)

instance ToJSON DisplayName where
    toJSON :: DisplayName -> Value
toJSON = CommoditySymbol -> Value
forall a. ToJSON a => a -> Value
toJSON (CommoditySymbol -> Value)
-> (DisplayName -> CommoditySymbol) -> DisplayName -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DisplayName -> CommoditySymbol
displayFull
    toEncoding :: DisplayName -> Encoding
toEncoding = CommoditySymbol -> Encoding
forall a. ToJSON a => a -> Encoding
toEncoding (CommoditySymbol -> Encoding)
-> (DisplayName -> CommoditySymbol) -> DisplayName -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DisplayName -> CommoditySymbol
displayFull

-- | Construct a flat display name, where the full name is also displayed at
-- depth 1
flatDisplayName :: AccountName -> DisplayName
flatDisplayName :: CommoditySymbol -> DisplayName
flatDisplayName CommoditySymbol
a = CommoditySymbol -> CommoditySymbol -> Int -> DisplayName
DisplayName CommoditySymbol
a CommoditySymbol
a Int
1

-- | Construct a tree display name, where only the leaf is displayed at its
-- given depth
treeDisplayName :: AccountName -> DisplayName
treeDisplayName :: CommoditySymbol -> DisplayName
treeDisplayName CommoditySymbol
a = CommoditySymbol -> CommoditySymbol -> Int -> DisplayName
DisplayName CommoditySymbol
a (CommoditySymbol -> CommoditySymbol
accountLeafName CommoditySymbol
a) (CommoditySymbol -> Int
accountNameLevel CommoditySymbol
a)

-- | Get the full, canonical, name of a PeriodicReportRow tagged by a
-- DisplayName.
prrFullName :: PeriodicReportRow DisplayName a -> AccountName
prrFullName :: forall a. PeriodicReportRow DisplayName a -> CommoditySymbol
prrFullName = DisplayName -> CommoditySymbol
displayFull (DisplayName -> CommoditySymbol)
-> (PeriodicReportRow DisplayName a -> DisplayName)
-> PeriodicReportRow DisplayName a
-> CommoditySymbol
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PeriodicReportRow DisplayName a -> DisplayName
forall a b. PeriodicReportRow a b -> a
prrName

-- | Get the display name of a PeriodicReportRow tagged by a DisplayName.
prrDisplayName :: PeriodicReportRow DisplayName a -> AccountName
prrDisplayName :: forall a. PeriodicReportRow DisplayName a -> CommoditySymbol
prrDisplayName = DisplayName -> CommoditySymbol
displayName (DisplayName -> CommoditySymbol)
-> (PeriodicReportRow DisplayName a -> DisplayName)
-> PeriodicReportRow DisplayName a
-> CommoditySymbol
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PeriodicReportRow DisplayName a -> DisplayName
forall a b. PeriodicReportRow a b -> a
prrName

-- | Get the display depth of a PeriodicReportRow tagged by a DisplayName.
prrDepth :: PeriodicReportRow DisplayName a -> Int
prrDepth :: forall a. PeriodicReportRow DisplayName a -> Int
prrDepth = DisplayName -> Int
displayDepth (DisplayName -> Int)
-> (PeriodicReportRow DisplayName a -> DisplayName)
-> PeriodicReportRow DisplayName a
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PeriodicReportRow DisplayName a -> DisplayName
forall a b. PeriodicReportRow a b -> a
prrName