Compare commits
No commits in common. "f8669e5a1551a53598ff0a43c31cf549201c466f" and "fc4da967be545a8dce0460f6c72ee3ad1ac4bbdd" have entirely different histories.
f8669e5a15
...
fc4da967be
|
@ -516,7 +516,12 @@ readUpdates hashes = do
|
||||||
|
|
||||||
splitFrom
|
splitFrom
|
||||||
:: [(EntryRId, EntryR)]
|
:: [(EntryRId, EntryR)]
|
||||||
-> InsertExcept (UEBlank, [UE_RO], [UEBalance], Vector (Maybe UEBalance))
|
-> InsertExcept
|
||||||
|
( UpdateEntry EntryRId ()
|
||||||
|
, [UpdateEntry () Rational]
|
||||||
|
, [UpdateEntry EntryRId Rational]
|
||||||
|
, Vector (Maybe (UpdateEntry EntryRId Rational))
|
||||||
|
)
|
||||||
splitFrom from = do
|
splitFrom from = do
|
||||||
-- ASSUME entries are sorted by index
|
-- ASSUME entries are sorted by index
|
||||||
(primary, rest) <- case from of
|
(primary, rest) <- case from of
|
||||||
|
@ -528,14 +533,14 @@ splitFrom from = do
|
||||||
return (primary, ro, toBal, idxVec)
|
return (primary, ro, toBal, idxVec)
|
||||||
|
|
||||||
splitTo
|
splitTo
|
||||||
:: Vector (Maybe UEBalance)
|
:: Vector (Maybe (UpdateEntry EntryRId Rational))
|
||||||
-> [(EntryRId, EntryR)]
|
-> [(EntryRId, EntryR)]
|
||||||
-> InsertExcept
|
-> InsertExcept
|
||||||
( UEBlank
|
( UpdateEntry EntryRId ()
|
||||||
, [UE_RO]
|
, [UpdateEntry () Rational]
|
||||||
, [UEBalance]
|
, [UpdateEntry EntryRId Rational]
|
||||||
, [UELink]
|
, [UpdateEntry EntryRId ()]
|
||||||
, [(UEBalance, [UELink])]
|
, [(UpdateEntry EntryRId Rational, [UpdateEntry EntryRId Rational])]
|
||||||
)
|
)
|
||||||
splitTo froms tos = do
|
splitTo froms tos = do
|
||||||
-- How to split the credit side of the database transaction in 1024 easy
|
-- How to split the credit side of the database transaction in 1024 easy
|
||||||
|
@ -555,18 +560,18 @@ splitTo froms tos = do
|
||||||
let (ro, toBal) = partitionEithers $ fmap splitDeferredValue unlinked
|
let (ro, toBal) = partitionEithers $ fmap splitDeferredValue unlinked
|
||||||
|
|
||||||
-- 3. Split paired entries by link == 0 (which are special) or link > 0
|
-- 3. Split paired entries by link == 0 (which are special) or link > 0
|
||||||
let (paired0, pairedN) = second (groupKey id) $ L.partition ((== 0) . fst) linked
|
let (paired0, pairedN) =
|
||||||
let paired0Res = mapErrors (makeLinkUnk . snd) paired0
|
bimap (fmap (uncurry makeUnkUE . snd)) (groupKey id) $
|
||||||
|
L.partition ((== 0) . fst) linked
|
||||||
|
|
||||||
-- 4. Group linked entries (which now have links > 0) according to the debit
|
-- 4. Group linked entries (which now have links > 0) according to the debit
|
||||||
-- entry to which they are linked. If the debit entry cannot be found or
|
-- entry to which they are linked. If the debit entry cannot be found or
|
||||||
-- if the linked entry has no scale, blow up in user's face. If the
|
-- if the linked entry has no scale, blow up in user's face. If the
|
||||||
-- debit entry is read-only (signified by Nothing in the 'from' array)
|
-- debit entry is read-only (signified by Nothing in the 'from' array)
|
||||||
-- then consider the linked entry as another credit read-only entry
|
-- then consider the linked entry as another credit read-only entry
|
||||||
let pairedRes = partitionEithers <$> mapErrors splitPaired pairedN
|
(pairedUnk, pairedRO) <- partitionEithers <$> mapErrors splitPaired pairedN
|
||||||
|
|
||||||
combineError paired0Res pairedRes $ \paired0' (pairedUnk, pairedRO) ->
|
return (primary, ro ++ concat pairedRO, toBal, paired0, pairedUnk)
|
||||||
(primary, ro ++ concat pairedRO, toBal, paired0', pairedUnk)
|
|
||||||
where
|
where
|
||||||
splitLinked t@(_, e) = maybe (Left t) (Right . (,t)) $ entryRDeferred_link e
|
splitLinked t@(_, e) = maybe (Left t) (Right . (,t)) $ entryRDeferred_link e
|
||||||
splitPaired (lnk, ts) = case froms V.!? (lnk - 1) of
|
splitPaired (lnk, ts) = case froms V.!? (lnk - 1) of
|
||||||
|
@ -576,19 +581,20 @@ splitTo froms tos = do
|
||||||
makeLinkUnk (k, e) =
|
makeLinkUnk (k, e) =
|
||||||
maybe
|
maybe
|
||||||
(throwError $ InsertException undefined)
|
(throwError $ InsertException undefined)
|
||||||
(return . makeUE k e . LinkScale)
|
(return . makeUE k e)
|
||||||
$ entryRDeferred_value e
|
$ entryRDeferred_value e
|
||||||
|
|
||||||
splitDeferredValue :: (EntryRId, EntryR) -> Either UE_RO UEBalance
|
splitDeferredValue
|
||||||
|
:: (EntryRId, EntryR)
|
||||||
|
-> Either (UpdateEntry () Rational) (UpdateEntry EntryRId Rational)
|
||||||
splitDeferredValue (k, e) =
|
splitDeferredValue (k, e) =
|
||||||
maybe (Left $ makeRoUE e) (Right . fmap BalanceTarget . makeUE k e) $
|
maybe (Left $ makeRoUE e) (Right . makeUE k e) $ entryRDeferred_value e
|
||||||
entryRDeferred_value e
|
|
||||||
|
|
||||||
makeUE :: i -> EntryR -> v -> UpdateEntry i v
|
makeUE :: i -> EntryR -> v -> UpdateEntry i v
|
||||||
makeUE k e v = UpdateEntry k (entryRAccount e) v (entryRIndex e)
|
makeUE k e v = UpdateEntry k (entryRAccount e) v (entryRIndex e)
|
||||||
|
|
||||||
makeRoUE :: EntryR -> UpdateEntry () EntryValue
|
makeRoUE :: EntryR -> UpdateEntry () Rational
|
||||||
makeRoUE e = makeUE () e $ EntryValue (entryRValue e)
|
makeRoUE e = makeUE () e (entryRValue e)
|
||||||
|
|
||||||
makeUnkUE :: EntryRId -> EntryR -> UpdateEntry EntryRId ()
|
makeUnkUE :: EntryRId -> EntryR -> UpdateEntry EntryRId ()
|
||||||
makeUnkUE k e = makeUE k e ()
|
makeUnkUE k e = makeUE k e ()
|
||||||
|
|
|
@ -9,7 +9,6 @@ where
|
||||||
import Control.Monad.Except
|
import Control.Monad.Except
|
||||||
import Data.Csv
|
import Data.Csv
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Database.Persist ((=.))
|
|
||||||
import Database.Persist.Monad hiding (get)
|
import Database.Persist.Monad hiding (get)
|
||||||
import Internal.Database
|
import Internal.Database
|
||||||
import Internal.Types.Main
|
import Internal.Types.Main
|
||||||
|
@ -79,10 +78,8 @@ insertHistory
|
||||||
-> m ()
|
-> m ()
|
||||||
insertHistory hs = do
|
insertHistory hs = do
|
||||||
(toUpdate, toInsert) <- balanceTxs hs
|
(toUpdate, toInsert) <- balanceTxs hs
|
||||||
mapM_ updateTx toUpdate
|
forM_ (groupWith txCommit toInsert) $ \(c, ts) -> do
|
||||||
forM_ (groupKey commitRHash $ (\x -> (txCommit x, x)) <$> toInsert) $
|
ck <- insert c
|
||||||
\(c, ts) -> do
|
|
||||||
ck <- insert $ c
|
|
||||||
mapM_ (insertTx ck) ts
|
mapM_ (insertTx ck) ts
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
@ -131,9 +128,6 @@ insertTx c Tx {txDate = d, txDescr = e, txEntries = ss} = do
|
||||||
k <- insert $ TransactionR c d e anyDeferred
|
k <- insert $ TransactionR c d e anyDeferred
|
||||||
mapM_ (insertEntry k) ss
|
mapM_ (insertEntry k) ss
|
||||||
|
|
||||||
updateTx :: MonadSqlQuery m => UEBalanced -> m ()
|
|
||||||
updateTx UpdateEntry {ueID, ueValue} = update ueID [EntryRValue =. (unEntryValue ueValue)]
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Statements
|
-- Statements
|
||||||
|
|
||||||
|
@ -337,17 +331,17 @@ matchNonDates ms = go ([], [], initZipper ms)
|
||||||
balanceTxs
|
balanceTxs
|
||||||
:: (MonadInsertError m, MonadFinance m)
|
:: (MonadInsertError m, MonadFinance m)
|
||||||
=> [EntryBin]
|
=> [EntryBin]
|
||||||
-> m ([UEBalanced], [KeyTx CommitR])
|
-> m ([UpdateEntry EntryRId Rational], [KeyTx CommitR])
|
||||||
balanceTxs es =
|
balanceTxs es =
|
||||||
(first concat . partitionEithers . catMaybes)
|
(first concat . partitionEithers . catMaybes)
|
||||||
<$> evalStateT (mapErrors go $ L.sortOn binDate es) M.empty
|
<$> evalStateT (mapM go $ L.sortOn binDate es) M.empty
|
||||||
where
|
where
|
||||||
go (ToUpdate utx) = fmap (Just . Left) $ liftInnerS $ rebalanceEntrySet utx
|
go (ToUpdate utx) = (Just . Left) <$> rebalanceEntrySet utx
|
||||||
go (ToRead ReadEntry {reCurrency, reAcnt, reValue}) = do
|
go (ToRead ReadEntry {reCurrency, reAcnt, reValue}) = do
|
||||||
modify $ mapAdd_ (reAcnt, reCurrency) reValue
|
modify $ mapAdd_ (reAcnt, reCurrency) reValue
|
||||||
return Nothing
|
return Nothing
|
||||||
go (ToInsert (t@Tx {txEntries, txDate})) =
|
go (ToInsert (t@Tx {txEntries, txDate})) =
|
||||||
(\es' -> Just $ Right $ t {txEntries = concat es'})
|
(\es -> Just $ Right $ t {txEntries = concat es})
|
||||||
<$> mapM (balanceEntrySet txDate) txEntries
|
<$> mapM (balanceEntrySet txDate) txEntries
|
||||||
|
|
||||||
binDate :: EntryBin -> Day
|
binDate :: EntryBin -> Day
|
||||||
|
@ -358,11 +352,11 @@ binDate (ToInsert (Tx {txDate})) = txDate
|
||||||
type EntryBals = M.Map (AccountRId, CurrencyRId) Rational
|
type EntryBals = M.Map (AccountRId, CurrencyRId) Rational
|
||||||
|
|
||||||
data UpdateEntryType a
|
data UpdateEntryType a
|
||||||
= UET_ReadOnly UE_RO
|
= UEReadOnly (UpdateEntry () Rational)
|
||||||
| UET_Balance UEBalance
|
| UEBlank (UpdateEntry EntryRId Rational)
|
||||||
| UET_Linked a
|
| UEPaired (UpdateEntry EntryRId Rational, UpdateEntry EntryRId a)
|
||||||
|
|
||||||
rebalanceEntrySet :: UpdateEntrySet -> State EntryBals [UEBalanced]
|
rebalanceEntrySet :: UpdateEntrySet -> State EntryBals [UpdateEntry EntryRId Rational]
|
||||||
rebalanceEntrySet
|
rebalanceEntrySet
|
||||||
UpdateEntrySet
|
UpdateEntrySet
|
||||||
{ utFrom0
|
{ utFrom0
|
||||||
|
@ -373,75 +367,53 @@ rebalanceEntrySet
|
||||||
, utFromRO
|
, utFromRO
|
||||||
, utToRO
|
, utToRO
|
||||||
, utCurrency
|
, utCurrency
|
||||||
, utToUnkLink0
|
|
||||||
, utTotalValue
|
, utTotalValue
|
||||||
} =
|
} =
|
||||||
do
|
do
|
||||||
let fs =
|
let fs =
|
||||||
L.sortOn idx $
|
L.sortOn index $
|
||||||
(UET_ReadOnly <$> utFromRO)
|
(UEReadOnly <$> utFromRO)
|
||||||
++ (UET_Balance <$> utFromUnk)
|
++ (UEBlank <$> utFromUnk)
|
||||||
++ (UET_Linked <$> utPairs)
|
++ (UEPaired <$> utPairs)
|
||||||
fs' <- mapM goFrom fs
|
fs' <- mapM goFrom fs
|
||||||
let f0val = utTotalValue - (sum $ fmap value fs')
|
let f0 = utFrom0 {ueValue = utTotalValue - (sum $ fmap value fs')}
|
||||||
let f0 = utFrom0 {ueValue = EntryValue f0val}
|
let (fs'', tpairs) = partitionEithers $ concatMap flatten fs'
|
||||||
let (tpairs, fs'') = partitionEithers $ concatMap flatten fs'
|
let ts = (Right <$> tpairs) ++ (Right <$> utToUnk) ++ (Left <$> utToRO)
|
||||||
let tsLink0 = fmap (\e -> e {ueValue = EntryValue $ -f0val * (unLinkScale $ ueValue e)}) utToUnkLink0
|
|
||||||
let ts =
|
|
||||||
L.sortOn idx2 $
|
|
||||||
(UET_Linked <$> (tpairs ++ tsLink0))
|
|
||||||
++ (UET_Balance <$> utToUnk)
|
|
||||||
++ (UET_ReadOnly <$> utToRO)
|
|
||||||
(tsRO, tsUnk) <- partitionEithers <$> mapM goTo ts
|
(tsRO, tsUnk) <- partitionEithers <$> mapM goTo ts
|
||||||
let t0val =
|
let t0 = utTo0 {ueValue = utTotalValue - (sum $ (fmap ueValue tsRO) ++ (fmap ueValue tsUnk))}
|
||||||
(EntryValue utTotalValue)
|
return $ f0 : fs'' ++ t0 : tsUnk
|
||||||
- (sum $ (fmap ueValue tsRO) ++ (fmap ueValue tsUnk))
|
|
||||||
let t0 = utTo0 {ueValue = t0val}
|
|
||||||
return $ (f0 : (fmap (fmap (EntryValue . unBalanceTarget)) fs'')) ++ (t0 : tsUnk)
|
|
||||||
where
|
where
|
||||||
project f _ _ (UET_ReadOnly e) = f e
|
project f _ _ (UEReadOnly e) = f e
|
||||||
project _ f _ (UET_Balance e) = f e
|
project _ f _ (UEBlank e) = f e
|
||||||
project _ _ f (UET_Linked p) = f p
|
project _ _ f (UEPaired p) = f p
|
||||||
idx = project ueIndex ueIndex (ueIndex . fst)
|
index = project ueIndex ueIndex (ueIndex . fst)
|
||||||
idx2 = project ueIndex ueIndex ueIndex
|
value = project ueValue ueValue (ueValue . fst)
|
||||||
value =
|
flatten = project (const []) ((: []) . Right) (\(a, b) -> [Right a, Left b])
|
||||||
project
|
|
||||||
(unEntryValue . ueValue)
|
|
||||||
(unBalanceTarget . ueValue)
|
|
||||||
(unBalanceTarget . ueValue . fst)
|
|
||||||
flatten = project (const []) ((: []) . Right) (\(a, bs) -> (Right a) : (Left <$> bs))
|
|
||||||
-- TODO the following is wetter than the average groupie
|
-- TODO the following is wetter than the average groupie
|
||||||
goFrom (UET_ReadOnly e) = do
|
goFrom (UEReadOnly e) = do
|
||||||
modify $ mapAdd_ (ueAcnt e, utCurrency) (unEntryValue $ ueValue e)
|
modify $ mapAdd_ (ueAcnt e, utCurrency) (ueValue e)
|
||||||
return $ UET_ReadOnly e
|
return $ UEReadOnly e
|
||||||
goFrom (UET_Balance e) = do
|
goFrom (UEBlank e) = do
|
||||||
let key = (ueAcnt e, utCurrency)
|
let key = (ueAcnt e, utCurrency)
|
||||||
curBal <- gets (M.findWithDefault 0 key)
|
curBal <- gets (M.findWithDefault 0 key)
|
||||||
let newVal = unBalanceTarget (ueValue e) - curBal
|
let newVal = ueValue e - curBal
|
||||||
modify $ mapAdd_ key newVal
|
modify $ mapAdd_ key newVal
|
||||||
return $ UET_Balance $ e {ueValue = BalanceTarget newVal}
|
return $ UEBlank $ e {ueValue = newVal}
|
||||||
goFrom (UET_Linked (e0, es)) = do
|
goFrom (UEPaired (e0, e1)) = do
|
||||||
let key = (ueAcnt e0, utCurrency)
|
let key = (ueAcnt e0, utCurrency)
|
||||||
curBal <- gets (M.findWithDefault 0 key)
|
curBal <- gets (M.findWithDefault 0 key)
|
||||||
let newVal = unBalanceTarget (ueValue e0) - curBal
|
let newVal = ueValue e0 - curBal
|
||||||
modify $ mapAdd_ key newVal
|
modify $ mapAdd_ key newVal
|
||||||
return $
|
return $ UEPaired $ (e0 {ueValue = newVal}, e1 {ueValue = -newVal})
|
||||||
UET_Linked $
|
goTo (Left e) = do
|
||||||
( e0 {ueValue = BalanceTarget newVal}
|
modify $ mapAdd_ (ueAcnt e, utCurrency) (ueValue e)
|
||||||
, fmap (\e -> e {ueValue = EntryValue $ (-newVal) * unLinkScale (ueValue e)}) es
|
|
||||||
)
|
|
||||||
goTo (UET_ReadOnly e) = do
|
|
||||||
modify $ mapAdd_ (ueAcnt e, utCurrency) (unEntryValue $ ueValue e)
|
|
||||||
return $ Left e
|
return $ Left e
|
||||||
goTo (UET_Linked e) = do
|
goTo (Right e) = do
|
||||||
modify $ mapAdd_ (ueAcnt e, utCurrency) (unEntryValue $ ueValue e)
|
|
||||||
return $ Right e
|
|
||||||
goTo (UET_Balance e) = do
|
|
||||||
let key = (ueAcnt e, utCurrency)
|
let key = (ueAcnt e, utCurrency)
|
||||||
curBal <- gets (M.findWithDefault 0 key)
|
curBal <- gets (M.findWithDefault 0 key)
|
||||||
let newVal = unBalanceTarget (ueValue e) - curBal
|
let newVal = ueValue e - curBal
|
||||||
modify $ mapAdd_ key newVal
|
modify $ mapAdd_ key newVal
|
||||||
return $ Right $ e {ueValue = EntryValue newVal}
|
return $ Right $ e {ueValue = newVal}
|
||||||
|
|
||||||
balanceEntrySet
|
balanceEntrySet
|
||||||
:: (MonadInsertError m, MonadFinance m)
|
:: (MonadInsertError m, MonadFinance m)
|
||||||
|
@ -463,8 +435,8 @@ balanceEntrySet
|
||||||
|
|
||||||
-- resolve accounts and balance debit entries since we need an array
|
-- resolve accounts and balance debit entries since we need an array
|
||||||
-- of debit entries for linked credit entries later
|
-- of debit entries for linked credit entries later
|
||||||
let balFromEntry = balanceEntry (\a -> liftInnerS . balanceDeferred curID a) curID
|
let balFromEntry = balanceEntry (balanceDeferred curID) curID
|
||||||
fs' <- doEntries balFromEntry curID esTotalValue f0 fs (NE.iterate (+ (-1)) (-1))
|
fs' <- doEntries balFromEntry curID esTotalValue f0 fs (NE.iterate (-1) (-1))
|
||||||
let fv = V.fromList $ fmap (eValue . feEntry) fs'
|
let fv = V.fromList $ fmap (eValue . feEntry) fs'
|
||||||
|
|
||||||
-- finally resolve credit entries
|
-- finally resolve credit entries
|
||||||
|
@ -474,15 +446,15 @@ balanceEntrySet
|
||||||
|
|
||||||
doEntries
|
doEntries
|
||||||
:: (MonadInsertError m, MonadFinance m)
|
:: (MonadInsertError m, MonadFinance m)
|
||||||
=> (Int -> Entry AcntID v TagID -> StateT EntryBals m (FullEntry AccountRId CurrencyRId TagRId))
|
=> (Int -> Entry AcntID v t -> State EntryBals (FullEntry AccountRId CurrencyRId t))
|
||||||
-> CurrencyRId
|
-> CurrencyRId
|
||||||
-> Rational
|
-> Rational
|
||||||
-> Entry AcntID () TagID
|
-> Entry AcntID () t
|
||||||
-> [Entry AcntID v TagID]
|
-> [Entry AcntID v t]
|
||||||
-> NonEmpty Int
|
-> NonEmpty Int
|
||||||
-> StateT EntryBals m [FullEntry AccountRId CurrencyRId TagRId]
|
-> StateT EntryBals m [FullEntry AccountRId CurrencyRId t]
|
||||||
doEntries f curID tot e es (i0 :| iN) = do
|
doEntries f curID tot e es (i0 :| iN) = do
|
||||||
es' <- mapM (uncurry f) $ zip iN es
|
es' <- liftInnerS $ mapM (uncurry f) $ zip iN es
|
||||||
let val0 = tot - entrySum es'
|
let val0 = tot - entrySum es'
|
||||||
e' <- balanceEntry (\_ _ -> return (val0, Nothing)) curID i0 e
|
e' <- balanceEntry (\_ _ -> return (val0, Nothing)) curID i0 e
|
||||||
return $ e' : es'
|
return $ e' : es'
|
||||||
|
@ -493,20 +465,19 @@ liftInnerS :: Monad m => StateT e Identity a -> StateT e m a
|
||||||
liftInnerS = mapStateT (return . runIdentity)
|
liftInnerS = mapStateT (return . runIdentity)
|
||||||
|
|
||||||
balanceLinked
|
balanceLinked
|
||||||
:: MonadInsertError m
|
:: Vector Rational
|
||||||
=> Vector Rational
|
|
||||||
-> CurrencyRId
|
-> CurrencyRId
|
||||||
-> Natural
|
-> Natural
|
||||||
-> AccountRId
|
-> AccountRId
|
||||||
-> LinkDeferred Rational
|
-> LinkDeferred Rational
|
||||||
-> StateT EntryBals m (Rational, Maybe DBDeferred)
|
-> StateT EntryBals Identity (Rational, Maybe DBDeferred)
|
||||||
balanceLinked from curID precision acntID lg = case lg of
|
balanceLinked from curID precision acntID lg = case lg of
|
||||||
(LinkIndex LinkedNumGetter {lngIndex, lngScale}) -> do
|
(LinkIndex g@LinkedNumGetter {lngIndex, lngScale}) -> do
|
||||||
let res = fmap (go lngScale) $ from V.!? fromIntegral lngIndex
|
let res = fmap (go lngScale) $ from V.!? fromIntegral lngIndex
|
||||||
case res of
|
case res of
|
||||||
Just v -> return $ (v, Just $ EntryLinked lngIndex $ toRational lngScale)
|
Just v -> return $ (v, Just $ EntryLinked lngIndex $ toRational lngScale)
|
||||||
Nothing -> throwError undefined
|
Nothing -> throwError undefined
|
||||||
(LinkDeferred d) -> liftInnerS $ balanceDeferred curID acntID d
|
(LinkDeferred d) -> balanceDeferred curID acntID d
|
||||||
where
|
where
|
||||||
go s = roundPrecision precision . (* s) . fromRational
|
go s = roundPrecision precision . (* s) . fromRational
|
||||||
|
|
||||||
|
@ -524,22 +495,22 @@ balanceEntry
|
||||||
=> (AccountRId -> v -> StateT EntryBals m (Rational, Maybe DBDeferred))
|
=> (AccountRId -> v -> StateT EntryBals m (Rational, Maybe DBDeferred))
|
||||||
-> CurrencyRId
|
-> CurrencyRId
|
||||||
-> Int
|
-> Int
|
||||||
-> Entry AcntID v TagID
|
-> Entry AcntID v t
|
||||||
-> StateT EntryBals m (FullEntry AccountRId CurrencyRId TagRId)
|
-> StateT EntryBals m (FullEntry AccountRId CurrencyRId t)
|
||||||
balanceEntry f curID idx e@Entry {eValue, eAcnt, eTags} = do
|
balanceEntry f curID index e@Entry {eValue, eAcnt} = do
|
||||||
let acntRes = lookupAccount eAcnt
|
(acntID, sign, _) <- lookupAccount eAcnt
|
||||||
let tagRes = mapErrors lookupTag eTags
|
|
||||||
combineErrorM acntRes tagRes $ \(acntID, sign, _) tags -> do
|
|
||||||
let s = fromIntegral $ sign2Int sign
|
let s = fromIntegral $ sign2Int sign
|
||||||
(newVal, deferred) <- f acntID eValue
|
(newVal, deferred) <- f acntID eValue
|
||||||
modify (mapAdd_ (acntID, curID) newVal)
|
modify (mapAdd_ (acntID, curID) newVal)
|
||||||
return $
|
return $
|
||||||
FullEntry
|
FullEntry
|
||||||
{ feEntry = e {eValue = s * newVal, eAcnt = acntID, eTags = tags}
|
{ feEntry = e {eValue = s * newVal, eAcnt = acntID}
|
||||||
, feCurrency = curID
|
, feCurrency = curID
|
||||||
, feDeferred = deferred
|
, feDeferred = deferred
|
||||||
, feIndex = idx
|
, feIndex = index
|
||||||
}
|
}
|
||||||
|
where
|
||||||
|
key = (eAcnt, curID)
|
||||||
|
|
||||||
findBalance :: AccountRId -> CurrencyRId -> Bool -> Rational -> State EntryBals Rational
|
findBalance :: AccountRId -> CurrencyRId -> Bool -> Rational -> State EntryBals Rational
|
||||||
findBalance acnt cur toBal v = do
|
findBalance acnt cur toBal v = do
|
||||||
|
|
|
@ -77,36 +77,17 @@ data UpdateEntry i v = UpdateEntry
|
||||||
, ueIndex :: !Int -- TODO this isn't needed for primary entries
|
, ueIndex :: !Int -- TODO this isn't needed for primary entries
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving instance Functor (UpdateEntry i)
|
|
||||||
|
|
||||||
newtype LinkScale = LinkScale {unLinkScale :: Rational}
|
|
||||||
deriving newtype (Num)
|
|
||||||
|
|
||||||
newtype BalanceTarget = BalanceTarget {unBalanceTarget :: Rational}
|
|
||||||
deriving newtype (Num)
|
|
||||||
|
|
||||||
newtype EntryValue = EntryValue {unEntryValue :: Rational}
|
|
||||||
deriving newtype (Num)
|
|
||||||
|
|
||||||
type UEBalance = UpdateEntry EntryRId BalanceTarget
|
|
||||||
|
|
||||||
type UELink = UpdateEntry EntryRId LinkScale
|
|
||||||
|
|
||||||
type UEBlank = UpdateEntry EntryRId ()
|
|
||||||
|
|
||||||
type UE_RO = UpdateEntry () EntryValue
|
|
||||||
|
|
||||||
type UEBalanced = UpdateEntry EntryRId EntryValue
|
|
||||||
|
|
||||||
data UpdateEntrySet = UpdateEntrySet
|
data UpdateEntrySet = UpdateEntrySet
|
||||||
{ utFrom0 :: !UEBlank
|
{ utFrom0 :: !(UpdateEntry EntryRId ())
|
||||||
, utTo0 :: !UEBlank
|
, utTo0 :: !(UpdateEntry EntryRId ())
|
||||||
, utPairs :: ![(UEBalance, [UELink])]
|
, -- for these next three, the Rational number is the balance target (not the
|
||||||
, utFromUnk :: ![UEBalance]
|
-- value of the account)
|
||||||
, utToUnk :: ![UEBalance]
|
utPairs :: ![(UpdateEntry EntryRId Rational, [UpdateEntry EntryRId Rational])]
|
||||||
, utToUnkLink0 :: ![UELink]
|
, utFromUnk :: ![UpdateEntry EntryRId Rational]
|
||||||
, utFromRO :: ![UE_RO]
|
, utToUnk :: ![UpdateEntry EntryRId Rational]
|
||||||
, utToRO :: ![UE_RO]
|
, utToUnkLink0 :: ![UpdateEntry EntryRId ()]
|
||||||
|
, utFromRO :: ![UpdateEntry () Rational]
|
||||||
|
, utToRO :: ![UpdateEntry () Rational]
|
||||||
, utCurrency :: !CurrencyRId
|
, utCurrency :: !CurrencyRId
|
||||||
, utDate :: !Day
|
, utDate :: !Day
|
||||||
, utTotalValue :: !Rational
|
, utTotalValue :: !Rational
|
||||||
|
|
Loading…
Reference in New Issue