1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
module Model.Income
( Income
, incomeDecoder
, incomeDefinedForAll
, cumulativeIncomesSince
) where
import Json.Decode as Json exposing ((:=))
import Time exposing (Time, hour)
import List exposing (..)
import Model.Date exposing (timeDecoder)
import Model.User exposing (UserId)
import Utils.Maybe exposing (isJust, catMaybes, maybeToList)
type alias Income =
{ creation : Time
, amount : Int
}
incomeDecoder : Json.Decoder Income
incomeDecoder =
Json.object2 Income
("creation" := timeDecoder)
("amount" := Json.int)
incomeDefinedForAll : List (List Income) -> Maybe Time
incomeDefinedForAll usersIncomes =
let firstIncomes = map (head << sortBy .creation) usersIncomes
in if all isJust firstIncomes
then head << reverse << List.sort << map .creation << catMaybes <| firstIncomes
else Nothing
cumulativeIncomesSince : Time -> Time -> (List Income) -> Int
cumulativeIncomesSince currentTime since incomes =
cumulativeIncome currentTime (getOrderedIncomesSince since incomes)
getOrderedIncomesSince : Time -> List Income -> List Income
getOrderedIncomesSince time incomes =
let mbStarterIncome = getIncomesAt time incomes
orderedIncomesSince = filter (\income -> income.creation >= time) incomes
in (maybeToList mbStarterIncome) ++ orderedIncomesSince
getIncomesAt : Time -> List Income -> Maybe Income
getIncomesAt time incomes =
case incomes of
[x] ->
if x.creation < time
then Just { creation = time, amount = x.amount }
else Nothing
x1 :: x2 :: xs ->
if x1.creation < time && x2.creation > time
then Just { creation = time, amount = x2.amount }
else getIncomesAt time (x2 :: xs)
[] ->
Nothing
cumulativeIncome : Time -> List Income -> Int
cumulativeIncome currentTime incomes =
getIncomesWithDuration (incomes ++ [{ creation = currentTime, amount = 0 }])
|> map durationIncome
|> sum
getIncomesWithDuration : List Income -> List (Float, Int)
getIncomesWithDuration incomes =
case incomes of
(income1 :: income2 :: xs) ->
(income2.creation - income1.creation, income1.amount) :: (getIncomesWithDuration (income2 :: xs))
_ ->
[]
durationIncome : (Float, Int) -> Int
durationIncome (duration, income) =
duration * toFloat income / (hour * 24 * 365 / 12)
|> truncate
|