WIP assign buckets more sanely
This commit is contained in:
parent
a16f6fbdd2
commit
53e1dde60f
|
@ -193,9 +193,18 @@ let TimeAmount = { taWhen : DatePat, taAmt : Amount, taAmtType : AmountType }
|
||||||
|
|
||||||
let Tax = { taxAcnt : AcntID, taxValue : Decimal }
|
let Tax = { taxAcnt : AcntID, taxValue : Decimal }
|
||||||
|
|
||||||
|
let TransferTarget =
|
||||||
|
< ExpenseTarget :
|
||||||
|
{ _1xtarget :
|
||||||
|
{- this is the only place expense accounts may be specified -}
|
||||||
|
AcntID
|
||||||
|
, _2xtarget : ExpenseBucket
|
||||||
|
}
|
||||||
|
| GenericTarget : AcntID
|
||||||
|
>
|
||||||
|
|
||||||
let Allocation =
|
let Allocation =
|
||||||
{ alloPath : AcntID
|
{ alloPath : TransferTarget
|
||||||
, alloBucket : ExpenseBucket
|
|
||||||
, alloAmts : List Amount
|
, alloAmts : List Amount
|
||||||
, alloCurrency : CurID
|
, alloCurrency : CurID
|
||||||
}
|
}
|
||||||
|
@ -204,17 +213,19 @@ let Income =
|
||||||
{ incGross : Decimal
|
{ incGross : Decimal
|
||||||
, incCurrency : CurID
|
, incCurrency : CurID
|
||||||
, incWhen : DatePat
|
, incWhen : DatePat
|
||||||
, incFrom : AcntID
|
, incFrom :
|
||||||
|
{- this must be an income AcntID, and is the only place income
|
||||||
|
accounts may be specified in the entire budget -}
|
||||||
|
AcntID
|
||||||
, incPretax : List Allocation
|
, incPretax : List Allocation
|
||||||
, incTaxes : List Tax
|
, incTaxes : List Tax
|
||||||
, incPosttax : List Allocation
|
, incPosttax : List Allocation
|
||||||
, incToBal : AcntID
|
, incToBal : TransferTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
let Transfer =
|
let Transfer =
|
||||||
{ transFrom : AcntID
|
{ transFrom : AcntID
|
||||||
, transTo : AcntID
|
, transTo : TransferTarget
|
||||||
, transBucket : ExpenseBucket
|
|
||||||
, transAmounts : List TimeAmount
|
, transAmounts : List TimeAmount
|
||||||
, transCurrency : CurID
|
, transCurrency : CurID
|
||||||
}
|
}
|
||||||
|
@ -267,4 +278,5 @@ in { CurID
|
||||||
, Amount
|
, Amount
|
||||||
, TimeAmount
|
, TimeAmount
|
||||||
, AmountType
|
, AmountType
|
||||||
|
, TransferTarget
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ IncomeBucketR sql=income_buckets
|
||||||
deriving Show Eq
|
deriving Show Eq
|
||||||
|]
|
|]
|
||||||
|
|
||||||
type AccountMap = M.Map AcntID (AccountRId, AcntSign)
|
type AccountMap = M.Map AcntID (AccountRId, AcntSign, AcntType)
|
||||||
|
|
||||||
type CurrencyMap = M.Map CurID CurrencyRId
|
type CurrencyMap = M.Map CurID CurrencyRId
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ tree2Entity t parents name des =
|
||||||
tree2Records
|
tree2Records
|
||||||
:: AcntType
|
:: AcntType
|
||||||
-> AccountTree
|
-> AccountTree
|
||||||
-> ([Entity AccountR], [AccountPathR], [(AcntPath, (AccountRId, AcntSign))])
|
-> ([Entity AccountR], [AccountPathR], [(AcntPath, (AccountRId, AcntSign, AcntType))])
|
||||||
tree2Records t = go []
|
tree2Records t = go []
|
||||||
where
|
where
|
||||||
go ps (Placeholder d n cs) =
|
go ps (Placeholder d n cs) =
|
||||||
|
@ -227,7 +227,7 @@ tree2Records t = go []
|
||||||
k = entityKey e
|
k = entityKey e
|
||||||
in ( [acnt k n (fmap snd ps) d]
|
in ( [acnt k n (fmap snd ps) d]
|
||||||
, expand k $ fmap fst ps
|
, expand k $ fmap fst ps
|
||||||
, [(AcntPath t $ reverse $ n : fmap snd ps, (k, sign))]
|
, [(AcntPath t $ reverse $ n : fmap snd ps, (k, sign, t))]
|
||||||
)
|
)
|
||||||
toPath = T.intercalate "/" . (atName t :) . reverse
|
toPath = T.intercalate "/" . (atName t :) . reverse
|
||||||
acnt k n ps = Entity k . AccountR n (toPath ps)
|
acnt k n ps = Entity k . AccountR n (toPath ps)
|
||||||
|
|
|
@ -7,6 +7,7 @@ where
|
||||||
import Data.Hashable
|
import Data.Hashable
|
||||||
import Database.Persist.Class
|
import Database.Persist.Class
|
||||||
import Database.Persist.Sql hiding (Single, Statement)
|
import Database.Persist.Sql hiding (Single, Statement)
|
||||||
|
import GHC.Utils.Misc hiding (split)
|
||||||
import Internal.Database.Model
|
import Internal.Database.Model
|
||||||
import Internal.Statement
|
import Internal.Statement
|
||||||
import Internal.Types hiding (sign)
|
import Internal.Types hiding (sign)
|
||||||
|
@ -14,6 +15,7 @@ import Internal.Utils
|
||||||
import RIO hiding (to)
|
import RIO hiding (to)
|
||||||
import qualified RIO.List as L
|
import qualified RIO.List as L
|
||||||
import qualified RIO.Map as M
|
import qualified RIO.Map as M
|
||||||
|
import qualified RIO.NonEmpty as NE
|
||||||
import qualified RIO.Text as T
|
import qualified RIO.Text as T
|
||||||
import RIO.Time
|
import RIO.Time
|
||||||
|
|
||||||
|
@ -95,12 +97,13 @@ dayToWeekday (ModifiedJulianDay d) = mod (fromIntegral d + 2) 7
|
||||||
withDates
|
withDates
|
||||||
:: MonadFinance m
|
:: MonadFinance m
|
||||||
=> DatePat
|
=> DatePat
|
||||||
-> (Day -> SqlPersistT m a)
|
-> (Day -> SqlPersistT m (EitherErrs a))
|
||||||
-> SqlPersistT m (EitherErrs [a])
|
-> SqlPersistT m (EitherErrs [a])
|
||||||
withDates dp f = do
|
withDates dp f = do
|
||||||
bounds <- lift $ askDBState kmBudgetInterval
|
bounds <- lift $ askDBState kmBudgetInterval
|
||||||
let days = expandDatePat bounds dp
|
case expandDatePat bounds dp of
|
||||||
mapM (mapM f) days
|
Left es -> return $ Left es
|
||||||
|
Right days -> concatEithersL <$> mapM f days
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- budget
|
-- budget
|
||||||
|
@ -159,55 +162,88 @@ insertIncome :: MonadFinance m => T.Text -> Income -> SqlPersistT m (EitherErrs
|
||||||
insertIncome
|
insertIncome
|
||||||
name
|
name
|
||||||
i@Income {incWhen, incCurrency, incFrom, incPretax, incPosttax, incTaxes, incToBal} =
|
i@Income {incWhen, incCurrency, incFrom, incPretax, incPosttax, incTaxes, incToBal} =
|
||||||
whenHash CTIncome i (Right []) $ \c -> case (balanceIncome i) of
|
whenHash CTIncome i (Right []) $ \c -> do
|
||||||
Left e -> return $ Left [e]
|
let balRes = balanceIncome i
|
||||||
Right balance ->
|
fromRes <- lift $ checkAcntType IncomeT incFrom (\j -> BudgetSplit j . Just)
|
||||||
fmap (fmap concat) $ withDates incWhen $ \day -> do
|
toRes <- lift $ expandTarget incToBal
|
||||||
let meta = BudgetMeta c day incCurrency name
|
case concatEither3 balRes fromRes toRes (,,) of
|
||||||
let fromAllos b = concatMap (fromAllo meta incFrom (Just b))
|
Left es -> return $ Left es
|
||||||
let pre = fromAllos PreTax incPretax
|
Right (balance, fromFun, to) ->
|
||||||
let tax = fmap (fromTax meta incFrom) incTaxes
|
fmap (fmap (concat . concat)) $
|
||||||
let post = fromAllos PostTax incPosttax
|
withDates incWhen $ \day -> do
|
||||||
let bal =
|
let meta = BudgetMeta c day incCurrency name
|
||||||
TransferTx
|
let fromAllos b =
|
||||||
{ trxMeta = meta
|
fmap (fmap concat . concatEitherL)
|
||||||
, trxFrom = BudgetSplit incFrom $ Just PostTax
|
. mapM (lift . fromAllo meta (fromFun b))
|
||||||
, trxTo = BudgetSplit incToBal Nothing
|
pre <- fromAllos PreTax incPretax
|
||||||
, trxValue = balance
|
tax <-
|
||||||
, trxType = FixedAmt
|
concatEitherL
|
||||||
, trxDesc = "balance after deductions"
|
<$> mapM (lift . fromTax meta (fromFun IntraTax)) incTaxes
|
||||||
}
|
post <- fromAllos PostTax incPosttax
|
||||||
return $ bal : (pre ++ tax ++ post)
|
let bal =
|
||||||
|
TransferTx
|
||||||
|
{ trxMeta = meta
|
||||||
|
, trxFrom = fromFun PostTax
|
||||||
|
, trxTo = to
|
||||||
|
, trxValue = balance
|
||||||
|
, trxType = FixedAmt
|
||||||
|
, trxDesc = "balance after deductions"
|
||||||
|
}
|
||||||
|
return $ concatEithersL [Right [bal], tax, pre, post]
|
||||||
|
|
||||||
fromAllo
|
fromAllo
|
||||||
:: BudgetMeta
|
:: MonadFinance m
|
||||||
-> AcntID
|
=> BudgetMeta
|
||||||
-> Maybe IncomeBucket
|
-> BudgetSplit IncomeBucket
|
||||||
-> Allocation
|
-> Allocation
|
||||||
-> [TransferTx]
|
-> m (EitherErr [TransferTx])
|
||||||
fromAllo meta from ib Allocation {alloPath, alloAmts, alloBucket} =
|
fromAllo meta from Allocation {alloPath, alloAmts} = do
|
||||||
fmap (toBT alloPath) alloAmts
|
-- TODO this is going to be repeated a zillion times (might matter)
|
||||||
|
res <- expandTarget alloPath
|
||||||
|
return $ (\to -> fmap (toBT to) alloAmts) <$> res
|
||||||
where
|
where
|
||||||
toBT to (Amount desc v) =
|
toBT to (Amount desc v) =
|
||||||
TransferTx
|
TransferTx
|
||||||
{ trxFrom = BudgetSplit from ib
|
{ trxFrom = from
|
||||||
, trxTo = BudgetSplit to $ Just alloBucket
|
, trxTo = to
|
||||||
, trxValue = dec2Rat v
|
, trxValue = dec2Rat v
|
||||||
, trxDesc = desc
|
, trxDesc = desc
|
||||||
, trxType = FixedAmt
|
, trxType = FixedAmt
|
||||||
, trxMeta = meta
|
, trxMeta = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
fromTax :: BudgetMeta -> AcntID -> Tax -> TransferTx
|
expandTarget :: MonadFinance m => TransferTarget -> m (EitherErr (BudgetSplit ExpenseBucket))
|
||||||
|
expandTarget t = case t of
|
||||||
|
ExpenseTarget i b -> checkAcntType ExpenseT i $ (`BudgetSplit` (Just b))
|
||||||
|
GenericTarget i -> checkAcntTypes (LiabilityT :| [AssetT, EquityT]) i $ (`BudgetSplit` Nothing)
|
||||||
|
|
||||||
|
checkAcntType :: MonadFinance m => AcntType -> AcntID -> (AcntID -> a) -> m (EitherErr a)
|
||||||
|
checkAcntType t = checkAcntTypes (t :| [])
|
||||||
|
|
||||||
|
checkAcntTypes :: MonadFinance m => NE.NonEmpty AcntType -> AcntID -> (AcntID -> a) -> m (EitherErr a)
|
||||||
|
checkAcntTypes ts i f = (go =<<) <$> lookupAccountType i
|
||||||
|
where
|
||||||
|
go t
|
||||||
|
| t `L.elem` ts = Right $ f i
|
||||||
|
| otherwise = Left $ AccountError i t
|
||||||
|
|
||||||
|
fromTax
|
||||||
|
:: MonadFinance m
|
||||||
|
=> BudgetMeta
|
||||||
|
-> BudgetSplit IncomeBucket
|
||||||
|
-> Tax
|
||||||
|
-> m (EitherErr TransferTx)
|
||||||
fromTax meta from Tax {taxAcnt = to, taxValue = v} =
|
fromTax meta from Tax {taxAcnt = to, taxValue = v} =
|
||||||
TransferTx
|
-- TODO this is going to be repeated a zillion times (might matter)
|
||||||
{ trxFrom = BudgetSplit from (Just IntraTax)
|
checkAcntType ExpenseT to $ \to_ ->
|
||||||
, trxTo = BudgetSplit to (Just Fixed)
|
TransferTx
|
||||||
, trxValue = dec2Rat v
|
{ trxFrom = from
|
||||||
, trxDesc = ""
|
, trxTo = BudgetSplit to_ (Just Fixed)
|
||||||
, trxType = FixedAmt
|
, trxValue = dec2Rat v
|
||||||
, trxMeta = meta
|
, trxDesc = ""
|
||||||
}
|
, trxType = FixedAmt
|
||||||
|
, trxMeta = meta
|
||||||
|
}
|
||||||
|
|
||||||
balanceIncome :: Income -> EitherErr Rational
|
balanceIncome :: Income -> EitherErr Rational
|
||||||
balanceIncome
|
balanceIncome
|
||||||
|
@ -234,7 +270,6 @@ expandTransfers name ts = do
|
||||||
txs <- mapM (expandTransfer name) ts
|
txs <- mapM (expandTransfer name) ts
|
||||||
return $ L.sortOn (bmWhen . trxMeta) . concat <$> concatEithersL txs
|
return $ L.sortOn (bmWhen . trxMeta) . concat <$> concatEithersL txs
|
||||||
|
|
||||||
-- TODO the entire budget needs to have this process applied to it
|
|
||||||
balanceTransfers :: [TransferTx] -> [BudgetTx]
|
balanceTransfers :: [TransferTx] -> [BudgetTx]
|
||||||
balanceTransfers ts = snd $ L.mapAccumR go initBals $ L.sortOn (bmWhen . trxMeta) ts
|
balanceTransfers ts = snd $ L.mapAccumR go initBals $ L.sortOn (bmWhen . trxMeta) ts
|
||||||
where
|
where
|
||||||
|
@ -268,30 +303,35 @@ balanceTransfers ts = snd $ L.mapAccumR go initBals $ L.sortOn (bmWhen . trxMeta
|
||||||
|
|
||||||
expandTransfer :: MonadFinance m => T.Text -> Transfer -> SqlPersistT m (EitherErrs [TransferTx])
|
expandTransfer :: MonadFinance m => T.Text -> Transfer -> SqlPersistT m (EitherErrs [TransferTx])
|
||||||
expandTransfer name t@Transfer {transAmounts, transTo, transCurrency, transFrom} =
|
expandTransfer name t@Transfer {transAmounts, transTo, transCurrency, transFrom} =
|
||||||
whenHash CTExpense t (Right []) $ \key -> do
|
whenHash CTExpense t (Right []) $ \key ->
|
||||||
res <- forM transAmounts $ \(TimeAmount (Amount desc v) atype pat) ->
|
fmap (fmap concat . concatEithersL) $
|
||||||
withDates pat $ \day ->
|
forM transAmounts $ \(TimeAmount (Amount desc v) atype pat) -> do
|
||||||
let meta =
|
-- TODO this is going to be repeated a zillion times (might matter)
|
||||||
BudgetMeta
|
res <- lift $ expandTarget transTo
|
||||||
{ bmWhen = day
|
case res of
|
||||||
, bmCur = transCurrency
|
Left e -> return $ Left [e]
|
||||||
, bmCommit = key
|
Right to -> withDates pat $ \day ->
|
||||||
, bmName = name
|
let meta =
|
||||||
}
|
BudgetMeta
|
||||||
in return $
|
{ bmWhen = day
|
||||||
TransferTx
|
, bmCur = transCurrency
|
||||||
{ trxMeta = meta
|
, bmCommit = key
|
||||||
, trxFrom = BudgetSplit transFrom Nothing
|
, bmName = name
|
||||||
, trxTo = BudgetSplit transTo Nothing
|
}
|
||||||
, trxValue = dec2Rat v
|
tx =
|
||||||
, trxType = atype
|
TransferTx
|
||||||
, trxDesc = desc
|
{ trxMeta = meta
|
||||||
}
|
, trxFrom = BudgetSplit transFrom Nothing
|
||||||
return $ concat <$> concatEithersL res
|
, trxTo = to
|
||||||
|
, trxValue = dec2Rat v
|
||||||
|
, trxType = atype
|
||||||
|
, trxDesc = desc
|
||||||
|
}
|
||||||
|
in return $ Right tx
|
||||||
|
|
||||||
insertBudgetTx :: MonadFinance m => BudgetTx -> SqlPersistT m [InsertError]
|
insertBudgetTx :: MonadFinance m => BudgetTx -> SqlPersistT m [InsertError]
|
||||||
insertBudgetTx BudgetTx {btFrom, btTo, btMeta, btValue, btDesc} = do
|
insertBudgetTx BudgetTx {btFrom, btTo, btMeta, btValue, btDesc} = do
|
||||||
res <- splitPair (bsAcnt btFrom) (bsAcnt btTo) (bmCur btMeta) btValue
|
res <- lift $ splitPair (bsAcnt btFrom) (bsAcnt btTo) (bmCur btMeta) btValue
|
||||||
unlessLefts_ res $ \(sFrom, sTo) -> do
|
unlessLefts_ res $ \(sFrom, sTo) -> do
|
||||||
k <- insert $ TransactionR (bmCommit btMeta) (bmWhen btMeta) btDesc
|
k <- insert $ TransactionR (bmCommit btMeta) (bmWhen btMeta) btDesc
|
||||||
insertBudgetLabel name k IncomeBucketR sFrom btFrom
|
insertBudgetLabel name k IncomeBucketR sFrom btFrom
|
||||||
|
@ -318,7 +358,7 @@ splitPair
|
||||||
-> AcntID
|
-> AcntID
|
||||||
-> CurID
|
-> CurID
|
||||||
-> Rational
|
-> Rational
|
||||||
-> SqlPersistT m (EitherErrs (KeySplit, KeySplit))
|
-> m (EitherErrs (KeySplit, KeySplit))
|
||||||
splitPair from to cur val = do
|
splitPair from to cur val = do
|
||||||
s1 <- split from (-val)
|
s1 <- split from (-val)
|
||||||
s2 <- split to val
|
s2 <- split to val
|
||||||
|
@ -358,7 +398,7 @@ insertManual
|
||||||
-- let days = expandDatePat bounds dp
|
-- let days = expandDatePat bounds dp
|
||||||
let dayRes = expandDatePat bounds dp
|
let dayRes = expandDatePat bounds dp
|
||||||
unlessLefts dayRes $ \days -> do
|
unlessLefts dayRes $ \days -> do
|
||||||
txRes <- mapM tx days
|
txRes <- mapM (lift . tx) days
|
||||||
unlessLefts_ (concatEithersL txRes) $ mapM_ (insertTx c)
|
unlessLefts_ (concatEithersL txRes) $ mapM_ (insertTx c)
|
||||||
where
|
where
|
||||||
tx day = txPair day from to u (dec2Rat v) e
|
tx day = txPair day from to u (dec2Rat v) e
|
||||||
|
@ -369,7 +409,7 @@ insertImport i = whenHash CTImport i [] $ \c -> do
|
||||||
-- transactions will be desired
|
-- transactions will be desired
|
||||||
recoverIO (lift $ readImport i) $ \r -> unlessLefts r $ \bs -> do
|
recoverIO (lift $ readImport i) $ \r -> unlessLefts r $ \bs -> do
|
||||||
bounds <- expandBounds <$> lift (askDBState kmStatementInterval)
|
bounds <- expandBounds <$> lift (askDBState kmStatementInterval)
|
||||||
res <- mapM resolveTx $ filter (inBounds bounds . txDate) bs
|
res <- mapM (lift . resolveTx) $ filter (inBounds bounds . txDate) bs
|
||||||
unlessLefts_ (concatEithersL res) $ mapM_ (insertTx c)
|
unlessLefts_ (concatEithersL res) $ mapM_ (insertTx c)
|
||||||
where
|
where
|
||||||
recoverIO x rest = do
|
recoverIO x rest = do
|
||||||
|
@ -391,7 +431,7 @@ txPair
|
||||||
-> CurID
|
-> CurID
|
||||||
-> Rational
|
-> Rational
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> SqlPersistT m (EitherErrs KeyTx)
|
-> m (EitherErrs KeyTx)
|
||||||
txPair day from to cur val desc = resolveTx tx
|
txPair day from to cur val desc = resolveTx tx
|
||||||
where
|
where
|
||||||
split a v = Split {sAcnt = a, sValue = v, sComment = "", sCurrency = cur}
|
split a v = Split {sAcnt = a, sValue = v, sComment = "", sCurrency = cur}
|
||||||
|
@ -403,12 +443,12 @@ txPair day from to cur val desc = resolveTx tx
|
||||||
, txSplits = [split from (-val), split to val]
|
, txSplits = [split from (-val), split to val]
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveTx :: MonadFinance m => BalTx -> SqlPersistT m (EitherErrs KeyTx)
|
resolveTx :: MonadFinance m => BalTx -> m (EitherErrs KeyTx)
|
||||||
resolveTx t@Tx {txSplits = ss} = do
|
resolveTx t@Tx {txSplits = ss} = do
|
||||||
res <- concatEithersL <$> mapM resolveSplit ss
|
res <- concatEithersL <$> mapM resolveSplit ss
|
||||||
return $ fmap (\kss -> t {txSplits = kss}) res
|
return $ fmap (\kss -> t {txSplits = kss}) res
|
||||||
|
|
||||||
resolveSplit :: MonadFinance m => BalSplit -> SqlPersistT m (EitherErrs KeySplit)
|
resolveSplit :: MonadFinance m => BalSplit -> m (EitherErrs KeySplit)
|
||||||
resolveSplit s@Split {sAcnt = p, sCurrency = c, sValue = v} = do
|
resolveSplit s@Split {sAcnt = p, sCurrency = c, sValue = v} = do
|
||||||
aid <- lookupAccountKey p
|
aid <- lookupAccountKey p
|
||||||
cid <- lookupCurrency c
|
cid <- lookupCurrency c
|
||||||
|
@ -431,17 +471,20 @@ insertSplit :: MonadUnliftIO m => Key TransactionR -> KeySplit -> SqlPersistT m
|
||||||
insertSplit t Split {sAcnt = aid, sCurrency = cid, sValue = v, sComment = c} = do
|
insertSplit t Split {sAcnt = aid, sCurrency = cid, sValue = v, sComment = c} = do
|
||||||
insert $ SplitR t cid aid c v
|
insert $ SplitR t cid aid c v
|
||||||
|
|
||||||
lookupAccount :: MonadFinance m => AcntID -> SqlPersistT m (EitherErr (Key AccountR, AcntSign))
|
lookupAccount :: MonadFinance m => AcntID -> m (EitherErr (Key AccountR, AcntSign, AcntType))
|
||||||
lookupAccount p = lookupErr (DBKey AcntField) p <$> lift (askDBState kmAccount)
|
lookupAccount p = lookupErr (DBKey AcntField) p <$> (askDBState kmAccount)
|
||||||
|
|
||||||
lookupAccountKey :: MonadFinance m => AcntID -> SqlPersistT m (EitherErr (Key AccountR))
|
lookupAccountKey :: MonadFinance m => AcntID -> m (EitherErr (Key AccountR))
|
||||||
lookupAccountKey = fmap (fmap fst) . lookupAccount
|
lookupAccountKey = (fmap (fmap fstOf3)) . lookupAccount
|
||||||
|
|
||||||
lookupAccountSign :: MonadFinance m => AcntID -> SqlPersistT m (EitherErr AcntSign)
|
lookupAccountSign :: MonadFinance m => AcntID -> m (EitherErr AcntSign)
|
||||||
lookupAccountSign = fmap (fmap snd) . lookupAccount
|
lookupAccountSign = fmap (fmap sndOf3) . lookupAccount
|
||||||
|
|
||||||
lookupCurrency :: MonadFinance m => T.Text -> SqlPersistT m (EitherErr (Key CurrencyR))
|
lookupAccountType :: MonadFinance m => AcntID -> m (EitherErr AcntType)
|
||||||
lookupCurrency c = lookupErr (DBKey CurField) c <$> lift (askDBState kmCurrency)
|
lookupAccountType = fmap (fmap thdOf3) . lookupAccount
|
||||||
|
|
||||||
|
lookupCurrency :: MonadFinance m => T.Text -> m (EitherErr (Key CurrencyR))
|
||||||
|
lookupCurrency c = lookupErr (DBKey CurField) c <$> (askDBState kmCurrency)
|
||||||
|
|
||||||
-- TODO this hashes twice (not that it really matters)
|
-- TODO this hashes twice (not that it really matters)
|
||||||
whenHash
|
whenHash
|
||||||
|
|
|
@ -34,6 +34,7 @@ makeHaskellTypesWith
|
||||||
, MultipleConstructors "ExpenseBucket" "(./dhall/Types.dhall).ExpenseBucket"
|
, MultipleConstructors "ExpenseBucket" "(./dhall/Types.dhall).ExpenseBucket"
|
||||||
, MultipleConstructors "IncomeBucket" "(./dhall/Types.dhall).IncomeBucket"
|
, MultipleConstructors "IncomeBucket" "(./dhall/Types.dhall).IncomeBucket"
|
||||||
, MultipleConstructors "AmountType" "(./dhall/Types.dhall).AmountType"
|
, MultipleConstructors "AmountType" "(./dhall/Types.dhall).AmountType"
|
||||||
|
, MultipleConstructors "TransferTarget" "(./dhall/Types.dhall).TransferTarget"
|
||||||
, SingleConstructor "Currency" "Currency" "(./dhall/Types.dhall).Currency"
|
, SingleConstructor "Currency" "Currency" "(./dhall/Types.dhall).Currency"
|
||||||
, SingleConstructor "Gregorian" "Gregorian" "(./dhall/Types.dhall).Gregorian"
|
, SingleConstructor "Gregorian" "Gregorian" "(./dhall/Types.dhall).Gregorian"
|
||||||
, SingleConstructor "GregorianM" "GregorianM" "(./dhall/Types.dhall).GregorianM"
|
, SingleConstructor "GregorianM" "GregorianM" "(./dhall/Types.dhall).GregorianM"
|
||||||
|
@ -50,8 +51,8 @@ makeHaskellTypesWith
|
||||||
, SingleConstructor "TimeAmount" "TimeAmount" "(./dhall/Types.dhall).TimeAmount"
|
, SingleConstructor "TimeAmount" "TimeAmount" "(./dhall/Types.dhall).TimeAmount"
|
||||||
, SingleConstructor "Allocation" "Allocation" "(./dhall/Types.dhall).Allocation"
|
, SingleConstructor "Allocation" "Allocation" "(./dhall/Types.dhall).Allocation"
|
||||||
, SingleConstructor "Income" "Income" "(./dhall/Types.dhall).Income"
|
, SingleConstructor "Income" "Income" "(./dhall/Types.dhall).Income"
|
||||||
, SingleConstructor "Transfer" "Transfer" "(./dhall/Types.dhall).Transfer"
|
|
||||||
, SingleConstructor "Budget" "Budget" "(./dhall/Types.dhall).Budget"
|
, SingleConstructor "Budget" "Budget" "(./dhall/Types.dhall).Budget"
|
||||||
|
, SingleConstructor "Transfer" "Transfer" "(./dhall/Types.dhall).Transfer"
|
||||||
]
|
]
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
@ -300,6 +301,10 @@ deriving instance Eq TimeAmount
|
||||||
|
|
||||||
deriving instance Hashable TimeAmount
|
deriving instance Hashable TimeAmount
|
||||||
|
|
||||||
|
deriving instance Eq TransferTarget
|
||||||
|
|
||||||
|
deriving instance Hashable TransferTarget
|
||||||
|
|
||||||
deriving instance Eq Transfer
|
deriving instance Eq Transfer
|
||||||
|
|
||||||
deriving instance Hashable Transfer
|
deriving instance Hashable Transfer
|
||||||
|
@ -582,6 +587,7 @@ data PatternSuberr = ZeroLength | ZeroRepeats deriving (Show)
|
||||||
data InsertError
|
data InsertError
|
||||||
= RegexError !T.Text
|
= RegexError !T.Text
|
||||||
| MatchValPrecisionError !Natural !Natural
|
| MatchValPrecisionError !Natural !Natural
|
||||||
|
| AccountError !AcntID !AcntType
|
||||||
| InsertIOError !T.Text
|
| InsertIOError !T.Text
|
||||||
| ParseError !T.Text
|
| ParseError !T.Text
|
||||||
| ConversionError !T.Text
|
| ConversionError !T.Text
|
||||||
|
|
|
@ -9,10 +9,13 @@ module Internal.Utils
|
||||||
, leftToMaybe
|
, leftToMaybe
|
||||||
, dec2Rat
|
, dec2Rat
|
||||||
, concatEithers2
|
, concatEithers2
|
||||||
|
, concatEithers3
|
||||||
, concatEither3
|
, concatEither3
|
||||||
, concatEither2
|
, concatEither2
|
||||||
, concatEitherL
|
, concatEitherL
|
||||||
, concatEithersL
|
, concatEithersL
|
||||||
|
, concatEither2M
|
||||||
|
, concatEithers2M
|
||||||
, parseRational
|
, parseRational
|
||||||
, showError
|
, showError
|
||||||
, unlessLeft_
|
, unlessLeft_
|
||||||
|
@ -23,7 +26,8 @@ module Internal.Utils
|
||||||
, showT
|
, showT
|
||||||
, lookupErr
|
, lookupErr
|
||||||
, gregorians
|
, gregorians
|
||||||
, uncurry3
|
-- , uncurry3
|
||||||
|
|
||||||
, xGregToDay
|
, xGregToDay
|
||||||
, plural
|
, plural
|
||||||
, compileMatch
|
, compileMatch
|
||||||
|
@ -313,6 +317,8 @@ showError other = (: []) $ case other of
|
||||||
where
|
where
|
||||||
showGreg (Just g) = showGregorian_ g
|
showGreg (Just g) = showGregorian_ g
|
||||||
showGreg Nothing = "Inf"
|
showGreg Nothing = "Inf"
|
||||||
|
-- TODO define
|
||||||
|
(AccountError _ _) -> undefined
|
||||||
(PatternError s b r p) -> T.unwords [msg, "in pattern: ", pat]
|
(PatternError s b r p) -> T.unwords [msg, "in pattern: ", pat]
|
||||||
where
|
where
|
||||||
pat =
|
pat =
|
||||||
|
@ -478,6 +484,11 @@ concatEither2 a b fun = case (a, b) of
|
||||||
(Right a_, Right b_) -> Right $ fun a_ b_
|
(Right a_, Right b_) -> Right $ fun a_ b_
|
||||||
_ -> Left $ catMaybes [leftToMaybe a, leftToMaybe b]
|
_ -> Left $ catMaybes [leftToMaybe a, leftToMaybe b]
|
||||||
|
|
||||||
|
concatEither2M :: Monad m => Either x a -> Either x b -> (a -> b -> m c) -> m (Either [x] c)
|
||||||
|
concatEither2M a b fun = case (a, b) of
|
||||||
|
(Right a_, Right b_) -> Right <$> fun a_ b_
|
||||||
|
_ -> return $ Left $ catMaybes [leftToMaybe a, leftToMaybe b]
|
||||||
|
|
||||||
concatEither3 :: Either x a -> Either x b -> Either x c -> (a -> b -> c -> d) -> Either [x] d
|
concatEither3 :: Either x a -> Either x b -> Either x c -> (a -> b -> c -> d) -> Either [x] d
|
||||||
concatEither3 a b c fun = case (a, b, c) of
|
concatEither3 a b c fun = case (a, b, c) of
|
||||||
(Right a_, Right b_, Right c_) -> Right $ fun a_ b_ c_
|
(Right a_, Right b_, Right c_) -> Right $ fun a_ b_ c_
|
||||||
|
@ -486,13 +497,21 @@ concatEither3 a b c fun = case (a, b, c) of
|
||||||
concatEithers2 :: Either [x] a -> Either [x] b -> (a -> b -> c) -> Either [x] c
|
concatEithers2 :: Either [x] a -> Either [x] b -> (a -> b -> c) -> Either [x] c
|
||||||
concatEithers2 a b = merge . concatEither2 a b
|
concatEithers2 a b = merge . concatEither2 a b
|
||||||
|
|
||||||
-- concatEithers3
|
concatEithers2M
|
||||||
-- :: Either [x] a
|
:: Monad m
|
||||||
-- -> Either [x] b
|
=> Either [x] a
|
||||||
-- -> Either [x] c
|
-> Either [x] b
|
||||||
-- -> (a -> b -> c -> d)
|
-> (a -> b -> m c)
|
||||||
-- -> Either [x] d
|
-> m (Either [x] c)
|
||||||
-- concatEithers3 a b c = merge . concatEither3 a b c
|
concatEithers2M a b = fmap merge . concatEither2M a b
|
||||||
|
|
||||||
|
concatEithers3
|
||||||
|
:: Either [x] a
|
||||||
|
-> Either [x] b
|
||||||
|
-> Either [x] c
|
||||||
|
-> (a -> b -> c -> d)
|
||||||
|
-> Either [x] d
|
||||||
|
concatEithers3 a b c = merge . concatEither3 a b c
|
||||||
|
|
||||||
concatEitherL :: [Either x a] -> Either [x] [a]
|
concatEitherL :: [Either x a] -> Either [x] [a]
|
||||||
concatEitherL as = case partitionEithers as of
|
concatEitherL as = case partitionEithers as of
|
||||||
|
|
Loading…
Reference in New Issue