ENH use intervals to define allocations
This commit is contained in:
parent
d89b63e59a
commit
ad4cb6a702
|
@ -195,9 +195,10 @@ let Amount = { amtValue : Decimal, amtDesc : Text }
|
||||||
|
|
||||||
let AmountType = < FixedAmt | Percent | Target >
|
let AmountType = < FixedAmt | Percent | Target >
|
||||||
|
|
||||||
let TimeAmount = { taWhen : DatePat, taAmt : Amount, taAmtType : AmountType }
|
let TimeAmount =
|
||||||
|
\(t : Type) -> { taWhen : t, taAmt : Amount, taAmtType : AmountType }
|
||||||
|
|
||||||
let Tax = { taxAcnt : AcntID, taxValue : Decimal }
|
let DateAmount = TimeAmount DatePat
|
||||||
|
|
||||||
let Exchange =
|
let Exchange =
|
||||||
{ xFromCur : CurID, xToCur : CurID, xAcnt : AcntID, xRate : Decimal }
|
{ xFromCur : CurID, xToCur : CurID, xAcnt : AcntID, xRate : Decimal }
|
||||||
|
@ -206,27 +207,32 @@ let BudgetCurrency = < NoX : CurID | X : Exchange >
|
||||||
|
|
||||||
let TaggedAcnt = { taAcnt : AcntID, taTags : List TagID }
|
let TaggedAcnt = { taAcnt : AcntID, taTags : List TagID }
|
||||||
|
|
||||||
let Allocation =
|
let Allocation_ =
|
||||||
{ alloTo : TaggedAcnt, alloAmts : List Amount, alloCur : BudgetCurrency }
|
\(t : Type) ->
|
||||||
|
{ alloTo : TaggedAcnt, alloAmts : List t, alloCur : BudgetCurrency }
|
||||||
|
|
||||||
|
let Allocation = Allocation_ Amount
|
||||||
|
|
||||||
|
let IntervalAllocation = Allocation_ (TimeAmount Interval)
|
||||||
|
|
||||||
let Income =
|
let Income =
|
||||||
{ incGross : Decimal
|
{ incGross : Decimal
|
||||||
, incCurrency : CurID
|
, incCurrency : CurID
|
||||||
, incWhen : DatePat
|
, incWhen : DatePat
|
||||||
|
, incPretax : List Allocation
|
||||||
|
, incTaxes : List Allocation
|
||||||
|
, incPosttax : List Allocation
|
||||||
, incFrom :
|
, incFrom :
|
||||||
{- this must be an income AcntID, and is the only place income
|
{- this must be an income AcntID, and is the only place income
|
||||||
accounts may be specified in the entire budget -}
|
accounts may be specified in the entire budget -}
|
||||||
TaggedAcnt
|
TaggedAcnt
|
||||||
, incPretax : List Allocation
|
|
||||||
, incTaxes : List Tax
|
|
||||||
, incPosttax : List Allocation
|
|
||||||
, incToBal : TaggedAcnt
|
, incToBal : TaggedAcnt
|
||||||
}
|
}
|
||||||
|
|
||||||
let Transfer =
|
let Transfer =
|
||||||
{ transFrom : TaggedAcnt
|
{ transFrom : TaggedAcnt
|
||||||
, transTo : TaggedAcnt
|
, transTo : TaggedAcnt
|
||||||
, transAmounts : List TimeAmount
|
, transAmounts : List DateAmount
|
||||||
, transCurrency : BudgetCurrency
|
, transCurrency : BudgetCurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +267,10 @@ let ShadowTransfer =
|
||||||
|
|
||||||
let Budget =
|
let Budget =
|
||||||
{ budgetLabel : Text
|
{ budgetLabel : Text
|
||||||
, income : List Income
|
, incomes : List Income
|
||||||
|
, pretax : List IntervalAllocation
|
||||||
|
, tax : List IntervalAllocation
|
||||||
|
, posttax : List IntervalAllocation
|
||||||
, transfers : List Transfer
|
, transfers : List Transfer
|
||||||
, shadowTransfers : List ShadowTransfer
|
, shadowTransfers : List ShadowTransfer
|
||||||
}
|
}
|
||||||
|
@ -306,8 +315,8 @@ in { CurID
|
||||||
, Transfer
|
, Transfer
|
||||||
, Income
|
, Income
|
||||||
, Budget
|
, Budget
|
||||||
, Tax
|
|
||||||
, Allocation
|
, Allocation
|
||||||
|
, IntervalAllocation
|
||||||
, Amount
|
, Amount
|
||||||
, TimeAmount
|
, TimeAmount
|
||||||
, AmountType
|
, AmountType
|
||||||
|
|
|
@ -119,15 +119,52 @@ withDates dp f = do
|
||||||
-- 5. insert all transactions
|
-- 5. insert all transactions
|
||||||
|
|
||||||
insertBudget :: MonadFinance m => Budget -> SqlPersistT m [InsertError]
|
insertBudget :: MonadFinance m => Budget -> SqlPersistT m [InsertError]
|
||||||
insertBudget b@(Budget {budgetLabel = name, income = is, transfers = es, shadowTransfers = ss}) =
|
insertBudget
|
||||||
|
b@( Budget
|
||||||
|
{ budgetLabel
|
||||||
|
, incomes
|
||||||
|
, transfers
|
||||||
|
, shadowTransfers
|
||||||
|
, pretax
|
||||||
|
, tax
|
||||||
|
, posttax
|
||||||
|
}
|
||||||
|
) =
|
||||||
whenHash CTBudget b [] $ \key -> do
|
whenHash CTBudget b [] $ \key -> do
|
||||||
res1 <- mapM (insertIncome key name) is
|
unlessLefts intAllos $ \intAllos_ -> do
|
||||||
res2 <- expandTransfers key name es
|
res1 <- mapM (insertIncome key budgetLabel intAllos_) incomes
|
||||||
|
res2 <- expandTransfers key budgetLabel transfers
|
||||||
unlessLefts (concatEithers2 (fmap concat $ concatEithersL res1) res2 (++)) $
|
unlessLefts (concatEithers2 (fmap concat $ concatEithersL res1) res2 (++)) $
|
||||||
\txs -> do
|
\txs -> do
|
||||||
unlessLefts (addShadowTransfers ss txs) $ \shadow -> do
|
unlessLefts (addShadowTransfers shadowTransfers txs) $ \shadow -> do
|
||||||
let bals = balanceTransfers $ txs ++ shadow
|
let bals = balanceTransfers $ txs ++ shadow
|
||||||
concat <$> mapM insertBudgetTx bals
|
concat <$> mapM insertBudgetTx bals
|
||||||
|
where
|
||||||
|
intAllos =
|
||||||
|
let pre_ = sortAllos pretax
|
||||||
|
tax_ = sortAllos tax
|
||||||
|
post_ = sortAllos posttax
|
||||||
|
in concatEithers3 pre_ tax_ post_ (,,)
|
||||||
|
sortAllos = concatEithersL . fmap sortAllo
|
||||||
|
|
||||||
|
type BoundAllocation = Allocation_ (TimeAmount (Day, Day))
|
||||||
|
|
||||||
|
type IntAllocations = ([BoundAllocation], [BoundAllocation], [BoundAllocation])
|
||||||
|
|
||||||
|
-- TODO this should actually error if there is no ultimate end date
|
||||||
|
sortAllo :: IntervalAllocation -> EitherErrs BoundAllocation
|
||||||
|
sortAllo a@Allocation_ {alloAmts = as} = do
|
||||||
|
bs <- fmap reverse <$> foldBounds (Right []) $ L.sort as
|
||||||
|
return $ a {alloAmts = L.sort bs}
|
||||||
|
where
|
||||||
|
foldBounds acc [] = acc
|
||||||
|
foldBounds acc (x : xs) =
|
||||||
|
let res = fmap (fmap expandBounds) $ case xs of
|
||||||
|
[] -> mapM resolveBounds x
|
||||||
|
(y : _) ->
|
||||||
|
let end = intStart $ taWhen y
|
||||||
|
in mapM (resolveBounds_ end) x
|
||||||
|
in foldBounds (concatEithers2 (plural res) acc (:)) xs
|
||||||
|
|
||||||
-- TODO this is going to be O(n*m), which might be a problem?
|
-- TODO this is going to be O(n*m), which might be a problem?
|
||||||
addShadowTransfers :: [ShadowTransfer] -> [BudgetTxType] -> EitherErrs [BudgetTxType]
|
addShadowTransfers :: [ShadowTransfer] -> [BudgetTxType] -> EitherErrs [BudgetTxType]
|
||||||
|
@ -219,12 +256,18 @@ data BudgetTxType = BudgetTxType
|
||||||
, bttTx :: !BudgetTx
|
, bttTx :: !BudgetTx
|
||||||
}
|
}
|
||||||
|
|
||||||
insertIncome :: MonadFinance m => CommitRId -> T.Text -> Income -> SqlPersistT m (EitherErrs [BudgetTxType])
|
insertIncome
|
||||||
|
:: MonadFinance m
|
||||||
|
=> CommitRId
|
||||||
|
-> T.Text
|
||||||
|
-> IntAllocations
|
||||||
|
-> Income
|
||||||
|
-> SqlPersistT m (EitherErrs [BudgetTxType])
|
||||||
insertIncome
|
insertIncome
|
||||||
key
|
key
|
||||||
name
|
name
|
||||||
|
(intPre, intTax, intPost)
|
||||||
i@Income {incWhen, incCurrency, incFrom, incPretax, incPosttax, incTaxes, incToBal} = do
|
i@Income {incWhen, incCurrency, incFrom, incPretax, incPosttax, incTaxes, incToBal} = do
|
||||||
-- whenHash CTIncome i (Right []) $ \c -> do
|
|
||||||
let meta = BudgetMeta key (NoX incCurrency) name
|
let meta = BudgetMeta key (NoX incCurrency) name
|
||||||
let balRes = balanceIncome i
|
let balRes = balanceIncome i
|
||||||
fromRes <- lift $ checkAcntType IncomeT $ taAcnt incFrom
|
fromRes <- lift $ checkAcntType IncomeT $ taAcnt incFrom
|
||||||
|
@ -233,13 +276,15 @@ insertIncome
|
||||||
-- TODO this hole seems sloppy...
|
-- TODO this hole seems sloppy...
|
||||||
Right (balance, _) ->
|
Right (balance, _) ->
|
||||||
fmap (fmap (concat . concat)) $
|
fmap (fmap (concat . concat)) $
|
||||||
|
-- TODO this will scan the interval allocations fully each time
|
||||||
|
-- iteration which is a total waste, but the fix requires turning this
|
||||||
|
-- loop into a fold which I don't feel like doing now :(
|
||||||
withDates incWhen $ \day -> do
|
withDates incWhen $ \day -> do
|
||||||
let fromAllos = fmap concat . mapM (lift . fromAllo day meta incFrom)
|
let fromAllos = fmap concat . mapM (lift . fromAllo day meta incFrom)
|
||||||
pre <- fromAllos incPretax
|
pre <- fromAllos $ incPretax ++ mapMaybe (selectAllos day) intPre
|
||||||
tax <-
|
-- TODO ensure these are all expense accounts
|
||||||
concatEitherL
|
tax <- fromAllos $ incTaxes ++ mapMaybe (selectAllos day) intTax
|
||||||
<$> mapM (lift . fromTax day meta (taAcnt incFrom)) incTaxes
|
post <- fromAllos $ incPosttax ++ mapMaybe (selectAllos day) intPost
|
||||||
post <- fromAllos incPosttax
|
|
||||||
let bal =
|
let bal =
|
||||||
BudgetTxType
|
BudgetTxType
|
||||||
{ bttTx =
|
{ bttTx =
|
||||||
|
@ -253,7 +298,19 @@ insertIncome
|
||||||
}
|
}
|
||||||
, bttType = FixedAmt
|
, bttType = FixedAmt
|
||||||
}
|
}
|
||||||
return $ concatEithersL [Right [bal], tax, Right pre, Right post]
|
return $ concatEithersL [Right [bal], Right tax, Right pre, Right post]
|
||||||
|
|
||||||
|
-- ASSUME allocations are sorted
|
||||||
|
selectAllos :: Day -> BoundAllocation -> Maybe Allocation
|
||||||
|
selectAllos day a@Allocation_ {alloAmts = as} = case select [] as of
|
||||||
|
[] -> Nothing
|
||||||
|
xs -> Just $ a {alloAmts = xs}
|
||||||
|
where
|
||||||
|
select acc [] = acc
|
||||||
|
select acc (x : xs)
|
||||||
|
| (fst $ taWhen x) < day = select acc xs
|
||||||
|
| inBounds (taWhen x) day = select (taAmt x : acc) xs
|
||||||
|
| otherwise = acc
|
||||||
|
|
||||||
fromAllo
|
fromAllo
|
||||||
:: MonadFinance m
|
:: MonadFinance m
|
||||||
|
@ -262,7 +319,7 @@ fromAllo
|
||||||
-> TaggedAcnt
|
-> TaggedAcnt
|
||||||
-> Allocation
|
-> Allocation
|
||||||
-> m [BudgetTxType]
|
-> m [BudgetTxType]
|
||||||
fromAllo day meta from Allocation {alloTo, alloAmts} = do
|
fromAllo day meta from Allocation_ {alloTo, alloAmts} = do
|
||||||
-- TODO this is going to be repeated a zillion times (might matter)
|
-- TODO this is going to be repeated a zillion times (might matter)
|
||||||
-- res <- expandTarget alloPath
|
-- res <- expandTarget alloPath
|
||||||
return $ fmap toBT alloAmts
|
return $ fmap toBT alloAmts
|
||||||
|
@ -281,31 +338,31 @@ fromAllo day meta from Allocation {alloTo, alloAmts} = do
|
||||||
, bttType = FixedAmt
|
, bttType = FixedAmt
|
||||||
}
|
}
|
||||||
|
|
||||||
-- TODO maybe allow tags here?
|
-- -- TODO maybe allow tags here?
|
||||||
fromTax
|
-- fromTax
|
||||||
:: MonadFinance m
|
-- :: MonadFinance m
|
||||||
=> Day
|
-- => Day
|
||||||
-> BudgetMeta
|
-- -> BudgetMeta
|
||||||
-> AcntID
|
-- -> AcntID
|
||||||
-> Tax
|
-- -> Tax
|
||||||
-> m (EitherErr BudgetTxType)
|
-- -> m (EitherErr BudgetTxType)
|
||||||
fromTax day meta from Tax {taxAcnt = to, taxValue = v} = do
|
-- fromTax day meta from Tax {taxAcnt = to, taxValue = v} = do
|
||||||
res <- checkAcntType ExpenseT to
|
-- res <- checkAcntType ExpenseT to
|
||||||
return $ fmap go res
|
-- return $ fmap go res
|
||||||
where
|
-- where
|
||||||
go to_ =
|
-- go to_ =
|
||||||
BudgetTxType
|
-- BudgetTxType
|
||||||
{ bttTx =
|
-- { bttTx =
|
||||||
BudgetTx
|
-- BudgetTx
|
||||||
{ btFrom = TaggedAcnt from []
|
-- { btFrom = TaggedAcnt from []
|
||||||
, btWhen = day
|
-- , btWhen = day
|
||||||
, btTo = TaggedAcnt to_ []
|
-- , btTo = TaggedAcnt to_ []
|
||||||
, btValue = dec2Rat v
|
-- , btValue = dec2Rat v
|
||||||
, btDesc = ""
|
-- , btDesc = ""
|
||||||
, btMeta = meta
|
-- , btMeta = meta
|
||||||
}
|
-- }
|
||||||
, bttType = FixedAmt
|
-- , bttType = FixedAmt
|
||||||
}
|
-- }
|
||||||
|
|
||||||
balanceIncome :: Income -> EitherErr Rational
|
balanceIncome :: Income -> EitherErr Rational
|
||||||
balanceIncome
|
balanceIncome
|
||||||
|
@ -319,13 +376,13 @@ balanceIncome
|
||||||
| bal < 0 = Left $ IncomeError dp
|
| bal < 0 = Left $ IncomeError dp
|
||||||
| otherwise = Right bal
|
| otherwise = Right bal
|
||||||
where
|
where
|
||||||
bal = dec2Rat g - sum (sumAllocation <$> pre ++ post) - sumTaxes tax
|
bal = dec2Rat g - sum (sumAllocation <$> pre ++ tax ++ post)
|
||||||
|
|
||||||
sumAllocation :: Allocation -> Rational
|
sumAllocation :: Allocation -> Rational
|
||||||
sumAllocation = sum . fmap (dec2Rat . amtValue) . alloAmts
|
sumAllocation = sum . fmap (dec2Rat . amtValue) . alloAmts
|
||||||
|
|
||||||
sumTaxes :: [Tax] -> Rational
|
-- sumTaxes :: [Tax] -> Rational
|
||||||
sumTaxes = sum . fmap (dec2Rat . taxValue)
|
-- sumTaxes = sum . fmap (dec2Rat . taxValue)
|
||||||
|
|
||||||
expandTransfers
|
expandTransfers
|
||||||
:: MonadFinance m
|
:: MonadFinance m
|
||||||
|
@ -341,7 +398,7 @@ expandTransfer :: MonadFinance m => CommitRId -> T.Text -> Transfer -> SqlPersis
|
||||||
expandTransfer key name Transfer {transAmounts, transTo, transCurrency, transFrom} =
|
expandTransfer key name Transfer {transAmounts, transTo, transCurrency, transFrom} =
|
||||||
-- whenHash CTExpense t (Right []) $ \key ->
|
-- whenHash CTExpense t (Right []) $ \key ->
|
||||||
fmap (fmap concat . concatEithersL) $
|
fmap (fmap concat . concatEithersL) $
|
||||||
forM transAmounts $ \(TimeAmount (Amount desc v) atype pat) -> do
|
forM transAmounts $ \(TimeAmount pat (Amount desc v) atype) -> do
|
||||||
withDates pat $ \day ->
|
withDates pat $ \day ->
|
||||||
let meta =
|
let meta =
|
||||||
BudgetMeta
|
BudgetMeta
|
||||||
|
|
|
@ -49,14 +49,12 @@ makeHaskellTypesWith
|
||||||
, SingleConstructor "Decimal" "D" "(./dhall/Types.dhall).Decimal"
|
, SingleConstructor "Decimal" "D" "(./dhall/Types.dhall).Decimal"
|
||||||
, SingleConstructor "MatchVal" "MatchVal" "(./dhall/Types.dhall).MatchVal.Type"
|
, SingleConstructor "MatchVal" "MatchVal" "(./dhall/Types.dhall).MatchVal.Type"
|
||||||
, SingleConstructor "Manual" "Manual" "(./dhall/Types.dhall).Manual"
|
, SingleConstructor "Manual" "Manual" "(./dhall/Types.dhall).Manual"
|
||||||
, SingleConstructor "Tax" "Tax" "(./dhall/Types.dhall).Tax"
|
|
||||||
, SingleConstructor "Amount" "Amount" "(./dhall/Types.dhall).Amount"
|
, SingleConstructor "Amount" "Amount" "(./dhall/Types.dhall).Amount"
|
||||||
, SingleConstructor "TimeAmount" "TimeAmount" "(./dhall/Types.dhall).TimeAmount"
|
, -- , SingleConstructor "TimeAmount" "TimeAmount" "(./dhall/Types.dhall).TimeAmount"
|
||||||
, SingleConstructor "Allocation" "Allocation" "(./dhall/Types.dhall).Allocation"
|
-- , SingleConstructor "Income" "Income" "(./dhall/Types.dhall).Income"
|
||||||
, SingleConstructor "Income" "Income" "(./dhall/Types.dhall).Income"
|
-- , SingleConstructor "Budget" "Budget" "(./dhall/Types.dhall).Budget"
|
||||||
, SingleConstructor "Budget" "Budget" "(./dhall/Types.dhall).Budget"
|
-- , SingleConstructor "Transfer" "Transfer" "(./dhall/Types.dhall).Transfer"
|
||||||
, SingleConstructor "Transfer" "Transfer" "(./dhall/Types.dhall).Transfer"
|
SingleConstructor "Exchange" "Exchange" "(./dhall/Types.dhall).Exchange"
|
||||||
, SingleConstructor "Exchange" "Exchange" "(./dhall/Types.dhall).Exchange"
|
|
||||||
, SingleConstructor "TaggedAcnt" "TaggedAcnt" "(./dhall/Types.dhall).TaggedAcnt"
|
, SingleConstructor "TaggedAcnt" "TaggedAcnt" "(./dhall/Types.dhall).TaggedAcnt"
|
||||||
, SingleConstructor "AcntSet" "AcntSet" "(./dhall/Types.dhall).AcntSet.Type"
|
, SingleConstructor "AcntSet" "AcntSet" "(./dhall/Types.dhall).AcntSet.Type"
|
||||||
, SingleConstructor "ShadowMatch" "ShadowMatch" "(./dhall/Types.dhall).ShadowMatch.Type"
|
, SingleConstructor "ShadowMatch" "ShadowMatch" "(./dhall/Types.dhall).ShadowMatch.Type"
|
||||||
|
@ -146,6 +144,12 @@ instance Ord GregorianM where
|
||||||
GregorianM {gmYear = y, gmMonth = m}
|
GregorianM {gmYear = y, gmMonth = m}
|
||||||
GregorianM {gmYear = y', gmMonth = m'} = compare y y' <> compare m m'
|
GregorianM {gmYear = y', gmMonth = m'} = compare y y' <> compare m m'
|
||||||
|
|
||||||
|
deriving instance Eq Interval
|
||||||
|
|
||||||
|
deriving instance Ord Interval
|
||||||
|
|
||||||
|
deriving instance Hashable Interval
|
||||||
|
|
||||||
deriving instance Eq ModPat
|
deriving instance Eq ModPat
|
||||||
|
|
||||||
deriving instance Ord ModPat
|
deriving instance Ord ModPat
|
||||||
|
@ -170,26 +174,55 @@ deriving instance Show DatePat
|
||||||
|
|
||||||
deriving instance Hashable DatePat
|
deriving instance Hashable DatePat
|
||||||
|
|
||||||
|
data Budget = Budget
|
||||||
|
{ budgetLabel :: Text
|
||||||
|
, incomes :: [Income]
|
||||||
|
, pretax :: [IntervalAllocation]
|
||||||
|
, tax :: [IntervalAllocation]
|
||||||
|
, posttax :: [IntervalAllocation]
|
||||||
|
, transfers :: [Transfer]
|
||||||
|
, shadowTransfers :: [ShadowTransfer]
|
||||||
|
}
|
||||||
|
|
||||||
deriving instance Eq Budget
|
deriving instance Eq Budget
|
||||||
|
|
||||||
|
deriving instance Generic Budget
|
||||||
|
|
||||||
deriving instance Hashable Budget
|
deriving instance Hashable Budget
|
||||||
|
|
||||||
|
deriving instance FromDhall Budget
|
||||||
|
|
||||||
deriving instance Eq TaggedAcnt
|
deriving instance Eq TaggedAcnt
|
||||||
|
|
||||||
deriving instance Hashable TaggedAcnt
|
deriving instance Hashable TaggedAcnt
|
||||||
|
|
||||||
deriving instance Ord TaggedAcnt
|
deriving instance Ord TaggedAcnt
|
||||||
|
|
||||||
|
type CurID = T.Text
|
||||||
|
|
||||||
|
data Income = Income
|
||||||
|
{ incGross :: Decimal
|
||||||
|
, incCurrency :: CurID
|
||||||
|
, incWhen :: DatePat
|
||||||
|
, incPretax :: [Allocation]
|
||||||
|
, incTaxes :: [Allocation]
|
||||||
|
, incPosttax :: [Allocation]
|
||||||
|
, incFrom :: TaggedAcnt
|
||||||
|
, incToBal :: TaggedAcnt
|
||||||
|
}
|
||||||
|
|
||||||
deriving instance Eq Income
|
deriving instance Eq Income
|
||||||
|
|
||||||
|
deriving instance Generic Income
|
||||||
|
|
||||||
deriving instance Hashable Income
|
deriving instance Hashable Income
|
||||||
|
|
||||||
deriving instance Eq Tax
|
deriving instance FromDhall Income
|
||||||
|
|
||||||
deriving instance Hashable Tax
|
|
||||||
|
|
||||||
deriving instance Eq Amount
|
deriving instance Eq Amount
|
||||||
|
|
||||||
|
deriving instance Ord Amount
|
||||||
|
|
||||||
deriving instance Hashable Amount
|
deriving instance Hashable Amount
|
||||||
|
|
||||||
deriving instance Eq Exchange
|
deriving instance Eq Exchange
|
||||||
|
@ -200,10 +233,32 @@ deriving instance Eq BudgetCurrency
|
||||||
|
|
||||||
deriving instance Hashable BudgetCurrency
|
deriving instance Hashable BudgetCurrency
|
||||||
|
|
||||||
|
data Allocation_ a = Allocation_
|
||||||
|
{ alloTo :: TaggedAcnt
|
||||||
|
, alloAmts :: [a]
|
||||||
|
, alloCur :: BudgetCurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
type Allocation = Allocation_ Amount
|
||||||
|
|
||||||
deriving instance Eq Allocation
|
deriving instance Eq Allocation
|
||||||
|
|
||||||
|
deriving instance Generic Allocation
|
||||||
|
|
||||||
deriving instance Hashable Allocation
|
deriving instance Hashable Allocation
|
||||||
|
|
||||||
|
deriving instance FromDhall Allocation
|
||||||
|
|
||||||
|
type IntervalAllocation = Allocation_ IntervalAmount
|
||||||
|
|
||||||
|
deriving instance Eq IntervalAllocation
|
||||||
|
|
||||||
|
deriving instance Generic IntervalAllocation
|
||||||
|
|
||||||
|
deriving instance Hashable IntervalAllocation
|
||||||
|
|
||||||
|
deriving instance FromDhall IntervalAllocation
|
||||||
|
|
||||||
toPersistText :: Show a => a -> PersistValue
|
toPersistText :: Show a => a -> PersistValue
|
||||||
toPersistText = PersistText . T.pack . show
|
toPersistText = PersistText . T.pack . show
|
||||||
|
|
||||||
|
@ -216,16 +271,54 @@ fromPersistText what x =
|
||||||
|
|
||||||
deriving instance Eq AmountType
|
deriving instance Eq AmountType
|
||||||
|
|
||||||
|
deriving instance Ord AmountType
|
||||||
|
|
||||||
deriving instance Hashable AmountType
|
deriving instance Hashable AmountType
|
||||||
|
|
||||||
deriving instance Eq TimeAmount
|
data TimeAmount a = TimeAmount
|
||||||
|
{ taWhen :: a
|
||||||
|
, taAmt :: Amount
|
||||||
|
, taAmtType :: AmountType
|
||||||
|
}
|
||||||
|
deriving (Eq, Ord, Functor, Generic, FromDhall, Hashable, Foldable, Traversable)
|
||||||
|
|
||||||
deriving instance Hashable TimeAmount
|
type DateAmount = TimeAmount DatePat
|
||||||
|
|
||||||
|
-- deriving instance Eq DateAmount
|
||||||
|
|
||||||
|
-- deriving instance Generic DateAmount
|
||||||
|
|
||||||
|
-- deriving instance Hashable DateAmount
|
||||||
|
|
||||||
|
-- deriving instance FromDhall DateAmount
|
||||||
|
|
||||||
|
type IntervalAmount = TimeAmount Interval
|
||||||
|
|
||||||
|
-- deriving instance Eq IntervalAmount
|
||||||
|
|
||||||
|
-- deriving instance Ord IntervalAmount
|
||||||
|
|
||||||
|
-- deriving instance Generic IntervalAmount
|
||||||
|
|
||||||
|
-- deriving instance Hashable IntervalAmount
|
||||||
|
|
||||||
|
-- deriving instance FromDhall IntervalAmount
|
||||||
|
|
||||||
|
data Transfer = Transfer
|
||||||
|
{ transFrom :: TaggedAcnt
|
||||||
|
, transTo :: TaggedAcnt
|
||||||
|
, transAmounts :: [DateAmount]
|
||||||
|
, transCurrency :: BudgetCurrency
|
||||||
|
}
|
||||||
|
|
||||||
deriving instance Eq Transfer
|
deriving instance Eq Transfer
|
||||||
|
|
||||||
|
deriving instance Generic Transfer
|
||||||
|
|
||||||
deriving instance Hashable Transfer
|
deriving instance Hashable Transfer
|
||||||
|
|
||||||
|
deriving instance FromDhall Transfer
|
||||||
|
|
||||||
deriving instance Eq ShadowTransfer
|
deriving instance Eq ShadowTransfer
|
||||||
|
|
||||||
deriving instance Hashable ShadowTransfer
|
deriving instance Hashable ShadowTransfer
|
||||||
|
@ -258,6 +351,8 @@ deriving instance Show MatchDate
|
||||||
|
|
||||||
deriving instance Eq Decimal
|
deriving instance Eq Decimal
|
||||||
|
|
||||||
|
deriving instance Ord Decimal
|
||||||
|
|
||||||
deriving instance Hashable Decimal
|
deriving instance Hashable Decimal
|
||||||
|
|
||||||
deriving instance Show Decimal
|
deriving instance Show Decimal
|
||||||
|
@ -360,8 +455,6 @@ instance FromDhall a => FromDhall (Config_ a)
|
||||||
-- TODO newtypes for these?
|
-- TODO newtypes for these?
|
||||||
type AcntID = T.Text
|
type AcntID = T.Text
|
||||||
|
|
||||||
type CurID = T.Text
|
|
||||||
|
|
||||||
type TagID = T.Text
|
type TagID = T.Text
|
||||||
|
|
||||||
data Statement
|
data Statement
|
||||||
|
|
|
@ -6,6 +6,7 @@ module Internal.Utils
|
||||||
, matches
|
, matches
|
||||||
, fromGregorian'
|
, fromGregorian'
|
||||||
, resolveBounds
|
, resolveBounds
|
||||||
|
, resolveBounds_
|
||||||
, leftToMaybe
|
, leftToMaybe
|
||||||
, dec2Rat
|
, dec2Rat
|
||||||
, concatEithers2
|
, concatEithers2
|
||||||
|
@ -130,9 +131,13 @@ inBounds :: (Day, Day) -> Day -> Bool
|
||||||
inBounds (d0, d1) x = d0 <= x && x < d1
|
inBounds (d0, d1) x = d0 <= x && x < d1
|
||||||
|
|
||||||
resolveBounds :: Interval -> EitherErr Bounds
|
resolveBounds :: Interval -> EitherErr Bounds
|
||||||
resolveBounds Interval {intStart = s, intEnd = e} =
|
resolveBounds i@Interval {intStart = s} =
|
||||||
|
resolveBounds_ (s {gYear = gYear s + 50}) i
|
||||||
|
|
||||||
|
resolveBounds_ :: Gregorian -> Interval -> EitherErr Bounds
|
||||||
|
resolveBounds_ def Interval {intStart = s, intEnd = e} =
|
||||||
case fromGregorian' <$> e of
|
case fromGregorian' <$> e of
|
||||||
Nothing -> Right $ toBounds $ fromGregorian' $ s {gYear = gYear s + 50}
|
Nothing -> Right $ toBounds $ fromGregorian' def
|
||||||
Just e_
|
Just e_
|
||||||
| s_ < e_ -> Right $ toBounds e_
|
| s_ < e_ -> Right $ toBounds e_
|
||||||
| otherwise -> Left $ BoundsError s e
|
| otherwise -> Left $ BoundsError s e
|
||||||
|
|
Loading…
Reference in New Issue