packages feed

tax-ato 2024.1.0.1 → 2025.1

raw patch · 21 files changed

+1927/−306 lines, 21 filesdep ~lensdep ~timePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: lens, time

API changes (from Hackage documentation)

- Data.Tax.ATO: PaymentSummary :: ABN -> Money a -> Money a -> Money a -> PaymentSummary a
- Data.Tax.ATO: [reportableEmployerSuperannuationContributions] :: PaymentSummary a -> Money a
- Data.Tax.ATO: [summaryABN] :: PaymentSummary a -> ABN
- Data.Tax.ATO: [summaryGross] :: PaymentSummary a -> Money a
- Data.Tax.ATO: [summaryWithheld] :: PaymentSummary a -> Money a
- Data.Tax.ATO: data PaymentSummary a
- Data.Tax.ATO: instance (Data.Foldable.Foldable t, Data.Tax.ATO.HasTaxWithheld x a a, GHC.Num.Num a) => Data.Tax.ATO.HasTaxWithheld t (x a) a
- Data.Tax.ATO: instance (GHC.Num.Num a, GHC.Classes.Eq a) => Data.Tax.ATO.CGT.HasCapitalLossCarryForward Data.Tax.ATO.TaxAssessment a
- Data.Tax.ATO: instance Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.PaymentSummary a a
- Data.Tax.ATO: instance Data.Tax.ATO.HasTaxWithheld Data.Tax.ATO.GrossAndWithheld a a
- Data.Tax.ATO: instance Data.Tax.ATO.HasTaxWithheld Data.Tax.ATO.PaymentSummary a a
- Data.Tax.ATO: instance Data.Tax.ATO.HasTaxWithheld Data.Tax.ATO.TaxAssessment a a
- Data.Tax.ATO: instance GHC.Num.Num a => Data.Tax.ATO.HasTaxWithheld (Data.Tax.ATO.TaxReturnInfo y) a a
- Data.Tax.ATO: instance GHC.Num.Num a => GHC.Base.Monoid (Data.Tax.ATO.ESSStatement a)
- Data.Tax.ATO: instance GHC.Num.Num a => GHC.Base.Semigroup (Data.Tax.ATO.ESSStatement a)
- Data.Tax.ATO: instance GHC.Real.RealFrac a => Data.Tax.ATO.HasTaxWithheld Data.Tax.ATO.Dividend a a
- Data.Tax.ATO: taxCreditsAndOffsets :: Getter (TaxAssessment a) (Money a)
- Data.Tax.ATO: type ABN = String
- Data.Tax.ATO.CGT: CGTAssessment :: Money a -> CGTNetGainOrLoss a -> CGTAssessment a
- Data.Tax.ATO.CGT: CGTLoss :: Money a -> CGTNetGainOrLoss a
- Data.Tax.ATO.CGT: CGTNetGain :: Money a -> CGTNetGainOrLoss a
- Data.Tax.ATO.CGT: cgtNetGainOrLoss :: Lens' (CGTAssessment a) (CGTNetGainOrLoss a)
- Data.Tax.ATO.CGT: data CGTNetGainOrLoss a
- Data.Tax.ATO.CGT: instance (GHC.Num.Num a, GHC.Classes.Eq a) => Data.Tax.ATO.CGT.HasCapitalLossCarryForward Data.Tax.ATO.CGT.CGTAssessment a
- Data.Tax.ATO.CGT: instance (GHC.Num.Num a, GHC.Classes.Eq a) => Data.Tax.ATO.CGT.HasCapitalLossCarryForward Data.Tax.ATO.CGT.CGTNetGainOrLoss a
- Data.Tax.ATO.CGT: instance Data.Tax.ATO.CGT.HasCapitalGain Data.Tax.ATO.CGT.CGTAssessment a a
- Data.Tax.ATO.CGT: instance GHC.Base.Functor Data.Tax.ATO.CGT.CGTNetGainOrLoss
- Data.Tax.ATO.CGT: instance GHC.Show.Show a => GHC.Show.Show (Data.Tax.ATO.CGT.CGTAssessment a)
- Data.Tax.ATO.CGT: instance GHC.Show.Show a => GHC.Show.Show (Data.Tax.ATO.CGT.CGTNetGainOrLoss a)
- Data.Tax.ATO.CGT: netCapitalGainOrLoss :: (Fractional a, Ord a, Foldable t) => Money a -> t (CGTEvent a) -> CGTNetGainOrLoss a
- Data.Tax.ATO.Common: [ttMedicareLevy] :: TaxTables y a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Pretty: summariseCGTAssessment :: CGTAssessment Rational -> Doc
+ Data.Tax.ATO: applyCentsPerKilometreMethod :: forall {k} (y :: k) a. (HasCentsPerKilometreMethod y, Fractional a, Ord a) => a -> Money a
+ Data.Tax.ATO: applyFixedRateMethod :: forall {k} (y :: k) a. (HasFixedRateMethod y, Fractional a) => a -> Money a
+ Data.Tax.ATO: applyFixedRateMethodPre2023 :: forall {k} (y :: k) a. (HasFixedRateMethodPre2023 y, Fractional a) => a -> Money a
+ Data.Tax.ATO: applyShortcutMethod :: forall {k} (y :: k) a. (HasShortcutMethod y, Fractional a) => a -> Money a
+ Data.Tax.ATO: class HasCentsPerKilometreMethod (y :: k)
+ Data.Tax.ATO: class HasFixedRateMethod (y :: k)
+ Data.Tax.ATO: class HasFixedRateMethodPre2023 (y :: k)
+ Data.Tax.ATO: class HasShortcutMethod (y :: k)
+ Data.Tax.ATO: class HasTaxableIncome (a :: k -> Type) (b :: k) c
+ Data.Tax.ATO: data ABN
+ Data.Tax.ATO: division293Income :: forall a (y :: Nat). RealFrac a => TaxReturnInfo y a -> Money a
+ Data.Tax.ATO: essEmployerDetails :: forall a f. Functor f => (PayerDetails -> f PayerDetails) -> ESSStatement a -> f (ESSStatement a)
+ Data.Tax.ATO: foreignIncomeTaxOffsets :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
+ Data.Tax.ATO: frankingCreditOffset :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
+ Data.Tax.ATO: instance Data.Tax.ATO.CGT.HasCapitalLossCarryForward Data.Tax.ATO.TaxAssessment a
+ Data.Tax.ATO: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.ESSStatement a a
+ Data.Tax.ATO: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.GrossAndWithheld a a
+ Data.Tax.ATO: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.TaxAssessment a a
+ Data.Tax.ATO: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.ESSStatement a)
+ Data.Tax.ATO: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Tax.ATO.ESSStatement a)
+ Data.Tax.ATO: instance GHC.Num.Num a => Data.Tax.ATO.Common.HasTaxWithheld (Data.Tax.ATO.TaxReturnInfo y) a a
+ Data.Tax.ATO: instance GHC.Real.RealFrac a => Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.Dividend a a
+ Data.Tax.ATO: medicareLevySurchargeDue :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
+ Data.Tax.ATO: offsetForSuperannuationContributionsOnBehalfOfYourSpouse :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
+ Data.Tax.ATO: paygInstalmentIncome :: forall a (y :: Nat). RealFrac a => TaxReturnInfo y a -> Money a
+ Data.Tax.ATO: paymentSummariesBusinessAndPersonalServicesIncome :: forall (y :: Nat) a f. Functor f => ([PaymentSummaryBusinessAndPersonalServicesIncome a] -> f [PaymentSummaryBusinessAndPersonalServicesIncome a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO: paymentSummariesForeignEmployment :: forall (y :: Nat) a f. Functor f => ([PaymentSummaryForeignEmployment a] -> f [PaymentSummaryForeignEmployment a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO: paymentSummariesIndividualNonBusiness :: forall (y :: Nat) a f. Functor f => ([PaymentSummaryIndividualNonBusiness a] -> f [PaymentSummaryIndividualNonBusiness a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO: paymentSummariesWithholdingWhereABNNotQuoted :: forall (y :: Nat) a f. Functor f => ([PaymentSummaryWithholdingWhereABNNotQuoted a] -> f [PaymentSummaryWithholdingWhereABNNotQuoted a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO.ABN: asInt :: ABN -> Int
+ Data.Tax.ATO.ABN: asString :: ABN -> String
+ Data.Tax.ATO.ABN: data ABN
+ Data.Tax.ATO.ABN: fromInt :: Int -> Maybe ABN
+ Data.Tax.ATO.ABN: instance Data.String.IsString Data.Tax.ATO.ABN.ABN
+ Data.Tax.ATO.ABN: instance GHC.Classes.Eq Data.Tax.ATO.ABN.ABN
+ Data.Tax.ATO.ABN: instance GHC.Classes.Ord Data.Tax.ATO.ABN.ABN
+ Data.Tax.ATO.ABN: instance GHC.Show.Show Data.Tax.ATO.ABN.ABN
+ Data.Tax.ATO.ABN: parse :: String -> Maybe ABN
+ Data.Tax.ATO.CGT: cgtNetLossesCarriedForward :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtTotalCurrentYearGains :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: instance Data.Tax.ATO.CGT.HasCapitalLossCarryForward Data.Tax.ATO.CGT.CGTAssessment a
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.CGT.CGTAssessment a)
+ Data.Tax.ATO.CGT: nullCGTAssessment :: Num a => CGTAssessment a
+ Data.Tax.ATO.Common: MedicareLevyRatesAndThresholds :: a -> Money a -> Money a -> Money a -> Money a -> Money a -> MedicareLevyRatesAndThresholds a
+ Data.Tax.ATO.Common: [medicareLevyRate] :: MedicareLevyRatesAndThresholds a -> a
+ Data.Tax.ATO.Common: [medicareLevyThresholdDependentChildIncrease] :: MedicareLevyRatesAndThresholds a -> Money a
+ Data.Tax.ATO.Common: [medicareLevyThresholdFamilySeniorAndPensioner] :: MedicareLevyRatesAndThresholds a -> Money a
+ Data.Tax.ATO.Common: [medicareLevyThresholdFamily] :: MedicareLevyRatesAndThresholds a -> Money a
+ Data.Tax.ATO.Common: [medicareLevyThresholdIndividualSeniorAndPensioner] :: MedicareLevyRatesAndThresholds a -> Money a
+ Data.Tax.ATO.Common: [medicareLevyThresholdIndividual] :: MedicareLevyRatesAndThresholds a -> Money a
+ Data.Tax.ATO.Common: [ttMedicareLevyRatesAndThresholds] :: TaxTables (y :: k) a -> MedicareLevyRatesAndThresholds a
+ Data.Tax.ATO.Common: applyCentsPerKilometreMethod :: forall {k} (y :: k) a. (HasCentsPerKilometreMethod y, Fractional a, Ord a) => a -> Money a
+ Data.Tax.ATO.Common: applyFixedRateMethod :: forall {k} (y :: k) a. (HasFixedRateMethod y, Fractional a) => a -> Money a
+ Data.Tax.ATO.Common: applyFixedRateMethodPre2023 :: forall {k} (y :: k) a. (HasFixedRateMethodPre2023 y, Fractional a) => a -> Money a
+ Data.Tax.ATO.Common: applyShortcutMethod :: forall {k} (y :: k) a. (HasShortcutMethod y, Fractional a) => a -> Money a
+ Data.Tax.ATO.Common: class HasCentsPerKilometreMethod (y :: k)
+ Data.Tax.ATO.Common: class HasFixedRateMethod (y :: k)
+ Data.Tax.ATO.Common: class HasFixedRateMethodPre2023 (y :: k)
+ Data.Tax.ATO.Common: class HasShortcutMethod (y :: k)
+ Data.Tax.ATO.Common: class HasTaxWithheld (a :: k -> Type) (b :: k) c
+ Data.Tax.ATO.Common: data MedicareLevyRatesAndThresholds a
+ Data.Tax.ATO.Common: instance (2002 Data.Type.Ord.<= y, y Data.Type.Ord.<= 2022, Data.Tax.ATO.FY.FinancialYear y) => Data.Tax.ATO.Common.HasFixedRateMethodPre2023 y
+ Data.Tax.ATO.Common: instance (2016 Data.Type.Ord.<= y, y Data.Type.Ord.<= 2025, Data.Tax.ATO.FY.FinancialYear y) => Data.Tax.ATO.Common.HasCentsPerKilometreMethod y
+ Data.Tax.ATO.Common: instance (2020 Data.Type.Ord.<= y, y Data.Type.Ord.<= 2022) => Data.Tax.ATO.Common.HasShortcutMethod y
+ Data.Tax.ATO.Common: instance (Data.Foldable.Foldable t, Data.Tax.ATO.Common.HasTaxWithheld x a a, GHC.Num.Num a) => Data.Tax.ATO.Common.HasTaxWithheld t (x a) a
+ Data.Tax.ATO.Common: instance Data.Tax.ATO.Common.HasFixedRateMethod 2023
+ Data.Tax.ATO.Common: instance Data.Tax.ATO.Common.HasFixedRateMethod 2024
+ Data.Tax.ATO.Common: instance Data.Tax.ATO.Common.HasFixedRateMethod 2025
+ Data.Tax.ATO.Common: medicareLevy' :: (Fractional a, Ord a) => MedicareLevyRatesAndThresholds a -> Money a -> Maybe (Money a) -> Integer -> Money a
+ Data.Tax.ATO.Common: taxWithheld :: HasTaxWithheld a b c => Getter (a b) (Money c)
+ Data.Tax.ATO.Depreciation: DepreciatingAsset :: Day -> Money a -> EffectiveLife -> DepreciationMethod a -> DepreciatingAsset a
+ Data.Tax.ATO.Depreciation: data DepreciatingAsset a
+ Data.Tax.ATO.Depreciation: declineInValue :: forall (y :: Nat) a. (FinancialYear y, Fractional a, Ord a) => Proxy y -> DepreciatingAsset a -> Money a
+ Data.Tax.ATO.Depreciation: depreciationSchedule :: (Fractional a, Ord a) => DepreciatingAsset a -> [(Year, Money a)]
+ Data.Tax.ATO.Depreciation: diminishingValueMethod :: Fractional a => DepreciationMethod a
+ Data.Tax.ATO.Depreciation: primeCostMethod :: Fractional a => DepreciationMethod a
+ Data.Tax.ATO.Depreciation: type DepreciationMethod a = Day -> EffectiveLife -> (Money a, Money a) -> Money a
+ Data.Tax.ATO.Depreciation: type EffectiveLife = Rational
+ Data.Tax.ATO.FY: daysInYear :: Year -> Integer
+ Data.Tax.ATO.FY: daysInYearFromProxy :: forall (y :: Nat). FinancialYear y => Proxy y -> Integer
+ Data.Tax.ATO.FY: fromProxy :: forall (y :: Nat). FinancialYear y => Proxy y -> Year
+ Data.Tax.ATO.FY.FY2017: fyProxy :: Proxy FY
+ Data.Tax.ATO.FY.FY2017: type FY = 2017
+ Data.Tax.ATO.FY.FY2025: fyProxy :: Proxy FY
+ Data.Tax.ATO.FY.FY2025: tables :: (Ord a, Fractional a) => TaxTables FY a
+ Data.Tax.ATO.FY.FY2025: type FY = 2025
+ Data.Tax.ATO.PaymentSummary: EmployerFBTExempt :: FBTEmployerExemption
+ Data.Tax.ATO.PaymentSummary: EmployerNotFBTExempt :: FBTEmployerExemption
+ Data.Tax.ATO.PaymentSummary: GrossPaymentsTypeF :: GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: GrossPaymentsTypeH :: GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: GrossPaymentsTypeJ :: GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: GrossPaymentsTypeP :: GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: LumpSumATypeR :: LumpSumAType
+ Data.Tax.ATO.PaymentSummary: LumpSumATypeT :: LumpSumAType
+ Data.Tax.ATO.PaymentSummary: ReportableFringeBenefits :: Money a -> FBTEmployerExemption -> ReportableFringeBenefits a
+ Data.Tax.ATO.PaymentSummary: allowance :: RealFrac a => String -> Money a -> Allowance a
+ Data.Tax.ATO.PaymentSummary: allowanceAmount :: forall a b f. Functor f => (Money a -> f (Money b)) -> Allowance a -> f (Allowance b)
+ Data.Tax.ATO.PaymentSummary: allowanceDetail :: forall a f. Functor f => (String -> f String) -> Allowance a -> f (Allowance a)
+ Data.Tax.ATO.PaymentSummary: allowances :: forall a f. Functor f => ([Allowance a] -> f [Allowance a]) -> PaymentSummaryIndividualNonBusiness a -> f (PaymentSummaryIndividualNonBusiness a)
+ Data.Tax.ATO.PaymentSummary: class HasGrossPayments (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasGrossPaymentsType (s :: k -> Type) a
+ Data.Tax.ATO.PaymentSummary: class HasLumpSumA (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasLumpSumD (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasLumpSumE (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasPayerDetails (s :: k -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasReportableEmployerSuperannuationContributions (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasReportableFringeBenefits (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: class HasTotalTaxWithheld (s :: Type -> Type)
+ Data.Tax.ATO.PaymentSummary: data Allowance a
+ Data.Tax.ATO.PaymentSummary: data FBTEmployerExemption
+ Data.Tax.ATO.PaymentSummary: data GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: data GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: data LumpSumA a
+ Data.Tax.ATO.PaymentSummary: data LumpSumAType
+ Data.Tax.ATO.PaymentSummary: data PayerDetails
+ Data.Tax.ATO.PaymentSummary: data PaymentSummaryBusinessAndPersonalServicesIncome a
+ Data.Tax.ATO.PaymentSummary: data PaymentSummaryForeignEmployment a
+ Data.Tax.ATO.PaymentSummary: data PaymentSummaryIndividualNonBusiness a
+ Data.Tax.ATO.PaymentSummary: data PaymentSummaryWithholdingWhereABNNotQuoted a
+ Data.Tax.ATO.PaymentSummary: data ReportableFringeBenefits a
+ Data.Tax.ATO.PaymentSummary: exemptForeignEmploymentIncome :: forall a f. Functor f => (Money a -> f (Money a)) -> PaymentSummaryIndividualNonBusiness a -> f (PaymentSummaryIndividualNonBusiness a)
+ Data.Tax.ATO.PaymentSummary: foreignTaxPaid :: forall a f. Functor f => (Money a -> f (Money a)) -> PaymentSummaryForeignEmployment a -> f (PaymentSummaryForeignEmployment a)
+ Data.Tax.ATO.PaymentSummary: fringeBenefitsEmployerExempt :: Money a -> Maybe (ReportableFringeBenefits a)
+ Data.Tax.ATO.PaymentSummary: fringeBenefitsEmployerNotExempt :: Money a -> Maybe (ReportableFringeBenefits a)
+ Data.Tax.ATO.PaymentSummary: grossPayments :: HasGrossPayments s => Lens' (s a) (Money a)
+ Data.Tax.ATO.PaymentSummary: grossPaymentsType :: forall (any :: k). HasGrossPaymentsType s a => Lens' (s any) a
+ Data.Tax.ATO.PaymentSummary: grossPaymentsTypeH :: Maybe GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: grossPaymentsTypeP :: Maybe GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.String.IsString Data.Tax.ATO.PaymentSummary.PayerDetails
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryWithholdingWhereABNNotQuoted a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.PaymentSummary.PaymentSummaryWithholdingWhereABNNotQuoted a a
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPayments Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPayments Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPayments Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPayments Data.Tax.ATO.PaymentSummary.PaymentSummaryWithholdingWhereABNNotQuoted
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPaymentsType Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasGrossPaymentsType Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness (GHC.Maybe.Maybe Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeIndividualNonBusiness)
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumA Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumA Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumD Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumD Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumE Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasLumpSumE Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasPayerDetails Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasPayerDetails Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasPayerDetails Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasPayerDetails Data.Tax.ATO.PaymentSummary.PaymentSummaryWithholdingWhereABNNotQuoted
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasReportableEmployerSuperannuationContributions Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasReportableEmployerSuperannuationContributions Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasReportableEmployerSuperannuationContributions Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasReportableFringeBenefits Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasReportableFringeBenefits Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasTotalTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryBusinessAndPersonalServicesIncome
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasTotalTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasTotalTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance Data.Tax.ATO.PaymentSummary.HasTotalTaxWithheld Data.Tax.ATO.PaymentSummary.PaymentSummaryWithholdingWhereABNNotQuoted
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq Data.Tax.ATO.PaymentSummary.FBTEmployerExemption
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq Data.Tax.ATO.PaymentSummary.LumpSumAType
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq Data.Tax.ATO.PaymentSummary.PayerDetails
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.PaymentSummary.Allowance a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.PaymentSummary.LumpSumA a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.PaymentSummary.ReportableFringeBenefits a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord Data.Tax.ATO.PaymentSummary.FBTEmployerExemption
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeForeignEmployment
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord Data.Tax.ATO.PaymentSummary.GrossPaymentsTypeIndividualNonBusiness
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord Data.Tax.ATO.PaymentSummary.LumpSumAType
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord Data.Tax.ATO.PaymentSummary.PayerDetails
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Tax.ATO.PaymentSummary.Allowance a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Tax.ATO.PaymentSummary.LumpSumA a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Tax.ATO.PaymentSummary.ReportableFringeBenefits a)
+ Data.Tax.ATO.PaymentSummary: instance GHC.Real.RealFrac a => Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.PaymentSummary.PaymentSummaryForeignEmployment a a
+ Data.Tax.ATO.PaymentSummary: instance GHC.Real.RealFrac a => Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.PaymentSummary.PaymentSummaryIndividualNonBusiness a a
+ Data.Tax.ATO.PaymentSummary: lumpSumA :: HasLumpSumA s => Lens' (s a) (Maybe (LumpSumA a))
+ Data.Tax.ATO.PaymentSummary: lumpSumAAmount :: forall a b f. Functor f => (Money a -> f (Money b)) -> LumpSumA a -> f (LumpSumA b)
+ Data.Tax.ATO.PaymentSummary: lumpSumAType :: forall a f. Functor f => (LumpSumAType -> f LumpSumAType) -> LumpSumA a -> f (LumpSumA a)
+ Data.Tax.ATO.PaymentSummary: lumpSumATypeR :: RealFrac a => Money a -> LumpSumA a
+ Data.Tax.ATO.PaymentSummary: lumpSumATypeT :: RealFrac a => Money a -> LumpSumA a
+ Data.Tax.ATO.PaymentSummary: lumpSumB :: forall a f. Functor f => (Money a -> f (Money a)) -> PaymentSummaryIndividualNonBusiness a -> f (PaymentSummaryIndividualNonBusiness a)
+ Data.Tax.ATO.PaymentSummary: lumpSumD :: HasLumpSumD s => Lens' (s a) (Money a)
+ Data.Tax.ATO.PaymentSummary: lumpSumE :: HasLumpSumE s => Lens' (s a) (Money a)
+ Data.Tax.ATO.PaymentSummary: newPayerDetails :: ABN -> Maybe Int -> String -> PayerDetails
+ Data.Tax.ATO.PaymentSummary: newPaymentSummaryBusinessAndPersonalServicesIncome :: Num a => PayerDetails -> PaymentSummaryBusinessAndPersonalServicesIncome a
+ Data.Tax.ATO.PaymentSummary: newPaymentSummaryForeignEmployment :: Num a => PayerDetails -> PaymentSummaryForeignEmployment a
+ Data.Tax.ATO.PaymentSummary: newPaymentSummaryIndividualNonBusiness :: Num a => PayerDetails -> PaymentSummaryIndividualNonBusiness a
+ Data.Tax.ATO.PaymentSummary: newPaymentSummaryWithholdingWhereABNNotQuoted :: Num a => PayerDetails -> PaymentSummaryWithholdingWhereABNNotQuoted a
+ Data.Tax.ATO.PaymentSummary: pattern PaymentSummary :: Num a => PayerDetails -> Money a -> Money a -> Money a -> PaymentSummaryIndividualNonBusiness a
+ Data.Tax.ATO.PaymentSummary: payerABN :: Lens' PayerDetails ABN
+ Data.Tax.ATO.PaymentSummary: payerBranchNumber :: Lens' PayerDetails (Maybe Int)
+ Data.Tax.ATO.PaymentSummary: payerDetails :: forall (a :: k). HasPayerDetails s => Lens' (s a) PayerDetails
+ Data.Tax.ATO.PaymentSummary: payerName :: Lens' PayerDetails String
+ Data.Tax.ATO.PaymentSummary: reportableEmployerSuperannuationContributions :: HasReportableEmployerSuperannuationContributions s => Lens' (s a) (Money a)
+ Data.Tax.ATO.PaymentSummary: reportableFringeBenefits :: HasReportableFringeBenefits s => Lens' (s a) (Maybe (ReportableFringeBenefits a))
+ Data.Tax.ATO.PaymentSummary: totalTaxWithheld :: HasTotalTaxWithheld s => Lens' (s a) (Money a)
+ Data.Tax.ATO.Pretty: formatMoney :: Money Rational -> Doc
+ Data.Tax.ATO.TFN: asInt :: TFN -> Int
+ Data.Tax.ATO.TFN: asString :: TFN -> String
+ Data.Tax.ATO.TFN: data TFN
+ Data.Tax.ATO.TFN: fromInt :: Int -> Maybe TFN
+ Data.Tax.ATO.TFN: instance Data.String.IsString Data.Tax.ATO.TFN.TFN
+ Data.Tax.ATO.TFN: instance GHC.Classes.Eq Data.Tax.ATO.TFN.TFN
+ Data.Tax.ATO.TFN: instance GHC.Classes.Ord Data.Tax.ATO.TFN.TFN
+ Data.Tax.ATO.TFN: instance GHC.Show.Show Data.Tax.ATO.TFN.TFN
+ Data.Tax.ATO.TFN: parse :: String -> Maybe TFN
- Data.Tax.ATO: assessTax :: (FinancialYear y, RealFrac a) => TaxTables y a -> TaxReturnInfo y a -> TaxAssessment a
+ Data.Tax.ATO: assessTax :: forall (y :: Nat) a. (FinancialYear y, RealFrac a) => TaxTables y a -> TaxReturnInfo y a -> TaxAssessment a
- Data.Tax.ATO: cgtEvents :: Lens' (TaxReturnInfo y a) [CGTEvent a]
+ Data.Tax.ATO: cgtEvents :: forall (y :: Nat) a f. Functor f => ([CGTEvent a] -> f [CGTEvent a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: childSupportPaid :: Lens' (IncomeTests a) (Money a)
+ Data.Tax.ATO: childSupportPaid :: forall a f. Functor f => (Money a -> f (Money a)) -> IncomeTests a -> f (IncomeTests a)
- Data.Tax.ATO: class HasCapitalLossCarryForward a b
+ Data.Tax.ATO: class HasCapitalLossCarryForward (a :: Type -> Type) b
- Data.Tax.ATO: class HasTaxWithheld a b c
+ Data.Tax.ATO: class HasTaxWithheld (a :: k -> Type) (b :: k) c
- Data.Tax.ATO: costOfManagingTaxAffairs :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: costOfManagingTaxAffairs :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: data TaxReturnInfo y a
+ Data.Tax.ATO: data TaxReturnInfo (y :: Nat) a
- Data.Tax.ATO: deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: deductionForProjectPool :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: deductionForProjectPool :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: deductions :: Lens' (TaxReturnInfo y a) (Deductions a)
+ Data.Tax.ATO: deductions :: forall (y :: Nat) a f. Functor f => (Deductions a -> f (Deductions a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: dependentChildren :: Lens' (IncomeTests a) Integer
+ Data.Tax.ATO: dependentChildren :: forall a f. Functor f => (Integer -> f Integer) -> IncomeTests a -> f (IncomeTests a)
- Data.Tax.ATO: dividendDeductions :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: dividendDeductions :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: dividends :: Lens' (TaxReturnInfo y a) [Dividend a]
+ Data.Tax.ATO: dividends :: forall (y :: Nat) a f. Functor f => ([Dividend a] -> f [Dividend a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: ess :: Lens' (TaxReturnInfo y a) (ESSStatement a)
+ Data.Tax.ATO: ess :: forall (y :: Nat) a f. Functor f => ([ESSStatement a] -> f [ESSStatement a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: essDeferral :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essDeferral :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: essForeignSourceDiscounts :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essForeignSourceDiscounts :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: essPre2009 :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essPre2009 :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: essTFNAmounts :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essTFNAmounts :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: essTaxedUpfrontNoReduction :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essTaxedUpfrontNoReduction :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: essTaxedUpfrontReduction :: Lens' (ESSStatement a) (Money a)
+ Data.Tax.ATO: essTaxedUpfrontReduction :: forall a f. Functor f => (Money a -> f (Money a)) -> ESSStatement a -> f (ESSStatement a)
- Data.Tax.ATO: foreignIncome :: Lens' (TaxReturnInfo y a) (Money a)
+ Data.Tax.ATO: foreignIncome :: forall (y :: Nat) a f. Functor f => (Money a -> f (Money a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: foreignIncomeDeductions :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: foreignIncomeDeductions :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: foreignTaxOffset :: Lens' (Offsets a) (Money a)
+ Data.Tax.ATO: foreignTaxOffset :: forall a f. Functor f => (Money a -> f (Money a)) -> Offsets a -> f (Offsets a)
- Data.Tax.ATO: forestryManagedInvestmentSchemeDeduction :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: forestryManagedInvestmentSchemeDeduction :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: giftsOrDonations :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: giftsOrDonations :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: helpBalance :: Lens' (TaxReturnInfo y a) (Money a)
+ Data.Tax.ATO: helpBalance :: forall (y :: Nat) a f. Functor f => (Money a -> f (Money a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: incomeTests :: Lens' (TaxReturnInfo y a) (IncomeTests a)
+ Data.Tax.ATO: incomeTests :: forall (y :: Nat) a f. Functor f => (IncomeTests a -> f (IncomeTests a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: interest :: Lens' (TaxReturnInfo y a) (GrossAndWithheld a)
+ Data.Tax.ATO: interest :: forall (y :: Nat) a f. Functor f => (GrossAndWithheld a -> f (GrossAndWithheld a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: interestDeductions :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: interestDeductions :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: lowValuePoolDeduction :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: lowValuePoolDeduction :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: medicareLevyDue :: Getter (TaxAssessment a) (Money a)
+ Data.Tax.ATO: medicareLevyDue :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: mlsExemption :: Lens' (TaxReturnInfo y a) (Days y)
+ Data.Tax.ATO: mlsExemption :: forall (y :: Nat) a f. Functor f => (Days y -> f (Days y)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: newESSStatement :: Num a => ESSStatement a
+ Data.Tax.ATO: newESSStatement :: Num a => PayerDetails -> ESSStatement a
- Data.Tax.ATO: newTaxReturnInfo :: (FinancialYear y, Num a) => TaxReturnInfo y a
+ Data.Tax.ATO: newTaxReturnInfo :: forall (y :: Nat) a. (FinancialYear y, Num a) => TaxReturnInfo y a
- Data.Tax.ATO: newTaxReturnInfoForTables :: (FinancialYear y, Num a) => TaxTables y a -> TaxReturnInfo y a
+ Data.Tax.ATO: newTaxReturnInfoForTables :: forall (y :: Nat) a. (FinancialYear y, Num a) => TaxTables y a -> TaxReturnInfo y a
- Data.Tax.ATO: offsets :: Lens' (TaxReturnInfo y a) (Offsets a)
+ Data.Tax.ATO: offsets :: forall (y :: Nat) a f. Functor f => (Offsets a -> f (Offsets a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: otherDeductions :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: otherDeductions :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: otherWorkRelatedExpenses :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: otherWorkRelatedExpenses :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: paygInstalments :: Lens' (Offsets a) (Money a)
+ Data.Tax.ATO: paygInstalments :: forall a f. Functor f => (Money a -> f (Money a)) -> Offsets a -> f (Offsets a)
- Data.Tax.ATO: paygInstalmentsCredit :: Lens' (TaxAssessment a) (Money a)
+ Data.Tax.ATO: paygInstalmentsCredit :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: paymentSummaries :: Lens' (TaxReturnInfo y a) [PaymentSummary a]
+ Data.Tax.ATO: paymentSummaries :: forall (y :: Nat) a f. Functor f => ([PaymentSummaryIndividualNonBusiness a] -> f [PaymentSummaryIndividualNonBusiness a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: personalSuperannuationContributions :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: personalSuperannuationContributions :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: privateHealthInsurancePolicyDetails :: Lens' (TaxReturnInfo y a) [PrivateHealthInsurancePolicyDetail a]
+ Data.Tax.ATO: privateHealthInsurancePolicyDetails :: forall (y :: Nat) a f. Functor f => ([PrivateHealthInsurancePolicyDetail a] -> f [PrivateHealthInsurancePolicyDetail a]) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: privateHealthInsuranceRebateAdjustment :: Lens' (TaxAssessment a) (Money a)
+ Data.Tax.ATO: privateHealthInsuranceRebateAdjustment :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: sfssBalance :: Lens' (TaxReturnInfo y a) (Money a)
+ Data.Tax.ATO: sfssBalance :: forall (y :: Nat) a f. Functor f => (Money a -> f (Money a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: spouseContributionOffset :: Lens' (Offsets a) (Money a)
+ Data.Tax.ATO: spouseContributionOffset :: forall a f. Functor f => (Money a -> f (Money a)) -> Offsets a -> f (Offsets a)
- Data.Tax.ATO: spouseDetails :: Lens' (TaxReturnInfo y a) (Maybe (SpouseDetails a))
+ Data.Tax.ATO: spouseDetails :: forall (y :: Nat) a f. Functor f => (Maybe (SpouseDetails a) -> f (Maybe (SpouseDetails a))) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
- Data.Tax.ATO: spouseTaxableIncome :: Lens' (SpouseDetails a) (Money a)
+ Data.Tax.ATO: spouseTaxableIncome :: forall a f. Functor f => (Money a -> f (Money a)) -> SpouseDetails a -> f (SpouseDetails a)
- Data.Tax.ATO: studyAndTrainingLoanRepayment :: Lens' (TaxAssessment a) (Money a)
+ Data.Tax.ATO: studyAndTrainingLoanRepayment :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: targetForeignIncome :: Lens' (IncomeTests a) (Money a)
+ Data.Tax.ATO: targetForeignIncome :: forall a f. Functor f => (Money a -> f (Money a)) -> IncomeTests a -> f (IncomeTests a)
- Data.Tax.ATO: taxBalance :: Num a => Getter (TaxAssessment a) (Money a)
+ Data.Tax.ATO: taxBalance :: (Num a, Ord a) => Getter (TaxAssessment a) (Money a)
- Data.Tax.ATO: taxCGTAssessment :: Lens' (TaxAssessment a) (CGTAssessment a)
+ Data.Tax.ATO: taxCGTAssessment :: forall a f. Functor f => (CGTAssessment a -> f (CGTAssessment a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: taxDue :: Getter (TaxAssessment a) (Money a)
+ Data.Tax.ATO: taxDue :: forall a f. Functor f => (Money a -> f (Money a)) -> TaxAssessment a -> f (TaxAssessment a)
- Data.Tax.ATO: taxFreeGovernmentPensionsOrBenefits :: Lens' (IncomeTests a) (Money a)
+ Data.Tax.ATO: taxFreeGovernmentPensionsOrBenefits :: forall a f. Functor f => (Money a -> f (Money a)) -> IncomeTests a -> f (IncomeTests a)
- Data.Tax.ATO: workRelatedCarExpenses :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: workRelatedCarExpenses :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: workRelatedClothingLaundryAndDryCleaningExpenses :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: workRelatedClothingLaundryAndDryCleaningExpenses :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: workRelatedSelfEducationExpenses :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: workRelatedSelfEducationExpenses :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO: workRelatedTravelExpenses :: Lens' (Deductions a) (Money a)
+ Data.Tax.ATO: workRelatedTravelExpenses :: forall a f. Functor f => (Money a -> f (Money a)) -> Deductions a -> f (Deductions a)
- Data.Tax.ATO.CGT: cgtNetGain :: Num a => Getter (CGTAssessment a) (Money a)
+ Data.Tax.ATO.CGT: cgtNetGain :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
- Data.Tax.ATO.CGT: class HasCapitalGain a b c
+ Data.Tax.ATO.CGT: class HasCapitalGain (a :: k -> Type) (b :: k) c
- Data.Tax.ATO.CGT: class HasCapitalLossCarryForward a b
+ Data.Tax.ATO.CGT: class HasCapitalLossCarryForward (a :: Type -> Type) b
- Data.Tax.ATO.Common: TaxTables :: Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> PrivateHealthInsuranceRebateRates a -> TaxTables y a
+ Data.Tax.ATO.Common: TaxTables :: Tax (Money a) (Money a) -> MedicareLevyRatesAndThresholds a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> Tax (Money a) (Money a) -> PrivateHealthInsuranceRebateRates a -> TaxTables (y :: k) a
- Data.Tax.ATO.Common: [ttAdditional] :: TaxTables y a -> Tax (Money a) (Money a)
+ Data.Tax.ATO.Common: [ttAdditional] :: TaxTables (y :: k) a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Common: [ttHelp] :: TaxTables y a -> Tax (Money a) (Money a)
+ Data.Tax.ATO.Common: [ttHelp] :: TaxTables (y :: k) a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Common: [ttIndividualIncomeTax] :: TaxTables y a -> Tax (Money a) (Money a)
+ Data.Tax.ATO.Common: [ttIndividualIncomeTax] :: TaxTables (y :: k) a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Common: [ttMedicareLevySurcharge] :: TaxTables y a -> Tax (Money a) (Money a)
+ Data.Tax.ATO.Common: [ttMedicareLevySurcharge] :: TaxTables (y :: k) a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Common: [ttPHIRebateRates] :: TaxTables y a -> PrivateHealthInsuranceRebateRates a
+ Data.Tax.ATO.Common: [ttPHIRebateRates] :: TaxTables (y :: k) a -> PrivateHealthInsuranceRebateRates a
- Data.Tax.ATO.Common: [ttSfss] :: TaxTables y a -> Tax (Money a) (Money a)
+ Data.Tax.ATO.Common: [ttSfss] :: TaxTables (y :: k) a -> Tax (Money a) (Money a)
- Data.Tax.ATO.Common: class HasTaxableIncome a b c
+ Data.Tax.ATO.Common: class HasTaxableIncome (a :: k -> Type) (b :: k) c
- Data.Tax.ATO.Common: data TaxTables y a
+ Data.Tax.ATO.Common: data TaxTables (y :: k) a
- Data.Tax.ATO.FY: days :: forall a. FinancialYear a => Integer -> Days a
+ Data.Tax.ATO.FY: days :: forall (a :: Nat). FinancialYear a => Integer -> Days a
- Data.Tax.ATO.FY: daysAll :: forall a. FinancialYear a => Days a
+ Data.Tax.ATO.FY: daysAll :: forall (a :: Nat). FinancialYear a => Days a
- Data.Tax.ATO.FY: daysNone :: Days a
+ Data.Tax.ATO.FY: daysNone :: forall (a :: Nat). Days a
- Data.Tax.ATO.FY: financialYearRangeFromProxy :: forall n. FinancialYear n => Proxy n -> (Day, Day)
+ Data.Tax.ATO.FY: financialYearRangeFromProxy :: forall (n :: Nat). FinancialYear n => Proxy n -> (Day, Day)
- Data.Tax.ATO.FY: getFraction :: forall a frac. (FinancialYear a, Fractional frac) => Days a -> frac
+ Data.Tax.ATO.FY: getFraction :: forall (a :: Nat) frac. (FinancialYear a, Fractional frac) => Days a -> frac
- Data.Tax.ATO.Pretty: summariseTaxReturnInfo :: TaxReturnInfo y Rational -> Doc
+ Data.Tax.ATO.Pretty: summariseTaxReturnInfo :: forall (y :: Nat). TaxReturnInfo y Rational -> Doc

Files

CHANGELOG.md view
@@ -1,3 +1,112 @@+## Version 2025.1++### Features and enhancements++- Overhauled payment summaries.  More comprehensive data types and+  optics are provided in module `Data.Tax.ATO.PaymentSummary`.++  The old `PaymentSummary` constructor persists as a (deprecated)+  pattern synonym, for backwards compatibility.  It will be removed+  in a future release.++- Implemented **reportable fringe benefits**. .  Use the+  `fringeBenefitsEmployerNotExempt` or+  `fringeBenefitsEmployerExempt` constructors, along with the+  `reportableFringeBenefits` lens to add it to the payment summary.+  The amount is properly included in the surcharge and student loan+  repayment income calculations.++- Implemented **allowances**.  A list of allowances can be added to+  a payment summary via the `allowances` lens.  Construct allowance+  values with `allowance :: String -> Money a -> Allowance a`.++- Implemented **non-super lump sum A, B, D and E** payments.++- Implemented additional payment summary types:+  - Foreign Employment+  - Business and personal services income+  - Withholding where ABN not quoted++- New module `Data.Tax.ATO.Depreciation` provides types and+  functions for calculating decline in value (for deductions).+  Use the `DepreciatingAsset` data type to define depreciating+  assets, and the `declineInValue` function for calculating the+  decline in value in a given financial year.++- Added the "cents-per-kilometre" method for car expense deductions.+  Usage: `applyCentsPerKilometreMethod @FY kms`.  ([#13])++- Added home office expense deduction methods ([#7]).  Usage++  ```+  applyFixedRateMethod @FY hours+  applyShortcutMethod @FY hours+  applyFixedRateMethodPre2023 @FY hours+  ```++- Implement Medicare levy low income family thresholds, including+  increase based on number of dependents.  Senior and pensioners+  individual and family thresholds remain unimplemented.++- CGT assessment types were overhauled and now contain more+  information about total capital gain and applied / unapplied+  losses.  This is step toward a more complete CGT implementation.+  Remaining gaps include foreign withholding credits and separate+  treatment of collectables.++- Multiple ESS statements can now be added to a tax return.  Also,+  the `essEmployeeDetails` field has been added, and+  `newESSStatement` was updated to take a `PayerDetails`.  This is a+  breaking change.  ([#16])++- Added `division293Income` which calculates the income component of+  Division 293 tax calculations.  Some elements are not included+  because the relevant feature is not yet implemented (e.g. rental+  losses or FHSS releases).  ([#12])++- Added `paygInstalmentIncome`, which calculates the PAYG instalment+  income.  Some elements are not included because the relevant+  features are not yet implement (e.g. rent, partnership and trust+  income, PSI).++- Added the `Data.Tax.ATO.ABN` and `Data.Tax.ATO.TFN` modules, which+  have more representative data types, conversion functions, and+  proper validation.  `IsString` instances are provided for+  compatibility with existing code.++- `TaxReturnInfo` pretty printing now includes more detailed ESS and+  CGT data, to help with preparation of tax returns.++- `TaxAssessment` pretty printing now separately reports Medicare+  levy, Medicare levy surcharge, and the various non-refundable and+  refundable tax offsets.  The formatting closely resembles the ATO+  *notice of assessment* layout.++- Add `FY2025` module.  All rates and thresholds are up to date.++- Added some new helper functions to the `Data.Tax.ATO.FY` module:+  - `fromProxy :: (FinancialYear y) => Proxy y -> Year`+  - `daysInYear :: Year -> Integer`+  - `daysInYearFromProxy :: FinancialYear y => Proxy y -> Integer`++### Bug fixes++- Non-refundable offsets now cannot reduce liability below $0, and+  the order of application of the various liabilities, offsets and+  credits has been fixed.++- Employee share scheme TFN amounts withheld are now included in+  assessment calculations ([#8]).++- Fix FY2024 private health insurance rebate tier thresholds.++[#7]: https://github.com/frasertweedale/hs-tax-ato/issues/7+[#8]: https://github.com/frasertweedale/hs-tax-ato/issues/8+[#12]: https://github.com/frasertweedale/hs-tax-ato/issues/12+[#13]: https://github.com/frasertweedale/hs-tax-ato/issues/13+[#16]: https://github.com/frasertweedale/hs-tax-ato/issues/16++ ## Version 2024.1  - The minimum supported version of GHC is now 9.2, due to a
src/Data/Tax/ATO.hs view
@@ -1,7 +1,5 @@-{-# LANGUAGE PolyKinds #-}- -- This file is part of hs-tax-ato--- Copyright (C) 2018-2021  Fraser Tweedale+-- Copyright (C) 2018-2025  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@@ -25,14 +23,11 @@ Lots of things are not implemented, including (but not limited to): __ETPs__, income from __partnerships and trusts__, __superannuation__ income streams and lump payments, tax losses from-previous years, __Medicare levy reduction/exemption__, adjustments,+previous years, Medicare levy exemptions, adjustments, and variations based on family income and dependents.  -} -{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}- module Data.Tax.ATO   (   -- * Synopsis@@ -42,14 +37,15 @@     TaxReturnInfo   , newTaxReturnInfo   , newTaxReturnInfoForTables-  , taxableIncome    -- ** Income    -- *** PAYG Payment Summaries-  , PaymentSummary(..)+  , paymentSummariesIndividualNonBusiness+  , paymentSummariesForeignEmployment+  , paymentSummariesBusinessAndPersonalServicesIncome+  , paymentSummariesWithholdingWhereABNNotQuoted   , paymentSummaries-  , ABN    -- *** Interest   , interest@@ -70,6 +66,7 @@   , ESSStatement   , newESSStatement   , ess+  , essEmployerDetails   , essTaxedUpfrontReduction   , essTaxedUpfrontNoReduction   , essDeferral@@ -124,6 +121,16 @@   , otherDeductions   , foreignIncomeDeductions +  -- *** Deduction methods+  , HasCentsPerKilometreMethod+  , applyCentsPerKilometreMethod+  , HasFixedRateMethod+  , applyFixedRateMethod+  , HasFixedRateMethodPre2023+  , applyFixedRateMethodPre2023+  , HasShortcutMethod+  , applyShortcutMethod+   -- ** Tax offsets   , Offsets   , offsets@@ -136,34 +143,50 @@   , assessTax   , taxBalance   , taxDue+  , offsetForSuperannuationContributionsOnBehalfOfYourSpouse+  , foreignIncomeTaxOffsets+  , frankingCreditOffset   , medicareLevyDue+  , medicareLevySurchargeDue   , studyAndTrainingLoanRepayment-  , taxCreditsAndOffsets   , paygInstalmentsCredit   , taxCGTAssessment   , privateHealthInsuranceRebateAdjustment +  -- *** Division 293+  , division293Income++  -- *** PAYG instalments+  , paygInstalmentIncome+   -- * Corporate tax   , corporateTax    -- * Miscellaneous   , GrossAndWithheld(..)+  , HasTaxableIncome(..)   , HasTaxWithheld(..)   , Proportion   , getProportion   , proportion   , module Data.Tax+  , module Data.Tax.ATO.ABN+  , module Data.Tax.ATO.Depreciation+  , module Data.Tax.ATO.PaymentSummary   , module Data.Tax.ATO.PrivateHealthInsuranceRebate   , module Data.Tax.ATO.Rounding   ) where -import Control.Lens (Getter, Lens', (&), foldOf, lens, set, to, view, views)+import Control.Lens (Getter, Lens', (&), foldOf, lens, preview, set, to, view, views) import Data.Time (Day)  import Data.Tax import Data.Tax.ATO.CGT+import Data.Tax.ATO.ABN (ABN) import Data.Tax.ATO.Common+import Data.Tax.ATO.Depreciation import Data.Tax.ATO.FY+import Data.Tax.ATO.PaymentSummary import Data.Tax.ATO.PrivateHealthInsuranceRebate import Data.Tax.ATO.Rounding @@ -181,7 +204,7 @@ import "Data.Tax.ATO.Pretty"  -- Import the tables for the financial year ending 30 June 2024-import qualified "Data.Tax.ATO.FY.FY2024" as FY+import "Data.Tax.ATO.FY.FY2025"  -- Convenience function for parsing a Data.Time.Day day :: String -> Day@@ -189,19 +212,19 @@  main :: IO () main = do-  let assessment = 'assessTax' FY.tables taxReturn+  let assessment = 'assessTax' tables taxReturn   putStrLn . render $ 'Data.Tax.ATO.Pretty.summariseTaxReturnInfo' taxReturn   putStrLn ""   putStrLn . render $ 'Data.Tax.ATO.Pretty.summariseAssessment' assessment -taxReturn :: 'TaxReturnInfo' FY.FY Rational+taxReturn :: 'TaxReturnInfo' FY Rational taxReturn = 'newTaxReturnInfo'-  & set 'paymentSummaries'-      [ 'PaymentSummary'-          "1234567890"      -- ABN-          (Money $ 180000)  -- Gross payments-          (Money 50000)     -- Tax withheld-          mempty            -- Reportable super contributions+  & set 'paymentSummariesIndividualNonBusiness'+      [ 'newPaymentSummaryIndividualNonBusiness' \"53 004 085 616\"  -- ABN+          & set 'grossPayments'                                       (Money 180000)+          & set 'totalTaxWithheld'                                    (Money  50000)+          & set 'reportableEmployerSuperannuationContributions'       (Money   3000)+          & set 'reportableFringeBenefits' ('fringeBenefitsEmployerNotExempt' $ Money 7274)       ]    & set 'cgtEvents'@@ -239,20 +262,12 @@           "MBF" "98765432" (Money 250) (Money  60) 'BenefitCode31'       ] -  & set ('deductions' . 'workRelatedTravelExpenses') (Money 1000)+  & set ('deductions' . 'workRelatedCarExpenses') ('applyCentsPerKilometreMethod' @FY 3333)   & set ('deductions' . 'personalSuperannuationContributions') (Money 5000) @  -} --- | Data that can have an amount of tax withheld-class HasTaxWithheld a b c where-  taxWithheld :: Getter (a b) (Money c)--instance (Foldable t, HasTaxWithheld x a a, Num a)-            => HasTaxWithheld t (x a) a where-  taxWithheld = to (foldMap (view taxWithheld))- -- TODO part year spouse newtype SpouseDetails a = SpouseDetails   { _spouseTaxableIncome :: Money a@@ -301,46 +316,60 @@ -- -- The following lenses are available: ----- +---------------------------------------+----------------------------------+--- | 'mlsExemption'                        | Medicare levy exemption          |--- +---------------------------------------+----------------------------------+--- | 'helpBalance'                         | HELP, VSL, SSL, ABSTUDY SSL,     |--- |                                       | and TSL account balance          |--- +---------------------------------------+----------------------------------+--- | 'sfssBalance'                         | SFSS account balance             |--- +---------------------------------------+----------------------------------+--- | 'paymentSummaries'                    | PAYG payment summaries           |--- +---------------------------------------+----------------------------------+--- | 'interest'                            | Interest income and tax withheld |--- +---------------------------------------+----------------------------------+--- | 'dividends'                           | Dividend data                    |--- +---------------------------------------+----------------------------------+--- | 'ess'                                 | Employee Share Scheme statement  |--- +---------------------------------------+----------------------------------+--- | 'foreignIncome'                       | Foreign income                   |--- +---------------------------------------+----------------------------------+--- | 'cgtEvents'                           | Capital gains and losses         |--- +---------------------------------------+----------------------------------+--- | 'deductions'                          | Deductions                       |--- +---------------------------------------+----------------------------------+--- | 'offsets'                             | Tax offsets                      |--- +---------------------------------------+----------------------------------+--- | 'privateHealthInsurancePolicyDetails' | Private health insurance         |--- |                                       | policy details                   |--- +---------------------------------------+----------------------------------+--- | 'spouseDetails'                       | Spouse Details (or @Nothing@)    |--- +---------------------------------------+----------------------------------+--- | 'incomeTests'                         | Income Tests                     |--- +---------------------------------------+----------------------------------++-- +------------------------------------------------------+----------------------------------++-- | 'mlsExemption'                                       | Medicare levy exemption          |+-- +------------------------------------------------------+----------------------------------++-- | 'helpBalance'                                        | HELP, VSL, SSL, ABSTUDY SSL,     |+-- |                                                      | and AASL/TSL account balance     |+-- +------------------------------------------------------+----------------------------------++-- | 'sfssBalance'                                        | SFSS account balance             |+-- +------------------------------------------------------+----------------------------------++-- | 'paymentSummariesIndividualNonBusiness'              | PAYG payment summaries -         |+-- |                                                      | individual non-business          |+-- +------------------------------------------------------+----------------------------------++-- | 'paymentSummariesForeignEmployment'                  | PAYG payment summaries -         |+-- |                                                      | foreign employment               |+-- +------------------------------------------------------+----------------------------------++-- | 'paymentSummariesBusinessAndPersonalServicesIncome'  | PAYG payment summaries -         |+-- |                                                      | business and personal services   |+-- |                                                      | income                           |+-- +------------------------------------------------------+----------------------------------++-- | 'paymentSummariesWithholdingWhereABNNotQuoted'       | PAYG payment summaries -         |+-- |                                                      | withholding where ABN not quoted |+-- +------------------------------------------------------+----------------------------------++-- | 'interest'                                           | Interest income and tax withheld |+-- +------------------------------------------------------+----------------------------------++-- | 'dividends'                                          | Dividend data                    |+-- +------------------------------------------------------+----------------------------------++-- | 'ess'                                                | Employee Share Scheme statement  |+-- +------------------------------------------------------+----------------------------------++-- | 'foreignIncome'                                      | Foreign income                   |+-- +------------------------------------------------------+----------------------------------++-- | 'cgtEvents'                                          | Capital gains and losses         |+-- +------------------------------------------------------+----------------------------------++-- | 'deductions'                                         | Deductions                       |+-- +------------------------------------------------------+----------------------------------++-- | 'offsets'                                            | Tax offsets                      |+-- +------------------------------------------------------+----------------------------------++-- | 'privateHealthInsurancePolicyDetails'                | Private health insurance         |+-- |                                                      | policy details                   |+-- +------------------------------------------------------+----------------------------------++-- | 'spouseDetails'                                      | Spouse Details (or @Nothing@)    |+-- +------------------------------------------------------+----------------------------------++-- | 'incomeTests'                                        | Income Tests                     |+-- +------------------------------------------------------+----------------------------------+ -- data TaxReturnInfo y a = TaxReturnInfo   { _mlsExemption :: Days y   , _helpBalance :: Money a   , _sfssBalance :: Money a-  , _paymentSummaries :: [PaymentSummary a]+  , _paymentSummariesIndividualNonBusiness :: [PaymentSummaryIndividualNonBusiness a]+  , _paymentSummariesForeignEmployment :: [PaymentSummaryForeignEmployment a]+  , _paymentSummariesBusinessAndPersonalServicesIncome :: [PaymentSummaryBusinessAndPersonalServicesIncome a]+  , _paymentSummariesWithholdingWhereABNNotQuoted :: [PaymentSummaryWithholdingWhereABNNotQuoted a]   , _interest :: GrossAndWithheld a   , _dividends :: [Dividend a]-  , _ess :: ESSStatement a+  , _ess :: [ESSStatement a]   , _foreignIncome :: Money a   , _cgtEvents :: [CGTEvent a]   , _deductions :: Deductions a@@ -366,7 +395,10 @@   daysAll  -- MLS exemption   mempty -- HELP   mempty -- SFSS-  mempty -- payment summaries+  [] -- payment summaries - individual non-business+  [] -- payment summaries - foreign employment+  [] -- payment summaries - business and personal services income+  [] -- payment summaries - withholding where ABN not quoted   mempty -- interest   mempty -- dividends   mempty -- ESS@@ -408,16 +440,34 @@ mlsExemption :: Lens' (TaxReturnInfo y a) (Days y) mlsExemption = lens _mlsExemption (\s b -> s { _mlsExemption = b }) -paymentSummaries :: Lens' (TaxReturnInfo y a) [PaymentSummary a]-paymentSummaries = lens _paymentSummaries (\s b -> s { _paymentSummaries = b })+paymentSummariesIndividualNonBusiness :: Lens' (TaxReturnInfo y a) [PaymentSummaryIndividualNonBusiness a]+paymentSummariesIndividualNonBusiness =+  lens _paymentSummariesIndividualNonBusiness (\s b -> s { _paymentSummariesIndividualNonBusiness = b }) +paymentSummariesForeignEmployment :: Lens' (TaxReturnInfo y a) [PaymentSummaryForeignEmployment a]+paymentSummariesForeignEmployment =+  lens _paymentSummariesForeignEmployment (\s b -> s { _paymentSummariesForeignEmployment = b })++paymentSummariesBusinessAndPersonalServicesIncome :: Lens' (TaxReturnInfo y a) [PaymentSummaryBusinessAndPersonalServicesIncome a]+paymentSummariesBusinessAndPersonalServicesIncome =+  lens _paymentSummariesBusinessAndPersonalServicesIncome (\s b -> s { _paymentSummariesBusinessAndPersonalServicesIncome = b })++paymentSummariesWithholdingWhereABNNotQuoted :: Lens' (TaxReturnInfo y a) [PaymentSummaryWithholdingWhereABNNotQuoted a]+paymentSummariesWithholdingWhereABNNotQuoted =+  lens _paymentSummariesWithholdingWhereABNNotQuoted (\s b -> s { _paymentSummariesWithholdingWhereABNNotQuoted = b })++-- | Deprecated synonym for 'paymentSummariesIndividualNonBusiness'+paymentSummaries :: Lens' (TaxReturnInfo y a) [PaymentSummaryIndividualNonBusiness a]+paymentSummaries = paymentSummariesIndividualNonBusiness+{-# DEPRECATED paymentSummaries "use 'paymentSummariesIndividualNonBusiness'" #-}+ interest :: Lens' (TaxReturnInfo y a) (GrossAndWithheld a) interest = lens _interest (\s b -> s { _interest = b })  dividends :: Lens' (TaxReturnInfo y a) [Dividend a] dividends = lens _dividends (\s b -> s { _dividends = b }) -ess :: Lens' (TaxReturnInfo y a) (ESSStatement a)+ess :: Lens' (TaxReturnInfo y a) [ESSStatement a] ess = lens _ess (\s b -> s { _ess = b })  foreignIncome :: Lens' (TaxReturnInfo y a) (Money a)@@ -448,9 +498,12 @@ data TaxAssessment a = TaxAssessment   { _taxableIncome :: Money a   , _taxDue :: Money a+  , _taSpouseContributionOffset :: Money a+  , _taForeignIncomeTaxOffset :: Money a+  , _taFrankingCreditOffset :: Money a   , _medicareLevyDue :: Money a+  , _medicareLevySurchargeDue :: Money a   , _taxWithheld :: Money a-  , _taxCreditsAndOffsets :: Money a   , _taCGTAssessment :: CGTAssessment a   , _phiAdj :: Money a   , _studyAndTrainingLoanRepayment :: Money a@@ -463,15 +516,29 @@ instance HasTaxWithheld TaxAssessment a a where   taxWithheld = to _taxWithheld -taxDue :: Getter (TaxAssessment a) (Money a)-taxDue = to _taxDue+taxDue :: Lens' (TaxAssessment a) (Money a)+taxDue = lens _taxDue (\s b -> s { _taxDue = b }) -medicareLevyDue :: Getter (TaxAssessment a) (Money a)-medicareLevyDue = to _medicareLevyDue+offsetForSuperannuationContributionsOnBehalfOfYourSpouse :: Lens' (TaxAssessment a) (Money a)+offsetForSuperannuationContributionsOnBehalfOfYourSpouse =+  lens _taSpouseContributionOffset (\s b -> s { _taSpouseContributionOffset = b }) -taxCreditsAndOffsets :: Getter (TaxAssessment a) (Money a)-taxCreditsAndOffsets = to _taxCreditsAndOffsets+foreignIncomeTaxOffsets :: Lens' (TaxAssessment a) (Money a)+foreignIncomeTaxOffsets =+  lens _taForeignIncomeTaxOffset (\s b -> s { _taForeignIncomeTaxOffset = b }) +frankingCreditOffset :: Lens' (TaxAssessment a) (Money a)+frankingCreditOffset =+  lens _taFrankingCreditOffset (\s b -> s { _taFrankingCreditOffset = b })++medicareLevyDue :: Lens' (TaxAssessment a) (Money a)+medicareLevyDue =+  lens _medicareLevyDue (\s b -> s { _medicareLevyDue = b })++medicareLevySurchargeDue :: Lens' (TaxAssessment a) (Money a)+medicareLevySurchargeDue =+  lens _medicareLevySurchargeDue (\s b -> s { _medicareLevySurchargeDue = b })+ taxCGTAssessment :: Lens' (TaxAssessment a) (CGTAssessment a) taxCGTAssessment = lens _taCGTAssessment (\s b -> s { _taCGTAssessment = b }) @@ -488,17 +555,27 @@  -- | What is the balance of the assessment?  Positive means a -- refund (tax withheld exceeds obligation), negative means a bill.-taxBalance :: Num a => Getter (TaxAssessment a) (Money a)-taxBalance = to $ \a ->-  view taxWithheld a-  $-$ view taxDue a-  $-$ view medicareLevyDue a-  $-$ view studyAndTrainingLoanRepayment a-  $-$ view privateHealthInsuranceRebateAdjustment a-  $+$ view taxCreditsAndOffsets a-  $+$ view paygInstalmentsCredit a+taxBalance :: (Num a, Ord a) => Getter (TaxAssessment a) (Money a)+taxBalance = to $ fmap negate . \a ->+  max (Money 0) (+    -- tax on taxable income+    view taxDue a+    -- less non-refundable offsets+    $-$ view offsetForSuperannuationContributionsOnBehalfOfYourSpouse a+    $-$ view foreignIncomeTaxOffsets a+  )+  -- less refundable tax offsets+  $-$ view frankingCreditOffset a+  -- plus other liabilities+  $+$ view medicareLevyDue a+  $+$ view medicareLevySurchargeDue a+  $+$ view privateHealthInsuranceRebateAdjustment a+  $+$ view studyAndTrainingLoanRepayment a+  -- less PAYG credits and other entitlements+  $-$ view taxWithheld a+  $-$ view paygInstalmentsCredit a -instance (Num a, Eq a) => HasCapitalLossCarryForward TaxAssessment a where+instance HasCapitalLossCarryForward TaxAssessment a where   capitalLossCarryForward = taxCGTAssessment . capitalLossCarryForward  @@ -523,31 +600,16 @@   limit (view helpBalance info) (ttHelp table)   <> limit (view sfssBalance info) (ttSfss table) --- | Medicare levy + surcharge-medicareLevyTax-  :: (FinancialYear y, Fractional a)-  => TaxTables y a-  -> TaxReturnInfo y a-  -> Tax (Money a) (Money a)    -- grand unified individual income tax-medicareLevyTax table info =-  let-    ml = ttMedicareLevy table-    mls = ttMedicareLevySurcharge table-    mlsFrac = 1 - getFraction (view mlsExemption info)-  in-    -- TODO medicare levy exemption-    ml-    -- FIXME income for MLS purposes includes-    -- fringe benefits; family thresholds apply-    <> fmap ($* mlsFrac) mls- -- | Taxable income instance (RealFrac a) => HasTaxableIncome (TaxReturnInfo y) a a where   taxableIncome = to $ \info ->     let       cf = view capitalLossCarryForward info       gross = foldMap wholeDollars-        [ view (paymentSummaries . taxableIncome) info+        [ view (paymentSummariesIndividualNonBusiness . taxableIncome) info+        , view (paymentSummariesForeignEmployment . taxableIncome) info+        , view (paymentSummariesBusinessAndPersonalServicesIncome . taxableIncome) info+        , view (paymentSummariesWithholdingWhereABNNotQuoted . taxableIncome) info         , view (interest . taxableIncome) info         , view (dividends . taxableIncome) info         , view (ess . taxableIncome) info@@ -557,13 +619,67 @@     in       wholeDollars (gross $-$ views deductions totalDeductions info) --- | Includes PAYG withholding by employer or bank.--- Does not include franking credits.+-- | Includes PAYG withholding by employer, and TFN+-- amounts withheld e.g. from bank interest, ESS discounts, etc.+--+-- Does not include franking credits (which are a refundable offset).+-- instance (Num a) => HasTaxWithheld (TaxReturnInfo y) a a where   taxWithheld = to $ \info ->-    view (paymentSummaries . taxWithheld) info+    view (paymentSummariesIndividualNonBusiness . taxWithheld) info+    <> view (paymentSummariesForeignEmployment . taxWithheld) info+    <> view (paymentSummariesBusinessAndPersonalServicesIncome . taxWithheld) info+    <> view (paymentSummariesWithholdingWhereABNNotQuoted . taxWithheld) info     <> view (interest . taxWithheld) info+    <> view (ess . taxWithheld) info +fringeBenefits :: (Num a) => TaxReturnInfo y a -> Money a+fringeBenefits info =+  foldOf l'inb info+  <> foldOf l'foreign info+  where+    l'inb =+      paymentSummariesIndividualNonBusiness . traverse+      . reportableFringeBenefits . traverse+      . to (\(ReportableFringeBenefits amount _) -> amount)+    l'foreign =+      paymentSummariesForeignEmployment . traverse+      . reportableFringeBenefits . traverse+      . to (\(ReportableFringeBenefits amount _) -> amount)++reportableSuperContributions :: (Num a) => TaxReturnInfo y a -> Money a+reportableSuperContributions info =+  foldOf (paymentSummariesIndividualNonBusiness . traverse . reportableEmployerSuperannuationContributions) info+  <> foldOf (paymentSummariesForeignEmployment . traverse . reportableEmployerSuperannuationContributions) info+  <> foldOf (paymentSummariesBusinessAndPersonalServicesIncome . traverse . reportableEmployerSuperannuationContributions) info+  <> view (deductions . personalSuperannuationContributions) info++-- | Calculate Division 293 income+division293Income :: (RealFrac a) => TaxReturnInfo y a -> Money a+division293Income info =+  view taxableIncome info+  <> fringeBenefits info+  -- TODO net financial investment loss+  -- TODO net rental property loss+  -- TODO net amount on which family trust distribution has been paid+  -- TODO super lump sum taxed elements with zero tax rate+  -- TODO assessable FHSS released amount++paygInstalmentIncome :: (RealFrac a) => TaxReturnInfo y a -> Money a+paygInstalmentIncome info =+  -- TODO gross rent+  view (dividends . taxableIncome) info+  -- TODO royalties?+  -- TODO foreign pensions assessable in Australia+  -- TODO share of income from partnerships and trusts+  <> view foreignIncome info+  <> view (interest . taxableIncome) info+  -- TODO business income (incl PSI etc)+  <> view (paymentSummariesWithholdingWhereABNNotQuoted . taxableIncome) info+  -- TODO gross income where tax withheld due to not provide TFN+  -- TODO withdrawal from farm management deposits+  -- TODO fuel tax credits+ -- | Assess a tax return, given tax tables and tax return info. assessTax   :: (FinancialYear y, RealFrac a)@@ -574,20 +690,47 @@           (view capitalLossCarryForward info) (view cgtEvents info)     taxable = view taxableIncome info     due = getTax (individualTax tables) taxable-    studyRepayment = getTax (studyAndTrainingLoanRepaymentTax tables info) taxable-    mlAndMLS = getTax (medicareLevyTax tables info) taxable -    incomeForSurchargePurposes =+    exemptForeignIncome =+      foldOf (paymentSummariesIndividualNonBusiness . traverse . exemptForeignEmploymentIncome) info++    repaymentIncome =       taxable-      -- TODO reportable fringe benefits-      -- TODO net investment losses-      <> foldOf (paymentSummaries . traverse . to reportableEmployerSuperannuationContributions) info+      <> fringeBenefits info+      -- TODO net financial investment losses+      -- TODO net rental property losses+      <> reportableSuperContributions info+      <> exemptForeignIncome +    studyRepayment = getTax (studyAndTrainingLoanRepaymentTax tables info) repaymentIncome++    ml = medicareLevy'+          (ttMedicareLevyRatesAndThresholds tables)+          taxable+          (preview (spouseDetails . traverse . spouseTaxableIncome) info)+          (view (incomeTests . dependentChildren) info)++    surchargeIncome =+      taxable+      <> fringeBenefits info+      -- TODO net financial investment losses+      -- TODO net rental property losses+      <> reportableSuperContributions info+      -- TODO spouse's share of net income of a trust on which the trustee+      --      must pay tax, if not included in taxable income+      <> ( if taxable > mempty then exemptForeignIncome else mempty )+      -- TODO reduction by taxed element of super lump sum++    mls =+      let mlsFrac = 1 - getFraction (view mlsExemption info)+      -- TODO family thresholds apply+      in getTax (fmap ($* mlsFrac) (ttMedicareLevySurcharge tables)) surchargeIncome+     spouseIncomeForSurchargePurposes =       fmap (view spouseTaxableIncome) (view spouseDetails info)      phiAdj = assessExcessPrivateHealthRebate-      incomeForSurchargePurposes+      surchargeIncome       spouseIncomeForSurchargePurposes       (view (incomeTests . dependentChildren) info)       (ttPHIRebateRates tables)@@ -595,7 +738,7 @@      foreignIncomeTaxOffsetLimit =       let-        step1 = due <> mlAndMLS+        step1 = due <> ml <> mls         step2 =           let             info' = info & set foreignIncome mempty@@ -603,48 +746,41 @@               view taxableIncome info'               <> view (deductions . foreignIncomeDeductions) info'             due' = getTax (individualTax tables) taxable'-            mlAndMLS' = getTax (medicareLevyTax tables info') taxable'+            ml' = medicareLevy'+                    (ttMedicareLevyRatesAndThresholds tables)+                    taxable+                    (preview (spouseDetails . traverse . spouseTaxableIncome) info)+                    (view (incomeTests . dependentChildren) info)+            mls' =+              let mlsFrac = 1 - getFraction (view mlsExemption info)+              -- FIXME income for MLS purposes includes fringe benefits; family thresholds apply+              in getTax (fmap ($* mlsFrac) (ttMedicareLevySurcharge tables)) taxable           in-            due' <> mlAndMLS'+            due' <> ml' <> mls'         step3 = step1 $-$ step2       in         max (Money 1000) step3      frankingCredit = wholeDollars $ view (dividends . taxWithheld) info-    off =-      view (offsets . spouseContributionOffset) info-      <> min (view (offsets . foreignTaxOffset) info) foreignIncomeTaxOffsetLimit+    spouseContribOffset = view (offsets . spouseContributionOffset) info+    fito = min (view (offsets . foreignTaxOffset) info) foreignIncomeTaxOffsetLimit    in     TaxAssessment       taxable       due-      mlAndMLS+      spouseContribOffset+      fito+      frankingCredit+      ml+      mls       (view taxWithheld info)-      (frankingCredit <> off)       cg       phiAdj       studyRepayment       (view (offsets . paygInstalments) info) --- | Australian Business Number-type ABN = String --- | PAYG payment summary - individual non-business-data PaymentSummary a = PaymentSummary-  { summaryABN :: ABN-  , summaryGross :: Money a-  , summaryWithheld :: Money a-  , reportableEmployerSuperannuationContributions :: Money a-  }---- | Gross income-instance HasTaxableIncome PaymentSummary a a where-  taxableIncome = to summaryGross--instance HasTaxWithheld PaymentSummary a a where-  taxWithheld = to summaryWithheld- -- | A proportion is a non-negative number in interval @[0,1]@. -- Use 'proportion' to construct. newtype Proportion a = Proportion@@ -991,6 +1127,8 @@ -- The following lenses are available: -- -- +------------------------------+--------------------------------------------++-- | 'essEmployerDetails'         | 'PayerDetails' for employer.               |+-- +------------------------------+--------------------------------------------+ -- | 'essTaxedUpfrontReduction'   | __D__ Discount from taxed up front         | -- |                              | schemes—eligible for reduction             | -- +------------------------------+--------------------------------------------+@@ -1009,18 +1147,24 @@ -- +------------------------------+--------------------------------------------+ -- data ESSStatement a = ESSStatement-  { _taxedUpfrontReduction :: Money a+  { _essPayer :: PayerDetails+  , _taxedUpfrontReduction :: Money a   , _taxedUpfrontNoReduction :: Money a   , _deferral :: Money a   , _pre2009 :: Money a   , _tfnAmounts :: Money a   , _foreignSourceDiscounts :: Money a   }+  deriving (Eq, Ord)  -- | Construct an 'ESSStatement' with all amounts at /zero/.-newESSStatement :: Num a => ESSStatement a-newESSStatement = ESSStatement mempty mempty mempty mempty mempty mempty+newESSStatement :: (Num a) => PayerDetails -> ESSStatement a+newESSStatement payer = ESSStatement payer mempty mempty mempty mempty mempty mempty +-- | Employer details+essEmployerDetails :: Lens' (ESSStatement a) PayerDetails+essEmployerDetails = lens _essPayer (\s b -> s { _essPayer = b })+ -- | Discount from taxed up front schemes—eligible for reduction. -- Item __D__ in /Employee share schemes/ section. essTaxedUpfrontReduction :: Lens' (ESSStatement a) (Money a)@@ -1064,10 +1208,5 @@     <> view essDeferral s     <> view essPre2009 s -instance (Num a) => Semigroup (ESSStatement a) where-  ESSStatement a b c d e f <> ESSStatement a' b' c' d' e' f' =-    ESSStatement (a <> a') (b <> b') (c <> c') (d <> d') (e <> e') (f <> f')--instance (Num a) => Monoid (ESSStatement a) where-  mempty = newESSStatement-  mappend = (<>)+instance HasTaxWithheld ESSStatement a a where+  taxWithheld = essTFNAmounts
+ src/Data/Tax/ATO/ABN.hs view
@@ -0,0 +1,94 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2025  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/>.++{-|++Australian Business Number (ABN) types and functions.++@+import qualified Data.Tax.ATO.ABN as ABN++main = do+  let+    abnStr = "53 004 085 616"+    Just abn = ABN.parse abnStr+    abnInt = ABN.asInt abn+    Just abn' = ABN.fromInt abnInt+  putStrLn $ ABN.asString abn'  -- prints "53 004 085 616"+@++It is recommended to import this module qualified.++You can use the @OverloadedStrings@ language extension or the 'parse' function+to convert string to ABNs.  Space characters are ignored, but other non-digits+will cause parse failure.++-}++module Data.Tax.ATO.ABN+  (+    ABN+  , parse+  , fromInt+  , asString+  , asInt+  ) where++import Data.Char (isDigit)+import Data.String+import Data.Maybe (fromJust)++-- | Australian Business Number (ABN)+newtype ABN = ABN Int+  deriving (Eq, Ord, Show)++-- | Parse an ABN, throwing an error if it is not valid.+instance IsString ABN where+  fromString = fromJust . parse++-- | Construct an ABN, checking validity.+fromInt :: Int -> Maybe ABN+fromInt n | valid n = Just (ABN n)+fromInt _           = Nothing++-- | Parse an ABN.  Spaces characters are allowed, other non-digit+-- characters are not.+parse :: String -> Maybe ABN+parse s+  | all isDigit s'  = fromInt (read s')+  | otherwise       = Nothing+  where s' = filter (/= ' ') s++valid :: Int -> Bool+valid n =+  (== 0) . (`mod` 89) . subtract 10 . snd $ foldr step (n, 0) weights+  where+    weights = [10,1,3,5,7,9,11,13,15,17,19]+    step weight (n',acc) = ((+ acc) . (* weight)) <$> divMod n' 10++asInt :: ABN -> Int+asInt (ABN n) = n++-- Format ABN in the standard way (XX XXX XXX XXX)+asString :: ABN -> String+asString (ABN n) =+  case s' of+    [a1,a2,b1,b2,b3,c1,c2,c3,d1,d2,d3]  -> [a1,a2,' ',b1,b2,b3,' ',c1,c2,c3,' ',d1,d2,d3]+    _                                   -> show n -- can't happen, but just in case...+  where+    n' = abs n  -- negative can't happen, but just in case...+    s = show n'+    s' = replicate (11 - length s) '0' <> s  -- left-pad to 11 digits
src/Data/Tax/ATO/CGT.hs view
@@ -27,9 +27,6 @@  -} -{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}- module Data.Tax.ATO.CGT   (   -- * CGT events@@ -37,11 +34,12 @@    -- * CGT assessments for tax returns   , assessCGTEvents-  , CGTAssessment(CGTAssessment)-  , CGTNetGainOrLoss(..)+  , CGTAssessment+  , nullCGTAssessment   , HasCapitalLossCarryForward(..)-  , cgtNetGainOrLoss   , cgtNetGain+  , cgtTotalCurrentYearGains+  , cgtNetLossesCarriedForward    -- * CGT computations   , HasCapitalGain(..)@@ -49,7 +47,6 @@   , isCapitalGain   , isCapitalLoss   , discountApplicable-  , netCapitalGainOrLoss   ) where  import Data.Foldable (toList)@@ -139,34 +136,6 @@   capitalGain = to (foldMap (view capitalGain))  ---- | Compute the /discounted/ gain or carry-forward loss------ Losses are used to offset non-discountable capital gains--- first, then discountable gains, before the discount is applied--- to discountable gains.------ *Does not implement the indexation method for cost-base reduction!*----netCapitalGainOrLoss-  :: (Fractional a, Ord a, Foldable t)-  => Money a                     -- ^ loss carried forward-  -> t (CGTEvent a)              -- ^ CGT events-  -> CGTNetGainOrLoss a-netCapitalGainOrLoss carry events =-  let-    l = toList events-    (discountableGain, nonDiscountableGain) =-      over both (view capitalGain) (partition discountApplicable l)-    loss = foldMap capitalLoss l-    (nonDiscLessLoss, remLoss) = sub nonDiscountableGain (loss <> carry)-    (discLessLoss, finalLoss) = sub discountableGain remLoss-    discGain = nonDiscLessLoss <> (discLessLoss $* 0.5)-  in-    if discGain > mempty-    then CGTNetGain discGain-    else CGTLoss finalLoss- -- | @sub x y@ = subtract @y@ from @x@, clamping to 0 and -- returning @(result, leftovers)@ --@@ -176,56 +145,88 @@   in (max mempty r, over money abs (min mempty r))  -- | Assess the total capital gains and net capital gain or loss.+--+-- Losses are used to offset non-discountable capital gains+-- first, then discountable gains, before the discount is applied+-- to discountable gains.+--+-- __Does not implement the indexation method for cost-base reduction.__+-- assessCGTEvents   :: (Fractional a, Ord a, Foldable t)   => Money a            -- ^ capital loss carried forward   -> t (CGTEvent a)   -> CGTAssessment a-assessCGTEvents carry evs = CGTAssessment-  (view capitalGain evs)-  (netCapitalGainOrLoss carry evs)+assessCGTEvents carry events =+  let+    l = toList events+    (discountableGain, nonDiscountableGain) =+      over both (view capitalGain) (partition discountApplicable l)+    totalGain = discountableGain <> nonDiscountableGain+    totalLoss = foldMap capitalLoss l+    (nonDiscountableGainLossesApplied, unappliedLosses) = sub nonDiscountableGain (totalLoss <> carry)+    (discountableGainLossesApplied, finalUnappliedLosses) = sub discountableGain unappliedLosses+    discount = discountableGainLossesApplied $* 0.5+    discountedGain = nonDiscountableGainLossesApplied <> (discountableGainLossesApplied $-$ discount) +    lossesApplied = (totalLoss <> carry) $-$ finalUnappliedLosses+    priorYearLossesApplied = min carry lossesApplied+    currentYearLossesApplied = lossesApplied $-$ priorYearLossesApplied+  in+    CGTAssessment+      totalGain+      totalLoss+      currentYearLossesApplied+      priorYearLossesApplied+      finalUnappliedLosses+      discount+      discountedGain+ -- | Total undiscounted gains and net gain/loss for tax assessment data CGTAssessment a = CGTAssessment-  { _cgtaTotal :: Money a-  , _cgtaNet :: CGTNetGainOrLoss a+  { _totalCurrentYearCapitalGains :: Money a+  , _totalCurrentYearCapitalLosses :: Money a+  , _totalCurrentYearCapitalLossesApplied :: Money a+  , _totalPriorYearCapitalLossesApplied :: Money a+  , _netCapitalLossesCarriedForward :: Money a+  , _totalCGTDiscountApplied :: Money a+  , _netCapitalGain :: Money a   }-  deriving (Show)--instance Functor CGTAssessment where-  fmap f (CGTAssessment a b) = CGTAssessment (fmap f a) (fmap f b)+  deriving (Eq) -instance HasCapitalGain CGTAssessment a a where-  capitalGain = to _cgtaTotal+-- | A 'CGTAssessment' whose values are all zero+nullCGTAssessment :: (Num a) => CGTAssessment a+nullCGTAssessment = CGTAssessment mempty mempty mempty mempty mempty mempty mempty --- | The 'CGTNetGainOrLoss' value of the 'CGTAssessment'-cgtNetGainOrLoss :: Lens' (CGTAssessment a) (CGTNetGainOrLoss a)-cgtNetGainOrLoss = lens _cgtaNet (\s b -> s { _cgtaNet = b })+instance Functor CGTAssessment where+  fmap f (CGTAssessment a b c d e g h) = CGTAssessment+    (fmap f a)+    (fmap f b)+    (fmap f c)+    (fmap f d)+    (fmap f e)+    (fmap f g)+    (fmap f h) --- | The net capital gain, or zero if a loss.-cgtNetGain :: (Num a) => Getter (CGTAssessment a) (Money a)-cgtNetGain = cgtNetGainOrLoss . to f-  where-  f (CGTNetGain a) = a-  f _ = mempty+-- | __18A__ The net capital gain, or zero if a loss.+cgtNetGain :: Lens' (CGTAssessment a) (Money a)+cgtNetGain = lens _netCapitalGain (\s b -> s { _netCapitalGain = b }) --- | A net (loss offset, discounted) gain, or the loss amount-data CGTNetGainOrLoss a = CGTNetGain (Money a) | CGTLoss (Money a)-  deriving (Show)+-- | __18H__ Total current year capital gains+cgtTotalCurrentYearGains :: Lens' (CGTAssessment a) (Money a)+cgtTotalCurrentYearGains =+  lens _totalCurrentYearCapitalGains (\s b -> s { _totalCurrentYearCapitalGains = b }) -instance Functor CGTNetGainOrLoss where-  fmap f (CGTNetGain a) = CGTNetGain (fmap f a)-  fmap f (CGTLoss a)    = CGTLoss (fmap f a)+-- | __18V__ Net capital losses carried forward to later income years+cgtNetLossesCarriedForward :: Lens' (CGTAssessment a) (Money a)+cgtNetLossesCarriedForward =+  lens _netCapitalLossesCarriedForward (\s b -> s { _netCapitalLossesCarriedForward = b })  -- | Types that have a carry-forward capital loss (either as an -- input or an output). class HasCapitalLossCarryForward a b where   capitalLossCarryForward :: Lens' (a b) (Money b) -instance (Num a, Eq a) => HasCapitalLossCarryForward CGTNetGainOrLoss a where-  capitalLossCarryForward = lens-    (\s -> case s of CGTLoss a -> a ; _ -> mempty)-    (\s b -> if b == mempty then s else CGTLoss b)--instance (Num a, Eq a) => HasCapitalLossCarryForward CGTAssessment a where-  capitalLossCarryForward = cgtNetGainOrLoss . capitalLossCarryForward+instance HasCapitalLossCarryForward CGTAssessment a where+  capitalLossCarryForward =+    lens _netCapitalLossesCarriedForward (\s b -> s { _netCapitalLossesCarriedForward = b })
src/Data/Tax/ATO/Common.hs view
@@ -20,9 +20,9 @@  -} -{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE UndecidableInstances #-}  module Data.Tax.ATO.Common   (@@ -31,7 +31,12 @@    -- * Classes   , HasTaxableIncome(..)+  , HasTaxWithheld(..) +  -- * Medicare levy+  , MedicareLevyRatesAndThresholds(..)+  , medicareLevy'+   -- * Common taxes and helpers   , medicareLevy   , lowIncomeTaxOffset@@ -39,6 +44,17 @@   , lamito   , corporateTax +  -- * Deduction rates that vary by financial year+  , applyCentsPerKilometreMethod+  , HasCentsPerKilometreMethod++  , applyFixedRateMethod+  , HasFixedRateMethod+  , applyFixedRateMethodPre2023+  , HasFixedRateMethodPre2023+  , applyShortcutMethod+  , HasShortcutMethod+   -- * Convenience functions   , thresholds'   , marginal'@@ -46,14 +62,17 @@  import Control.Lens (Getter, review, to, view) import Data.Bifunctor (first)+import Data.Proxy+import GHC.TypeLits  import Data.Tax import Data.Tax.ATO.PrivateHealthInsuranceRebate+import Data.Tax.ATO.FY  -- | A set of tax tables for a particular financial year data TaxTables y a = TaxTables   { ttIndividualIncomeTax :: Tax (Money a) (Money a)-  , ttMedicareLevy :: Tax (Money a) (Money a)+  , ttMedicareLevyRatesAndThresholds :: MedicareLevyRatesAndThresholds a   , ttMedicareLevySurcharge :: Tax (Money a) (Money a)   , ttHelp :: Tax (Money a) (Money a)   , ttSfss :: Tax (Money a) (Money a)@@ -62,6 +81,40 @@   , ttPHIRebateRates :: PrivateHealthInsuranceRebateRates a   } ++data MedicareLevyRatesAndThresholds a = MedicareLevyRatesAndThresholds+  { medicareLevyRate :: a+  , medicareLevyThresholdIndividual :: Money a+  , medicareLevyThresholdIndividualSeniorAndPensioner :: Money a+  , medicareLevyThresholdFamily :: Money a+  , medicareLevyThresholdFamilySeniorAndPensioner :: Money a+  , medicareLevyThresholdDependentChildIncrease :: Money a+  }++medicareLevy'+  :: (Fractional a, Ord a)+  => MedicareLevyRatesAndThresholds a+  -> Money a          -- ^ taxable income+  -> Maybe (Money a)  -- ^ spouse taxable income+  -> Integer          -- ^ number of dependents+  -> Money a+medicareLevy' rates me mYou nDeps = case mYou of+  Nothing | nDeps <= 0 ->+    let+      t = medicareLevyThresholdIndividual rates+    in+      getTax (mk t) me+  _ ->+    let+      t = medicareLevyThresholdFamily rates+          $+$ fromIntegral nDeps *$ medicareLevyThresholdDependentChildIncrease rates+      combinedIncome = maybe me (me $+$) mYou+    in+      (me $/$ combinedIncome) *$ getTax (mk t) combinedIncome+  where+    mk l = lesserOf (above l 0.1) (flat (medicareLevyRate rates))++ -- | 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.@@ -116,3 +169,164 @@     => HasTaxableIncome t (x a) a     where   taxableIncome = to (foldMap (view taxableIncome))++-- | Types that can have an amount of tax withheld.+class HasTaxWithheld a b c where+  taxWithheld :: Getter (a b) (Money c)++instance (Foldable t, HasTaxWithheld x a a, Num a)+            => HasTaxWithheld t (x a) a where+  taxWithheld = to (foldMap (view taxWithheld))+++-- | See 'applyCentsPerKilometreMethod'.+class HasCentsPerKilometreMethod y where+  centsPerKilometre :: Num a => a++instance (2016 <= y, y <= 2025, FinancialYear y) => HasCentsPerKilometreMethod y where+  centsPerKilometre = case fromProxy (Proxy @y) of+    y | y == 2025           -> 88+      | y == 2024           -> 85+      | y == 2023           -> 78+      | y > 2020, y <= 2022 -> 72+      | y > 2018, y <= 2020 -> 68+      | y > 2015, y <= 2018 -> 66+      | otherwise           ->  0  -- can't happen++-- | Apply the single-rate cents per kilometre method (in use since+-- the 2015–16 FY).  Clamped (by law) at 5000 kms.  Use+-- @TypeApplications@ to specify the financial year, e.g.+--+-- @+-- import Data.Tax.ATO.FY.2025 (FY)+--+-- y = applyCentsPerKilometreMethod \@2025 1111  -- using type literal+-- x = applyCentsPerKilometreMethod \@FY   1111  -- same thing, using type synonym+-- @+--+applyCentsPerKilometreMethod+  :: forall y a. (HasCentsPerKilometreMethod y, Fractional a, Ord a)+  => a -> Money a+applyCentsPerKilometreMethod kms = Money $ centsPerKilometre @y * min kms 5000 / 100+++-- | See 'applyFixedRateMethod'+class HasFixedRateMethod y where+  fixedRateMethodCentsPerHour :: Num a => a++instance HasFixedRateMethod 2023 where+  fixedRateMethodCentsPerHour = 67+instance HasFixedRateMethod 2024 where+  fixedRateMethodCentsPerHour = 67+instance HasFixedRateMethod 2025 where+  fixedRateMethodCentsPerHour = 70++-- | The updated fixed rate method available from the 2022–23 income+-- year.  It covers:+--+-- * home and mobile internet or data expenses+-- * mobile and home phone usage expenses+-- * electricity and gas (energy expenses) for heating, cooling and lighting+-- * stationery and computer consumables, such as printer ink and paper.+--+-- You can separately claim deductions for work-related use of+-- technology and office furniture, and (in limited circumstances)+-- occupancy expenses and cleaning expenses.+--+-- Use @TypeApplications@ to specify the financial year, e.g.+--+-- @+-- import Data.Tax.ATO.FY.2025 (FY)+--+-- y = applyFixedRateMethod \@2025 1111  -- using type literal+-- x = applyFixedRateMethod \@FY   1111  -- same thing, using type synonym+-- @+--+-- For earlier income years use 'applyFixedRateMethodPre2023'.+--+applyFixedRateMethod+  :: forall y a. (HasFixedRateMethod y, Fractional a)+  => a -> Money a+applyFixedRateMethod hours = Money $ fixedRateMethodCentsPerHour @y * hours / 100+++-- | See 'applyShortcutMethod'+class HasShortcutMethod y where+  shortcutMethodCentsPerHour :: Num a => a++instance (2020 <= y, y <= 2022) => HasShortcutMethod y where+  shortcutMethodCentsPerHour = 80++-- | The shortcut method for working from home deductions was+-- available from 1 March 2020 to 30 June 2020 in the 2019–20 income+-- year, and for the 2020–21 and 2021–22 income years.  It covers:+--+-- * phone and data expenses+-- * internet expenses+-- * the decline in value of equipment and furniture+-- * electricity and gas (energy expenses) for heating, cooling and lighting.+--+-- Use @TypeApplications@ to specify the financial year, e.g.+--+-- @+-- import Data.Tax.ATO.FY.2025 (FY)+--+-- y = applyShortcutMethod \@2025 1111  -- using type literal+-- x = applyShortcutMethod \@FY   1111  -- same thing, using type synonym+-- @+--+applyShortcutMethod+  :: forall y a. (HasShortcutMethod y, Fractional a)+  => a -> Money a+applyShortcutMethod hours = Money $ shortcutMethodCentsPerHour @y * hours / 100+++-- | See 'applyFixedRateMethodPre2023'+class HasFixedRateMethodPre2023 y where+  fixedRateMethodPre2023CentsPerHour :: Num a => a++instance (2002 <= y, y <= 2022, FinancialYear y) => HasFixedRateMethodPre2023 y where+  fixedRateMethodPre2023CentsPerHour = case fromProxy (Proxy @y) of+    y | y > 2018, y <= 2022 -> 52+      | y > 2014, y <= 2018 -> 45+      | y > 2010, y <= 2014 -> 34+      | y > 2004, y <= 2010 -> 26+      | y > 2001, y <= 2004 -> 20+      | otherwise           ->  0  -- can't happen++-- | The fixed rate method available up to the 2021–22 income year.+-- It differs from the current fixed rate method (see+-- 'HasFixedRateMethod') in which categories of expenses are+-- included.  This method covers:+--+-- * the decline in value of home office furniture and+--   furnishings – for example, a desk+-- * electricity and gas (energy expenses) for heating,+--   cooling and lighting+-- * cleaning your dedicated home office.+--+-- You should separately claim for:+--+-- * home phone and internet expenses, including the decline in+--   value of the handset+-- * stationery and computer consumables, such as printer ink+--   and paper+-- * decline in value of depreciating assets other than+--   home office furniture and furnishings used for work+--   purposes – for example, computers and laptops.+--+-- Use @TypeApplications@ to specify the financial year, e.g.+--+-- @+-- import Data.Tax.ATO.FY.2025 (FY)+--+-- y = applyFixedRateMethodPre2023 \@2025 1111  -- using type literal+-- x = applyFixedRateMethodPre2023 \@FY   1111  -- same thing, using type synonym+-- @+--+-- For later income years, use 'applyFixedRateMethod'.+--+applyFixedRateMethodPre2023+  :: forall y a. (HasFixedRateMethodPre2023 y, Fractional a)+  => a -> Money a+applyFixedRateMethodPre2023 hours = Money $ fixedRateMethodPre2023CentsPerHour @y * hours / 100
+ src/Data/Tax/ATO/Depreciation.hs view
@@ -0,0 +1,87 @@++{-|++Types and computations for calculating decline in value.++-}++module Data.Tax.ATO.Depreciation+  ( DepreciatingAsset(..)+  , EffectiveLife+  , DepreciationMethod+  , diminishingValueMethod+  , primeCostMethod+  , depreciationSchedule+  , declineInValue+  ) where++import Data.Proxy (Proxy(..))++import Data.Time (Day, Year, diffDays, fromGregorian)++import Data.Tax+import Data.Tax.ATO.FY++-- | Effective life in years+type EffectiveLife = Rational++data DepreciatingAsset a = DepreciatingAsset+  Day             -- ^ Start date of decline in value+  (Money a)       -- ^ Asset's cost+  EffectiveLife   -- ^ Effective life, in years.+  (DepreciationMethod a)++-- | Given the start date, effective life and the pair+-- @(cost, baseValue)@, calculate the decline in value over+-- a full year (i.e. /days held/ = 365).+--+type DepreciationMethod a =+  Day -> EffectiveLife -> (Money a, Money a) -> Money a++-- | Decline in value = @remainingValue * r / effectiveLife@,+-- where @r = 1.5@ for assets acquired before 2006-05-10,+-- otherwise @2.0@.+diminishingValueMethod :: (Fractional a) => DepreciationMethod a+diminishingValueMethod start life = ($/ fromRational life) . ($* factor) . snd+  where+  factor  | start < fromGregorian 2006 05 10  = 1.5+          | otherwise                         = 2++-- | /Straight-line depreciation/.+-- Decline in value = cost / effective life.+primeCostMethod :: (Fractional a) => DepreciationMethod a+primeCostMethod _ life = ($/ fromRational life) . fst++-- | Calculate decline in value over financial years+depreciationSchedule+  :: (Fractional a, Ord a)+  => DepreciatingAsset a -> [(Year, Money a)]+depreciationSchedule (DepreciatingAsset t1 cost life method) =+  let+    fy = financialYear t1+    (_, eofy) = financialYearRange fy+    daysList = diffDays eofy t1 + 1 : fmap daysInYear [fy + 1..]++    step (_, value) nDays =+      let+        decline = (fromIntegral nDays *$ method t1 life (cost, value)) $/ 365+      in+        if decline > value+          then (value, Money 0)+          else (decline, value $-$ decline)+  in+    zip [fy..]+    . takeWhile (>= Money 1)+    . fmap fst+    . drop 1+    $ scanl step (Money 0, cost) daysList++-- | Calculate decline in value for the given financial year+-- (financial year given as type, via 'Proxy').+declineInValue+  :: (FinancialYear y, Fractional a, Ord a)+  => Proxy y -> DepreciatingAsset a -> Money a+declineInValue proxy asset =+  case dropWhile ((< fromProxy proxy) . fst) (depreciationSchedule asset) of+    (y,r):_ | y == fromProxy proxy  -> r+    _                               -> Money 0
src/Data/Tax/ATO/FY.hs view
@@ -20,10 +20,7 @@  -} -{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ScopedTypeVariables #-}  module Data.Tax.ATO.FY   ( Days@@ -33,9 +30,12 @@   , getDays   , getFraction   , FinancialYear+  , fromProxy   , financialYear   , financialYearRange   , financialYearRangeFromProxy+  , daysInYear+  , daysInYearFromProxy   )   where @@ -47,11 +47,19 @@  type FinancialYear = KnownNat -daysInYear :: KnownNat n => Proxy n -> Integer-daysInYear proxy-  | isLeapYear (natVal proxy) = 366-  | otherwise                 = 365+fromProxy :: (FinancialYear y) => Proxy y -> Year+fromProxy = natVal +-- | Number of days in the financial year ending June 30 of the given year.+daysInYear :: Year -> Integer+daysInYear y+  | isLeapYear y  = 366+  | otherwise     = 365++-- | Number of days in the financial year ending June 30 (type-level variant).+daysInYearFromProxy :: FinancialYear y => Proxy y -> Integer+daysInYearFromProxy = daysInYear . natVal+ -- | Some number of days in a year.  Use 'days' to construct. newtype Days (n :: Nat) = Days   { getDays :: Integer@@ -62,11 +70,11 @@ -- | Construct a 'Days' value.  If out of range, the number of days -- is clamped to 0 or 365/366 (no runtime errors). days :: forall a. (FinancialYear a) => Integer -> Days a-days = Days . max 0 . min (daysInYear (Proxy :: Proxy a))+days = Days . max 0 . min (daysInYearFromProxy (Proxy :: Proxy a))  -- | Every day of the year daysAll :: forall a. (FinancialYear a) => Days a-daysAll = Days (daysInYear (Proxy :: Proxy a))+daysAll = Days (daysInYearFromProxy (Proxy :: Proxy a))  -- | Zero days of the year daysNone :: Days a@@ -76,7 +84,7 @@ -- The denominator is determined by the year type. -- getFraction :: forall a frac. (FinancialYear a, Fractional frac) => Days a -> frac-getFraction n = fromRational $ getDays n % daysInYear (Proxy :: Proxy a)+getFraction n = fromRational $ getDays n % daysInYearFromProxy (Proxy :: Proxy a)  -- | The financial year in which the given day falls. --
src/Data/Tax/ATO/FY/FY2017.hs view
@@ -17,13 +17,18 @@ {-# LANGUAGE DataKinds #-}  -- | Tax tables for 2016–17 financial year.-module Data.Tax.ATO.FY.FY2017 (tables, individualIncomeTax) where+module Data.Tax.ATO.FY.FY2017 (FY, fyProxy, tables, individualIncomeTax) where -import Control.Lens (review)+import Data.Proxy+ import Data.Tax import Data.Tax.ATO.Common import Data.Tax.ATO.PrivateHealthInsuranceRebate +type FY = 2017+fyProxy :: Proxy FY+fyProxy = Proxy+ -- | In FY2017 the 37% threshold was raised from $80,000 to $87,000 -- individualIncomeTax :: (Fractional a, Ord a) => Tax (Money a) (Money a)@@ -34,7 +39,7 @@   , (180000, 0.45 - 0.37) ]  temporaryBudgetRepairLevy :: (Fractional a, Ord a) => Tax (Money a) (Money a)-temporaryBudgetRepairLevy = above (review money 180000) 0.02+temporaryBudgetRepairLevy = above (Money 180000) 0.02  help, sfss :: (Fractional a, Ord a) => Tax (Money a) (Money a) help = thresholds'@@ -43,6 +48,16 @@   , (82551, 0.005), (86895, 0.005), (95627, 0.005), (101900, 0.005) ] sfss = thresholds' [(54869, 0.02), (67369, 0.01), (95627, 0.01)] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 21655+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 34244+  , medicareLevyThresholdFamily                       = Money 36541+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 47670+  , medicareLevyThresholdDependentChildIncrease       = Money  3356+  }+ -- | /Medicare levy surcharge (MLS)/.  Certain exemptions are available. -- -- __Known issues__: the MLS is levied on taxable income + fringe@@ -64,7 +79,7 @@ tables :: (Ord a, Fractional a) => TaxTables 2017 a tables = TaxTables   (individualIncomeTax <> temporaryBudgetRepairLevy)-  (medicareLevy (review money 21656))+  medicare   medicareLevySurcharge   help   sfss
src/Data/Tax/ATO/FY/FY2018.hs view
@@ -20,7 +20,6 @@ module Data.Tax.ATO.FY.FY2018 (FY, fyProxy, tables) where  import Data.Proxy-import Control.Lens (review) import Data.Tax import Data.Tax.ATO.Common import Data.Tax.ATO.PrivateHealthInsuranceRebate@@ -37,6 +36,16 @@   , (84063, 0.005), (88487, 0.005), (97378, 0.005), (103766, 0.005) ] sfss = thresholds' [(55874, 0.02), (68603, 0.01), (97378, 0.01)] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 21980+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 34758+  , medicareLevyThresholdFamily                       = Money 37089+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 48385+  , medicareLevyThresholdDependentChildIncrease       = Money  3406+  }+ -- | Individual tax rates unchanged from 2017. -- -- The /temporary budget repair levy/ no longer applies.@@ -44,7 +53,7 @@ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   FY2017.individualIncomeTax-  (medicareLevy (review money 21980))+  medicare   (ttMedicareLevySurcharge FY2017.tables)   help   sfss
src/Data/Tax/ATO/FY/FY2019.hs view
@@ -20,7 +20,6 @@ module Data.Tax.ATO.FY.FY2019 (FY, fyProxy, tables) where  import Data.Proxy-import Control.Lens (review)  import Data.Tax import Data.Tax.ATO.Common@@ -46,6 +45,16 @@   , (86856, 0.005), (91426, 0.005), (100614, 0.005), (107214, 0.005) ] sfss = thresholds' [(51957, 0.02), (64307, 0.01), (91426, 0.01)] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 22398+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 35418+  , medicareLevyThresholdFamily                       = Money 37794+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 49304+  , medicareLevyThresholdDependentChildIncrease       = Money  3471+  }+ -- | The 37% threshold was increased from $87,000 to $90,000. -- -- The new /low and middle income tax offset (LAMITO)/ was@@ -54,7 +63,7 @@ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   individualIncomeTax-  (medicareLevy (review money 22398))+  medicare   (ttMedicareLevySurcharge FY2018.tables)   help   sfss
src/Data/Tax/ATO/FY/FY2020.hs view
@@ -20,7 +20,6 @@ module Data.Tax.ATO.FY.FY2020 (FY, fyProxy, tables) where  import Data.Proxy-import Control.Lens (review)  import Data.Tax import Data.Tax.ATO.Common@@ -53,6 +52,16 @@   , (134573, 0.005)   ] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 22801+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 36056+  , medicareLevyThresholdFamily                       = Money 38474+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 50191+  , medicareLevyThresholdDependentChildIncrease       = Money  3533+  }+ -- | From 1 July 2019, all study and training loans are covered by -- one set of thresholds and rates.  For backwards compatibility, -- 'ttHelp' and 'ttSfss' now refer to the same value.@@ -60,7 +69,7 @@ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   (ttIndividualIncomeTax FY2019.tables)-  (medicareLevy (review money 22801))+  medicare   (ttMedicareLevySurcharge FY2019.tables)   help   help
src/Data/Tax/ATO/FY/FY2021.hs view
@@ -20,7 +20,6 @@ module Data.Tax.ATO.FY.FY2021 (FY, fyProxy, tables, individualIncomeTax) where  import Data.Proxy-import Control.Lens (review)  import Data.Tax import Data.Tax.ATO.Common@@ -63,10 +62,20 @@   , (136740, 0.005)   ] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 23226+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 36705+  , medicareLevyThresholdFamily                       = Money 39167+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 51094+  , medicareLevyThresholdDependentChildIncrease       = Money  3597+  }+ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   individualIncomeTax-  (medicareLevy (review money 23226))+  medicare   (ttMedicareLevySurcharge FY2020.tables)   help   help
src/Data/Tax/ATO/FY/FY2022.hs view
@@ -20,7 +20,6 @@ module Data.Tax.ATO.FY.FY2022 (FY, fyProxy, tables) where  import Data.Proxy-import Control.Lens (review)  import Data.Tax import Data.Tax.ATO.Common@@ -53,10 +52,20 @@   , (137898, 0.005)   ] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 23365+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 36925+  , medicareLevyThresholdFamily                       = Money 39402+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 51401+  , medicareLevyThresholdDependentChildIncrease       = Money  3619+  }+ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   FY2021.individualIncomeTax-  (medicareLevy (review money 23365))+  medicare   (ttMedicareLevySurcharge FY2021.tables)   help   help@@ -75,7 +84,7 @@ -- | LMITO ceiling increased by $420 to $1500 in FY2022 lmito2022 :: (Fractional a, Ord a) => Tax (Money a) (Money a) lmito2022 = limit mempty $-  greaterOf (lump (review money (-1500)))-    ( lump (review money (-255))-    <> above (review money 37000) (-0.075) )-  <> above (review money 90000) 0.03+  greaterOf (lump (Money (-1500)))+    ( lump (Money (-255))+    <> above (Money 37000) (-0.075) )+  <> above (Money 90000) 0.03
src/Data/Tax/ATO/FY/FY2023.hs view
@@ -50,11 +50,20 @@   , (141848, 0.005)   ] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 24276+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 38365+  , medicareLevyThresholdFamily                       = Money 40939+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 53406+  , medicareLevyThresholdDependentChildIncrease       = Money  3760+  }+ tables :: (Ord a, Fractional a) => TaxTables 2023 a tables = TaxTables   (ttIndividualIncomeTax FY2022.tables)--  (medicareLevy (Money 24276))+  medicare   (ttMedicareLevySurcharge FY2022.tables)    help
src/Data/Tax/ATO/FY/FY2024.hs view
@@ -22,6 +22,7 @@ import Data.Proxy import Data.Tax import Data.Tax.ATO.Common+import Data.Tax.ATO.PrivateHealthInsuranceRebate import qualified Data.Tax.ATO.FY.FY2023 as FY2023  type FY = 2024@@ -50,6 +51,16 @@   , (151201, 0.005)   ] +medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 26000+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 41089+  , medicareLevyThresholdFamily                       = Money 43846+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 57198+  , medicareLevyThresholdDependentChildIncrease       = Money  4027+  }+ -- | Medicare levy surcharge thresholds changed for 2023–24 medicareLevySurcharge :: (Fractional a, Ord a) => Tax (Money a) (Money a) medicareLevySurcharge =@@ -57,18 +68,25 @@   <> threshold (Money 108000) 0.0025   <> threshold (Money 144000) 0.0025 +-- Rebate adjustment factor = 1.000 (no change)+-- https://www.health.gov.au/news/phi-circulars/phi-1724-private-health-insurance-rebate-adjustment-factor-effective-1-april-2024+-- However, the /thresholds/ did change this year.+privateHealthInsuranceRebateRates+  :: (Fractional a) => PrivateHealthInsuranceRebateRates a+privateHealthInsuranceRebateRates =+  [ ( 93000, (0.24608, 0.24608), (0.28710, 0.28710), (0.32812, 0.32812) )+  , (108000, (0.16405, 0.16405), (0.20507, 0.20507), (0.24608, 0.24608) )+  , (144000, (0.08202, 0.08202), (0.12303, 0.12303), (0.16405, 0.16405) )+  ]+ tables :: (Ord a, Fractional a) => TaxTables FY a tables = TaxTables   (ttIndividualIncomeTax FY2023.tables)--  (medicareLevy (Money 26000))-+  medicare   medicareLevySurcharge   help   help    lowIncomeTaxOffset2021 -  -- Rebate adjustment factor = 1.000 (no change)-  -- https://www.health.gov.au/news/phi-circulars/phi-1724-private-health-insurance-rebate-adjustment-factor-effective-1-april-2024-  (ttPHIRebateRates FY2023.tables)+  privateHealthInsuranceRebateRates
+ src/Data/Tax/ATO/FY/FY2025.hs view
@@ -0,0 +1,102 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2024  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/>.++{-# LANGUAGE DataKinds #-}++-- | Tax tables for 2024–25 financial year.+--+-- These data are NOT YET FINAL.  We are waiting on federal budget+-- (25 March 2025) to confirm Medicare Levy thresholds, and the PHI+-- rebate adjustment factor (~1 April 2025).+module Data.Tax.ATO.FY.FY2025 (FY, fyProxy, tables) where++import Data.Proxy+import Data.Tax+import Data.Tax.ATO.Common+import Data.Tax.ATO.PrivateHealthInsuranceRebate++type FY = 2025+fyProxy :: Proxy FY+fyProxy = Proxy++help :: (Fractional a, Ord a) => Tax (Money a) (Money a)+help = thresholds'+  [ (54435, 0.01)+  , (62851, 0.01)+  , (66621, 0.005)+  , (70619, 0.005)+  , (74856, 0.005)+  , (79347, 0.005)+  , (84108, 0.005)+  , (89155, 0.005)+  , (94504, 0.005)+  , (100175, 0.005)+  , (106186, 0.005)+  , (122557, 0.005)+  , (119310, 0.005)+  , (126468, 0.005)+  , (134057, 0.005)+  , (142101, 0.005)+  , (150627, 0.005)+  , (159664, 0.005)+  ]++medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 27222+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 43020+  , medicareLevyThresholdFamily                       = Money 45907+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 59886+  , medicareLevyThresholdDependentChildIncrease       = Money  4216+  }++-- | Medicare levy surcharge thresholds changed for 2024–25+medicareLevySurcharge :: (Fractional a, Ord a) => Tax (Money a) (Money a)+medicareLevySurcharge =+  threshold (Money 97000) 0.01+  <> threshold (Money 113000) 0.0025+  <> threshold (Money 151000) 0.0025++-- | In 2024–25 the "stage three tax cuts" came into effect.+individualIncomeTax :: (Fractional a, Ord a) => Tax (Money a) (Money a)+individualIncomeTax = marginal'+  [ (18200, 0.16)+  , (45000, 0.30 - 0.16)+  , (135000, 0.37 - 0.30)+  , (190000, 0.45 - 0.37) ]++-- Rebate adjustment factor = TBC (currently re-using FY2024 rates)+-- However, the /thresholds/ did change this year.+privateHealthInsuranceRebateRates+  :: (Fractional a) => PrivateHealthInsuranceRebateRates a+privateHealthInsuranceRebateRates =+  [ ( 97000, (0.24608, 0.24288), (0.28710, 0.28337), (0.32812, 0.32385) )+  , (113000, (0.16405, 0.16192), (0.20507, 0.20240), (0.24608, 0.24288) )+  , (151000, (0.08202, 0.08095), (0.12303, 0.12143), (0.16405, 0.16192) )+  ]++tables :: (Ord a, Fractional a) => TaxTables FY a+tables = TaxTables+  individualIncomeTax+  medicare+  medicareLevySurcharge+  help+  help++  lowIncomeTaxOffset2021++  privateHealthInsuranceRebateRates
+ src/Data/Tax/ATO/PaymentSummary.hs view
@@ -0,0 +1,646 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2025  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/>.++{-# LANGUAGE PatternSynonyms #-}++{-|++Types and optics for payment summaries.++-}+module Data.Tax.ATO.PaymentSummary+  (+  -- ** Individual non-business+    PaymentSummaryIndividualNonBusiness+  , newPaymentSummaryIndividualNonBusiness+  , GrossPaymentsTypeIndividualNonBusiness(..)+  , grossPaymentsTypeP+  , grossPaymentsTypeH++  -- *** Allowances+  , allowances+  , Allowance+  , allowance+  , allowanceDetail+  , allowanceAmount++  -- *** Fringe benefits+  , HasReportableFringeBenefits(..)+  , fringeBenefitsEmployerNotExempt+  , fringeBenefitsEmployerExempt+  , ReportableFringeBenefits(..)+  , FBTEmployerExemption(..)++  -- *** Lump sum A+  , HasLumpSumA(..)+  , lumpSumATypeR+  , lumpSumATypeT+  , LumpSumA+  , lumpSumAType+  , lumpSumAAmount+  , LumpSumAType(..)++  -- *** Lump sum B+  , lumpSumB++  -- *** Lump sum D+  , HasLumpSumD(..)++  -- *** Lump sum E+  , HasLumpSumE(..)++  -- *** Exempt foreign employment income+  , exemptForeignEmploymentIncome++  -- ** Foreign employment+  , PaymentSummaryForeignEmployment+  , newPaymentSummaryForeignEmployment+  , GrossPaymentsTypeForeignEmployment(..)+  , foreignTaxPaid++  -- ** Business and personal services income+  , PaymentSummaryBusinessAndPersonalServicesIncome+  , newPaymentSummaryBusinessAndPersonalServicesIncome++  -- ** Withholding where ABN not quoted+  , PaymentSummaryWithholdingWhereABNNotQuoted+  , newPaymentSummaryWithholdingWhereABNNotQuoted++  -- ** Payer details+  , PayerDetails+  , newPayerDetails+  , payerABN+  , payerBranchNumber+  , payerName+  , HasPayerDetails(..)++  -- ** Classes and helpers+  , HasGrossPayments(..)+  , HasGrossPaymentsType(..)+  , HasTotalTaxWithheld(..)+  , HasReportableEmployerSuperannuationContributions(..)+  , pattern PaymentSummary+  )+  where++import Data.String (IsString(..))++import Control.Lens++import Data.Tax+import Data.Tax.ATO.ABN (ABN)+import Data.Tax.ATO.Common+import Data.Tax.ATO.Rounding+++-- | Deprecated pattern provided for compatibility.  Will be removed+-- in a future release.  Use 'PaymentSummaryIndividualNonBusiness'+-- constructor and accessors instead.+--+pattern PaymentSummary+  :: (Num a) => PayerDetails -> Money a -> Money a -> Money a -> PaymentSummaryIndividualNonBusiness a+pattern PaymentSummary payer gross tax resc <-+  PaymentSummaryIndividualNonBusiness payer tax gross _type resc _fb+    _allow _lumpA _lumpB _lumpD _lumpE _foreign+  where+  PaymentSummary payer gross tax resc = newPaymentSummaryIndividualNonBusiness payer+    & set grossPayments gross+    & set totalTaxWithheld tax+    & set reportableEmployerSuperannuationContributions resc+{-# DEPRECATED PaymentSummary "see instead PaymentSummaryIndividualNonBusiness" #-}+++-- | PAYG payment summary - individual non-business.+--+-- Use 'newPaymentSummaryIndividualNonBusiness' to construct this data+-- type (all amounts initially zero).+--+-- To @set@ and @view@ the various fields, these lenses are available:+--+-- +-------------------------------------------------+-----------------------------------------++-- | 'payerDetails'                                  | Use 'newPayerDetails' to construct.     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'totalTaxWithheld'                              | TOTAL TAX WITHHELD                      |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPayments'                                 | GROSS PAYMENTS.  Do not include amounts |+-- |                                                 | shown at 'allowances', 'lumpSumA',      |+-- |                                                 | 'lumpSumB', 'lumpSumD', 'lumpSumE',     |+-- |                                                 | or 'exemptForeignEmploymentIncome'.     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPaymentsType'                             | Use 'grossPaymentsTypeP' for non super  |+-- |                                                 | pensions and annuities, or              |+-- |                                                 | 'grossPaymentsTypeH' for working        |+-- |                                                 | holiday makers. Otherwise, leave unset. |+-- +-------------------------------------------------+-----------------------------------------++-- | 'reportableEmployerSuperannuationContributions' | Reportable employer superannuation      |+-- |                                                 | contributions (do not include           |+-- |                                                 | compulsory super guarantee amounts)     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'reportableFringeBenefits'                      | Fringe benefits amount for FBT year     |+-- |                                                 | 1 April to 31 March, and employer       |+-- |                                                 | FBT exemption status.  See also         |+-- |                                                 | 'ReportableFringeBenefits'.             |+-- +-------------------------------------------------+-----------------------------------------++-- | 'exemptForeignEmploymentIncome'                 |                                         |+-- +-------------------------------------------------+-----------------------------------------++-- | 'allowances'                                    | List of 'allowance'.                    |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumA'                                      | Lump sum A. Use 'lumpSumATypeR' or      |+-- |                                                 | 'lumpSumATypeT' to construct.           |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumB'                                      | Lump sum B.                             |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumD'                                      | Lump sum D.                             |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumE'                                      | Lump sum E - payments in arrears.  This |+-- |                                                 | amount is included in taxable income.   |+-- |                                                 | The tax offset calculations are not yet |+-- |                                                 | implemented.                            |+-- +-------------------------------------------------+-----------------------------------------++--+data PaymentSummaryIndividualNonBusiness a = PaymentSummaryIndividualNonBusiness+  { _inbPayer :: PayerDetails+  , _inbWithholding :: Money a+  , _inbGross :: Money a+  , _inbGrossPaymentsType :: Maybe GrossPaymentsTypeIndividualNonBusiness+  , _inbRESC :: Money a+  , _inbFringeBenefits :: Maybe (ReportableFringeBenefits a)+  , _inbAllowances :: [Allowance a]+  , _inbLumpSumA :: Maybe (LumpSumA a)+  , _inbLumpSumB :: Money a+  , _inbLumpSumD :: Money a+  , _inbLumpSumE :: Money a+  , _inbForeign :: Money a+  }++-- | Construct a new payment summary.  All amounts are initially zero.+newPaymentSummaryIndividualNonBusiness+  :: (Num a) => PayerDetails -> PaymentSummaryIndividualNonBusiness a+newPaymentSummaryIndividualNonBusiness payer =+  PaymentSummaryIndividualNonBusiness payer+    mempty    -- total tax withheld+    mempty    -- gross payments+    Nothing   -- gross payments type+    mempty    -- reportable super contributions+    Nothing   -- reportable fringe benefits+    []        -- allowances+    Nothing   -- lump sum a+    mempty    -- lump sum b+    mempty    -- lump sum d+    mempty    -- lump sum e+    mempty    -- exempt foreign employment income++data GrossPaymentsTypeIndividualNonBusiness+  = GrossPaymentsTypeP+  -- ^ non super pensions or annuity.  See also 'grossPaymentsTypeP'.+  | GrossPaymentsTypeH+  -- ^ working holiday makers.  See also 'grossPaymentsTypeH'.+  deriving (Eq, Ord)++-- | Helper constructor - __P - non super pensions or annuity__+grossPaymentsTypeP :: Maybe GrossPaymentsTypeIndividualNonBusiness+grossPaymentsTypeP = Just GrossPaymentsTypeP++-- | Helper constructor - __H - working holiday makers__+grossPaymentsTypeH :: Maybe GrossPaymentsTypeIndividualNonBusiness+grossPaymentsTypeH = Just GrossPaymentsTypeH++instance (RealFrac a) => HasTaxableIncome PaymentSummaryIndividualNonBusiness a a where+  taxableIncome = to $ \s ->+    view grossPayments s+    <> foldOf (allowances . traverse . allowanceAmount) s+    <> foldOf (lumpSumA . traverse . lumpSumAAmount) s+    <> view (lumpSumB . to (wholeDollars . ($/ 20))) s+    <> view lumpSumE s++instance HasTaxWithheld PaymentSummaryIndividualNonBusiness a a where+  taxWithheld = totalTaxWithheld++instance HasPayerDetails PaymentSummaryIndividualNonBusiness where+  payerDetails = lens _inbPayer (\s b -> s { _inbPayer = b })++instance HasTotalTaxWithheld PaymentSummaryIndividualNonBusiness where+  totalTaxWithheld = lens _inbWithholding (\s b -> s { _inbWithholding = b })++instance HasGrossPayments PaymentSummaryIndividualNonBusiness where+  grossPayments = lens _inbGross (\s b -> s { _inbGross = b })++instance HasGrossPaymentsType PaymentSummaryIndividualNonBusiness+    (Maybe GrossPaymentsTypeIndividualNonBusiness) where+  grossPaymentsType = lens _inbGrossPaymentsType (\s b -> s { _inbGrossPaymentsType = b })++instance HasReportableEmployerSuperannuationContributions PaymentSummaryIndividualNonBusiness where+  reportableEmployerSuperannuationContributions =+    lens _inbRESC (\s b -> s { _inbRESC = b })++instance HasReportableFringeBenefits PaymentSummaryIndividualNonBusiness where+  reportableFringeBenefits =+    lens _inbFringeBenefits (\s b -> s { _inbFringeBenefits = b })++instance HasLumpSumA PaymentSummaryIndividualNonBusiness where+  lumpSumA = lens _inbLumpSumA (\s b -> s { _inbLumpSumA = b })++lumpSumB :: Lens' (PaymentSummaryIndividualNonBusiness a) (Money a)+lumpSumB = lens _inbLumpSumB (\s b -> s { _inbLumpSumB = b })++instance HasLumpSumD PaymentSummaryIndividualNonBusiness where+  lumpSumD = lens _inbLumpSumD (\s b -> s { _inbLumpSumD = b })++instance HasLumpSumE PaymentSummaryIndividualNonBusiness where+  lumpSumE = lens _inbLumpSumE (\s b -> s { _inbLumpSumE = b })++exemptForeignEmploymentIncome :: Lens' (PaymentSummaryIndividualNonBusiness a) (Money a)+exemptForeignEmploymentIncome = lens _inbForeign (\s b -> s { _inbForeign = b })++allowances :: Lens' (PaymentSummaryIndividualNonBusiness a) [Allowance a]+allowances = lens _inbAllowances (\s b -> s { _inbAllowances = b })+++-- | PAYG payment summary - foreign employment+--+-- Use 'newPaymentSummaryForeignEmployment' to construct this data+-- type (all amounts initially zero).+--+-- To @set@ and @view@ the various fields, these lenses are available:+--+-- +-------------------------------------------------+-----------------------------------------++-- | 'payerDetails'                                  | Use 'newPayerDetails' to construct.     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'totalTaxWithheld'                              | TOTAL TAX WITHHELD                      |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPayments'                                 | GROSS PAYMENTS.  You __must__ include   |+-- |                                                 | allowances.  Do not include 'lumpSumA'  |+-- |                                                 | 'lumpSumD' or 'lumpSumE' amounts.       |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPaymentsType'                             | Initial value 'GrossPaymentsTypeF'.     |+-- |                                                 | @set@ to 'GrossPaymentsTypeJ' for income|+-- |                                                 | earned from work conducted in the Joint |+-- |                                                 | Petroleum Development Area (JPDA).      |+-- +-------------------------------------------------+-----------------------------------------++-- | 'foreignTaxPaid'                                |                                         |+-- +-------------------------------------------------+-----------------------------------------++-- | 'reportableEmployerSuperannuationContributions' | Reportable employer superannuation      |+-- |                                                 | contributions (do not include           |+-- |                                                 | compulsory super guarantee amounts)     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'reportableFringeBenefits'                      | Fringe benefits amount for FBT year     |+-- |                                                 | 1 April to 31 March, and employer       |+-- |                                                 | FBT exemption status.  See also         |+-- |                                                 | 'ReportableFringeBenefits'.             |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumA'                                      | Lump sum A. Use 'lumpSumATypeR' or      |+-- |                                                 | 'lumpSumATypeT' to construct.           |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumD'                                      | Lump sum D.                             |+-- +-------------------------------------------------+-----------------------------------------++-- | 'lumpSumE'                                      | Lump sum E - payments in arrears.  This |+-- |                                                 | amount is included in taxable income.   |+-- |                                                 | The tax offset calculations are not yet |+-- |                                                 | implemented.                            |+-- +-------------------------------------------------+-----------------------------------------++--+data PaymentSummaryForeignEmployment a = PaymentSummaryForeignEmployment+  { _foreignPayer :: PayerDetails+  , _foreignWithholding :: Money a+  , _foreignGross :: Money a+  , _foreignGrossPaymentsType :: GrossPaymentsTypeForeignEmployment+  , _foreignForeignTaxPaid :: Money a+  , _foreignRESC :: Money a+  , _foreignFringeBenefits :: Maybe (ReportableFringeBenefits a)+  , _foreignLumpSumA :: Maybe (LumpSumA a)+  , _foreignLumpSumD :: Money a+  , _foreignLumpSumE :: Money a+  }++-- | Construct a new payment summary.  All amounts are initially zero.+newPaymentSummaryForeignEmployment+  :: (Num a) => PayerDetails -> PaymentSummaryForeignEmployment a+newPaymentSummaryForeignEmployment payer =+  PaymentSummaryForeignEmployment payer+    mempty    -- total tax withheld+    mempty    -- gross payments+    GrossPaymentsTypeF   -- gross payments type+    mempty    -- foreign tax paid+    mempty    -- reportable super contributions+    Nothing   -- reportable fringe benefits+    Nothing   -- lump sum a+    mempty    -- lump sum d+    mempty    -- lump sum e++data GrossPaymentsTypeForeignEmployment+  = GrossPaymentsTypeF+  -- ^ foreign employment income+  | GrossPaymentsTypeJ+  -- ^ income earned from work conducted in the Joint Petroleum+  -- Development Area (JPDA).+  deriving (Eq, Ord)++instance (RealFrac a) => HasTaxableIncome PaymentSummaryForeignEmployment a a where+  taxableIncome = to $ \s ->+    view grossPayments s+    <> foldOf (lumpSumA . traverse . lumpSumAAmount) s+    <> view lumpSumE s++instance HasTaxWithheld PaymentSummaryForeignEmployment a a where+  taxWithheld = totalTaxWithheld++instance HasPayerDetails PaymentSummaryForeignEmployment where+  payerDetails = lens _foreignPayer (\s b -> s { _foreignPayer = b })++instance HasTotalTaxWithheld PaymentSummaryForeignEmployment where+  totalTaxWithheld = lens _foreignWithholding (\s b -> s { _foreignWithholding = b })++instance HasGrossPayments PaymentSummaryForeignEmployment where+  grossPayments = lens _foreignGross (\s b -> s { _foreignGross = b })++instance HasGrossPaymentsType PaymentSummaryForeignEmployment+    GrossPaymentsTypeForeignEmployment where+  grossPaymentsType = lens _foreignGrossPaymentsType (\s b -> s { _foreignGrossPaymentsType = b })++foreignTaxPaid :: Lens' (PaymentSummaryForeignEmployment a) (Money a)+foreignTaxPaid =+  lens _foreignForeignTaxPaid (\s b -> s { _foreignForeignTaxPaid = b })++instance HasReportableEmployerSuperannuationContributions PaymentSummaryForeignEmployment where+  reportableEmployerSuperannuationContributions =+    lens _foreignRESC (\s b -> s { _foreignRESC = b })++instance HasReportableFringeBenefits PaymentSummaryForeignEmployment where+  reportableFringeBenefits =+    lens _foreignFringeBenefits (\s b -> s { _foreignFringeBenefits = b })++instance HasLumpSumA PaymentSummaryForeignEmployment where+  lumpSumA = lens _foreignLumpSumA (\s b -> s { _foreignLumpSumA = b })++instance HasLumpSumD PaymentSummaryForeignEmployment where+  lumpSumD = lens _foreignLumpSumD (\s b -> s { _foreignLumpSumD = b })++instance HasLumpSumE PaymentSummaryForeignEmployment where+  lumpSumE = lens _foreignLumpSumE (\s b -> s { _foreignLumpSumE = b })+++-- | PAYG payment summary - business and personal services income+--+-- Use 'newPaymentSummaryBusinessAndPersonalServicesIncome' to construct this data+-- type (all amounts initially zero).+--+-- To @set@ and @view@ the various fields, these lenses are available:+--+-- +-------------------------------------------------+-----------------------------------------++-- | 'payerDetails'                                  | Use 'newPayerDetails' to construct.     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'totalTaxWithheld'                              | TOTAL TAX WITHHELD                      |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPayments'                                 | Gross payments or gross attributed      |+-- |                                                 | income.                                 |+-- +-------------------------------------------------+-----------------------------------------++-- | 'reportableEmployerSuperannuationContributions' | Reportable employer superannuation      |+-- |                                                 | contributions (do not include           |+-- |                                                 | compulsory super guarantee amounts)     |+-- +-------------------------------------------------+-----------------------------------------++--+data PaymentSummaryBusinessAndPersonalServicesIncome a = PaymentSummaryBusinessAndPersonalServicesIncome+  { _bpsiPayer :: PayerDetails+  , _bpsiWithholding :: Money a+  , _bpsiGross :: Money a+  , _bpsiRESC :: Money a+  }++-- | Construct a new payment summary.  All amounts are initially zero.+newPaymentSummaryBusinessAndPersonalServicesIncome+  :: (Num a) => PayerDetails -> PaymentSummaryBusinessAndPersonalServicesIncome a+newPaymentSummaryBusinessAndPersonalServicesIncome payer =+  PaymentSummaryBusinessAndPersonalServicesIncome payer+    mempty    -- total tax withheld+    mempty    -- gross payments+    mempty    -- reportable super contributions++instance HasTaxableIncome PaymentSummaryBusinessAndPersonalServicesIncome a a where+  taxableIncome = grossPayments++instance HasTaxWithheld PaymentSummaryBusinessAndPersonalServicesIncome a a where+  taxWithheld = totalTaxWithheld++instance HasPayerDetails PaymentSummaryBusinessAndPersonalServicesIncome where+  payerDetails = lens _bpsiPayer (\s b -> s { _bpsiPayer = b })++instance HasTotalTaxWithheld PaymentSummaryBusinessAndPersonalServicesIncome where+  totalTaxWithheld = lens _bpsiWithholding (\s b -> s { _bpsiWithholding = b })++instance HasGrossPayments PaymentSummaryBusinessAndPersonalServicesIncome where+  grossPayments = lens _bpsiGross (\s b -> s { _bpsiGross = b })++instance HasReportableEmployerSuperannuationContributions PaymentSummaryBusinessAndPersonalServicesIncome where+  reportableEmployerSuperannuationContributions =+    lens _bpsiRESC (\s b -> s { _bpsiRESC = b })+++-- | PAYG payment summary - withholding where ABN not quoted (other+-- than those covered by annual investment income reporting).+--+-- Use 'newPaymentSummaryWithholdingWhereABNNotQuoted' to construct this data+-- type (all amounts initially zero).+--+-- To @set@ and @view@ the various fields, these lenses are available:+--+-- +-------------------------------------------------+-----------------------------------------++-- | 'payerDetails'                                  | Use 'newPayerDetails' to construct.     |+-- +-------------------------------------------------+-----------------------------------------++-- | 'totalTaxWithheld'                              | TOTAL AMOUNT WITHHELD                   |+-- +-------------------------------------------------+-----------------------------------------++-- | 'grossPayments'                                 | Gross payment (including the market     |+-- |                                                 | value of non-cash benefits).            |+-- +-------------------------------------------------+-----------------------------------------++--+data PaymentSummaryWithholdingWhereABNNotQuoted a = PaymentSummaryWithholdingWhereABNNotQuoted+  { _noabnPayer :: PayerDetails+  , _noabnWithholding :: Money a+  , _noabnGross :: Money a+  }++-- | Construct a new payment summary.  All amounts are initially zero.+newPaymentSummaryWithholdingWhereABNNotQuoted+  :: (Num a) => PayerDetails -> PaymentSummaryWithholdingWhereABNNotQuoted a+newPaymentSummaryWithholdingWhereABNNotQuoted payer =+  PaymentSummaryWithholdingWhereABNNotQuoted payer+    mempty    -- total tax withheld+    mempty    -- gross payments++instance HasTaxableIncome PaymentSummaryWithholdingWhereABNNotQuoted a a where+  taxableIncome = grossPayments++instance HasTaxWithheld PaymentSummaryWithholdingWhereABNNotQuoted a a where+  taxWithheld = totalTaxWithheld++instance HasPayerDetails PaymentSummaryWithholdingWhereABNNotQuoted where+  payerDetails = lens _noabnPayer (\s b -> s { _noabnPayer = b })++instance HasTotalTaxWithheld PaymentSummaryWithholdingWhereABNNotQuoted where+  totalTaxWithheld = lens _noabnWithholding (\s b -> s { _noabnWithholding = b })++instance HasGrossPayments PaymentSummaryWithholdingWhereABNNotQuoted where+  grossPayments = lens _noabnGross (\s b -> s { _noabnGross = b })+++-- | Objects which have a /GROSS PAYMENTS/ field.+class HasGrossPayments s where+  grossPayments :: Lens' (s a) (Money a)++-- | Objects which have a /gross payments type/ field.+-- The value type may vary.+--+class HasGrossPaymentsType s a where+  grossPaymentsType :: Lens' (s any) a++-- | Objects which have a /GROSS PAYMENTS/ field.+class HasTotalTaxWithheld s where+  totalTaxWithheld :: Lens' (s a) (Money a)++-- | Objects which may have Reportable employer superannuation contributions+class HasReportableEmployerSuperannuationContributions s where+  reportableEmployerSuperannuationContributions :: Lens' (s a) (Money a)+++-- | Objects which may have reportable fringe benefit amounts+class HasReportableFringeBenefits s where+  reportableFringeBenefits :: Lens' (s a) (Maybe (ReportableFringeBenefits a))++-- | Helper constructor for fringe benefits amount (employer not exempt from FBT).+-- See also 'fringeBenefitsEmployerExempt'.+fringeBenefitsEmployerNotExempt :: Money a -> Maybe (ReportableFringeBenefits a)+fringeBenefitsEmployerNotExempt x = Just $ ReportableFringeBenefits x EmployerNotFBTExempt++-- | Helper constructor for fringe benefits amount (employer exempt from FBT)+-- See also 'fringeBenefitsEmployerNotExempt'.+fringeBenefitsEmployerExempt :: Money a -> Maybe (ReportableFringeBenefits a)+fringeBenefitsEmployerExempt x = Just $ ReportableFringeBenefits x EmployerFBTExempt++data FBTEmployerExemption = EmployerNotFBTExempt | EmployerFBTExempt+  deriving (Eq, Ord)++-- | Reportable fringe benefits amount, with the employer exemption status.+--+-- For setting the fringe benefits amount in a+-- 'PaymentSummaryIndividualNonBusiness', we provide more ergonomic helper+-- constructors: 'fringeBenefitsEmployerNotExempt' and+-- 'fringeBenefitsEmployerExempt'.+--+data ReportableFringeBenefits a =+  ReportableFringeBenefits (Money a) FBTEmployerExemption+  deriving (Eq, Ord)+++-- | Use 'allowance' to construct, and lenses 'allowanceDetail' and+-- 'allowanceAmount' for field access.+--+data Allowance a = Allowance+  { _allowanceDetail :: String+  , _allowanceAmount :: (Money a)+  }+  deriving (Eq, Ord)++allowance+  :: (RealFrac a)+  => String   -- ^ Allowance details+  -> Money a  -- ^ Amount (discards cents)+  -> Allowance a+allowance s = Allowance s . wholeDollars++allowanceDetail :: Lens' (Allowance a) String+allowanceDetail = lens _allowanceDetail (\s b -> s { _allowanceDetail = b })++allowanceAmount :: Lens (Allowance a) (Allowance b) (Money a) (Money b)+allowanceAmount = lens _allowanceAmount (\s b -> s { _allowanceAmount = b })+++-- | Use 'lumpSumATypeR' or 'lumpSumATypeT' to construct, and lenses+-- 'lumpSumAType' and 'lumpSumAAmount' for field access.+data LumpSumA a = LumpSumA+  { _lumpSumAType   :: LumpSumAType+  , _lumpSumAAmount :: Money a+  }+  deriving (Eq, Ord)++data LumpSumAType+  = LumpSumATypeR+  -- ^ if the payment was made for a genuine redundancy, invalidity+  -- or under an early retirement scheme+  | LumpSumATypeT+  -- ^ if the payment was made for any other reason+  deriving (Eq, Ord)++-- | A /lump sum A/ payment made for genuine redundancy, invalidity+-- or under an early retirement scheme.  See also 'lumpSumATypeT'.+lumpSumATypeR :: (RealFrac a) => Money a -> LumpSumA a+lumpSumATypeR = LumpSumA LumpSumATypeR . wholeDollars++-- | A /lump sum A/ payment made for any other reason.+-- See also 'lumpSumATypeR'.+lumpSumATypeT :: (RealFrac a) => Money a -> LumpSumA a+lumpSumATypeT = LumpSumA LumpSumATypeT . wholeDollars++lumpSumAType :: Lens' (LumpSumA a) LumpSumAType+lumpSumAType = lens _lumpSumAType (\s b -> s { _lumpSumAType = b })++lumpSumAAmount :: Lens (LumpSumA a) (LumpSumA b) (Money a) (Money b)+lumpSumAAmount = lens _lumpSumAAmount (\s b -> s { _lumpSumAAmount = b })++class HasLumpSumA s where+  lumpSumA :: Lens' (s a) (Maybe (LumpSumA a))+++class HasLumpSumD s where+  lumpSumD :: Lens' (s a) (Money a)+++class HasLumpSumE s where+  lumpSumE :: Lens' (s a) (Money a)+++-- | Payer details.  Use 'newPayerDetails' to construct.+-- Use 'payerABN', 'payerBranchNumber' and 'payerName' lenses to view or+-- set the fields.+--+-- Use the 'payerDetails' classy optic to access the payer details field+-- in payment summary data types.+--+data PayerDetails = PayerDetails+  { _payerABN :: ABN+  , _payerBranch :: Maybe Int+  , _payerName :: String+  }+  deriving (Eq, Ord)++-- | __Deprecated__ instance that interprets string as ABN and+-- sets payer name to the empty string.+--+instance IsString PayerDetails where+  fromString s = PayerDetails (fromString s) Nothing ""++newPayerDetails :: ABN -> Maybe Int -> String -> PayerDetails+newPayerDetails = PayerDetails++payerABN :: Lens' PayerDetails ABN+payerABN = lens _payerABN (\s b -> s { _payerABN = b })++payerBranchNumber :: Lens' PayerDetails (Maybe Int)+payerBranchNumber = lens _payerBranch (\s b -> s { _payerBranch = b })++payerName :: Lens' PayerDetails String+payerName = lens _payerName (\s b -> s { _payerName = b })++class HasPayerDetails s where+  payerDetails :: Lens' (s a) PayerDetails
src/Data/Tax/ATO/Pretty.hs view
@@ -27,13 +27,12 @@ module Data.Tax.ATO.Pretty   ( summariseTaxReturnInfo   , summariseAssessment-  , summariseCGTAssessment+  , formatMoney   ) where -import Data.Function (on)-import Data.List (groupBy, sortOn)+import Data.List.NonEmpty as NE (NonEmpty, groupAllWith, head) -import Control.Lens (ALens', cloneLens, view, views)+import Control.Lens (ALens', cloneLens, foldOf, view, views) import qualified Text.PrettyPrint as P  import Data.Tax.ATO@@ -62,6 +61,11 @@ twoCol :: (P.Doc, Money Rational) -> P.Doc twoCol (label, value) = label P.$$ P.nest (80 - colWidthMoney) (formatMoney value) +omitIfZero :: ((a, Money Rational) -> P.Doc) -> (a, Money Rational) -> P.Doc+omitIfZero f rec@(_,x)+  | x == mempty = P.empty+  | otherwise   = f rec+ threeCol :: (P.Doc, Money Rational, Money Rational) -> P.Doc threeCol (label, v1, v2) =   label@@ -81,14 +85,18 @@ summariseTaxReturnInfo info =   "Income"   P.$+$ vcatWith threeCol-    [ ("  1   Salary or wages"  , view (paymentSummaries . taxWithheld) info, view (paymentSummaries . taxableIncome) info)+    [ ( "  1   Salary or wages"+      , view (paymentSummariesIndividualNonBusiness . taxWithheld) info+      , view (paymentSummariesIndividualNonBusiness . taxableIncome) info+      )     , ("  10  Interest"         , view (interest . taxWithheld) info, view (interest . taxableIncome) info)     ]   P.$+$ "  11  Dividends"   P.$+$ views dividends summariseDividends info+  P.$+$ views ess summariseESS info+  P.$+$ summariseCGT info   P.$+$ vcatWith twoCol-    [ ("  12  Employee share schemes" , view (ess . taxableIncome) info)-    , ("  20M Other net foreign source income" , view foreignIncome info)+    [ ("  20M Other net foreign source income" , view foreignIncome info)     ]   P.$+$ "Deductions"   P.$+$ P.vcat (uncurry (summariseDeduction (view deductions info)) <$> deductionsTable)@@ -100,16 +108,50 @@ summariseDividends :: [Dividend Rational] -> P.Doc summariseDividends =   vcatWith (threeCol . prep)-  . groupBy ((==) `on` dividendSource)-  . sortOn dividendSource+  . groupAllWith dividendSource   where-    prep :: [Dividend Rational] -> (P.Doc, Money Rational, Money Rational)+    prep :: NonEmpty (Dividend Rational) -> (P.Doc, Money Rational, Money Rational)     prep l =-      ( P.text ("        " <> dividendSource (head l))+      ( P.text ("        " <> dividendSource (NE.head l))       , view taxWithheld l       , view taxableIncome l       ) +summariseESS :: [ESSStatement Rational] -> P.Doc+summariseESS [] = P.empty+summariseESS l =+  "  12  Employee share schemes"+  P.$+$ P.vcat+    [ twoCol+        ( "    D Discount from upfront schemes - eligible for reduction"+        , foldOf (traverse . essTaxedUpfrontReduction) l )+    , twoCol+        ( "    E Discount from upfront schemes - ineligible for reduction"+        , foldOf (traverse . essTaxedUpfrontNoReduction) l )+    , twoCol+        ( "    F Discount from deferral schemes"+        , foldOf (traverse . essDeferral) l )+    , threeColLeft+        ( "    C TFN amounts withheld from discounts"+        , foldOf (traverse . essTFNAmounts) l )+    , twoCol+        ( "    A Foreign source discounts"+        , foldOf (traverse . essForeignSourceDiscounts) l )+    ]++summariseCGT :: TaxReturnInfo y Rational -> P.Doc+summariseCGT info+  | o == nullCGTAssessment = P.empty+  | otherwise =+      "  18  Capital gains"+      P.$+$ P.vcat+        [ twoCol        ("    A Net capital gain",                   view cgtNetGain o)+        , threeColLeft  ("    H Total current year capital gains",   view cgtTotalCurrentYearGains o)+        , threeColLeft  ("    V Net capital losses carried forward", view cgtNetLossesCarriedForward o)+        ]+  where+    o = assessCGTEvents (view capitalLossCarryForward info) (view cgtEvents info)+ deductionsTable :: [(ALens' (Deductions Rational) (Money Rational), String)] deductionsTable =   [ (workRelatedCarExpenses, "D1  Work-related car expenses")@@ -135,33 +177,34 @@   -> String   -> P.Doc summariseDeduction a l desc-  | amt > mempty-  = P.nest 2 (P.text desc) P.$$ P.nest colWidthLabel (formatMoney amt)-  | otherwise-  = P.empty-  where-    amt = view (cloneLens l) a+  = omitIfZero twoCol (P.nest 2 (P.text desc), view (cloneLens l) a)   summariseAssessment :: TaxAssessment Rational -> P.Doc summariseAssessment assessment =   "Your taxable income is $" P.<> formatMoney (view taxableIncome assessment)   P.$+$ P.text (replicate 80 '-')-  P.$+$ vcatWith twoCol-    [ ("Tax on your taxable income"                 , view taxDue assessment)-    , ("Less credits and offsets"                   , views taxCreditsAndOffsets (fmap negate) assessment)-    , ("Medicare levy (and surcharge, if any)"      , view medicareLevyDue assessment)-    , ("Study and training loan repayment"          , view studyAndTrainingLoanRepayment assessment)-    , ("Excess private health reduction or refund"  , view privateHealthInsuranceRebateAdjustment assessment)-    , ("Less PAYG withholding"                      , views taxWithheld (fmap negate) assessment)-    , ("Less PAYG instalments"                      , views paygInstalmentsCredit (fmap negate) assessment)+  P.$+$ threeColLeft ("Tax on your taxable on net income"          , view taxDue assessment)+  P.$+$ "Less non-refundable tax offsets"+  P.$+$ vcatWith (omitIfZero twoCol)+    [ ("  Offset for super contributions on behalf of your spouse"+      , view offsetForSuperannuationContributionsOnBehalfOfYourSpouse assessment )+    , ("  Foreign income tax offsets"                 , view foreignIncomeTaxOffsets assessment)     ]+  P.$+$ "Less refundable tax offsets"+  P.$+$ twoCol ("  Franking credit offset"            , view frankingCreditOffset assessment)+  P.$+$ "Plus other liabilities"+  P.$+$ vcatWith (omitIfZero threeColLeft)+    [ ("  Medicare levy"                              , view medicareLevyDue assessment)+    , ("  Medicare levy surcharge"                    , view medicareLevySurchargeDue assessment)+    , ("  Study and training loan repayment"          , view studyAndTrainingLoanRepayment assessment)+    , ("  Excess private health reduction or refund"  , view privateHealthInsuranceRebateAdjustment assessment)+    ]+  P.$+$ "Less Pay as you go (PAYG) credits and other entitlements"+  P.$+$ vcatWith (omitIfZero twoCol)+    [ ("  PAYG instalments"                           , view paygInstalmentsCredit assessment)+    , ("  PAYG withholding"                           , view taxWithheld assessment)+    ]   P.$+$ P.text (replicate 80 '-')   P.$+$ "Result of this notice" P.$$ P.nest colWidthLabel (views taxBalance formatMoney assessment)   P.$+$ "Net capital loss to carry forward" P.$$ P.nest colWidthLabel (views (taxCGTAssessment . capitalLossCarryForward) formatMoney assessment)--summariseCGTAssessment :: CGTAssessment Rational -> P.Doc-summariseCGTAssessment cgtAss@(CGTAssessment total _) =-  "Total FY capital gains" P.$$ (P.nest colWidthLabel . formatMoney) total-  P.$+$ "Net capital gain" P.$$ P.nest colWidthLabel (views cgtNetGain formatMoney cgtAss)-  P.$+$ "Net capital loss to carry forward" P.$$ P.nest colWidthLabel (views capitalLossCarryForward formatMoney cgtAss)
src/Data/Tax/ATO/PrivateHealthInsuranceRebate.hs view
@@ -14,8 +14,6 @@ -- 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/>. -{-# LANGUAGE RankNTypes #-}- {- |  Types and functions for the Private Health Insurance Rebate.
+ src/Data/Tax/ATO/TFN.hs view
@@ -0,0 +1,94 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2025  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/>.++{-|++Tax File Number (TFN) types and functions.++@+import qualified Data.Tax.ATO.TFN as TFN++main = do+  let+    tfnStr = "330 600 376"+    Just tfn = TFN.parse tfnStr+    tfnInt = TFN.asInt tfn+    Just tfn' = TFN.fromInt tfnInt+  putStrLn $ TFN.asString tfn'  -- prints "330 600 376"+@++It is recommended to import this module qualified.++You can use the @OverloadedStrings@ language extension or the 'parse' function+to convert string to TFNs.  Space characters are ignored, but other non-digits+will cause parse failure.++-}++module Data.Tax.ATO.TFN+  (+    TFN+  , parse+  , fromInt+  , asString+  , asInt+  ) where++import Data.Char (isDigit)+import Data.String+import Data.Maybe (fromJust)++-- | Tax File Number (TFN)+newtype TFN = TFN Int+  deriving (Eq, Ord, Show)++-- | Parse a TFN, throwing an error if it is not valid.+instance IsString TFN where+  fromString = fromJust . parse++-- | Construct a TFN, checking validity.+fromInt :: Int -> Maybe TFN+fromInt n | valid n = Just (TFN n)+fromInt _           = Nothing++-- | Parse a TFN.  Spaces characters are allowed, other non-digit+-- characters are not.+parse :: String -> Maybe TFN+parse s+  | all isDigit s'  = fromInt (read s')+  | otherwise       = Nothing+  where s' = filter (/= ' ') s++valid :: Int -> Bool+valid n =+  (== 0) . (`mod` 11) . snd $ foldr step (n, 0) weights+  where+    weights = [1,4,3,7,5,8,6,9,10]+    step weight (n',acc) = ((+ acc) . (* weight)) <$> divMod n' 10++asInt :: TFN -> Int+asInt (TFN n) = n++-- Format TFN in the standard way (XXX XXX XXX)+asString :: TFN -> String+asString (TFN n) =+  case s' of+    [a1,a2,a3,b1,b2,b3,c1,c2,c3]  -> [a1,a2,a3,' ',b1,b2,b3,' ',c1,c2,c3]+    _                             -> show n -- can't happen, but just in case...+  where+    n' = abs n  -- negative can't happen, but just in case...+    s = show n'+    s' = replicate (9 - length s) '0' <> s  -- left-pad to 9 digits
tax-ato.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                tax-ato-version:             2024.1.0.1+version:             2025.1 synopsis:            Tax types and computations for Australia description:   This library provides types and tax computations for tax@@ -14,7 +14,7 @@ copyright:           Copyright (C) 2018-2023 Fraser Tweedale category:            Finance build-type:          Simple-tested-with:         GHC ==9.2.8 || ==9.4.7 || ==9.6.3 || ==9.8.1+tested-with:         GHC ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2 extra-source-files:   .hlint.yaml extra-doc-files:@@ -27,7 +27,7 @@   location: https://github.com/frasertweedale/hs-tax-ato.git  common common-  default-language: Haskell2010+  default-language: GHC2021   ghc-options:     -Wall     -Wcompat@@ -41,18 +41,12 @@     -Wredundant-constraints     -Wunused-packages     -fhide-source-paths-  if impl(ghc >= 9.0)-    ghc-options:-      -Winvalid-haddock-      -Werror=unicode-bidirectional-format-characters-  if impl(ghc >= 9.2)-    ghc-options:-      -Wimplicit-lift-      -Woperator-whitespace-      -Wredundant-bang-patterns-  if impl(ghc >= 9.4)-    ghc-options:-      -Wredundant-strictness-flags+    -Winvalid-haddock+    -Werror=unicode-bidirectional-format-characters+    -Wimplicit-lift+    -Woperator-whitespace+    -Wredundant-bang-patterns+    -Wredundant-strictness-flags   build-depends:     base >= 4.14 && < 5 @@ -61,8 +55,12 @@   hs-source-dirs:      src   exposed-modules:     Data.Tax.ATO+    Data.Tax.ATO.ABN+    Data.Tax.ATO.TFN     Data.Tax.ATO.CGT     Data.Tax.ATO.Common+    Data.Tax.ATO.Depreciation+    Data.Tax.ATO.PaymentSummary     Data.Tax.ATO.Pretty     Data.Tax.ATO.PrivateHealthInsuranceRebate     Data.Tax.ATO.Rounding@@ -75,8 +73,9 @@     Data.Tax.ATO.FY.FY2022     Data.Tax.ATO.FY.FY2023     Data.Tax.ATO.FY.FY2024+    Data.Tax.ATO.FY.FY2025   build-depends:-    , lens >= 4.12 && < 6-    , time >= 1.11 && < 1.13+    , lens >= 4.18 && < 6+    , time >= 1.11 && < 1.15     , tax >= 0.2 && < 0.3     , pretty >= 1.1.3.6 && < 2