module Model.Payment exposing ( perPage , Payments , Payment , PaymentId , Frequency(..) , paymentsDecoder , paymentIdDecoder , edit , delete , totalPayments , punctual , monthly , groupAndSortByMonth , search , validateFrequency ) import Date exposing (..) import Date.Extra.Core exposing (monthToInt, intToMonth) import Json.Decode as Json exposing ((:=)) import String import Form.Validate as Validate exposing (Validation) import Model.User exposing (UserId, userIdDecoder) import Model.Date exposing (dateDecoder) import Utils.List as List perPage : Int perPage = 7 type alias Payments = List Payment type alias Payment = { id : PaymentId , name : String , cost : Int , date : Date , userId : UserId , frequency : Frequency } type alias PaymentId = Int type Frequency = Punctual | Monthly paymentsDecoder : Json.Decoder Payments paymentsDecoder = Json.list paymentDecoder paymentDecoder : Json.Decoder Payment paymentDecoder = Json.object6 Payment ("id" := paymentIdDecoder) ("name" := Json.string) ("cost" := Json.int) ("date" := dateDecoder) ("userId" := userIdDecoder) ("frequency" := frequencyDecoder) paymentIdDecoder : Json.Decoder PaymentId paymentIdDecoder = Json.int frequencyDecoder : Json.Decoder Frequency frequencyDecoder = Json.customDecoder Json.string (\input -> case input of "Punctual" -> Ok Punctual "Monthly" -> Ok Monthly _ -> Err ("Could not deduce Punctual nor Monthly from " ++ input) ) edit : Payment -> Payments -> Payments edit payment payments = payment :: delete payment.id payments delete : PaymentId -> Payments -> Payments delete paymentId = List.filter (((/=) paymentId) << .id) totalPayments : (Payment -> Bool) -> UserId -> Payments -> Int totalPayments paymentFilter userId payments = payments |> List.filter (\payment -> paymentFilter payment && payment.userId == userId ) |> List.map .cost |> List.sum punctual : Payments -> Payments punctual = List.filter ((==) Punctual << .frequency) monthly : Payments -> Payments monthly = List.filter ((==) Monthly << .frequency) groupAndSortByMonth : Payments -> List ((Month, Int), Payments) groupAndSortByMonth payments = payments |> List.groupBy (\payment -> (Date.year payment.date, monthToInt << Date.month <| payment.date)) |> List.sortBy fst |> List.map (\((year, month), payments) -> ((intToMonth month, year), payments)) |> List.reverse search : String -> Frequency -> Payments -> Payments search name frequency payments = payments |> List.filter ((==) frequency << .frequency) |> paymentSort frequency |> List.filter (searchSuccess name) paymentSort : Frequency -> Payments -> Payments paymentSort frequency = case frequency of Punctual -> List.reverse << List.sortBy (Date.toTime << .date) Monthly -> List.sortBy (String.toLower << .name) searchSuccess : String -> Payment -> Bool searchSuccess text { name } = (String.toLower text) `String.contains` (String.toLower name) validateFrequency : Validation String Frequency validateFrequency = Validate.customValidation Validate.string (\str -> if str == toString Punctual then Ok Punctual else if str == toString Monthly then Ok Monthly else Err (Validate.customError "InvalidFrequency") )