ADD local budget interval
This commit is contained in:
parent
6117784d0e
commit
5dfbc3ef41
|
@ -19,8 +19,15 @@ import Database.Esqueleto.Experimental ((==.), (^.))
|
||||||
import qualified Database.Esqueleto.Experimental as E
|
import qualified Database.Esqueleto.Experimental as E
|
||||||
import Database.Esqueleto.Internal.Internal (SqlSelect)
|
import Database.Esqueleto.Internal.Internal (SqlSelect)
|
||||||
import Database.Persist.Monad
|
import Database.Persist.Monad
|
||||||
-- import Database.Persist.Sql hiding (delete, runMigration, (==.), (||.))
|
import Database.Persist.Sqlite hiding
|
||||||
import Database.Persist.Sqlite hiding (delete, deleteWhere, insert, insertKey, runMigration, (==.), (||.))
|
( delete
|
||||||
|
, deleteWhere
|
||||||
|
, insert
|
||||||
|
, insertKey
|
||||||
|
, runMigration
|
||||||
|
, (==.)
|
||||||
|
, (||.)
|
||||||
|
)
|
||||||
import GHC.Err
|
import GHC.Err
|
||||||
import Internal.Types
|
import Internal.Types
|
||||||
import Internal.Utils
|
import Internal.Utils
|
||||||
|
|
|
@ -95,6 +95,22 @@ expandMDYPat lower upper (Repeat RepeatPat {rpStart = s, rpBy = b, rpRepeats = r
|
||||||
dayToWeekday :: Day -> Int
|
dayToWeekday :: Day -> Int
|
||||||
dayToWeekday (ModifiedJulianDay d) = mod (fromIntegral d + 2) 7
|
dayToWeekday (ModifiedJulianDay d) = mod (fromIntegral d + 2) 7
|
||||||
|
|
||||||
|
askDays
|
||||||
|
:: (MonadFinance m, MonadInsertError m)
|
||||||
|
=> DatePat
|
||||||
|
-> Maybe Interval
|
||||||
|
-> m [Day]
|
||||||
|
askDays dp i = do
|
||||||
|
globalBounds <- askDBState kmBudgetInterval
|
||||||
|
case i of
|
||||||
|
Just i' -> do
|
||||||
|
localBounds <- liftExcept $ resolveBounds i'
|
||||||
|
let bounds = intersectBounds globalBounds localBounds
|
||||||
|
maybe (return []) expand bounds
|
||||||
|
Nothing -> expand globalBounds
|
||||||
|
where
|
||||||
|
expand bs = liftExcept $ expandDatePat bs dp
|
||||||
|
|
||||||
withDates
|
withDates
|
||||||
:: (MonadSqlQuery m, MonadFinance m, MonadInsertError m)
|
:: (MonadSqlQuery m, MonadFinance m, MonadInsertError m)
|
||||||
=> DatePat
|
=> DatePat
|
||||||
|
@ -105,15 +121,13 @@ withDates dp f = do
|
||||||
days <- liftExcept $ expandDatePat bounds dp
|
days <- liftExcept $ expandDatePat bounds dp
|
||||||
combineErrors $ fmap f days
|
combineErrors $ fmap f days
|
||||||
|
|
||||||
foldDates
|
foldDays
|
||||||
:: (MonadSqlQuery m, MonadFinance m, MonadInsertError m)
|
:: MonadInsertError m
|
||||||
=> DatePat
|
=> (Day -> Day -> m a)
|
||||||
-> Day
|
-> Day
|
||||||
-> (Day -> Day -> m a)
|
-> [Day]
|
||||||
-> m [a]
|
-> m [a]
|
||||||
foldDates dp start f = do
|
foldDays f start days =
|
||||||
bounds <- askDBState kmBudgetInterval
|
|
||||||
days <- liftExcept $ expandDatePat bounds dp
|
|
||||||
combineErrors $
|
combineErrors $
|
||||||
snd $
|
snd $
|
||||||
L.mapAccumL (\prevDay day -> (day, f prevDay day)) start days
|
L.mapAccumL (\prevDay day -> (day, f prevDay day)) start days
|
||||||
|
@ -145,11 +159,12 @@ insertBudget
|
||||||
, bgtPretax
|
, bgtPretax
|
||||||
, bgtTax
|
, bgtTax
|
||||||
, bgtPosttax
|
, bgtPosttax
|
||||||
|
, bgtInterval
|
||||||
} =
|
} =
|
||||||
whenHash CTBudget b () $ \key -> do
|
whenHash CTBudget b () $ \key -> do
|
||||||
intAllos <- combineError3 pre_ tax_ post_ (,,)
|
intAllos <- combineError3 pre_ tax_ post_ (,,)
|
||||||
let res1 = mapErrors (insertIncome key bgtLabel intAllos) bgtIncomes
|
let res1 = mapErrors (insertIncome key bgtLabel intAllos bgtInterval) bgtIncomes
|
||||||
let res2 = expandTransfers key bgtLabel bgtTransfers
|
let res2 = expandTransfers key bgtLabel bgtInterval bgtTransfers
|
||||||
txs <- combineError (concat <$> res1) res2 (++)
|
txs <- combineError (concat <$> res1) res2 (++)
|
||||||
m <- askDBState kmCurrency
|
m <- askDBState kmCurrency
|
||||||
shadow <- liftExcept $ addShadowTransfers m bgtShadowTransfers txs
|
shadow <- liftExcept $ addShadowTransfers m bgtShadowTransfers txs
|
||||||
|
@ -160,7 +175,7 @@ insertBudget
|
||||||
post_ = sortAllos bgtPosttax
|
post_ = sortAllos bgtPosttax
|
||||||
sortAllos = liftExcept . combineErrors . fmap sortAllo
|
sortAllos = liftExcept . combineErrors . fmap sortAllo
|
||||||
|
|
||||||
type BoundAllocation = Allocation (Day, Day)
|
type BoundAllocation = Allocation Bounds
|
||||||
|
|
||||||
type IntAllocations =
|
type IntAllocations =
|
||||||
( [BoundAllocation PretaxValue]
|
( [BoundAllocation PretaxValue]
|
||||||
|
@ -180,7 +195,7 @@ sortAllo a@Allocation {alloAmts = as} = do
|
||||||
res <- case xs of
|
res <- case xs of
|
||||||
[] -> resolveBounds start
|
[] -> resolveBounds start
|
||||||
(y : _) -> resolveBounds_ (intStart $ amtWhen y) start
|
(y : _) -> resolveBounds_ (intStart $ amtWhen y) start
|
||||||
foldBounds (x {amtWhen = expandBounds res} : acc) xs
|
foldBounds (x {amtWhen = 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
|
addShadowTransfers
|
||||||
|
@ -209,35 +224,35 @@ fromShadow cm tx t@ShadowTransfer {stFrom, stTo, stDesc, stRatio, stCurrency, st
|
||||||
Just $
|
Just $
|
||||||
-- TODO does this actually share the same metadata as the "parent" tx?
|
-- TODO does this actually share the same metadata as the "parent" tx?
|
||||||
FlatTransfer
|
FlatTransfer
|
||||||
{ cbtMeta = cbtMeta tx
|
{ ftMeta = ftMeta tx
|
||||||
, cbtWhen = cbtWhen tx
|
, ftWhen = ftWhen tx
|
||||||
, cbtCur = stCurrency
|
, ftCur = stCurrency
|
||||||
, cbtFrom = stFrom
|
, ftFrom = stFrom
|
||||||
, cbtTo = stTo
|
, ftTo = stTo
|
||||||
, cbtValue = UnbalancedValue stType $ v * cvValue (cbtValue tx)
|
, ftValue = UnbalancedValue stType $ v * cvValue (ftValue tx)
|
||||||
, cbtDesc = stDesc
|
, ftDesc = stDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowMatches :: TransferMatcher -> UnbalancedTransfer -> InsertExcept Bool
|
shadowMatches :: TransferMatcher -> UnbalancedTransfer -> InsertExcept Bool
|
||||||
shadowMatches TransferMatcher {tmFrom, tmTo, tmDate, tmVal} tx = do
|
shadowMatches TransferMatcher {tmFrom, tmTo, tmDate, tmVal} tx = do
|
||||||
valRes <- valMatches tmVal $ cvValue $ cbtValue tx
|
valRes <- valMatches tmVal $ cvValue $ ftValue tx
|
||||||
return $
|
return $
|
||||||
memberMaybe (taAcnt $ cbtFrom tx) tmFrom
|
memberMaybe (taAcnt $ ftFrom tx) tmFrom
|
||||||
&& memberMaybe (taAcnt $ cbtTo tx) tmTo
|
&& memberMaybe (taAcnt $ ftTo tx) tmTo
|
||||||
&& maybe True (`dateMatches` cbtWhen tx) tmDate
|
&& maybe True (`dateMatches` ftWhen tx) tmDate
|
||||||
&& valRes
|
&& valRes
|
||||||
where
|
where
|
||||||
memberMaybe x AcntSet {asList, asInclude} =
|
memberMaybe x AcntSet {asList, asInclude} =
|
||||||
(if asInclude then id else not) $ x `elem` asList
|
(if asInclude then id else not) $ x `elem` asList
|
||||||
|
|
||||||
balanceTransfers :: [UnbalancedTransfer] -> [BalancedTransfer]
|
balanceTransfers :: [UnbalancedTransfer] -> [BalancedTransfer]
|
||||||
balanceTransfers = snd . L.mapAccumR go M.empty . reverse . L.sortOn cbtWhen
|
balanceTransfers = snd . L.mapAccumR go M.empty . reverse . L.sortOn ftWhen
|
||||||
where
|
where
|
||||||
go bals f@FlatTransfer {cbtFrom, cbtTo, cbtValue = UnbalancedValue {cvValue, cvType}} =
|
go bals f@FlatTransfer {ftFrom, ftTo, ftValue = UnbalancedValue {cvValue, cvType}} =
|
||||||
let balTo = M.findWithDefault 0 cbtTo bals
|
let balTo = M.findWithDefault 0 ftTo bals
|
||||||
x = amtToMove balTo cvType cvValue
|
x = amtToMove balTo cvType cvValue
|
||||||
bals' = mapAdd_ cbtTo x $ mapAdd_ cbtFrom (-x) bals
|
bals' = mapAdd_ ftTo x $ mapAdd_ ftFrom (-x) bals
|
||||||
in (bals', f {cbtValue = x})
|
in (bals', f {ftValue = x})
|
||||||
-- TODO might need to query signs to make this intuitive; as it is this will
|
-- TODO might need to query signs to make this intuitive; as it is this will
|
||||||
-- probably work, but for credit accounts I might need to supply a negative
|
-- probably work, but for credit accounts I might need to supply a negative
|
||||||
-- target value
|
-- target value
|
||||||
|
@ -255,13 +270,13 @@ data BudgetMeta = BudgetMeta
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
data FlatTransfer v = FlatTransfer
|
data FlatTransfer v = FlatTransfer
|
||||||
{ cbtFrom :: !TaggedAcnt
|
{ ftFrom :: !TaggedAcnt
|
||||||
, cbtTo :: !TaggedAcnt
|
, ftTo :: !TaggedAcnt
|
||||||
, cbtValue :: !v
|
, ftValue :: !v
|
||||||
, cbtWhen :: !Day
|
, ftWhen :: !Day
|
||||||
, cbtDesc :: !T.Text
|
, ftDesc :: !T.Text
|
||||||
, cbtMeta :: !BudgetMeta
|
, ftMeta :: !BudgetMeta
|
||||||
, cbtCur :: !BudgetCurrency
|
, ftCur :: !BudgetCurrency
|
||||||
}
|
}
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
|
@ -276,16 +291,18 @@ type UnbalancedTransfer = FlatTransfer UnbalancedValue
|
||||||
type BalancedTransfer = FlatTransfer Rational
|
type BalancedTransfer = FlatTransfer Rational
|
||||||
|
|
||||||
insertIncome
|
insertIncome
|
||||||
:: (MonadInsertError m, MonadSqlQuery m, MonadFinance m)
|
:: (MonadInsertError m, MonadFinance m)
|
||||||
=> CommitRId
|
=> CommitRId
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> IntAllocations
|
-> IntAllocations
|
||||||
|
-> Maybe Interval
|
||||||
-> Income
|
-> Income
|
||||||
-> m [UnbalancedTransfer]
|
-> m [UnbalancedTransfer]
|
||||||
insertIncome
|
insertIncome
|
||||||
key
|
key
|
||||||
name
|
name
|
||||||
(intPre, intTax, intPost)
|
(intPre, intTax, intPost)
|
||||||
|
localInterval
|
||||||
Income
|
Income
|
||||||
{ incWhen
|
{ incWhen
|
||||||
, incCurrency
|
, incCurrency
|
||||||
|
@ -304,7 +321,8 @@ insertIncome
|
||||||
-- TODO this will scan the interval allocations fully each time
|
-- TODO this will scan the interval allocations fully each time
|
||||||
-- iteration which is a total waste, but the fix requires turning this
|
-- iteration which is a total waste, but the fix requires turning this
|
||||||
-- loop into a fold which I don't feel like doing now :(
|
-- loop into a fold which I don't feel like doing now :(
|
||||||
res <- foldDates incWhen start (allocate precision gross)
|
days <- askDays incWhen localInterval
|
||||||
|
res <- foldDays (allocate precision gross) start days
|
||||||
return $ concat res
|
return $ concat res
|
||||||
where
|
where
|
||||||
start = fromGregorian' $ pStart incPayPeriod
|
start = fromGregorian' $ pStart incPayPeriod
|
||||||
|
@ -330,13 +348,13 @@ insertIncome
|
||||||
balance = aftertaxGross - sumAllos post
|
balance = aftertaxGross - sumAllos post
|
||||||
bal =
|
bal =
|
||||||
FlatTransfer
|
FlatTransfer
|
||||||
{ cbtMeta = meta
|
{ ftMeta = meta
|
||||||
, cbtWhen = day
|
, ftWhen = day
|
||||||
, cbtFrom = incFrom
|
, ftFrom = incFrom
|
||||||
, cbtCur = NoX incCurrency
|
, ftCur = NoX incCurrency
|
||||||
, cbtTo = incToBal
|
, ftTo = incToBal
|
||||||
, cbtValue = UnbalancedValue BTFixed balance
|
, ftValue = UnbalancedValue BTFixed balance
|
||||||
, cbtDesc = "balance after deductions"
|
, ftDesc = "balance after deductions"
|
||||||
}
|
}
|
||||||
in if balance < 0
|
in if balance < 0
|
||||||
then throwError $ InsertException [IncomeError day name balance]
|
then throwError $ InsertException [IncomeError day name balance]
|
||||||
|
@ -404,13 +422,13 @@ allo2Trans
|
||||||
-> UnbalancedTransfer
|
-> UnbalancedTransfer
|
||||||
allo2Trans meta day from FlatAllocation {faValue, faTo, faDesc, faCur} =
|
allo2Trans meta day from FlatAllocation {faValue, faTo, faDesc, faCur} =
|
||||||
FlatTransfer
|
FlatTransfer
|
||||||
{ cbtMeta = meta
|
{ ftMeta = meta
|
||||||
, cbtWhen = day
|
, ftWhen = day
|
||||||
, cbtFrom = from
|
, ftFrom = from
|
||||||
, cbtCur = faCur
|
, ftCur = faCur
|
||||||
, cbtTo = faTo
|
, ftTo = faTo
|
||||||
, cbtValue = UnbalancedValue BTFixed faValue
|
, ftValue = UnbalancedValue BTFixed faValue
|
||||||
, cbtDesc = faDesc
|
, ftDesc = faDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
allocateTax
|
allocateTax
|
||||||
|
@ -501,12 +519,19 @@ expandTransfers
|
||||||
:: (MonadInsertError m, MonadSqlQuery m, MonadFinance m)
|
:: (MonadInsertError m, MonadSqlQuery m, MonadFinance m)
|
||||||
=> CommitRId
|
=> CommitRId
|
||||||
-> T.Text
|
-> T.Text
|
||||||
|
-> Maybe Interval
|
||||||
-> [BudgetTransfer]
|
-> [BudgetTransfer]
|
||||||
-> m [UnbalancedTransfer]
|
-> m [UnbalancedTransfer]
|
||||||
expandTransfers key name ts =
|
expandTransfers key name localInterval ts = do
|
||||||
fmap (L.sortOn cbtWhen . concat) $
|
txs <-
|
||||||
combineErrors $
|
fmap (L.sortOn ftWhen . concat) $
|
||||||
fmap (expandTransfer key name) ts
|
combineErrors $
|
||||||
|
fmap (expandTransfer key name) ts
|
||||||
|
case localInterval of
|
||||||
|
Nothing -> return txs
|
||||||
|
Just i -> do
|
||||||
|
bounds <- liftExcept $ resolveBounds i
|
||||||
|
return $ filter (inBounds bounds . ftWhen) txs
|
||||||
|
|
||||||
initialCurrency :: BudgetCurrency -> CurID
|
initialCurrency :: BudgetCurrency -> CurID
|
||||||
initialCurrency (NoX c) = c
|
initialCurrency (NoX c) = c
|
||||||
|
@ -533,28 +558,28 @@ expandTransfer key name Transfer {transAmounts, transTo, transCurrency, transFro
|
||||||
let meta = BudgetMeta {bmCommit = key, bmName = name}
|
let meta = BudgetMeta {bmCommit = key, bmName = name}
|
||||||
return
|
return
|
||||||
FlatTransfer
|
FlatTransfer
|
||||||
{ cbtMeta = meta
|
{ ftMeta = meta
|
||||||
, cbtWhen = day
|
, ftWhen = day
|
||||||
, cbtCur = transCurrency
|
, ftCur = transCurrency
|
||||||
, cbtFrom = transFrom
|
, ftFrom = transFrom
|
||||||
, cbtTo = transTo
|
, ftTo = transTo
|
||||||
, cbtValue = UnbalancedValue y $ roundPrecision precision v
|
, ftValue = UnbalancedValue y $ roundPrecision precision v
|
||||||
, cbtDesc = desc
|
, ftDesc = desc
|
||||||
}
|
}
|
||||||
|
|
||||||
insertBudgetTx :: (MonadInsertError m, MonadSqlQuery m, MonadFinance m) => BalancedTransfer -> m ()
|
insertBudgetTx :: (MonadInsertError m, MonadSqlQuery m, MonadFinance m) => BalancedTransfer -> m ()
|
||||||
insertBudgetTx FlatTransfer {cbtFrom, cbtTo, cbtMeta, cbtCur, cbtValue, cbtDesc, cbtWhen} = do
|
insertBudgetTx FlatTransfer {ftFrom, ftTo, ftMeta, ftCur, ftValue, ftDesc, ftWhen} = do
|
||||||
((sFrom, sTo), exchange) <- splitPair cbtFrom cbtTo cbtCur cbtValue
|
((sFrom, sTo), exchange) <- splitPair ftFrom ftTo ftCur ftValue
|
||||||
insertPair sFrom sTo
|
insertPair sFrom sTo
|
||||||
forM_ exchange $ uncurry insertPair
|
forM_ exchange $ uncurry insertPair
|
||||||
where
|
where
|
||||||
insertPair from to = do
|
insertPair from to = do
|
||||||
k <- insert $ TransactionR (bmCommit cbtMeta) cbtWhen cbtDesc
|
k <- insert $ TransactionR (bmCommit ftMeta) ftWhen ftDesc
|
||||||
insertBudgetLabel k from
|
insertBudgetLabel k from
|
||||||
insertBudgetLabel k to
|
insertBudgetLabel k to
|
||||||
insertBudgetLabel k split = do
|
insertBudgetLabel k split = do
|
||||||
sk <- insertSplit k split
|
sk <- insertSplit k split
|
||||||
insert_ $ BudgetLabelR sk $ bmName cbtMeta
|
insert_ $ BudgetLabelR sk $ bmName ftMeta
|
||||||
|
|
||||||
type SplitPair = (KeySplit, KeySplit)
|
type SplitPair = (KeySplit, KeySplit)
|
||||||
|
|
||||||
|
@ -646,7 +671,7 @@ insertHistTransfer
|
||||||
readHistStmt :: (MonadUnliftIO m, MonadFinance m) => Statement -> m (Maybe (CommitR, [KeyTx]))
|
readHistStmt :: (MonadUnliftIO m, MonadFinance m) => Statement -> m (Maybe (CommitR, [KeyTx]))
|
||||||
readHistStmt i = whenHash_ CTImport i $ do
|
readHistStmt i = whenHash_ CTImport i $ do
|
||||||
bs <- readImport i
|
bs <- readImport i
|
||||||
bounds <- expandBounds <$> askDBState kmStatementInterval
|
bounds <- askDBState kmStatementInterval
|
||||||
liftIOExceptT $ mapErrors resolveTx $ filter (inBounds bounds . txDate) bs
|
liftIOExceptT $ mapErrors resolveTx $ filter (inBounds bounds . txDate) bs
|
||||||
|
|
||||||
insertHistStmt :: (MonadSqlQuery m) => CommitR -> [KeyTx] -> m ()
|
insertHistStmt :: (MonadSqlQuery m) => CommitR -> [KeyTx] -> m ()
|
||||||
|
|
|
@ -200,6 +200,7 @@ data Budget = Budget
|
||||||
, bgtPosttax :: [MultiAllocation PosttaxValue]
|
, bgtPosttax :: [MultiAllocation PosttaxValue]
|
||||||
, bgtTransfers :: [BudgetTransfer]
|
, bgtTransfers :: [BudgetTransfer]
|
||||||
, bgtShadowTransfers :: [ShadowTransfer]
|
, bgtShadowTransfers :: [ShadowTransfer]
|
||||||
|
, bgtInterval :: !(Maybe Interval)
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving instance Hashable PretaxValue
|
deriving instance Hashable PretaxValue
|
||||||
|
|
|
@ -8,6 +8,7 @@ module Internal.Utils
|
||||||
, fromGregorian'
|
, fromGregorian'
|
||||||
, resolveBounds
|
, resolveBounds
|
||||||
, resolveBounds_
|
, resolveBounds_
|
||||||
|
, intersectBounds
|
||||||
, liftInner
|
, liftInner
|
||||||
, liftExceptT
|
, liftExceptT
|
||||||
, liftExcept
|
, liftExcept
|
||||||
|
@ -161,14 +162,26 @@ compareDate (In md offset) x = do
|
||||||
fromGregorian' :: Gregorian -> Day
|
fromGregorian' :: Gregorian -> Day
|
||||||
fromGregorian' = uncurry3 fromGregorian . gregTup
|
fromGregorian' = uncurry3 fromGregorian . gregTup
|
||||||
|
|
||||||
-- TODO misleading name
|
inBounds :: Bounds -> Day -> Bool
|
||||||
inBounds :: (Day, Day) -> Day -> Bool
|
inBounds bs = withinDays (expandBounds bs)
|
||||||
inBounds (d0, d1) x = d0 <= x && x < d1
|
|
||||||
|
withinDays :: (Day, Day) -> Day -> Bool
|
||||||
|
withinDays (d0, d1) x = d0 <= x && x < d1
|
||||||
|
|
||||||
resolveBounds :: Interval -> InsertExcept Bounds
|
resolveBounds :: Interval -> InsertExcept Bounds
|
||||||
resolveBounds i@Interval {intStart = s} =
|
resolveBounds i@Interval {intStart = s} =
|
||||||
resolveBounds_ (s {gYear = gYear s + 50}) i
|
resolveBounds_ (s {gYear = gYear s + 50}) i
|
||||||
|
|
||||||
|
-- TODO not DRY
|
||||||
|
intersectBounds :: Bounds -> Bounds -> Maybe Bounds
|
||||||
|
intersectBounds a b =
|
||||||
|
if b' > a' then Nothing else Just (a', fromIntegral $ diffDays b' a' - 1)
|
||||||
|
where
|
||||||
|
(a0, a1) = expandBounds a
|
||||||
|
(b0, b1) = expandBounds b
|
||||||
|
a' = max a0 a1
|
||||||
|
b' = min b0 b1
|
||||||
|
|
||||||
resolveBounds_ :: Gregorian -> Interval -> InsertExcept Bounds
|
resolveBounds_ :: Gregorian -> Interval -> InsertExcept Bounds
|
||||||
resolveBounds_ def Interval {intStart = s, intEnd = e} =
|
resolveBounds_ def Interval {intStart = s, intEnd = e} =
|
||||||
case fromGregorian' <$> e of
|
case fromGregorian' <$> e of
|
||||||
|
|
Loading…
Reference in New Issue