{-# LANGUAGE ImportQualifiedPost #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Tax.Canada.ON428.Fix (fixON428) where import Control.Applicative (liftA2) import Control.Monad (guard, mfilter) import Data.Fixed (Centi) import Rank2 qualified import Tax.Canada.ON428.Types import Tax.Util (fixEq, fractionOf, nonNegativeDifference, totalOf) fixON428 :: ON428 Maybe -> ON428 Maybe fixON428 = fixEq $ \on428@ON428{..}-> ON428{page1 = fixPage1 page1, page2 = fixPage2 on428 page2, page3 = fixPage3 on428 page3, page4 = fixPage4 on428 page4} fixPage1 :: Page1 Maybe -> Page1 Maybe fixPage1 = fixEq $ \Page1{..}-> Page1{ line1 = line1, partA = fixPage1PartA line1 partA, partB = fixPage1PartB partB} fixPage1PartA :: Maybe Centi -> Page1PartA Maybe -> Page1PartA Maybe fixPage1PartA income = fixEq $ \Page1PartA{..}-> Page1PartA{ column1 = fixTaxIncomeBracket income (Just column2) column1, column2 = fixTaxIncomeBracket income (Just column3) column2, column3 = fixTaxIncomeBracket income (Just column4) column3, column4 = fixTaxIncomeBracket income (Just column5) column4, column5 = fixTaxIncomeBracket income Nothing column5} fixTaxIncomeBracket :: Maybe Centi -> Maybe (TaxIncomeBracket Maybe) -> TaxIncomeBracket Maybe -> TaxIncomeBracket Maybe fixTaxIncomeBracket income nextBracket bracket@TaxIncomeBracket{..} = bracket{ line2_income = do i <- income floor <- line3_threshold let ceiling = nextBracket >>= (.line3_threshold) guard (floor <= i && all (i <) ceiling) income, line4_overThreshold = liftA2 (-) line2_income line3_threshold, line6_timesRate = fromRational <$> liftA2 (*) (toRational <$> line4_overThreshold) line5_rate, line8_equalsTax = liftA2 (+) line6_timesRate line7_baseTax} fixPage1PartB :: Page1PartB Maybe -> Page1PartB Maybe fixPage1PartB = fixEq $ \part@Page1PartB{..}-> part{ line9_basic = Just 11141, line11_base = Just 10406, line13_difference = mfilter (> 0) $ liftA2 (-) line11_base line12_spouseIncome, line13_cont = line13_difference, line14_base = Just 10406, line16_difference = mfilter (> 0) $ liftA2 (-) line14_base line15_dependentIncome, line16_cont = line16_difference, line18 = totalOf [line9_basic, line10_age, line13_cont, line16_cont, line17_caregiver], line24_sum = totalOf [line19_cppQpp, line20_cppQpp, line21_employmentInsurance, line22_employmentInsurance, line23_adoption], line24_cont = line24_sum, line25 = totalOf [line18, line24_cont]} fixPage2 :: ON428 Maybe -> Page2 Maybe -> Page2 Maybe fixPage2 on428 = fixEq $ \Page2{..}-> Page2{ partB = fixPage2PartB on428 partB, partC = fixPage2PartC on428 partC} fixPage2PartB :: ON428 Maybe -> Page2PartB Maybe -> Page2PartB Maybe fixPage2PartB on428 = fixEq $ \part@Page2PartB{..}-> part{ line26 = on428.page1.partB.line25, line28 = totalOf [line26, line27_pension], line31 = totalOf [line28, line29_disability, line30], line35 = totalOf [line31, line32_interest, line33_education, line34_transferred], medicalExpenses = fixMedicalExpenses medicalExpenses, line43_sum = totalOf [medicalExpenses.line41_difference, line42], line43_cont = line43_sum, line44 = totalOf [line35, line43_cont], line46_fraction = line45_rate `fractionOf` line44, donations = fixDonations donations, line50 = totalOf [line46_fraction, donations.line49_cont]} fixPage2PartC :: ON428 Maybe -> Page2PartC Maybe -> Page2PartC Maybe fixPage2PartC on428 = fixEq $ \part@Page2PartC{..}-> part{ line51_tax = totalOf [on428.page1.partA.column1.line8_equalsTax, on428.page1.partA.column2.line8_equalsTax, on428.page1.partA.column3.line8_equalsTax, on428.page1.partA.column4.line8_equalsTax, on428.page1.partA.column5.line8_equalsTax], line52_credits = on428.page2.partB.line50, line53 = nonNegativeDifference line51_tax line52_credits, line55 = totalOf [line53, line54], line56 = line53, line58 = nonNegativeDifference line56 line57, line59_product = Just 0.3367 `fractionOf` line59_copy, line60_lesser = min <$> line58 <*> line59_product, line61 = nonNegativeDifference line55 line60_lesser} fixMedicalExpenses :: MedicalExpenses Maybe -> MedicalExpenses Maybe fixMedicalExpenses = fixEq $ \part@MedicalExpenses{..} -> part{ line38_rate = Just 0.03, line39_fraction = line38_rate `fractionOf` line37_income, line40_lesser = min 2522 <$> line39_fraction, line41_difference = nonNegativeDifference line36_expenses line40_lesser} fixDonations :: Donations Maybe -> Donations Maybe fixDonations = fixEq $ \part@Donations{..} -> part{ line47_fraction = Just 0.0505 `fractionOf` line47_base, line48_fraction = Just 0.1116 `fractionOf` line48_base, line49_sum = totalOf [line47_fraction, line48_fraction], line49_cont = line49_sum} fixPage3 :: ON428 Maybe -> Page3 Maybe -> Page3 Maybe fixPage3 on428 = fixEq $ \page@Page3{..}-> page{ line62 = on428.page2.partC.line61, line63 = line62, line64 = on428.page2.partC.line54, line65 = nonNegativeDifference line63 line64, line66_copy = line65, line66_surtax = Just 0.2 `fractionOf` nonNegativeDifference line66_copy (Just 4991), line67_copy = line65, line67_surtax = Just 0.36 `fractionOf` nonNegativeDifference line67_copy (Just 6387), line68_sum = totalOf [line66_surtax, line67_surtax], line68_cont = line68_sum, line69 = totalOf [line62, line68_cont], line70 = on428.page2.partC.line57, line71 = nonNegativeDifference line69 line70, line73 = totalOf [line71, line72], line74_basicReduction = Just 257, line75_amount = ((475 *) . fromIntegral) <$> line75_childrenNum, line76_amount = ((475 *) . fromIntegral) <$> line76_childrenNum, line77 = totalOf [line74_basicReduction, line75_amount, line76_amount], line78_copy = line77, line78_product = (2 *) <$> line78_copy, line79 = line73, line80_difference = nonNegativeDifference line78_product line79, line80_cont = line80_difference, line81 = nonNegativeDifference line73 line80_cont, line83 = nonNegativeDifference line81 line82} fixPage4 :: ON428 Maybe -> Page4 Maybe -> Page4 Maybe fixPage4 on428 = fixEq $ \page@Page4{..}-> page{ line84 = on428.page3.line83, line86 = nonNegativeDifference line84 line85_lift, line87_fraction = Just 0.25 `fractionOf` line87_foodDonations, line88 = nonNegativeDifference line86 line87_fraction, line89_health = totalOf [between 0 20000 0, healthPremium.row1.equalsTax, between 25000 36000 300, healthPremium.row2.equalsTax, between 38500 48000 450, healthPremium.row3.equalsTax, between 48600 72000 600, healthPremium.row4.equalsTax, between 72600 200000 750, healthPremium.row5.equalsTax, if income > 200600 then Just 900 else Nothing], line90 = totalOf [line88, line89_health], healthPremium = fixHealthPremium income healthPremium} where income = sum on428.page1.line1 between floor ceiling tax | income > floor && income <= ceiling = Just tax | otherwise = Nothing fixHealthPremium :: Centi -> HealthPremium Maybe -> HealthPremium Maybe fixHealthPremium income = fixEq $ \HealthPremium{..}-> HealthPremium{ row1 = fixHealthPremiumBracket income 20000 25000 0.06 0 row1, row2 = fixHealthPremiumBracket income 36000 38500 0.06 300 row2, row3 = fixHealthPremiumBracket income 48000 48600 0.25 450 row3, row4 = fixHealthPremiumBracket income 72000 72600 0.25 600 row4, row5 = fixHealthPremiumBracket income 200000 200600 0.25 750 row5} fixHealthPremiumBracket :: Centi -> Centi -> Centi -> Rational -> Centi -> HealthPremiumBracket Maybe -> HealthPremiumBracket Maybe fixHealthPremiumBracket income floor ceiling rate base HealthPremiumBracket{..} | income > floor && income < ceiling = HealthPremiumBracket{ taxableIncome = Just income, overThreshold = Just $ income - floor, timesRate = Just rate `fractionOf` overThreshold, equalsTax = totalOf [timesRate, Just base]} | otherwise = Rank2.pure Nothing