{-# OPTIONS_GHC -Wno-warnings-deprecations #-}
{-# LANGUAGE StandaloneDeriving, RecordWildCards, OverloadedStrings #-}
module Hledger.Data.Amount (
amount,
nullamt,
missingamt,
num,
usd,
eur,
gbp,
per,
hrs,
at,
(@@),
amountWithCommodity,
amountCost,
amountIsZero,
amountLooksZero,
divideAmount,
multiplyAmount,
divideAmountAndPrice,
multiplyAmountAndPrice,
amountTotalPriceToUnitPrice,
amountstyle,
styleAmount,
styleAmountExceptPrecision,
showAmount,
cshowAmount,
showAmountWithZeroCommodity,
showAmountDebug,
showAmountWithoutPrice,
maxprecision,
maxprecisionwithpoint,
setAmountPrecision,
withPrecision,
setFullPrecision,
setNaturalPrecision,
setNaturalPrecisionUpTo,
setAmountInternalPrecision,
withInternalPrecision,
setAmountDecimalPoint,
withDecimalPoint,
canonicaliseAmount,
nullmixedamt,
missingmixedamt,
mixed,
amounts,
filterMixedAmount,
filterMixedAmountByCommodity,
mapMixedAmount,
normaliseMixedAmountSquashPricesForDisplay,
normaliseMixedAmount,
mixedAmountStripPrices,
mixedAmountCost,
divideMixedAmount,
multiplyMixedAmount,
divideMixedAmountAndPrice,
multiplyMixedAmountAndPrice,
averageMixedAmounts,
isNegativeAmount,
isNegativeMixedAmount,
mixedAmountIsZero,
mixedAmountLooksZero,
mixedAmountTotalPriceToUnitPrice,
styleMixedAmount,
showMixedAmount,
showMixedAmountOneLine,
showMixedAmountDebug,
showMixedAmountWithoutPrice,
showMixedAmountOneLineWithoutPrice,
cshowMixedAmountWithoutPrice,
cshowMixedAmountOneLineWithoutPrice,
showMixedAmountWithZeroCommodity,
showMixedAmountWithPrecision,
setMixedAmountPrecision,
canonicaliseMixedAmount,
ltraceamount,
tests_Amount
) where
import Data.Char (isDigit)
import Data.Decimal (roundTo, decimalPlaces, normalizeDecimal)
import Data.Function (on)
import Data.List
import qualified Data.Map as M
import Data.Map (findWithDefault)
import Data.Maybe
import qualified Data.Text as T
import Safe (maximumDef)
import Text.Printf
import Hledger.Data.Types
import Hledger.Data.Commodity
import Hledger.Utils
deriving instance Show MarketPrice
amountstyle :: AmountStyle
amountstyle = Side
-> Bool
-> Int
-> Maybe Char
-> Maybe DigitGroupStyle
-> AmountStyle
AmountStyle Side
L Bool
False 0 (Char -> Maybe Char
forall a. a -> Maybe a
Just '.') Maybe DigitGroupStyle
forall a. Maybe a
Nothing
instance Num Amount where
abs :: Amount -> Amount
abs a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Amount
a{aquantity :: Quantity
aquantity=Quantity -> Quantity
forall a. Num a => a -> a
abs Quantity
q}
signum :: Amount -> Amount
signum a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Amount
a{aquantity :: Quantity
aquantity=Quantity -> Quantity
forall a. Num a => a -> a
signum Quantity
q}
fromInteger :: Integer -> Amount
fromInteger i :: Integer
i = Amount
nullamt{aquantity :: Quantity
aquantity=Integer -> Quantity
forall a. Num a => Integer -> a
fromInteger Integer
i}
negate :: Amount -> Amount
negate a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Amount
a{aquantity :: Quantity
aquantity= -Quantity
q}
+ :: Amount -> Amount -> Amount
(+) = (Quantity -> Quantity -> Quantity) -> Amount -> Amount -> Amount
similarAmountsOp Quantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
(+)
(-) = (Quantity -> Quantity -> Quantity) -> Amount -> Amount -> Amount
similarAmountsOp (-)
* :: Amount -> Amount -> Amount
(*) = (Quantity -> Quantity -> Quantity) -> Amount -> Amount -> Amount
similarAmountsOp Quantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
(*)
amount, nullamt :: Amount
amount :: Amount
amount = Amount :: CommoditySymbol
-> Quantity -> Bool -> AmountStyle -> Maybe AmountPrice -> Amount
Amount{acommodity :: CommoditySymbol
acommodity="", aquantity :: Quantity
aquantity=0, aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing, astyle :: AmountStyle
astyle=AmountStyle
amountstyle, aismultiplier :: Bool
aismultiplier=Bool
False}
nullamt :: Amount
nullamt = Amount
amount
missingamt :: Amount
missingamt :: Amount
missingamt = Amount
amount{acommodity :: CommoditySymbol
acommodity="AUTO"}
num :: Quantity -> Amount
num n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="", aquantity :: Quantity
aquantity=Quantity
n}
hrs :: Quantity -> Amount
hrs n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="h", aquantity :: Quantity
aquantity=Quantity
n, astyle :: AmountStyle
astyle=AmountStyle
amountstyle{asprecision :: Int
asprecision=2, ascommodityside :: Side
ascommodityside=Side
R}}
usd :: Quantity -> Amount
usd n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="$", aquantity :: Quantity
aquantity=Word8 -> Quantity -> Quantity
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo 2 Quantity
n, astyle :: AmountStyle
astyle=AmountStyle
amountstyle{asprecision :: Int
asprecision=2}}
eur :: Quantity -> Amount
eur n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="€", aquantity :: Quantity
aquantity=Word8 -> Quantity -> Quantity
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo 2 Quantity
n, astyle :: AmountStyle
astyle=AmountStyle
amountstyle{asprecision :: Int
asprecision=2}}
gbp :: Quantity -> Amount
gbp n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="£", aquantity :: Quantity
aquantity=Word8 -> Quantity -> Quantity
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo 2 Quantity
n, astyle :: AmountStyle
astyle=AmountStyle
amountstyle{asprecision :: Int
asprecision=2}}
per :: Quantity -> Amount
per n :: Quantity
n = Amount
amount{acommodity :: CommoditySymbol
acommodity="%", aquantity :: Quantity
aquantity=Quantity
n, astyle :: AmountStyle
astyle=AmountStyle
amountstyle{asprecision :: Int
asprecision=1, ascommodityside :: Side
ascommodityside=Side
R, ascommodityspaced :: Bool
ascommodityspaced=Bool
True}}
amt :: Amount
amt at :: Amount -> Amount -> Amount
`at` priceamt :: Amount
priceamt = Amount
amt{aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
UnitPrice Amount
priceamt}
amt :: Amount
amt @@ :: Amount -> Amount -> Amount
@@ priceamt :: Amount
priceamt = Amount
amt{aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
TotalPrice Amount
priceamt}
similarAmountsOp :: (Quantity -> Quantity -> Quantity) -> Amount -> Amount -> Amount
similarAmountsOp :: (Quantity -> Quantity -> Quantity) -> Amount -> Amount -> Amount
similarAmountsOp op :: Quantity -> Quantity -> Quantity
op Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
_, aquantity :: Amount -> Quantity
aquantity=Quantity
q1, astyle :: Amount -> AmountStyle
astyle=AmountStyle{asprecision :: AmountStyle -> Int
asprecision=Int
p1}}
Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
c2, aquantity :: Amount -> Quantity
aquantity=Quantity
q2, astyle :: Amount -> AmountStyle
astyle=s2 :: AmountStyle
s2@AmountStyle{asprecision :: AmountStyle -> Int
asprecision=Int
p2}} =
Amount
amount{acommodity :: CommoditySymbol
acommodity=CommoditySymbol
c2, aquantity :: Quantity
aquantity=Quantity
q1 Quantity -> Quantity -> Quantity
`op` Quantity
q2, astyle :: AmountStyle
astyle=AmountStyle
s2{asprecision :: Int
asprecision=Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
p1 Int
p2}}
amountWithCommodity :: CommoditySymbol -> Amount -> Amount
amountWithCommodity :: CommoditySymbol -> Amount -> Amount
amountWithCommodity c :: CommoditySymbol
c a :: Amount
a = Amount
a{acommodity :: CommoditySymbol
acommodity=CommoditySymbol
c, aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
amountCost :: Amount -> Amount
amountCost :: Amount -> Amount
amountCost a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q, aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
mp} =
case Maybe AmountPrice
mp of
Nothing -> Amount
a
Just (UnitPrice p :: Amount
p@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
pq}) -> Amount
p{aquantity :: Quantity
aquantity=Quantity
pq Quantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
* Quantity
q}
Just (TotalPrice p :: Amount
p@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
pq}) -> Amount
p{aquantity :: Quantity
aquantity=Quantity
pq Quantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
* Quantity -> Quantity
forall a. Num a => a -> a
signum Quantity
q}
amountTotalPriceToUnitPrice :: Amount -> Amount
amountTotalPriceToUnitPrice :: Amount -> Amount
amountTotalPriceToUnitPrice
a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q, aprice :: Amount -> Maybe AmountPrice
aprice=Just (TotalPrice pa :: Amount
pa@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
pq, astyle :: Amount -> AmountStyle
astyle=ps :: AmountStyle
ps@AmountStyle{asprecision :: AmountStyle -> Int
asprecision=Int
pp}})}
= Amount
a{aprice :: Maybe AmountPrice
aprice = AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
UnitPrice Amount
pa{aquantity :: Quantity
aquantity=Quantity -> Quantity
forall a. Num a => a -> a
abs (Quantity
pqQuantity -> Quantity -> Quantity
forall a. Fractional a => a -> a -> a
/Quantity
q), astyle :: AmountStyle
astyle=AmountStyle
ps{asprecision :: Int
asprecision=Int
ppInt -> Int -> Int
forall a. Num a => a -> a -> a
+1}}}
amountTotalPriceToUnitPrice a :: Amount
a = Amount
a
divideAmount :: Quantity -> Amount -> Amount
divideAmount :: Quantity -> Amount -> Amount
divideAmount n :: Quantity
n a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Amount
a{aquantity :: Quantity
aquantity=Quantity
qQuantity -> Quantity -> Quantity
forall a. Fractional a => a -> a -> a
/Quantity
n}
multiplyAmount :: Quantity -> Amount -> Amount
multiplyAmount :: Quantity -> Amount -> Amount
multiplyAmount n :: Quantity
n a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Amount
a{aquantity :: Quantity
aquantity=Quantity
qQuantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
*Quantity
n}
divideAmountAndPrice :: Quantity -> Amount -> Amount
divideAmountAndPrice :: Quantity -> Amount -> Amount
divideAmountAndPrice n :: Quantity
n a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q,aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
p} = Amount
a{aquantity :: Quantity
aquantity=Quantity
qQuantity -> Quantity -> Quantity
forall a. Fractional a => a -> a -> a
/Quantity
n, aprice :: Maybe AmountPrice
aprice=AmountPrice -> AmountPrice
f (AmountPrice -> AmountPrice)
-> Maybe AmountPrice -> Maybe AmountPrice
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe AmountPrice
p}
where
f :: AmountPrice -> AmountPrice
f (TotalPrice a :: Amount
a) = Amount -> AmountPrice
TotalPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> Amount
forall a. Num a => a -> a
abs (Amount -> Amount) -> Amount -> Amount
forall a b. (a -> b) -> a -> b
$ Quantity
n Quantity -> Amount -> Amount
`divideAmount` Amount
a
f p :: AmountPrice
p = AmountPrice
p
multiplyAmountAndPrice :: Quantity -> Amount -> Amount
multiplyAmountAndPrice :: Quantity -> Amount -> Amount
multiplyAmountAndPrice n :: Quantity
n a :: Amount
a@Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q,aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
p} = Amount
a{aquantity :: Quantity
aquantity=Quantity
qQuantity -> Quantity -> Quantity
forall a. Num a => a -> a -> a
*Quantity
n, aprice :: Maybe AmountPrice
aprice=AmountPrice -> AmountPrice
f (AmountPrice -> AmountPrice)
-> Maybe AmountPrice -> Maybe AmountPrice
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe AmountPrice
p}
where
f :: AmountPrice -> AmountPrice
f (TotalPrice a :: Amount
a) = Amount -> AmountPrice
TotalPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> Amount
forall a. Num a => a -> a
abs (Amount -> Amount) -> Amount -> Amount
forall a b. (a -> b) -> a -> b
$ Quantity
n Quantity -> Amount -> Amount
`multiplyAmount` Amount
a
f p :: AmountPrice
p = AmountPrice
p
isNegativeAmount :: Amount -> Bool
isNegativeAmount :: Amount -> Bool
isNegativeAmount Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Quantity
q Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< 0
digits :: String
digits = "123456789" :: String
amountLooksZero :: Amount -> Bool
amountLooksZero :: Amount -> Bool
amountLooksZero = Bool -> Bool
not (Bool -> Bool) -> (Amount -> Bool) -> Amount -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
digits) (String -> Bool) -> (Amount -> String) -> Amount -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> String
showAmountWithoutPriceOrCommodity
amountIsZero :: Amount -> Bool
amountIsZero :: Amount -> Bool
amountIsZero Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q} = Quantity
q Quantity -> Quantity -> Bool
forall a. Eq a => a -> a -> Bool
== 0
showAmountWithPrecision :: Int -> Amount -> String
showAmountWithPrecision :: Int -> Amount -> String
showAmountWithPrecision p :: Int
p = Amount -> String
showAmount (Amount -> String) -> (Amount -> Amount) -> Amount -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Amount -> Amount
setAmountPrecision Int
p
withPrecision :: Amount -> Int -> Amount
withPrecision :: Amount -> Int -> Amount
withPrecision = (Int -> Amount -> Amount) -> Amount -> Int -> Amount
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Amount -> Amount
setAmountPrecision
setAmountPrecision :: Int -> Amount -> Amount
setAmountPrecision :: Int -> Amount -> Amount
setAmountPrecision p :: Int
p a :: Amount
a@Amount{astyle :: Amount -> AmountStyle
astyle=AmountStyle
s} = Amount
a{astyle :: AmountStyle
astyle=AmountStyle
s{asprecision :: Int
asprecision=Int
p}}
setFullPrecision :: Amount -> Amount
setFullPrecision :: Amount -> Amount
setFullPrecision a :: Amount
a = Int -> Amount -> Amount
setAmountPrecision Int
p Amount
a
where
p :: Int
p = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
displayprecision Int
naturalprecision
displayprecision :: Int
displayprecision = AmountStyle -> Int
asprecision (AmountStyle -> Int) -> AmountStyle -> Int
forall a b. (a -> b) -> a -> b
$ Amount -> AmountStyle
astyle Amount
a
naturalprecision :: Int
naturalprecision = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> Word8 -> Int
forall a b. (a -> b) -> a -> b
$ Quantity -> Word8
forall i. DecimalRaw i -> Word8
decimalPlaces (Quantity -> Word8) -> Quantity -> Word8
forall a b. (a -> b) -> a -> b
$ Quantity -> Quantity
forall i. Integral i => DecimalRaw i -> DecimalRaw i
normalizeDecimal (Quantity -> Quantity) -> Quantity -> Quantity
forall a b. (a -> b) -> a -> b
$ Amount -> Quantity
aquantity Amount
a
setNaturalPrecision :: Amount -> Amount
setNaturalPrecision :: Amount -> Amount
setNaturalPrecision a :: Amount
a = Int -> Amount -> Amount
setAmountPrecision Int
normalprecision Amount
a
where
normalprecision :: Int
normalprecision = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> Word8 -> Int
forall a b. (a -> b) -> a -> b
$ Quantity -> Word8
forall i. DecimalRaw i -> Word8
decimalPlaces (Quantity -> Word8) -> Quantity -> Word8
forall a b. (a -> b) -> a -> b
$ Quantity -> Quantity
forall i. Integral i => DecimalRaw i -> DecimalRaw i
normalizeDecimal (Quantity -> Quantity) -> Quantity -> Quantity
forall a b. (a -> b) -> a -> b
$ Amount -> Quantity
aquantity Amount
a
setNaturalPrecisionUpTo :: Int -> Amount -> Amount
setNaturalPrecisionUpTo :: Int -> Amount -> Amount
setNaturalPrecisionUpTo n :: Int
n a :: Amount
a = Int -> Amount -> Amount
setAmountPrecision (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
n Int
normalprecision) Amount
a
where
normalprecision :: Int
normalprecision = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> Word8 -> Int
forall a b. (a -> b) -> a -> b
$ Quantity -> Word8
forall i. DecimalRaw i -> Word8
decimalPlaces (Quantity -> Word8) -> Quantity -> Word8
forall a b. (a -> b) -> a -> b
$ Quantity -> Quantity
forall i. Integral i => DecimalRaw i -> DecimalRaw i
normalizeDecimal (Quantity -> Quantity) -> Quantity -> Quantity
forall a b. (a -> b) -> a -> b
$ Amount -> Quantity
aquantity Amount
a
showAmountDebug :: Amount -> String
showAmountDebug :: Amount -> String
showAmountDebug Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
"AUTO"} = "(missing)"
showAmountDebug Amount{..} = String -> String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf "Amount {acommodity=%s, aquantity=%s, aprice=%s, astyle=%s}" (CommoditySymbol -> String
forall a. Show a => a -> String
show CommoditySymbol
acommodity) (Quantity -> String
forall a. Show a => a -> String
show Quantity
aquantity) (Maybe AmountPrice -> String
showAmountPriceDebug Maybe AmountPrice
aprice) (AmountStyle -> String
forall a. Show a => a -> String
show AmountStyle
astyle)
showAmountWithoutPrice :: Amount -> String
showAmountWithoutPrice :: Amount -> String
showAmountWithoutPrice a :: Amount
a = Amount -> String
showAmount Amount
a{aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
setAmountInternalPrecision :: Int -> Amount -> Amount
setAmountInternalPrecision :: Int -> Amount -> Amount
setAmountInternalPrecision p :: Int
p a :: Amount
a@Amount{ aquantity :: Amount -> Quantity
aquantity=Quantity
q, astyle :: Amount -> AmountStyle
astyle=AmountStyle
s } = Amount
a{
astyle :: AmountStyle
astyle=AmountStyle
s{asprecision :: Int
asprecision=Int
p}
,aquantity :: Quantity
aquantity=Word8 -> Quantity -> Quantity
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
p) Quantity
q
}
withInternalPrecision :: Amount -> Int -> Amount
withInternalPrecision :: Amount -> Int -> Amount
withInternalPrecision = (Int -> Amount -> Amount) -> Amount -> Int -> Amount
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Amount -> Amount
setAmountInternalPrecision
setAmountDecimalPoint :: Maybe Char -> Amount -> Amount
setAmountDecimalPoint :: Maybe Char -> Amount -> Amount
setAmountDecimalPoint mc :: Maybe Char
mc a :: Amount
a@Amount{ astyle :: Amount -> AmountStyle
astyle=AmountStyle
s } = Amount
a{ astyle :: AmountStyle
astyle=AmountStyle
s{asdecimalpoint :: Maybe Char
asdecimalpoint=Maybe Char
mc} }
withDecimalPoint :: Amount -> Maybe Char -> Amount
withDecimalPoint :: Amount -> Maybe Char -> Amount
withDecimalPoint = (Maybe Char -> Amount -> Amount) -> Amount -> Maybe Char -> Amount
forall a b c. (a -> b -> c) -> b -> a -> c
flip Maybe Char -> Amount -> Amount
setAmountDecimalPoint
cshowAmountWithoutPrice :: Amount -> String
cshowAmountWithoutPrice :: Amount -> String
cshowAmountWithoutPrice a :: Amount
a = Amount -> String
cshowAmount Amount
a{aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
showAmountWithoutPriceOrCommodity :: Amount -> String
showAmountWithoutPriceOrCommodity :: Amount -> String
showAmountWithoutPriceOrCommodity a :: Amount
a = Amount -> String
showAmount Amount
a{acommodity :: CommoditySymbol
acommodity="", aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
showAmountPrice :: Maybe AmountPrice -> String
showAmountPrice :: Maybe AmountPrice -> String
showAmountPrice Nothing = ""
showAmountPrice (Just (UnitPrice pa :: Amount
pa)) = " @ " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Amount -> String
showAmount Amount
pa
showAmountPrice (Just (TotalPrice pa :: Amount
pa)) = " @@ " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Amount -> String
showAmount Amount
pa
showAmountPriceDebug :: Maybe AmountPrice -> String
showAmountPriceDebug :: Maybe AmountPrice -> String
showAmountPriceDebug Nothing = ""
showAmountPriceDebug (Just (UnitPrice pa :: Amount
pa)) = " @ " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Amount -> String
showAmountDebug Amount
pa
showAmountPriceDebug (Just (TotalPrice pa :: Amount
pa)) = " @@ " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Amount -> String
showAmountDebug Amount
pa
styleAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount
styleAmount :: Map CommoditySymbol AmountStyle -> Amount -> Amount
styleAmount styles :: Map CommoditySymbol AmountStyle
styles a :: Amount
a =
case CommoditySymbol
-> Map CommoditySymbol AmountStyle -> Maybe AmountStyle
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (Amount -> CommoditySymbol
acommodity Amount
a) Map CommoditySymbol AmountStyle
styles of
Just s :: AmountStyle
s -> Amount
a{astyle :: AmountStyle
astyle=AmountStyle
s}
Nothing -> Amount
a
styleAmountExceptPrecision :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount
styleAmountExceptPrecision :: Map CommoditySymbol AmountStyle -> Amount -> Amount
styleAmountExceptPrecision styles :: Map CommoditySymbol AmountStyle
styles a :: Amount
a@Amount{astyle :: Amount -> AmountStyle
astyle=AmountStyle{asprecision :: AmountStyle -> Int
asprecision=Int
origp}} =
case CommoditySymbol
-> Map CommoditySymbol AmountStyle -> Maybe AmountStyle
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (Amount -> CommoditySymbol
acommodity Amount
a) Map CommoditySymbol AmountStyle
styles of
Just s :: AmountStyle
s -> Amount
a{astyle :: AmountStyle
astyle=AmountStyle
s{asprecision :: Int
asprecision=Int
origp}}
Nothing -> Amount
a
showAmount :: Amount -> String
showAmount :: Amount -> String
showAmount = Bool -> Amount -> String
showAmountHelper Bool
False
cshowAmount :: Amount -> String
cshowAmount :: Amount -> String
cshowAmount a :: Amount
a =
(if Amount -> Bool
isNegativeAmount Amount
a then ColorIntensity -> Color -> ShowS
color ColorIntensity
Dull Color
Red else ShowS
forall a. a -> a
id) ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
Bool -> Amount -> String
showAmountHelper Bool
False Amount
a
showAmountHelper :: Bool -> Amount -> String
showAmountHelper :: Bool -> Amount -> String
showAmountHelper _ Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
"AUTO"} = ""
showAmountHelper showzerocommodity :: Bool
showzerocommodity a :: Amount
a@Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
c, aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
mp, astyle :: Amount -> AmountStyle
astyle=AmountStyle{..}} =
case Side
ascommodityside of
L -> String -> String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf "%s%s%s%s" (CommoditySymbol -> String
T.unpack CommoditySymbol
c') String
space String
quantity' String
price
R -> String -> String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf "%s%s%s%s" String
quantity' String
space (CommoditySymbol -> String
T.unpack CommoditySymbol
c') String
price
where
quantity :: String
quantity = Amount -> String
showamountquantity Amount
a
displayingzero :: Bool
displayingzero = Bool -> Bool
not ((Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
digits) String
quantity)
(quantity' :: String
quantity',c' :: CommoditySymbol
c') | Bool
displayingzero Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
showzerocommodity = ("0","")
| Bool
otherwise = (String
quantity, CommoditySymbol -> CommoditySymbol
quoteCommoditySymbolIfNeeded CommoditySymbol
c)
space :: String
space = if Bool -> Bool
not (CommoditySymbol -> Bool
T.null CommoditySymbol
c') Bool -> Bool -> Bool
&& Bool
ascommodityspaced then " " else "" :: String
price :: String
price = Maybe AmountPrice -> String
showAmountPrice Maybe AmountPrice
mp
showAmountWithZeroCommodity :: Amount -> String
showAmountWithZeroCommodity :: Amount -> String
showAmountWithZeroCommodity = Bool -> Amount -> String
showAmountHelper Bool
True
showamountquantity :: Amount -> String
showamountquantity :: Amount -> String
showamountquantity Amount{aquantity :: Amount -> Quantity
aquantity=Quantity
q, astyle :: Amount -> AmountStyle
astyle=AmountStyle{asprecision :: AmountStyle -> Int
asprecision=Int
p, asdecimalpoint :: AmountStyle -> Maybe Char
asdecimalpoint=Maybe Char
mdec, asdigitgroups :: AmountStyle -> Maybe DigitGroupStyle
asdigitgroups=Maybe DigitGroupStyle
mgrps}} =
Char -> Maybe DigitGroupStyle -> ShowS
punctuatenumber (Char -> Maybe Char -> Char
forall a. a -> Maybe a -> a
fromMaybe '.' Maybe Char
mdec) Maybe DigitGroupStyle
mgrps String
qstr
where
qstr :: String
qstr
| Int
p Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
maxprecisionwithpoint = Quantity -> String
forall a. Show a => a -> String
show Quantity
q
| Int
p Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
maxprecision = ShowS
chopdotzero ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Quantity -> String
forall a. Show a => a -> String
show Quantity
q
| Bool
otherwise = Quantity -> String
forall a. Show a => a -> String
show (Quantity -> String) -> Quantity -> String
forall a b. (a -> b) -> a -> b
$ Word8 -> Quantity -> Quantity
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
p) Quantity
q
punctuatenumber :: Char -> Maybe DigitGroupStyle -> String -> String
punctuatenumber :: Char -> Maybe DigitGroupStyle -> ShowS
punctuatenumber dec :: Char
dec mgrps :: Maybe DigitGroupStyle
mgrps s :: String
s = String
sign String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. [a] -> [a]
reverse (Maybe DigitGroupStyle -> ShowS
applyDigitGroupStyle Maybe DigitGroupStyle
mgrps (ShowS
forall a. [a] -> [a]
reverse String
int)) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
frac''
where
(sign :: String
sign,num :: String
num) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isDigit String
s
(int :: String
int,frac :: String
frac) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
=='.') String
num
frac' :: String
frac' = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
=='.') String
frac
frac'' :: String
frac'' | String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
frac' = ""
| Bool
otherwise = Char
decChar -> ShowS
forall a. a -> [a] -> [a]
:String
frac'
applyDigitGroupStyle :: Maybe DigitGroupStyle -> String -> String
applyDigitGroupStyle :: Maybe DigitGroupStyle -> ShowS
applyDigitGroupStyle Nothing s :: String
s = String
s
applyDigitGroupStyle (Just (DigitGroups c :: Char
c gs :: [Int]
gs)) s :: String
s = [Int] -> ShowS
addseps ([Int] -> [Int]
forall a. [a] -> [a]
repeatLast [Int]
gs) String
s
where
addseps :: [Int] -> ShowS
addseps [] s :: String
s = String
s
addseps (g :: Int
g:gs :: [Int]
gs) s :: String
s
| String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
g = String
s
| Bool
otherwise = let (part :: String
part,rest :: String
rest) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
g String
s
in String
part String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char
c] String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Int] -> ShowS
addseps [Int]
gs String
rest
repeatLast :: [a] -> [a]
repeatLast [] = []
repeatLast gs :: [a]
gs = [a] -> [a]
forall a. [a] -> [a]
init [a]
gs [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ a -> [a]
forall a. a -> [a]
repeat ([a] -> a
forall a. [a] -> a
last [a]
gs)
chopdotzero :: ShowS
chopdotzero str :: String
str = ShowS
forall a. [a] -> [a]
reverse ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ case ShowS
forall a. [a] -> [a]
reverse String
str of
'0':'.':s :: String
s -> String
s
s :: String
s -> String
s
maxprecision :: Int
maxprecision :: Int
maxprecision = 999998
maxprecisionwithpoint :: Int
maxprecisionwithpoint :: Int
maxprecisionwithpoint = 999999
canonicaliseAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount
canonicaliseAmount :: Map CommoditySymbol AmountStyle -> Amount -> Amount
canonicaliseAmount styles :: Map CommoditySymbol AmountStyle
styles a :: Amount
a@Amount{acommodity :: Amount -> CommoditySymbol
acommodity=CommoditySymbol
c, astyle :: Amount -> AmountStyle
astyle=AmountStyle
s} = Amount
a{astyle :: AmountStyle
astyle=AmountStyle
s'}
where
s' :: AmountStyle
s' = AmountStyle
-> CommoditySymbol
-> Map CommoditySymbol AmountStyle
-> AmountStyle
forall k a. Ord k => a -> k -> Map k a -> a
findWithDefault AmountStyle
s CommoditySymbol
c Map CommoditySymbol AmountStyle
styles
instance Num MixedAmount where
fromInteger :: Integer -> MixedAmount
fromInteger i :: Integer
i = [Amount] -> MixedAmount
Mixed [Integer -> Amount
forall a. Num a => Integer -> a
fromInteger Integer
i]
negate :: MixedAmount -> MixedAmount
negate (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
forall a. Num a => a -> a
negate [Amount]
as
+ :: MixedAmount -> MixedAmount -> MixedAmount
(+) (Mixed as :: [Amount]
as) (Mixed bs :: [Amount]
bs) = MixedAmount -> MixedAmount
normaliseMixedAmount (MixedAmount -> MixedAmount) -> MixedAmount -> MixedAmount
forall a b. (a -> b) -> a -> b
$ [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ [Amount]
as [Amount] -> [Amount] -> [Amount]
forall a. [a] -> [a] -> [a]
++ [Amount]
bs
* :: MixedAmount -> MixedAmount -> MixedAmount
(*) = String -> MixedAmount -> MixedAmount -> MixedAmount
forall a. String -> a
error' "error, mixed amounts do not support multiplication"
abs :: MixedAmount -> MixedAmount
abs = String -> MixedAmount -> MixedAmount
forall a. String -> a
error' "error, mixed amounts do not support abs"
signum :: MixedAmount -> MixedAmount
signum = String -> MixedAmount -> MixedAmount
forall a. String -> a
error' "error, mixed amounts do not support signum"
nullmixedamt :: MixedAmount
nullmixedamt :: MixedAmount
nullmixedamt = [Amount] -> MixedAmount
Mixed []
missingmixedamt :: MixedAmount
missingmixedamt :: MixedAmount
missingmixedamt = [Amount] -> MixedAmount
Mixed [Amount
missingamt]
mixed :: [Amount] -> MixedAmount
mixed :: [Amount] -> MixedAmount
mixed = MixedAmount -> MixedAmount
normaliseMixedAmount (MixedAmount -> MixedAmount)
-> ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Amount] -> MixedAmount
Mixed
normaliseMixedAmount :: MixedAmount -> MixedAmount
normaliseMixedAmount :: MixedAmount -> MixedAmount
normaliseMixedAmount = Bool -> MixedAmount -> MixedAmount
normaliseHelper Bool
False
normaliseHelper :: Bool -> MixedAmount -> MixedAmount
normaliseHelper :: Bool -> MixedAmount -> MixedAmount
normaliseHelper squashprices :: Bool
squashprices (Mixed as :: [Amount]
as)
| Amount
missingamt Amount -> [Amount] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Amount]
as = MixedAmount
missingmixedamt
| [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Amount]
nonzeros = [Amount] -> MixedAmount
Mixed [Amount
newzero]
| Bool
otherwise = [Amount] -> MixedAmount
Mixed [Amount]
nonzeros
where
newzero :: Amount
newzero = case (CommoditySymbol -> Bool) -> [CommoditySymbol] -> [CommoditySymbol]
forall a. (a -> Bool) -> [a] -> [a]
filter (CommoditySymbol -> CommoditySymbol -> Bool
forall a. Eq a => a -> a -> Bool
/= "") ((Amount -> CommoditySymbol) -> [Amount] -> [CommoditySymbol]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> CommoditySymbol
acommodity [Amount]
zeros) of
_:_ -> [Amount] -> Amount
forall a. [a] -> a
last [Amount]
zeros
_ -> Amount
nullamt
(zeros :: [Amount]
zeros, nonzeros :: [Amount]
nonzeros) = (Amount -> Bool) -> [Amount] -> ([Amount], [Amount])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Amount -> Bool
amountIsZero ([Amount] -> ([Amount], [Amount]))
-> [Amount] -> ([Amount], [Amount])
forall a b. (a -> b) -> a -> b
$
([Amount] -> Amount) -> [[Amount]] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map [Amount] -> Amount
sumSimilarAmountsUsingFirstPrice ([[Amount]] -> [Amount]) -> [[Amount]] -> [Amount]
forall a b. (a -> b) -> a -> b
$
(Amount -> Amount -> Bool) -> [Amount] -> [[Amount]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy Amount -> Amount -> Bool
groupfn ([Amount] -> [[Amount]]) -> [Amount] -> [[Amount]]
forall a b. (a -> b) -> a -> b
$
(Amount -> Amount -> Ordering) -> [Amount] -> [Amount]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy Amount -> Amount -> Ordering
sortfn
[Amount]
as
sortfn :: Amount -> Amount -> Ordering
sortfn | Bool
squashprices = CommoditySymbol -> CommoditySymbol -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (CommoditySymbol -> CommoditySymbol -> Ordering)
-> (Amount -> CommoditySymbol) -> Amount -> Amount -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Amount -> CommoditySymbol
acommodity
| Bool
otherwise = (CommoditySymbol, Maybe AmountPrice)
-> (CommoditySymbol, Maybe AmountPrice) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((CommoditySymbol, Maybe AmountPrice)
-> (CommoditySymbol, Maybe AmountPrice) -> Ordering)
-> (Amount -> (CommoditySymbol, Maybe AmountPrice))
-> Amount
-> Amount
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` \a :: Amount
a -> (Amount -> CommoditySymbol
acommodity Amount
a, Amount -> Maybe AmountPrice
aprice Amount
a)
groupfn :: Amount -> Amount -> Bool
groupfn | Bool
squashprices = CommoditySymbol -> CommoditySymbol -> Bool
forall a. Eq a => a -> a -> Bool
(==) (CommoditySymbol -> CommoditySymbol -> Bool)
-> (Amount -> CommoditySymbol) -> Amount -> Amount -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Amount -> CommoditySymbol
acommodity
| Bool
otherwise = \a1 :: Amount
a1 a2 :: Amount
a2 -> Amount -> CommoditySymbol
acommodity Amount
a1 CommoditySymbol -> CommoditySymbol -> Bool
forall a. Eq a => a -> a -> Bool
== Amount -> CommoditySymbol
acommodity Amount
a2 Bool -> Bool -> Bool
&& Amount -> Amount -> Bool
combinableprices Amount
a1 Amount
a2
combinableprices :: Amount -> Amount -> Bool
combinableprices Amount{aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
Nothing} Amount{aprice :: Amount -> Maybe AmountPrice
aprice=Maybe AmountPrice
Nothing} = Bool
True
combinableprices Amount{aprice :: Amount -> Maybe AmountPrice
aprice=Just (UnitPrice p1 :: Amount
p1)} Amount{aprice :: Amount -> Maybe AmountPrice
aprice=Just (UnitPrice p2 :: Amount
p2)} = Amount
p1 Amount -> Amount -> Bool
forall a. Eq a => a -> a -> Bool
== Amount
p2
combinableprices _ _ = Bool
False
normaliseMixedAmountSquashPricesForDisplay :: MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay :: MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay = Bool -> MixedAmount -> MixedAmount
normaliseHelper Bool
True
sumSimilarAmountsUsingFirstPrice :: [Amount] -> Amount
sumSimilarAmountsUsingFirstPrice :: [Amount] -> Amount
sumSimilarAmountsUsingFirstPrice [] = Amount
nullamt
sumSimilarAmountsUsingFirstPrice as :: [Amount]
as = ([Amount] -> Amount
forall a. Num a => [a] -> a
sumStrict [Amount]
as){aprice :: Maybe AmountPrice
aprice=Amount -> Maybe AmountPrice
aprice (Amount -> Maybe AmountPrice) -> Amount -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ [Amount] -> Amount
forall a. [a] -> a
head [Amount]
as}
amounts :: MixedAmount -> [Amount]
amounts :: MixedAmount -> [Amount]
amounts (Mixed as :: [Amount]
as) = [Amount]
as
filterMixedAmount :: (Amount -> Bool) -> MixedAmount -> MixedAmount
filterMixedAmount :: (Amount -> Bool) -> MixedAmount -> MixedAmount
filterMixedAmount p :: Amount -> Bool
p (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Bool) -> [Amount] -> [Amount]
forall a. (a -> Bool) -> [a] -> [a]
filter Amount -> Bool
p [Amount]
as
filterMixedAmountByCommodity :: CommoditySymbol -> MixedAmount -> MixedAmount
filterMixedAmountByCommodity :: CommoditySymbol -> MixedAmount -> MixedAmount
filterMixedAmountByCommodity c :: CommoditySymbol
c (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed [Amount]
as'
where
as' :: [Amount]
as' = case (Amount -> Bool) -> [Amount] -> [Amount]
forall a. (a -> Bool) -> [a] -> [a]
filter ((CommoditySymbol -> CommoditySymbol -> Bool
forall a. Eq a => a -> a -> Bool
==CommoditySymbol
c) (CommoditySymbol -> Bool)
-> (Amount -> CommoditySymbol) -> Amount -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> CommoditySymbol
acommodity) [Amount]
as of
[] -> [Amount
nullamt{acommodity :: CommoditySymbol
acommodity=CommoditySymbol
c}]
as'' :: [Amount]
as'' -> [[Amount] -> Amount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Amount]
as'']
mapMixedAmount :: (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount :: (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount f :: Amount -> Amount
f (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
f [Amount]
as
mixedAmountCost :: MixedAmount -> MixedAmount
mixedAmountCost :: MixedAmount -> MixedAmount
mixedAmountCost (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
amountCost [Amount]
as
divideMixedAmount :: Quantity -> MixedAmount -> MixedAmount
divideMixedAmount :: Quantity -> MixedAmount -> MixedAmount
divideMixedAmount n :: Quantity
n = (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount (Quantity -> Amount -> Amount
divideAmount Quantity
n)
multiplyMixedAmount :: Quantity -> MixedAmount -> MixedAmount
multiplyMixedAmount :: Quantity -> MixedAmount -> MixedAmount
multiplyMixedAmount n :: Quantity
n = (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount (Quantity -> Amount -> Amount
multiplyAmount Quantity
n)
divideMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
divideMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
divideMixedAmountAndPrice n :: Quantity
n = (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount (Quantity -> Amount -> Amount
divideAmountAndPrice Quantity
n)
multiplyMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
multiplyMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
multiplyMixedAmountAndPrice n :: Quantity
n = (Amount -> Amount) -> MixedAmount -> MixedAmount
mapMixedAmount (Quantity -> Amount -> Amount
multiplyAmountAndPrice Quantity
n)
averageMixedAmounts :: [MixedAmount] -> MixedAmount
averageMixedAmounts :: [MixedAmount] -> MixedAmount
averageMixedAmounts [] = 0
averageMixedAmounts as :: [MixedAmount]
as = Int -> Quantity
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([MixedAmount] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [MixedAmount]
as) Quantity -> MixedAmount -> MixedAmount
`divideMixedAmount` [MixedAmount] -> MixedAmount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [MixedAmount]
as
isNegativeMixedAmount :: MixedAmount -> Maybe Bool
isNegativeMixedAmount :: MixedAmount -> Maybe Bool
isNegativeMixedAmount m :: MixedAmount
m =
case MixedAmount -> [Amount]
amounts (MixedAmount -> [Amount]) -> MixedAmount -> [Amount]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay MixedAmount
m of
[] -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
[a :: Amount
a] -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ Amount -> Bool
isNegativeAmount Amount
a
as :: [Amount]
as | (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Amount -> Bool
isNegativeAmount [Amount]
as -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
as :: [Amount]
as | Bool -> Bool
not ((Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Amount -> Bool
isNegativeAmount [Amount]
as) -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
_ -> Maybe Bool
forall a. Maybe a
Nothing
mixedAmountLooksZero :: MixedAmount -> Bool
mixedAmountLooksZero :: MixedAmount -> Bool
mixedAmountLooksZero = (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Amount -> Bool
amountLooksZero ([Amount] -> Bool)
-> (MixedAmount -> [Amount]) -> MixedAmount -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> [Amount]
amounts (MixedAmount -> [Amount])
-> (MixedAmount -> MixedAmount) -> MixedAmount -> [Amount]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay
mixedAmountIsZero :: MixedAmount -> Bool
mixedAmountIsZero :: MixedAmount -> Bool
mixedAmountIsZero = (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Amount -> Bool
amountIsZero ([Amount] -> Bool)
-> (MixedAmount -> [Amount]) -> MixedAmount -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> [Amount]
amounts (MixedAmount -> [Amount])
-> (MixedAmount -> MixedAmount) -> MixedAmount -> [Amount]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay
styleMixedAmount :: M.Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount
styleMixedAmount :: Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount
styleMixedAmount styles :: Map CommoditySymbol AmountStyle
styles (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map (Map CommoditySymbol AmountStyle -> Amount -> Amount
styleAmount Map CommoditySymbol AmountStyle
styles) [Amount]
as
showMixedAmount :: MixedAmount -> String
showMixedAmount :: MixedAmount -> String
showMixedAmount = Bool -> Bool -> MixedAmount -> String
showMixedAmountHelper Bool
False Bool
False
showMixedAmountWithZeroCommodity :: MixedAmount -> String
showMixedAmountWithZeroCommodity :: MixedAmount -> String
showMixedAmountWithZeroCommodity = Bool -> Bool -> MixedAmount -> String
showMixedAmountHelper Bool
True Bool
False
showMixedAmountOneLine :: MixedAmount -> String
showMixedAmountOneLine :: MixedAmount -> String
showMixedAmountOneLine = Bool -> Bool -> MixedAmount -> String
showMixedAmountHelper Bool
False Bool
True
showMixedAmountHelper :: Bool -> Bool -> MixedAmount -> String
showMixedAmountHelper :: Bool -> Bool -> MixedAmount -> String
showMixedAmountHelper showzerocommodity :: Bool
showzerocommodity useoneline :: Bool
useoneline m :: MixedAmount
m =
[String] -> String
join ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
showamt ([Amount] -> [String]) -> [Amount] -> [String]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> [Amount]
amounts (MixedAmount -> [Amount]) -> MixedAmount -> [Amount]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay MixedAmount
m
where
join :: [String] -> String
join | Bool
useoneline = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate ", "
| Bool
otherwise = [String] -> String
vConcatRightAligned
showamt :: Amount -> String
showamt | Bool
showzerocommodity = Amount -> String
showAmountWithZeroCommodity
| Bool
otherwise = Amount -> String
showAmount
ltraceamount :: String -> MixedAmount -> MixedAmount
ltraceamount :: String -> MixedAmount -> MixedAmount
ltraceamount s :: String
s = (MixedAmount -> String) -> MixedAmount -> MixedAmount
forall a. Show a => (a -> String) -> a -> a
traceWith (((String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ ": ") String -> ShowS
forall a. [a] -> [a] -> [a]
++)ShowS -> (MixedAmount -> String) -> MixedAmount -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.MixedAmount -> String
showMixedAmount)
setMixedAmountPrecision :: Int -> MixedAmount -> MixedAmount
setMixedAmountPrecision :: Int -> MixedAmount -> MixedAmount
setMixedAmountPrecision p :: Int
p (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Amount -> Amount
setAmountPrecision Int
p) [Amount]
as
showMixedAmountWithPrecision :: Int -> MixedAmount -> String
showMixedAmountWithPrecision :: Int -> MixedAmount -> String
showMixedAmountWithPrecision p :: Int
p m :: MixedAmount
m =
[String] -> String
vConcatRightAligned ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Amount -> String
showAmountWithPrecision Int
p) ([Amount] -> [String]) -> [Amount] -> [String]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> [Amount]
amounts (MixedAmount -> [Amount]) -> MixedAmount -> [Amount]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay MixedAmount
m
showMixedAmountDebug :: MixedAmount -> String
showMixedAmountDebug :: MixedAmount -> String
showMixedAmountDebug m :: MixedAmount
m | MixedAmount
m MixedAmount -> MixedAmount -> Bool
forall a. Eq a => a -> a -> Bool
== MixedAmount
missingmixedamt = "(missing)"
| Bool
otherwise = String -> ShowS
forall r. PrintfType r => String -> r
printf "Mixed [%s]" String
as
where as :: String
as = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\n " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
showAmountDebug ([Amount] -> [String]) -> [Amount] -> [String]
forall a b. (a -> b) -> a -> b
$ MixedAmount -> [Amount]
amounts MixedAmount
m
showMixedAmountWithoutPrice :: MixedAmount -> String
showMixedAmountWithoutPrice :: MixedAmount -> String
showMixedAmountWithoutPrice m :: MixedAmount
m = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\n" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
showamt [Amount]
as
where
Mixed as :: [Amount]
as = MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay (MixedAmount -> MixedAmount) -> MixedAmount -> MixedAmount
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
mixedAmountStripPrices MixedAmount
m
showamt :: Amount -> String
showamt = String -> ShowS
forall r. PrintfType r => String -> r
printf (String -> Int -> String
forall r. PrintfType r => String -> r
printf "%%%ds" Int
width) ShowS -> (Amount -> String) -> Amount -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> String
showAmountWithoutPrice
where
width :: Int
width = Int -> [Int] -> Int
forall a. Ord a => a -> [a] -> a
maximumDef 0 ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Amount -> Int) -> [Amount] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (Amount -> String) -> Amount -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> String
showAmount) [Amount]
as
cshowMixedAmountWithoutPrice :: MixedAmount -> String
cshowMixedAmountWithoutPrice :: MixedAmount -> String
cshowMixedAmountWithoutPrice m :: MixedAmount
m = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\n" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
showamt [Amount]
as
where
Mixed as :: [Amount]
as = MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay (MixedAmount -> MixedAmount) -> MixedAmount -> MixedAmount
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
mixedAmountStripPrices MixedAmount
m
showamt :: Amount -> String
showamt a :: Amount
a =
(if Amount -> Bool
isNegativeAmount Amount
a then ColorIntensity -> Color -> ShowS
color ColorIntensity
Dull Color
Red else ShowS
forall a. a -> a
id) ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
forall r. PrintfType r => String -> r
printf (String -> Int -> String
forall r. PrintfType r => String -> r
printf "%%%ds" Int
width) ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Amount -> String
showAmountWithoutPrice Amount
a
where
width :: Int
width = Int -> [Int] -> Int
forall a. Ord a => a -> [a] -> a
maximumDef 0 ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Amount -> Int) -> [Amount] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (Amount -> String) -> Amount -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> String
showAmount) [Amount]
as
mixedAmountStripPrices :: MixedAmount -> MixedAmount
mixedAmountStripPrices :: MixedAmount -> MixedAmount
mixedAmountStripPrices (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map (\a :: Amount
a -> Amount
a{aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}) [Amount]
as
showMixedAmountOneLineWithoutPrice :: MixedAmount -> String
showMixedAmountOneLineWithoutPrice :: MixedAmount -> String
showMixedAmountOneLineWithoutPrice m :: MixedAmount
m = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate ", " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
showAmountWithoutPrice [Amount]
as
where
(Mixed as :: [Amount]
as) = MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay (MixedAmount -> MixedAmount) -> MixedAmount -> MixedAmount
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
stripPrices MixedAmount
m
stripPrices :: MixedAmount -> MixedAmount
stripPrices (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
stripprice [Amount]
as where stripprice :: Amount -> Amount
stripprice a :: Amount
a = Amount
a{aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
cshowMixedAmountOneLineWithoutPrice :: MixedAmount -> String
cshowMixedAmountOneLineWithoutPrice :: MixedAmount -> String
cshowMixedAmountOneLineWithoutPrice m :: MixedAmount
m = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate ", " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Amount -> String) -> [Amount] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> String
cshowAmountWithoutPrice [Amount]
as
where
(Mixed as :: [Amount]
as) = MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay (MixedAmount -> MixedAmount) -> MixedAmount -> MixedAmount
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
stripPrices MixedAmount
m
stripPrices :: MixedAmount -> MixedAmount
stripPrices (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
stripprice [Amount]
as where stripprice :: Amount -> Amount
stripprice a :: Amount
a = Amount
a{aprice :: Maybe AmountPrice
aprice=Maybe AmountPrice
forall a. Maybe a
Nothing}
canonicaliseMixedAmount :: M.Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount
canonicaliseMixedAmount :: Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount
canonicaliseMixedAmount styles :: Map CommoditySymbol AmountStyle
styles (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map (Map CommoditySymbol AmountStyle -> Amount -> Amount
canonicaliseAmount Map CommoditySymbol AmountStyle
styles) [Amount]
as
mixedAmountTotalPriceToUnitPrice :: MixedAmount -> MixedAmount
mixedAmountTotalPriceToUnitPrice :: MixedAmount -> MixedAmount
mixedAmountTotalPriceToUnitPrice (Mixed as :: [Amount]
as) = [Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount) -> [Amount] -> MixedAmount
forall a b. (a -> b) -> a -> b
$ (Amount -> Amount) -> [Amount] -> [Amount]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> Amount
amountTotalPriceToUnitPrice [Amount]
as
tests_Amount :: TestTree
tests_Amount = String -> [TestTree] -> TestTree
tests "Amount" [
String -> [TestTree] -> TestTree
tests "Amount" [
String -> Assertion -> TestTree
test "amountCost" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Amount -> Amount
amountCost (Quantity -> Amount
eur 1) Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
eur 1
Amount -> Amount
amountCost (Quantity -> Amount
eur 2){aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
UnitPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Quantity -> Amount
usd 2} Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd 4
Amount -> Amount
amountCost (Quantity -> Amount
eur 1){aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
TotalPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Quantity -> Amount
usd 2} Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd 2
Amount -> Amount
amountCost (Quantity -> Amount
eur (-1)){aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
TotalPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Quantity -> Amount
usd 2} Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd (-2)
,String -> Assertion -> TestTree
test "amountLooksZero" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
HasCallStack => String -> Bool -> Assertion
String -> Bool -> Assertion
assertBool "" (Bool -> Assertion) -> Bool -> Assertion
forall a b. (a -> b) -> a -> b
$ Amount -> Bool
amountLooksZero Amount
amount
HasCallStack => String -> Bool -> Assertion
String -> Bool -> Assertion
assertBool "" (Bool -> Assertion) -> Bool -> Assertion
forall a b. (a -> b) -> a -> b
$ Amount -> Bool
amountLooksZero (Amount -> Bool) -> Amount -> Bool
forall a b. (a -> b) -> a -> b
$ Quantity -> Amount
usd 0
,String -> Assertion -> TestTree
test "negating amounts" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Amount -> Amount
forall a. Num a => a -> a
negate (Quantity -> Amount
usd 1) Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= (Quantity -> Amount
usd 1){aquantity :: Quantity
aquantity= -1}
let b :: Amount
b = (Quantity -> Amount
usd 1){aprice :: Maybe AmountPrice
aprice=AmountPrice -> Maybe AmountPrice
forall a. a -> Maybe a
Just (AmountPrice -> Maybe AmountPrice)
-> AmountPrice -> Maybe AmountPrice
forall a b. (a -> b) -> a -> b
$ Amount -> AmountPrice
UnitPrice (Amount -> AmountPrice) -> Amount -> AmountPrice
forall a b. (a -> b) -> a -> b
$ Quantity -> Amount
eur 2} in Amount -> Amount
forall a. Num a => a -> a
negate Amount
b Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Amount
b{aquantity :: Quantity
aquantity= -1}
,String -> Assertion -> TestTree
test "adding amounts without prices" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
(Quantity -> Amount
usd 1.23 Amount -> Amount -> Amount
forall a. Num a => a -> a -> a
+ Quantity -> Amount
usd (-1.23)) Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd 0
(Quantity -> Amount
usd 1.23 Amount -> Amount -> Amount
forall a. Num a => a -> a -> a
+ Quantity -> Amount
usd (-1.23)) Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd 0
(Quantity -> Amount
usd (-1.23) Amount -> Amount -> Amount
forall a. Num a => a -> a -> a
+ Quantity -> Amount
usd (-1.23)) Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd (-2.46)
[Amount] -> Amount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Quantity -> Amount
usd 1.23,Quantity -> Amount
usd (-1.23),Quantity -> Amount
usd (-1.23),-(Quantity -> Amount
usd (-1.23))] Amount -> Amount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Quantity -> Amount
usd 0
AmountStyle -> Int
asprecision (Amount -> AmountStyle
astyle (Amount -> AmountStyle) -> Amount -> AmountStyle
forall a b. (a -> b) -> a -> b
$ [Amount] -> Amount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Quantity -> Amount
usd 1 Amount -> Int -> Amount
`withPrecision` 1, Quantity -> Amount
usd 1 Amount -> Int -> Amount
`withPrecision` 3]) Int -> Int -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= 3
AmountStyle -> Int
asprecision (Amount -> AmountStyle
astyle (Amount -> AmountStyle) -> Amount -> AmountStyle
forall a b. (a -> b) -> a -> b
$ [Amount] -> Amount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Quantity -> Amount
usd 1 Amount -> Int -> Amount
`withPrecision` 3, Quantity -> Amount
usd 1 Amount -> Int -> Amount
`withPrecision` 1]) Int -> Int -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= 3
HasCallStack => String -> Bool -> Assertion
String -> Bool -> Assertion
assertBool "" (Bool -> Assertion) -> Bool -> Assertion
forall a b. (a -> b) -> a -> b
$ Amount -> Bool
amountLooksZero (Quantity -> Amount
usd 1.23 Amount -> Amount -> Amount
forall a. Num a => a -> a -> a
- Quantity -> Amount
eur 1.23)
,String -> Assertion -> TestTree
test "showAmount" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Amount -> String
showAmount (Quantity -> Amount
usd 0 Amount -> Amount -> Amount
forall a. Num a => a -> a -> a
+ Quantity -> Amount
gbp 0) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "0"
]
,String -> [TestTree] -> TestTree
tests "MixedAmount" [
String -> Assertion -> TestTree
test "adding mixed amounts to zero, the commodity and amount style are preserved" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
[MixedAmount] -> MixedAmount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Amount -> MixedAmount) -> [Amount] -> [MixedAmount]
forall a b. (a -> b) -> [a] -> [b]
map ([Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount)
-> (Amount -> [Amount]) -> Amount -> MixedAmount
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Amount -> [Amount] -> [Amount]
forall a. a -> [a] -> [a]
:[]))
[Quantity -> Amount
usd 1.25
,Quantity -> Amount
usd (-1) Amount -> Int -> Amount
`withPrecision` 3
,Quantity -> Amount
usd (-0.25)
])
MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 0 Amount -> Int -> Amount
`withPrecision` 3]
,String -> Assertion -> TestTree
test "adding mixed amounts with total prices" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
[MixedAmount] -> MixedAmount
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Amount -> MixedAmount) -> [Amount] -> [MixedAmount]
forall a b. (a -> b) -> [a] -> [b]
map ([Amount] -> MixedAmount
Mixed ([Amount] -> MixedAmount)
-> (Amount -> [Amount]) -> Amount -> MixedAmount
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Amount -> [Amount] -> [Amount]
forall a. a -> [a] -> [a]
:[]))
[Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1
,Quantity -> Amount
usd (-2) Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1
])
MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1
,Quantity -> Amount
usd (-2) Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1
]
,String -> Assertion -> TestTree
test "showMixedAmount" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
MixedAmount -> String
showMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1]) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "$1.00"
MixedAmount -> String
showMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 2]) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "$1.00 @ €2.00"
MixedAmount -> String
showMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 0]) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "0"
MixedAmount -> String
showMixedAmount ([Amount] -> MixedAmount
Mixed []) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "0"
MixedAmount -> String
showMixedAmount MixedAmount
missingmixedamt String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ""
,String -> Assertion -> TestTree
test "showMixedAmountWithoutPrice" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
let a :: Amount
a = Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 2
MixedAmount -> String
showMixedAmountWithoutPrice ([Amount] -> MixedAmount
Mixed [Amount
a]) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "$1.00"
MixedAmount -> String
showMixedAmountWithoutPrice ([Amount] -> MixedAmount
Mixed [Amount
a, -Amount
a]) String -> String -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= "0"
,String -> [TestTree] -> TestTree
tests "normaliseMixedAmount" [
String -> Assertion -> TestTree
test "a missing amount overrides any other amounts" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
MixedAmount -> MixedAmount
normaliseMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1, Amount
missingamt]) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= MixedAmount
missingmixedamt
,String -> Assertion -> TestTree
test "unpriced same-commodity amounts are combined" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
MixedAmount -> MixedAmount
normaliseMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 0, Quantity -> Amount
usd 2]) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 2]
,String -> Assertion -> TestTree
test "amounts with same unit price are combined" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
MixedAmount -> MixedAmount
normaliseMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 1, Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 1]) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 2 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 1]
,String -> Assertion -> TestTree
test "amounts with different unit prices are not combined" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
MixedAmount -> MixedAmount
normaliseMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 1, Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 2]) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 1, Quantity -> Amount
usd 1 Amount -> Amount -> Amount
`at` Quantity -> Amount
eur 2]
,String -> Assertion -> TestTree
test "amounts with total prices are not combined" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$
MixedAmount -> MixedAmount
normaliseMixedAmount ([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1, Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1]) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1, Quantity -> Amount
usd 1 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 1]
]
,String -> Assertion -> TestTree
test "normaliseMixedAmountSquashPricesForDisplay" (Assertion -> TestTree) -> Assertion -> TestTree
forall a b. (a -> b) -> a -> b
$ do
MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay ([Amount] -> MixedAmount
Mixed []) MixedAmount -> MixedAmount -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= [Amount] -> MixedAmount
Mixed [Amount
nullamt]
HasCallStack => String -> Bool -> Assertion
String -> Bool -> Assertion
assertBool "" (Bool -> Assertion) -> Bool -> Assertion
forall a b. (a -> b) -> a -> b
$ MixedAmount -> Bool
mixedAmountLooksZero (MixedAmount -> Bool) -> MixedAmount -> Bool
forall a b. (a -> b) -> a -> b
$ MixedAmount -> MixedAmount
normaliseMixedAmountSquashPricesForDisplay
([Amount] -> MixedAmount
Mixed [Quantity -> Amount
usd 10
,Quantity -> Amount
usd 10 Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 7
,Quantity -> Amount
usd (-10)
,Quantity -> Amount
usd (-10) Amount -> Amount -> Amount
@@ Quantity -> Amount
eur 7
])
]
]