packages feed

national-australia-bank-0.0.11: src/Data/Bank/NationalAustraliaBank/Report.hs

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE LambdaCase #-}

module Data.Bank.NationalAustraliaBank.Report(
  cumulativeSumTransactions
, cumulativeDays
, cumulativeDays'
, cumulativePerDay
, cumulativePerDay'
) where

import Control.Lens ( view, over, Field1(_1), Field2(_2) )
import Data.Bank.NationalAustraliaBank.Transaction
    ( Transaction,
      Amount,
      Date,
      diffDates,
      realAmount,
      date',
      amount' )
import Data.Bool ( bool )
import Data.List ( sortOn )
import Data.Ratio ( Ratio )

withMinimumDate ::
  (Date -> [a])
  -> [Transaction]
  -> [a]
withMinimumDate _ [] =
  []
withMinimumDate f ts@(_:_) =
  f (minimum (fmap date' ts))

sortedByDateTransactions ::
  ([(Integer, Transaction)] -> [(Integer, x)])
  -> [Transaction]
  -> [x]
sortedByDateTransactions f ts =
  let ts' =
        sortOn (date' . view _2) (zip [0..] ts)
      r =
        sortOn (view _1) (f ts')
  in  fmap (view _2) r

cumulativeSumTransactions ::
  [Transaction]
  -> [Amount]
cumulativeSumTransactions =
  sortedByDateTransactions
    (\case
        [] ->
          []
        (n, h):t ->
          scanl (\(_, a) -> over _2 (\t' -> amount' t' <> a)) (n, amount' h) t
    )

cumulativeDays ::
  [Transaction]
  -> [Integer]
cumulativeDays ts =
  withMinimumDate (`cumulativeDays'` ts) ts

cumulativeDays' ::
  Date
  -> [Transaction]
  -> [Integer]
cumulativeDays' d =
  sortedByDateTransactions (fmap (fmap (\t -> date' t `diffDates` d + 1)))

cumulativePerDay ::
  [Transaction]
  -> [Ratio Integer]
cumulativePerDay ts =
  withMinimumDate (`cumulativePerDay'` ts) ts

cumulativePerDay' ::
  Date
  -> [Transaction]
  -> [Ratio Integer]
cumulativePerDay' dt txs =
  zipWith (\a i -> bool (realAmount a / fromInteger i) 0 (i == 0)) (cumulativeSumTransactions txs) (cumulativeDays' dt txs)