-- This file is part of hs-tax-ato
-- Copyright (C) 2018  Fraser Tweedale
--
-- hs-tax-ato is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

{-|

Common taxes and helpers.

-}

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}

module Data.Tax.ATO.Common
  (
  -- * Tax tables
    TaxTables(..)

  -- * Classes
  , HasTaxableIncome(..)

  -- * Common taxes and helpers
  , medicareLevy
  , lowIncomeTaxOffset
  , lowIncomeTaxOffset2021
  , lamito
  , corporateTax

  -- * Convenience functions
  , thresholds'
  , marginal'
  ) where

import Control.Lens (Getter, review, to, view)
import Data.Bifunctor (first)

import Data.Tax
import Data.Tax.ATO.PrivateHealthInsuranceRebate

-- | A set of tax tables for a particular financial year
data TaxTables y a = TaxTables
  { forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttIndividualIncomeTax :: Tax (Money a) (Money a)
  , forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttMedicareLevy :: Tax (Money a) (Money a)
  , forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttMedicareLevySurcharge :: Tax (Money a) (Money a)
  , forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttHelp :: Tax (Money a) (Money a)
  , forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttSfss :: Tax (Money a) (Money a)
  , forall {k} (y :: k) a. TaxTables y a -> Tax (Money a) (Money a)
ttAdditional :: Tax (Money a) (Money a)
  -- ^ Additional taxes and offsets that apply at EOY
  , forall {k} (y :: k) a.
TaxTables y a -> PrivateHealthInsuranceRebateRates a
ttPHIRebateRates :: PrivateHealthInsuranceRebateRates a
  }

-- | The Medicare levy, incorporating the Medicare levy reduction.
-- The rate is 10% of the income above the given shade-in threshold
-- or 2% of the total income, whichever is less.
--
medicareLevy :: (Fractional a, Ord a) => Money a -> Tax (Money a) (Money a)
medicareLevy :: forall a.
(Fractional a, Ord a) =>
Money a -> Tax (Money a) (Money a)
medicareLevy Money a
l = Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. Ord a => Tax b a -> Tax b a -> Tax b a
lesserOf (Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above Money a
l a
0.1) (a -> Tax (Money a) (Money a)
forall a. Num a => a -> Tax (Money a) (Money a)
flat a
0.02)

-- | /Low income tax offset (LITO)/.  $445, reduced by 1.5c for
-- every dollar earned over $37,000. The lump amount may change in
-- the future.
lowIncomeTaxOffset :: (Fractional a, Ord a) => Tax (Money a) (Money a)
lowIncomeTaxOffset :: forall a. (Fractional a, Ord a) => Tax (Money a) (Money a)
lowIncomeTaxOffset =
  Money a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. Ord a => a -> Tax b a -> Tax b a
limit Money a
forall a. Monoid a => a
mempty
  (Money a -> Tax (Money a) (Money a)
forall a b. a -> Tax b a
lump (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money (-a
445)) Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a. Semigroup a => a -> a -> a
<> Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money a
37000) a
0.015)

-- | /Low income tax offset/, 2020–21 version.
lowIncomeTaxOffset2021 :: (Fractional a, Ord a) => Tax (Money a) (Money a)
lowIncomeTaxOffset2021 :: forall a. (Fractional a, Ord a) => Tax (Money a) (Money a)
lowIncomeTaxOffset2021 =
  Money a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. Ord a => a -> Tax b a -> Tax b a
limit Money a
forall a. Monoid a => a
mempty (Tax (Money a) (Money a) -> Tax (Money a) (Money a))
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. (a -> b) -> a -> b
$
    Money a -> Tax (Money a) (Money a)
forall a b. a -> Tax b a
lump (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money (-a
700))
    Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a. Semigroup a => a -> a -> a
<> Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money a
37500) a
0.05
    Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a. Semigroup a => a -> a -> a
<> Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money a
45000) (-a
0.035)

