DZ7G36NC3LJLRBZDFIYINFKNABIK2WIBINKLW7FCSKT5G4YSBYUQC 46OSK255NO5Q6JYMR653W542P3ZKL2A674CBVLGPYY34IMO5SPHAC CI4OPKQMU4CIX3QPGA5GWSEOPJ2FAREDBVU6X33E7X3EEQXAICRQC AXKKXBWN4EMUOLV43WN52JSKJPBV7TLSGLNJW5EZXHSJNKCYUWOQC NJNMO72S7VIUV22JXB4IFPZMHWTJAOTP6EC6Z4QSKYIROSXT52MQC NVOCQVASZWTKQJG7GPH7KHKZZR7NUG4WLV5YY4KAIRPCJRWCZPIAC X3ES7NUA42D2BF7CQDDKXM5CLMVCYA3H5YU5KXLPTGDBFPE2LNVAC IR75ZMX32SFFMDNV2I2L22X5JTWCOC4UUBCSPU7S6VHR6HFV6ADQC QMRKFEPGFBCEWAIXPEIG5ILKAJ2JH5L3TOITHR4HNJXK5FN3KXBQC UWMGUJOW5X5HQTS76T2FD7MNAJF7SESPQVU5FDIZO52V75TT2X6AC U7YAT2ZK6GMS7KVFFEQTDRFX6GIN7HVHNWGKIFDGJGE2G2IXSF6QC 7KZP4RHZ3QSYTPPQ257A65Z5UPX44TF2LAI2U5EMULQCLDCEUK2AC 2OIPAQCBDIUJBXB4K2QVP3IEBIUOCQHSWSWFVMVSVZC7GHX2VK7AC A2J7B4SCCJYKQV3G2LDHEFNE2GUICO3N3Y5FKF4EUZW5AG7PTDWAC SCXG6TJWYIPRUMT27KGKIIF6FYKTUTY74UNZ2FQTT63XZ6HIF3AAC N4NDAZYTLSI2W22KT3SYXL257DBMSH3UT2BXOYM7LH7FSZAY4RLAC NEDDHXUK3GNFMOFO3KLU7NRIHCTYNWBT3D6HTKZAOXFDE6HMDZ6AC Y35QCWYW2OTZ27ZVTH2BA3XJTUCJ2WMLKU32ZCOCDY3AW7TIZXRAC LTSVBVA235BQAIU3SQURKSRHIAL33K47G4J6TSEP2K353OCHNJEAC KNSI575VAW6HRCZYXOEPQ4DTSML4EORML5MV4DJBRKE7TXCPS4EAC LHJ2HFXVUQ4VG25I7DADWU73G5K5WNZBDQ3SVNKFYLZ5BEYM4XCQC EFSXYZPOGA5M4DN65IEIDO7JK6U34DMQELAPHOIL2UAT6HRC66BAC 5DRIWGLUKMQZU2ZPBXSTLAWJKAMOD5YXAHM5LEDQHDFGYYLHWCDQC NMWWP4ZNOKHZKSJ6F5KYEREWXXR5F4UD35WOKI3EH42AZWVCTCJAC -- |-- - The depreciation function should return a value between 0 and 1;-- - this result is multiplied by the length of an interval of work to determine-- - the depreciated value of the work.type DepF = C.UTCTime -> Interval C.UTCTime -> NDT
-- |-- - The depreciation function should return a value between 0 and 1;-- - this result is multiplied by the length of an interval of work to determine-- - the depreciated value of the work.---- arguments:-- * date of first revenue (if applicable)-- * date on which the depreciated value is being computed-- *type DepF = Maybe C.UTCTime -> C.UTCTime -> Interval C.UTCTime -> NDT
-- - A very simple linear function for calculating depreciation.linearDepreciation ::-- | The number of initial days during which no depreciation occursC.Days ->-- | The number of days over which each logged interval will be depreciatedC.Days ->-- | The resulting configured depreciation function.DepFlinearDepreciation undepDays depDays =let -- length of a number of days as NominalDiffTimeundepLength = daysToNDT undepDaysdepLength = daysToNDT depDays-- The percentage of the depreciation period that the end of the interval-- represents.depPercentage :: NDT -> RationaldepPercentage intervalAge =if intervalAge < undepLengththen 1else max 0 (1 - (C.toSeconds (intervalAge ^-^ undepLength) / C.toSeconds depLength))in \firstRevenue payoutDate ival ->let ivalEnd = case firstRevenue of-- if the end of the interval was before first revenue, count it as-- having ended at the first revenue date for the purpose of depreciationJust dt -> max dt (ival ^. end)Nothing -> ival ^. endin depPercentage (payoutDate .-. ivalEnd) *^ ilen ival-- |
-- |-- - A very simple linear function for calculating depreciation.linearDepreciation ::-- | The number of initial days during which no depreciation occursC.Days ->-- | The number of days over which each logged interval will be depreciatedC.Days ->-- | The resulting configured depreciation function.DepFlinearDepreciation undepLength depLength =let daysLength :: C.Days -> NDTdaysLength d = C.fromSeconds $ 60 * 60 * 24 * dmaxDepreciable :: NDTmaxDepreciable = daysLength undepLength ^+^ daysLength depLengthdepPct :: NDT -> RationaldepPct dt =if dt < daysLength undepLengththen 1elseC.toSeconds (max zeroV (maxDepreciable ^-^ dt))/ C.toSeconds maxDepreciablein \ptime ival ->let depreciation = depPct $ ptime .-. (ival ^. end)in depreciation *^ ilen ival
let initTime = toThyme . fromJust $ parseISO8601 "2014-01-01T00:08:00Z"len = fromInteger @NominalDiffTime 360timestamps = iterate (addUTCTime len) initTime
let initTime = C.toThyme . fromJust $ parseISO8601 "2014-01-01T00:08:00Z"len = fromInteger @C.NominalDiffTime 360timestamps = iterate (.+^ len) initTime
describe "depreciation functions" $ doit "computes linear depreciation" $ dolet depf = linearDepreciation 10 100hour = fromInteger (60 * 60)t0 :: C.UTCTime = C.toThyme . fromJust $ parseISO8601 "2014-01-01T00:08:00Z"ival = I.Interval (t0 .+^ negate hour) t0t1 = t0 .+^ daysToNDT 5t2 = t0 .+^ daysToNDT 10t3 = t0 .+^ daysToNDT 20t4 = t0 .+^ daysToNDT 60t5 = t0 .+^ daysToNDT 110daysToNDT 1 `shouldBe` (60 * 60 * 24)-- undepreciated; within the first 10 daysdepf Nothing t1 ival `shouldBe` 3600-- still undepreciated if it ends at the last depreciation momentdepf Nothing t2 ival `shouldBe` 3600-- depreciated by 10% of its valuedepf Nothing t3 ival `shouldBe` 3240-- depreciated by 50% of its valuedepf Nothing t4 ival `shouldBe` 1800-- depreciated by 100% of its valuedepf Nothing t5 ival `shouldBe` 0-- undepreciated - before first revenuedepf (Just t3) t1 ival `shouldBe` 3600-- undepreciated - before first revenuedepf (Just t3) t2 ival `shouldBe` 3600-- depreciated by 10% of its valuedepf (Just t3) t3 ival `shouldBe` 3600-- depreciated by 30% of its valuedepf (Just t3) t4 ival `shouldBe` 2520-- depreciated by 80% of its valuedepf (Just t3) t5 ival `shouldBe` 720