WIP add code to actually insert updates in the db

This commit is contained in:
Nathan Dwarshuis 2023-06-26 00:10:40 -04:00
parent 7a44aeb5db
commit f8669e5a15
1 changed files with 48 additions and 39 deletions

View File

@ -9,6 +9,7 @@ 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
@ -78,8 +79,10 @@ insertHistory
-> m () -> m ()
insertHistory hs = do insertHistory hs = do
(toUpdate, toInsert) <- balanceTxs hs (toUpdate, toInsert) <- balanceTxs hs
forM_ (groupWith txCommit toInsert) $ \(c, ts) -> do mapM_ updateTx toUpdate
ck <- insert c forM_ (groupKey commitRHash $ (\x -> (txCommit x, x)) <$> toInsert) $
\(c, ts) -> do
ck <- insert $ c
mapM_ (insertTx ck) ts mapM_ (insertTx ck) ts
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -128,6 +131,9 @@ 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
@ -334,14 +340,14 @@ balanceTxs
-> m ([UEBalanced], [KeyTx CommitR]) -> m ([UEBalanced], [KeyTx CommitR])
balanceTxs es = balanceTxs es =
(first concat . partitionEithers . catMaybes) (first concat . partitionEithers . catMaybes)
<$> evalStateT (mapM go $ L.sortOn binDate es) M.empty <$> evalStateT (mapErrors go $ L.sortOn binDate es) M.empty
where where
go (ToUpdate utx) = (Just . Left) <$> rebalanceEntrySet utx go (ToUpdate utx) = fmap (Just . Left) $ liftInnerS $ 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
@ -372,7 +378,7 @@ rebalanceEntrySet
} = } =
do do
let fs = let fs =
L.sortOn index $ L.sortOn idx $
(UET_ReadOnly <$> utFromRO) (UET_ReadOnly <$> utFromRO)
++ (UET_Balance <$> utFromUnk) ++ (UET_Balance <$> utFromUnk)
++ (UET_Linked <$> utPairs) ++ (UET_Linked <$> utPairs)
@ -380,11 +386,12 @@ rebalanceEntrySet
let f0val = utTotalValue - (sum $ fmap value fs') let f0val = utTotalValue - (sum $ fmap value fs')
let f0 = utFrom0 {ueValue = EntryValue f0val} let f0 = utFrom0 {ueValue = EntryValue f0val}
let (tpairs, fs'') = partitionEithers $ concatMap flatten fs' let (tpairs, fs'') = partitionEithers $ concatMap flatten fs'
let tsLink0 = fmap (\e -> e {ueValue = EntryValue $ -f0val * (unLinkScale $ ueValue e)}) utToUnkLink0
let ts = let ts =
(UET_Linked <$> tpairs) L.sortOn idx2 $
(UET_Linked <$> (tpairs ++ tsLink0))
++ (UET_Balance <$> utToUnk) ++ (UET_Balance <$> utToUnk)
++ (UET_ReadOnly <$> utToRO) ++ (UET_ReadOnly <$> utToRO)
let tsLink0 = fmap (\e -> e {ueValue = -f0val * (unLinkScale $ ueValue e)}) utToUnkLink0
(tsRO, tsUnk) <- partitionEithers <$> mapM goTo ts (tsRO, tsUnk) <- partitionEithers <$> mapM goTo ts
let t0val = let t0val =
(EntryValue utTotalValue) (EntryValue utTotalValue)
@ -395,7 +402,8 @@ rebalanceEntrySet
project f _ _ (UET_ReadOnly e) = f e project f _ _ (UET_ReadOnly e) = f e
project _ f _ (UET_Balance e) = f e project _ f _ (UET_Balance e) = f e
project _ _ f (UET_Linked p) = f p project _ _ f (UET_Linked p) = f p
index = project ueIndex ueIndex (ueIndex . fst) idx = project ueIndex ueIndex (ueIndex . fst)
idx2 = project ueIndex ueIndex ueIndex
value = value =
project project
(unEntryValue . ueValue) (unEntryValue . ueValue)
@ -455,8 +463,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 (balanceDeferred curID) curID let balFromEntry = balanceEntry (\a -> liftInnerS . balanceDeferred curID a) 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
@ -466,15 +474,15 @@ balanceEntrySet
doEntries doEntries
:: (MonadInsertError m, MonadFinance m) :: (MonadInsertError m, MonadFinance m)
=> (Int -> Entry AcntID v t -> State EntryBals (FullEntry AccountRId CurrencyRId t)) => (Int -> Entry AcntID v TagID -> StateT EntryBals m (FullEntry AccountRId CurrencyRId TagRId))
-> CurrencyRId -> CurrencyRId
-> Rational -> Rational
-> Entry AcntID () t -> Entry AcntID () TagID
-> [Entry AcntID v t] -> [Entry AcntID v TagID]
-> NonEmpty Int -> NonEmpty Int
-> StateT EntryBals m [FullEntry AccountRId CurrencyRId t] -> StateT EntryBals m [FullEntry AccountRId CurrencyRId TagRId]
doEntries f curID tot e es (i0 :| iN) = do doEntries f curID tot e es (i0 :| iN) = do
es' <- liftInnerS $ mapM (uncurry f) $ zip iN es es' <- 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'
@ -485,19 +493,20 @@ liftInnerS :: Monad m => StateT e Identity a -> StateT e m a
liftInnerS = mapStateT (return . runIdentity) liftInnerS = mapStateT (return . runIdentity)
balanceLinked balanceLinked
:: Vector Rational :: MonadInsertError m
=> Vector Rational
-> CurrencyRId -> CurrencyRId
-> Natural -> Natural
-> AccountRId -> AccountRId
-> LinkDeferred Rational -> LinkDeferred Rational
-> StateT EntryBals Identity (Rational, Maybe DBDeferred) -> StateT EntryBals m (Rational, Maybe DBDeferred)
balanceLinked from curID precision acntID lg = case lg of balanceLinked from curID precision acntID lg = case lg of
(LinkIndex g@LinkedNumGetter {lngIndex, lngScale}) -> do (LinkIndex 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) -> balanceDeferred curID acntID d (LinkDeferred d) -> liftInnerS $ balanceDeferred curID acntID d
where where
go s = roundPrecision precision . (* s) . fromRational go s = roundPrecision precision . (* s) . fromRational
@ -515,22 +524,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 t -> Entry AcntID v TagID
-> StateT EntryBals m (FullEntry AccountRId CurrencyRId t) -> StateT EntryBals m (FullEntry AccountRId CurrencyRId TagRId)
balanceEntry f curID index e@Entry {eValue, eAcnt} = do balanceEntry f curID idx e@Entry {eValue, eAcnt, eTags} = do
(acntID, sign, _) <- lookupAccount eAcnt let acntRes = 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} { feEntry = e {eValue = s * newVal, eAcnt = acntID, eTags = tags}
, feCurrency = curID , feCurrency = curID
, feDeferred = deferred , feDeferred = deferred
, feIndex = index , feIndex = idx
} }
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