-- 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
  , HasIncome(..)

  -- * Common taxes and helpers
  , medicareLevy
  , medicareLevySurcharge
  , 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 = forall a b. Ord a => Tax b a -> Tax b a -> Tax b a
lesserOf (forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above Money a
l a
0.1) (forall a. Num a => a -> Tax (Money a) (Money a)
flat a
0.02)

-- | /Medicare levy surcharge (MLS)/.  Certain exemptions are available.
--
-- __Known issues__: the MLS is levied on taxable income + fringe
-- benefits, but this is not implemented properly yet.  The
-- thresholds are affected by family income and number of
-- dependents; this also is not implemented.
medicareLevySurcharge :: (Fractional a, Ord a) => Tax (Money a) (Money a)
medicareLevySurcharge :: forall a. (Fractional a, Ord a) => Tax (Money a) (Money a)
medicareLevySurcharge =
  forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
threshold (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money a
90000) a
0.01
  forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
threshold (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money a
105000) a
0.0025
  forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
threshold (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money a
140000) a
0.0025

-- | /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 =
  forall a b. Ord a => a -> Tax b a -> Tax b a
limit forall a. Monoid a => a
mempty
  (forall a b. a -> Tax b a
lump (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money (-a
445)) forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a 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 =
  forall a b. Ord a => a -> Tax b a -> Tax b a
limit forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$
    forall a b. a -> Tax b a
lump (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money (-a
700))
    forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money a
37500) a
0.05
    forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a 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 = forall a b. Ord a => a -> Tax b a -> Tax b a
limit forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$
  forall a b. Ord a => Tax b a -> Tax b a -> Tax b a
greaterOf (forall a b. a -> Tax b a
lump (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money (-a
1080)))
    ( forall a b. a -> Tax b a
lump (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money (-a
255))
    forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money a
37000) (-a
0.075) )
  forall a. Semigroup a => a -> a -> a
<> forall a. (Num a, Ord a) => Money a -> a -> Tax (Money a) (Money a)
above (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a 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 = 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' = forall a.
(Fractional a, Ord a) =>
[(Money a, a)] -> Tax (Money a) (Money a)
thresholds forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a 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' = forall a.
(Fractional a, Ord a) =>
[(Money a, a)] -> Tax (Money a) (Money a)
marginal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall a b. Iso (Money a) (Money b) a b
money))
-- ^ Convenience wrapper for 'marginal'.  Turns the margins into 'Money'


-- | Types that have an income value.
class HasIncome a b c where
  income :: Getter (a b) (Money c)

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