-- | Low and middle income tax offset. FY2019, 2020, 2021.
--
lamito :: (Fractional a, Ord a) => Tax (Money a) (Money a)
lamito :: forall a. (Fractional a, Ord a) => Tax (Money a) (Money a)
lamito = Money a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. Ord a => a -> Tax b a -> Tax b a
limit Money a
forall a. Monoid a => a
mempty (Tax (Money a) (Money a) -> Tax (Money a) (Money a))
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. (a -> b) -> a -> b
$
  Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a b. Ord a => Tax b a -> Tax b a -> Tax b a
greaterOf (Money a -> Tax (Money a) (Money a)
forall a b. a -> Tax b a
lump (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money (-a
1080)))
    ( Money a -> Tax (Money a) (Money a)
forall a b. a -> Tax b a
lump (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money (-a
255))
    Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a. Semigroup a => a -> a -> a
<> Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money a
37000) (-a
0.075) )
  Tax (Money a) (Money a)
-> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
forall a. Semigroup a => a -> a -> a
<> Money a -> a -> Tax (Money a) (Money a)
forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money a
90000) a
0.03

-- | The corporate tax rate of 30%.  In the future, different rates may
-- be levied depending on business turnover/income.
corporateTax :: (Fractional a) => Tax (Money a) (Money a)
corporateTax :: forall a. Fractional a => Tax (Money a) (Money a)
corporateTax = a -> Tax (Money a) (Money a)
forall a. Num a => a -> Tax (Money a) (Money a)
flat a
0.3

thresholds', marginal'
  :: (Fractional a, Ord a) => [(a, a)] -> Tax (Money a) (Money a)
thresholds' :: forall a.
(Fractional a, Ord a) =>
[(a, a)] -> Tax (Money a) (Money a)
thresholds' = [(Money a, a)] -> Tax (Money a) (Money a)
forall a.
(Fractional a, Ord a) =>
[(Money a, a)] -> Tax (Money a) (Money a)
thresholds ([(Money a, a)] -> Tax (Money a) (Money a))
-> ([(a, a)] -> [(Money a, a)])
-> [(a, a)]
-> Tax (Money a) (Money a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, a) -> (Money a, a)) -> [(a, a)] -> [(Money a, a)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> Money a) -> (a, a) -> (Money a, a)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money))
-- ^ Convenience wrapper for 'thresholds'.  Turns the thresholds into 'Money'
marginal' :: forall a.
(Fractional a, Ord a) =>
[(a, a)] -> Tax (Money a) (Money a)
marginal' = [(Money a, a)] -> Tax (Money a) (Money a)
forall a.
(Fractional a, Ord a) =>
[(Money a, a)] -> Tax (Money a) (Money a)
marginal ([(Money a, a)] -> Tax (Money a) (Money a))
-> ([(a, a)] -> [(Money a, a)])
-> [(a, a)]
-> Tax (Money a) (Money a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, a) -> (Money a, a)) -> [(a, a)] -> [(Money a, a)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> Money a) -> (a, a) -> (Money a, a)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (AReview (Money a) a -> a -> Money a
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview (Money a) a
forall a b (p :: * -> * -> *) (f :: * -> *).
(Profunctor p, Functor f) =>
p a (f b) -> p (Money a) (f (Money b))
money))
-- ^ Convenience wrapper for 'marginal'.  Turns the margins into 'Money'


-- | Types that may have a taxable income component.
class HasTaxableIncome a b c where
  taxableIncome :: Getter (a b) (Money c)

instance
    (Foldable t, HasTaxableIncome x a a, Num a)
    => HasTaxableIncome t (x a) a
    where
  taxableIncome :: Getter (t (x a)) (Money a)
taxableIncome = (t (x a) -> Money a)
-> (Money a -> f (Money a)) -> t (x a) -> f (t (x a))
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to ((x a -> Money a) -> t (x a) -> Money a
forall m a. Monoid m => (a -> m) -> t a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Getting (Money a) (x a) (Money a) -> x a -> Money a
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Money a) (x a) (Money a)
forall {k} (a :: k -> *) (b :: k) c.
HasTaxableIncome a b c =>
Getter (a b) (Money c)
Getter (x a) (Money a)
taxableIncome))