packages feed

tax-ato 2025.1 → 2026.1

raw patch · 10 files changed

+1460/−197 lines, 10 filesdep +containersdep ~timePVP ok

version bump matches the API change (PVP)

Dependencies added: containers

Dependency ranges changed: time

API changes (from Hackage documentation)

- Data.Tax.ATO.CGT: CGTEvent :: String -> a -> Day -> Money a -> Money a -> Day -> Money a -> Money a -> Money a -> Money a -> CGTEvent a
- Data.Tax.ATO.CGT: [acquisitionCosts] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [acquisitionDate] :: CGTEvent a -> Day
- Data.Tax.ATO.CGT: [acquisitionPrice] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [assetDesc] :: CGTEvent a -> String
- Data.Tax.ATO.CGT: [capitalCosts] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [disposalCosts] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [disposalDate] :: CGTEvent a -> Day
- Data.Tax.ATO.CGT: [disposalPrice] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [ownershipCosts] :: CGTEvent a -> Money a
- Data.Tax.ATO.CGT: [units] :: CGTEvent a -> a
- Data.Tax.ATO.CGT: class HasCapitalGain (a :: k -> Type) (b :: k) c
- Data.Tax.ATO.CGT: instance (Data.Foldable.Foldable t, Data.Tax.ATO.CGT.HasCapitalGain x a a, GHC.Num.Num a) => Data.Tax.ATO.CGT.HasCapitalGain t (x a) a
- Data.Tax.ATO.CGT: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Data.Tax.ATO.CGT.HasCapitalGain Data.Tax.ATO.CGT.CGTEvent a a
- 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 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: businessAndProfessionalItems :: forall (y :: Nat) a f. Functor f => (BusinessAndProfessionalItemsSchedule a -> f (BusinessAndProfessionalItemsSchedule a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO: capitalLossCarryForwardCollectables :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalLossCarryForward a -> f (CapitalLossCarryForward a)
+ Data.Tax.ATO: capitalLossCarryForwardOther :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalLossCarryForward a -> f (CapitalLossCarryForward a)
+ Data.Tax.ATO: data OtherIncome a
+ Data.Tax.ATO: instance GHC.Num.Num a => Data.Tax.ATO.Common.HasTaxWithheld Data.Tax.ATO.OtherIncome a a
+ Data.Tax.ATO: instance GHC.Num.Num a => Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.OtherIncome a a
+ Data.Tax.ATO: otherIncome :: forall (y :: Nat) a f. Functor f => (OtherIncome a -> f (OtherIncome a)) -> TaxReturnInfo y a -> f (TaxReturnInfo y a)
+ Data.Tax.ATO: otherIncomeCategory1 :: forall a f. Functor f => ([(String, Money a)] -> f [(String, Money a)]) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: otherIncomeCategory2 :: forall a f. Functor f => ([(String, Money a)] -> f [(String, Money a)]) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: otherIncomeCategory3 :: forall a f. Functor f => (Money a -> f (Money a)) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: otherIncomeCategory4 :: forall a f. Functor f => ([(String, Money a)] -> f [(String, Money a)]) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: taxWithheldAssessableFHSSReleasedAmount :: forall a f. Functor f => (Money a -> f (Money a)) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: taxWithheldLumpSumPaymentsInArrears :: forall a f. Functor f => (Money a -> f (Money a)) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO: taxableProfessionalIncome :: forall a f. Functor f => (Money a -> f (Money a)) -> OtherIncome a -> f (OtherIncome a)
+ Data.Tax.ATO.BPI: data BusinessAndProfessionalItemsSchedule a
+ Data.Tax.ATO.BPI: data PersonalServicesIncome a
+ Data.Tax.ATO.BPI: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.BPI.BusinessAndProfessionalItemsSchedule a a
+ Data.Tax.ATO.BPI: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Data.Tax.ATO.Common.HasTaxableIncome Data.Tax.ATO.BPI.PersonalServicesIncome a a
+ Data.Tax.ATO.BPI: netPSI :: Num a => PersonalServicesIncome a -> Money a
+ Data.Tax.ATO.BPI: newBusinessAndProfessionalItemsSchedule :: Num a => BusinessAndProfessionalItemsSchedule a
+ Data.Tax.ATO.BPI: newPersonalServicesIncome :: Num a => PersonalServicesIncome a
+ Data.Tax.ATO.BPI: personalServicesIncome :: forall a f. Functor f => (PersonalServicesIncome a -> f (PersonalServicesIncome a)) -> BusinessAndProfessionalItemsSchedule a -> f (BusinessAndProfessionalItemsSchedule a)
+ Data.Tax.ATO.BPI: psiDeductionsForPaymentsToAssociatesForPrincipalWork :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.BPI: psiLabourHireOrOtherSpecifiedPayments :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.BPI: psiOther :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.BPI: psiTotalAmountOfOtherDeductions :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.BPI: psiVoluntaryAgreement :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.BPI: psiWhereABNNotQuoted :: forall a f. Functor f => (Money a -> f (Money a)) -> PersonalServicesIncome a -> f (PersonalServicesIncome a)
+ Data.Tax.ATO.CGT: AffordableHousing :: CGTAssetFlag
+ Data.Tax.ATO.CGT: AffordableHousingDiscount :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: AssetTypeCollectable :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeOther :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypePersonalUse :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeRealEstateAU :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeRealEstateOther :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeSharesAUListed :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeSharesOther :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeUnitsAUListed :: CGTAssetType
+ Data.Tax.ATO.CGT: AssetTypeUnitsOther :: CGTAssetType
+ Data.Tax.ATO.CGT: CGTScheduleCategoryCollectable :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryDeferred :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryOther :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryRealEstateAU :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryRealEstateOther :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategorySharesAUListed :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategorySharesOther :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryTrust :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryUnitsAUListed :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CGTScheduleCategoryUnitsOther :: CGTScheduleCategory
+ Data.Tax.ATO.CGT: CapitalGainsDisregardedAsAResultOfTheSaleOfAPreCGTAsset :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: DemergerRollover :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: DisposalOrCreationOfAssetsInAWhollyOwnedCompany :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: EarlyStageInnovationCompany :: CGTAssetFlag
+ Data.Tax.ATO.CGT: EarlyStageInvestor :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ExchangeOfRightsOrOptions :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ExchangeOfSharesInOneCompanyForSharesInAnotherCompany :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ExchangeOfSharesOrUnits :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ExchangeOfUnitsInAUnitTrustForSharesInACompany :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ForeignResidentCGTExemption :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: MainResidence :: CGTAssetFlag
+ Data.Tax.ATO.CGT: MainResidenceExemption :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: OtherExemptionsAndRollovers :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ReplacementAssetRollovers :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SameAssetRollovers :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: ScripForScripRollover :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SmallBusiness15YearExemption :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SmallBusinessActiveAsset :: CGTAssetFlag
+ Data.Tax.ATO.CGT: SmallBusinessActiveAssetReduction :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SmallBusinessRestructureRollover :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SmallBusinessRetirementExemption :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: SmallBusinessRollover :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: VentureCapitalInvestment :: CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: assetAcquisitionCosts :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetAcquisitionDate :: forall a f. Functor f => (Day -> f Day) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetAcquisitionPrice :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetCapitalCosts :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetDescription :: forall a f. Functor f => (String -> f String) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetFlag :: forall a f. Functor f => (Maybe CGTAssetFlag -> f (Maybe CGTAssetFlag)) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetOwnershipCosts :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetShare :: forall a f. Functor f => (Rational -> f Rational) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetType :: forall a f. Functor f => (CGTAssetType -> f CGTAssetType) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: assetUnits :: forall a f. Functor f => (Rational -> f Rational) -> CGTAsset a -> f (CGTAsset a)
+ Data.Tax.ATO.CGT: capitalLossCarryForwardCollectables :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalLossCarryForward a -> f (CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: capitalLossCarryForwardOther :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalLossCarryForward a -> f (CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: cgtEventA1 :: CGTAsset a -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode -> Day -> Money a -> Money a -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtEventB1 :: CGTAsset a -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode -> Day -> Money a -> Money a -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtEventC1 :: CGTAsset a -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode -> Day -> Money a -> Money a -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtEventC2 :: CGTAsset a -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode -> Day -> Money a -> Money a -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtEventC3 :: Num a => CGTAsset a -> Day -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtEventE10 :: Num a => CGTAsset a -> Day -> Money a -> CGTEvent a
+ Data.Tax.ATO.CGT: cgtGainsAndLossesByCategory :: forall a f. Functor f => (Map CGTScheduleCategory (Money a, Money a) -> f (Map CGTScheduleCategory (Money a, Money a))) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtTotalCGTDiscountApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtTotalCurrentYearLosses :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtTotalCurrentYearLossesApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtTotalPriorYearLossesApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: data CGTAsset a
+ Data.Tax.ATO.CGT: data CGTAssetFlag
+ Data.Tax.ATO.CGT: data CGTAssetType
+ Data.Tax.ATO.CGT: data CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: data CGTScheduleCategory
+ Data.Tax.ATO.CGT: data CapitalGainsFromTrust a
+ Data.Tax.ATO.CGT: data CapitalLossCarryForward a
+ Data.Tax.ATO.CGT: eventAsset :: forall a f. Applicative f => (CGTAsset a -> f (CGTAsset a)) -> CGTEvent a -> f (CGTEvent a)
+ Data.Tax.ATO.CGT: eventCode :: forall a f. Functor f => (Maybe CGTExemptionRolloverOrAdditionalDiscountCode -> f (Maybe CGTExemptionRolloverOrAdditionalDiscountCode)) -> CGTEvent a -> f (CGTEvent a)
+ Data.Tax.ATO.CGT: eventCosts :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTEvent a -> f (CGTEvent a)
+ Data.Tax.ATO.CGT: eventDate :: forall a f. Functor f => (Day -> f Day) -> CGTEvent a -> f (CGTEvent a)
+ Data.Tax.ATO.CGT: eventPrice :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTEvent a -> f (CGTEvent a)
+ Data.Tax.ATO.CGT: eventProceeds :: CGTEvent Rational -> Money Rational
+ Data.Tax.ATO.CGT: instance GHC.Base.Functor Data.Tax.ATO.CGT.CGTAsset
+ Data.Tax.ATO.CGT: instance GHC.Base.Functor Data.Tax.ATO.CGT.CGTEventType
+ Data.Tax.ATO.CGT: instance GHC.Base.Functor Data.Tax.ATO.CGT.CapitalLossCarryForward
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq Data.Tax.ATO.CGT.CGTAssetFlag
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq Data.Tax.ATO.CGT.CGTAssetType
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq Data.Tax.ATO.CGT.CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq Data.Tax.ATO.CGT.CGTScheduleCategory
+ Data.Tax.ATO.CGT: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Tax.ATO.CGT.CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: instance GHC.Classes.Ord Data.Tax.ATO.CGT.CGTAssetFlag
+ Data.Tax.ATO.CGT: instance GHC.Classes.Ord Data.Tax.ATO.CGT.CGTAssetType
+ Data.Tax.ATO.CGT: instance GHC.Classes.Ord Data.Tax.ATO.CGT.CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: instance GHC.Classes.Ord Data.Tax.ATO.CGT.CGTScheduleCategory
+ Data.Tax.ATO.CGT: instance GHC.Num.Num a => GHC.Base.Monoid (Data.Tax.ATO.CGT.CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: instance GHC.Num.Num a => GHC.Base.Semigroup (Data.Tax.ATO.CGT.CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: instance GHC.Show.Show Data.Tax.ATO.CGT.CGTAssetFlag
+ Data.Tax.ATO.CGT: instance GHC.Show.Show Data.Tax.ATO.CGT.CGTAssetType
+ Data.Tax.ATO.CGT: instance GHC.Show.Show Data.Tax.ATO.CGT.CGTExemptionRolloverOrAdditionalDiscountCode
+ Data.Tax.ATO.CGT: instance GHC.Show.Show Data.Tax.ATO.CGT.CGTScheduleCategory
+ Data.Tax.ATO.CGT: instance GHC.Show.Show Data.Tax.ATO.CGT.IsDiscountable
+ 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.CGTAsset a)
+ Data.Tax.ATO.CGT: instance GHC.Show.Show a => GHC.Show.Show (Data.Tax.ATO.CGT.CGTEventType a)
+ Data.Tax.ATO.CGT: instance GHC.Show.Show a => GHC.Show.Show (Data.Tax.ATO.CGT.CapitalGainsFromTrust a)
+ Data.Tax.ATO.CGT: instance GHC.Show.Show a => GHC.Show.Show (Data.Tax.ATO.CGT.CapitalLossCarryForward a)
+ Data.Tax.ATO.CGT: newCGTAsset :: Num a => String -> Rational -> CGTAssetType -> Rational -> Day -> Money a -> Money a -> CGTAsset a
+ Data.Tax.ATO.CGT: newCapitalGainsFromTrust :: Money a -> Money a -> Money a -> Money a -> CapitalGainsFromTrust a
+ Data.Tax.ATO.CGT: newCapitalLossCarryForward :: Num a => CapitalLossCarryForward a
+ Data.Tax.ATO.CGT: prepTrustCGT :: (Fractional a, Eq a) => CapitalGainsFromTrust a -> [CGTEvent a]
+ Data.Tax.ATO.CGT: trustCGTDiscountApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalGainsFromTrust a -> f (CapitalGainsFromTrust a)
+ Data.Tax.ATO.CGT: trustCGTSmallBusinessConcessionApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalGainsFromTrust a -> f (CapitalGainsFromTrust a)
+ Data.Tax.ATO.CGT: trustCapitalLossesApplied :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalGainsFromTrust a -> f (CapitalGainsFromTrust a)
+ Data.Tax.ATO.CGT: trustGrossCapitalGain :: forall a f. Functor f => (Money a -> f (Money a)) -> CapitalGainsFromTrust a -> f (CapitalGainsFromTrust a)
+ Data.Tax.ATO.Common: Company :: EntityType
+ Data.Tax.ATO.Common: Individual :: EntityType
+ Data.Tax.ATO.Common: SuperFund :: EntityType
+ Data.Tax.ATO.Common: Trust :: EntityType
+ Data.Tax.ATO.Common: data EntityType
+ Data.Tax.ATO.Common: instance (2016 Data.Type.Ord.<= y, y Data.Type.Ord.<= 2027, Data.Tax.ATO.FY.FinancialYear y) => Data.Tax.ATO.Common.HasCentsPerKilometreMethod y
+ Data.Tax.ATO.Common: instance (2023 Data.Type.Ord.<= y, y Data.Type.Ord.<= 2027, Data.Tax.ATO.FY.FinancialYear y) => Data.Tax.ATO.Common.HasFixedRateMethod y
+ Data.Tax.ATO.Common: instance GHC.Classes.Eq Data.Tax.ATO.Common.EntityType
+ Data.Tax.ATO.Common: instance GHC.Classes.Ord Data.Tax.ATO.Common.EntityType
+ Data.Tax.ATO.Common: instance GHC.Show.Show Data.Tax.ATO.Common.EntityType
+ Data.Tax.ATO.FY.FY2026: fyProxy :: Proxy FY
+ Data.Tax.ATO.FY.FY2026: tables :: (Ord a, Fractional a) => TaxTables FY a
+ Data.Tax.ATO.FY.FY2026: type FY = 2026
+ Data.Tax.ATO.FY.FY2027: fyProxy :: Proxy FY
+ Data.Tax.ATO.FY.FY2027: tables :: (Ord a, Fractional a) => TaxTables FY a
+ Data.Tax.ATO.FY.FY2027: type FY = 2027
+ Data.Tax.ATO.Pretty: summariseCGTSchedule :: CGTAssessment Rational -> Doc
- Data.Tax.ATO: capitalLossCarryForward :: HasCapitalLossCarryForward a b => Lens' (a b) (Money b)
+ Data.Tax.ATO: capitalLossCarryForward :: HasCapitalLossCarryForward a b => Lens' (a b) (CapitalLossCarryForward b)
- Data.Tax.ATO: paygInstalmentIncome :: forall a (y :: Nat). RealFrac a => TaxReturnInfo y a -> Money a
+ Data.Tax.ATO: paygInstalmentIncome :: forall (y :: Nat) a. RealFrac a => TaxReturnInfo y a -> Money a
- Data.Tax.ATO.CGT: assessCGTEvents :: (Fractional a, Ord a, Foldable t) => Money a -> t (CGTEvent a) -> CGTAssessment a
+ Data.Tax.ATO.CGT: assessCGTEvents :: (Fractional a, Ord a, Foldable t) => EntityType -> CapitalLossCarryForward a -> t (CGTEvent a) -> CGTAssessment a
- Data.Tax.ATO.CGT: capitalGain :: HasCapitalGain a b c => Getter (a b) (Money c)
+ Data.Tax.ATO.CGT: capitalGain :: (Fractional a, Ord a) => CGTEvent a -> Money a
- Data.Tax.ATO.CGT: capitalLoss :: (Num a, Ord a) => CGTEvent a -> Money a
+ Data.Tax.ATO.CGT: capitalLoss :: (Fractional a, Ord a) => CGTEvent a -> Money a
- Data.Tax.ATO.CGT: capitalLossCarryForward :: HasCapitalLossCarryForward a b => Lens' (a b) (Money b)
+ Data.Tax.ATO.CGT: capitalLossCarryForward :: HasCapitalLossCarryForward a b => Lens' (a b) (CapitalLossCarryForward b)
- Data.Tax.ATO.CGT: cgtNetLossesCarriedForward :: forall a f. Functor f => (Money a -> f (Money a)) -> CGTAssessment a -> f (CGTAssessment a)
+ Data.Tax.ATO.CGT: cgtNetLossesCarriedForward :: Num a => Getter (CGTAssessment a) (Money a)
- Data.Tax.ATO.CGT: isCapitalGain :: (Num a, Ord a) => CGTEvent a -> Bool
+ Data.Tax.ATO.CGT: isCapitalGain :: (Fractional a, Ord a) => CGTEvent a -> Bool
- Data.Tax.ATO.CGT: isCapitalLoss :: (Num a, Ord a) => CGTEvent a -> Bool
+ Data.Tax.ATO.CGT: isCapitalLoss :: (Fractional a, Ord a) => CGTEvent a -> Bool

Files

CHANGELOG.md view
@@ -1,3 +1,97 @@+## Version 2026.1++### CGT overhaul++Capital gains tax (CGT) received a significant overhaul.+Enhancements include:++- Added the a `CGTAsset` data type, which includes `CGTAssetType`+  for tracking different categories of CGT assets.++- Implemented a separate loss carry-forward for collectables.  The+  new `CapitalLossCarryForward` data type has separate fields for+  capital losses on collectables and other capital losses.++- Capital losses on personal use assets (`AssetTypePersonalUse`) are+  disregarded.++- Added the `EntityType` data type.  This ensures the correct CGT+  discount proportion is used depending on whether the taxed entity+  is an `Individual`, `Company`, `Trust` or `SuperFund`.++- The `assessCGTEvents` function now has an `EntityType` argument.++- Capital gains from trusts can now be included in CGT calculations.+  The `CapitalGainsFromTrust` data type represents capital gains+  from trust distributions.  The 'prepTrustCGT' function converts+  `CapitalGainsFromTrust` values into CGT events that represent the+  grossed-up gain, including eligibility for the CGT discount or+  small business concession.++- Added convenience constructors for various kinds of CGT events.++- Added some data types that will support the implementation (in a+  future release) of various CGT exemptions and small business CGT+  concessions.++- The `Data.Tax.ATO.Pretty.summariseCGTSchedule` prints the *CGT+  schedule* for a given `CGTAssessment`.++### Personal services income (PSI)++Added module `Data.Tax.ATO.BPI` (*Business and professional items*),+which provides for declaring personal services income and associated+deductions.++Usage:++```haskell+info =+  newTaxReturnInfoForTables tables+  & set+      ( businessAndProfessionalItems+      . personalServicesIncome+      . psiOther )+      ( Money 18000 )+  & set+      ( businessAndProfessionalItems+      . personalServicesIncome+      . psiTotalAmountOfOtherDeductions+      )+      ( Money  2000 )+```++### "Other income"++Added the `otherIncome` field and the `OtherIncome` data type, which+contains a number of fields for declaring various kinds of income+(including FHSS released amounts).++Example usage:++```haskell+info =+  newTaxReturnInfoForTables tables+  & set (otherIncome . otherIncomeCategory4) [("Airdrop", Money 5000)]+```++### Other features and enhancements++- Add `FY2026` module.  Apart from the usual Medicare levy and+  private health insurance rebate adjustments, study loan repayments+  changed to a marginal tax (previously a threshold tax).++- Add preliminary `FY2027` module.  Values are not final.  The+  new *$1,000 instant deduction* is not yet implemented.++### Bug fixes++- FY2020+ now calculate study and training loan repayment correctly+  where individual has both HELP and SFSS balances.++- Pretty-printers updated to omit various line items when zero.++ ## Version 2025.1  ### Features and enhancements
src/Data/Tax/ATO.hs view
@@ -60,6 +60,8 @@    -- *** Capital gains tax (CGT)   , HasCapitalLossCarryForward(..)+  , capitalLossCarryForwardOther+  , capitalLossCarryForwardCollectables   , cgtEvents    -- *** Employee share schemes@@ -74,9 +76,24 @@   , essTFNAmounts   , essForeignSourceDiscounts +  -- ***Business and professional items***+  , businessAndProfessionalItems+  , module Data.Tax.ATO.BPI+   -- *** Foreign income   , foreignIncome +  -- *** Other income+  , OtherIncome+  , otherIncome+  , otherIncomeCategory1+  , otherIncomeCategory2+  , otherIncomeCategory3+  , otherIncomeCategory4+  , taxWithheldLumpSumPaymentsInArrears+  , taxWithheldAssessableFHSSReleasedAmount+  , taxableProfessionalIncome+   -- ** Medicare Levy Surcharge and Private Health Insurance   , mlsExemption   , privateHealthInsurancePolicyDetails@@ -177,12 +194,18 @@   , module Data.Tax.ATO.Rounding   ) where -import Control.Lens (Getter, Lens', (&), foldOf, lens, preview, set, to, view, views)+import Data.Proxy++import Control.Lens+  ( Getter, Lens'+  , (&), _2, 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.BPI+import Data.Tax.ATO.CGT import Data.Tax.ATO.Common import Data.Tax.ATO.Depreciation import Data.Tax.ATO.FY@@ -316,48 +339,56 @@ -- -- The following lenses are available: ----- +------------------------------------------------------+----------------------------------+--- | '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                     |--- +------------------------------------------------------+----------------------------------++-- +------------------------------------------------------+----------------------------------------++-- | '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        |+-- +------------------------------------------------------+----------------------------------------++-- | 'otherIncome'                                        | /Other income/ fields                  |+-- +------------------------------------------------------+----------------------------------------++-- | 'businessAndProfessionalItems'                       | See                                    |+-- |                                                      | 'BusinessAndProfessionalItemsSchedule' |+-- +------------------------------------------------------+----------------------------------------++-- | 'foreignIncome'                                      | Foreign income                         |+-- +------------------------------------------------------+----------------------------------------++-- | 'cgtEvents' :: ['CGTEvent']                          | Capital gains tax events for           |+-- |                                                      | this income year                       |+-- +------------------------------------------------------+----------------------------------------++-- | 'capitalLossCarryForward'                            | Capital losses carried forward         |+-- |   :: 'CapitalLossCarryForward'                       | from previous income years             |+-- +------------------------------------------------------+----------------------------------------++-- | '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@@ -370,11 +401,13 @@   , _interest :: GrossAndWithheld a   , _dividends :: [Dividend a]   , _ess :: [ESSStatement a]+  , _otherIncome :: OtherIncome a+  , _businessAndProfessionalItems :: BusinessAndProfessionalItemsSchedule a   , _foreignIncome :: Money a   , _cgtEvents :: [CGTEvent a]   , _deductions :: Deductions a   , _offsets :: Offsets a-  , _triCapitalLossCarryForward :: Money a+  , _triCapitalLossCarryForward :: CapitalLossCarryForward a   , _phi :: [PrivateHealthInsurancePolicyDetail a]   , _spouseDetails :: Maybe (SpouseDetails a)   , _incomeTests :: IncomeTests a@@ -402,11 +435,13 @@   mempty -- interest   mempty -- dividends   mempty -- ESS+  newOtherIncome+  newBusinessAndProfessionalItemsSchedule   mempty -- foreign income   mempty -- CGT events   mempty -- deductions   mempty -- offsets-  mempty -- cap loss carry forward+  newCapitalLossCarryForward   mempty -- private health insurance policy details   Nothing -- spouse details   newIncomeTests@@ -467,9 +502,17 @@ dividends :: Lens' (TaxReturnInfo y a) [Dividend a] dividends = lens _dividends (\s b -> s { _dividends = b }) +businessAndProfessionalItems+  :: Lens' (TaxReturnInfo y a) (BusinessAndProfessionalItemsSchedule a)+businessAndProfessionalItems =+  lens _businessAndProfessionalItems (\s b -> s { _businessAndProfessionalItems = b })+ ess :: Lens' (TaxReturnInfo y a) [ESSStatement a] ess = lens _ess (\s b -> s { _ess = b }) +otherIncome :: Lens' (TaxReturnInfo y a) (OtherIncome a)+otherIncome = lens _otherIncome (\s b -> s { _otherIncome = b })+ foreignIncome :: Lens' (TaxReturnInfo y a) (Money a) foreignIncome = lens _foreignIncome (\s b -> s { _foreignIncome = b }) @@ -592,13 +635,16 @@ -- | Tax to calculate compulsory study and training loan repayments -- (e.g. HELP, SFSS) studyAndTrainingLoanRepaymentTax-  :: (Fractional a, Ord a)+  :: forall y a. (FinancialYear y, Fractional a, Ord a)   => TaxTables y a   -> TaxReturnInfo y a   -> Tax (Money a) (Money a)-studyAndTrainingLoanRepaymentTax table info =-  limit (view helpBalance info) (ttHelp table)-  <> limit (view sfssBalance info) (ttSfss table)+studyAndTrainingLoanRepaymentTax table info = case fromProxy (Proxy @y) of+  y | y < 2020 ->+        limit (view helpBalance info) (ttHelp table)+        <> limit (view sfssBalance info) (ttSfss table)+    | otherwise ->+        limit (view helpBalance info <> view sfssBalance info) (ttHelp table)  -- | Taxable income instance (RealFrac a) => HasTaxableIncome (TaxReturnInfo y) a a where@@ -613,7 +659,9 @@         , view (interest . taxableIncome) info         , view (dividends . taxableIncome) info         , view (ess . taxableIncome) info-        , view (cgtEvents . to (assessCGTEvents cf) . cgtNetGain) info+        , view (otherIncome . taxableIncome) info+        , view (businessAndProfessionalItems . taxableIncome) info+        , view (cgtEvents . to (assessCGTEvents Individual cf) . cgtNetGain) info         , view foreignIncome info         ]     in@@ -632,6 +680,7 @@     <> view (paymentSummariesWithholdingWhereABNNotQuoted . taxWithheld) info     <> view (interest . taxWithheld) info     <> view (ess . taxWithheld) info+    <> view (otherIncome . taxWithheld) info  fringeBenefits :: (Num a) => TaxReturnInfo y a -> Money a fringeBenefits info =@@ -665,7 +714,17 @@   -- TODO super lump sum taxed elements with zero tax rate   -- TODO assessable FHSS released amount -paygInstalmentIncome :: (RealFrac a) => TaxReturnInfo y a -> Money a+-- | PAYG instalment income includes:+--+-- * Dividends and interest payments+-- * Foreign income+-- * Payments where amounts withheld due to non-quotation of TFN or ABN+--+-- It also includes rent, business income and partnership/trust income, but+-- this library does not yet implement these features so these amounts are+-- are not reflected in this calculation.+--+paygInstalmentIncome :: forall y a. (RealFrac a) => TaxReturnInfo y a -> Money a paygInstalmentIncome info =   -- TODO gross rent   view (dividends . taxableIncome) info@@ -686,7 +745,7 @@   => TaxTables y a -> TaxReturnInfo y a -> TaxAssessment a assessTax tables info =   let-    cg = assessCGTEvents+    cg = assessCGTEvents Individual           (view capitalLossCarryForward info) (view cgtEvents info)     taxable = view taxableIncome info     due = getTax (individualTax tables) taxable@@ -1210,3 +1269,67 @@  instance HasTaxWithheld ESSStatement a a where   taxWithheld = essTFNAmounts+++-- | __24__ Other income+data OtherIncome a = OtherIncome+  { _category1 :: [(String, Money a)]+  , _category2 :: [(String, Money a)]+  , _category3 :: Money a+  , _category4 :: [(String, Money a)]+  , _taxWithheldLSPIA :: Money a+  , _taxWithheldFHSS :: Money a+  , _taxableProfessionalIncome :: Money a+  }++newOtherIncome :: (Num a) => OtherIncome a+newOtherIncome = OtherIncome+  { _category1 = []+  , _category2 = []+  , _category3 = mempty+  , _category4 = []+  , _taxWithheldLSPIA = mempty+  , _taxWithheldFHSS  = mempty+  , _taxableProfessionalIncome = mempty+  }++otherIncomeCategory1 :: Lens' (OtherIncome a) [(String, Money a)]+otherIncomeCategory1 = lens _category1 (\s b -> s { _category1 = b })++otherIncomeCategory2 :: Lens' (OtherIncome a) [(String, Money a)]+otherIncomeCategory2 = lens _category2 (\s b -> s { _category2 = b })++otherIncomeCategory3 :: Lens' (OtherIncome a) (Money a)+otherIncomeCategory3 = lens _category3 (\s b -> s { _category3 = b })++otherIncomeCategory4 :: Lens' (OtherIncome a) [(String, Money a)]+otherIncomeCategory4 = lens _category4 (\s b -> s { _category4 = b })++taxWithheldLumpSumPaymentsInArrears :: Lens' (OtherIncome a) (Money a)+taxWithheldLumpSumPaymentsInArrears =+  lens _taxWithheldLSPIA (\s b -> s { _taxWithheldLSPIA = b })++taxWithheldAssessableFHSSReleasedAmount :: Lens' (OtherIncome a) (Money a)+taxWithheldAssessableFHSSReleasedAmount =+  lens _taxWithheldFHSS (\s b -> s { _taxWithheldFHSS = b })++-- | __Z__ Taxable professional income+--+-- This field is used for __income averaging__ for /special professionals/+-- (which this library does not yet implement).+--+taxableProfessionalIncome :: Lens' (OtherIncome a) (Money a)+taxableProfessionalIncome =+  lens _taxableProfessionalIncome (\s b -> s { _taxableProfessionalIncome = b })++instance (Num a) => HasTaxableIncome OtherIncome a a where+  taxableIncome = to $ \s ->+    view (otherIncomeCategory1 . traverse . _2) s+    <> view (otherIncomeCategory2 . traverse . _2) s+    <> view otherIncomeCategory3 s+    <> view (otherIncomeCategory4 . traverse . _2) s++instance (Num a) => HasTaxWithheld OtherIncome a a where+  taxWithheld = to $ \s ->+    view taxWithheldLumpSumPaymentsInArrears s+    <> view taxWithheldAssessableFHSSReleasedAmount s
+ src/Data/Tax/ATO/BPI.hs view
@@ -0,0 +1,131 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2026  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/>.++{-|++Business and professional items (BPI) schedule++Only Personal services income (PSI) and deductions are implemented at the+current time.++-}++module Data.Tax.ATO.BPI+  ( BusinessAndProfessionalItemsSchedule+  , newBusinessAndProfessionalItemsSchedule+  , personalServicesIncome++  , PersonalServicesIncome+  , newPersonalServicesIncome+  , psiVoluntaryAgreement+  , psiWhereABNNotQuoted+  , psiLabourHireOrOtherSpecifiedPayments+  , psiOther+  , psiDeductionsForPaymentsToAssociatesForPrincipalWork+  , psiTotalAmountOfOtherDeductions+  , netPSI+  ) where++import Control.Lens+import Data.Tax++import Data.Tax.ATO.Common++-- | Business and professional items (BPI) schedule+data BusinessAndProfessionalItemsSchedule a = BusinessAndProfessionalItemsSchedule+  { _personalServicesIncome :: PersonalServicesIncome a+  }++newBusinessAndProfessionalItemsSchedule :: (Num a) => BusinessAndProfessionalItemsSchedule a+newBusinessAndProfessionalItemsSchedule = BusinessAndProfessionalItemsSchedule+  { _personalServicesIncome = newPersonalServicesIncome+  }++instance (Num a, Ord a)+    => HasTaxableIncome BusinessAndProfessionalItemsSchedule a a where+  taxableIncome = personalServicesIncome . taxableIncome++-- | __P1__ Personal services income (PSI)+personalServicesIncome+  :: Lens' (BusinessAndProfessionalItemsSchedule a) (PersonalServicesIncome a)+personalServicesIncome =+  lens _personalServicesIncome (\s b -> s { _personalServicesIncome = b })+++data PersonalServicesIncome a = PersonalServicesIncome+  { _psiVoluntaryAgreement :: Money a+  , _psiWhereABNNotQuoted :: Money a+  , _psiLabourHireOrOtherSpecifiedPayments :: Money a+  , _psiOther :: Money a+  , _psiDeductionsForPaymentsToAssociatesForPrincipalWork :: Money a+  , _psiTotalAmountOfOtherDeductions :: Money a+  }++newPersonalServicesIncome :: (Num a) => PersonalServicesIncome a+newPersonalServicesIncome = PersonalServicesIncome+  { _psiVoluntaryAgreement = mempty+  , _psiWhereABNNotQuoted = mempty+  , _psiLabourHireOrOtherSpecifiedPayments = mempty+  , _psiOther = mempty+  , _psiDeductionsForPaymentsToAssociatesForPrincipalWork = mempty+  , _psiTotalAmountOfOtherDeductions = mempty+  }++-- | __M__ PSI — voluntary agreement+psiVoluntaryAgreement :: Lens' (PersonalServicesIncome a) (Money a)+psiVoluntaryAgreement =+  lens _psiVoluntaryAgreement (\s b -> s { _psiVoluntaryAgreement = b })++-- | __N__ PSI — where Australian business number not quoted+psiWhereABNNotQuoted :: Lens' (PersonalServicesIncome a) (Money a)+psiWhereABNNotQuoted =+  lens _psiWhereABNNotQuoted (\s b -> s { _psiWhereABNNotQuoted = b })++-- | __O__ PSI — labour hire or other specified payments+psiLabourHireOrOtherSpecifiedPayments :: Lens' (PersonalServicesIncome a) (Money a)+psiLabourHireOrOtherSpecifiedPayments =+  lens _psiLabourHireOrOtherSpecifiedPayments (\s b -> s { _psiLabourHireOrOtherSpecifiedPayments = b })++-- | __J__ PSI — other+psiOther :: Lens' (PersonalServicesIncome a) (Money a)+psiOther =+  lens _psiOther (\s b -> s { _psiOther = b })++-- | __K__ Deductions for payments to associates for principal work+psiDeductionsForPaymentsToAssociatesForPrincipalWork+  :: Lens' (PersonalServicesIncome a) (Money a)+psiDeductionsForPaymentsToAssociatesForPrincipalWork =+  lens _psiDeductionsForPaymentsToAssociatesForPrincipalWork+    (\s b -> s { _psiDeductionsForPaymentsToAssociatesForPrincipalWork = b })++-- | __L__ Total amount of other deductions against PSI+psiTotalAmountOfOtherDeductions :: Lens' (PersonalServicesIncome a) (Money a)+psiTotalAmountOfOtherDeductions =+  lens _psiTotalAmountOfOtherDeductions (\s b -> s { _psiTotalAmountOfOtherDeductions = b })+++instance (Num a, Ord a) => HasTaxableIncome PersonalServicesIncome a a where+  taxableIncome = to (max mempty . netPSI)++-- | Net PSI+netPSI :: (Num a) => PersonalServicesIncome a -> Money a+netPSI a =+  view psiVoluntaryAgreement a+  $+$ view psiWhereABNNotQuoted a+  $+$ view psiLabourHireOrOtherSpecifiedPayments a+  $+$ view psiOther a+  $-$ view psiDeductionsForPaymentsToAssociatesForPrincipalWork a+  $-$ view psiTotalAmountOfOtherDeductions a
src/Data/Tax/ATO/CGT.hs view
@@ -15,6 +15,8 @@ -- along with this program.  If not, see <http://www.gnu.org/licenses/>.  +{-# LANGUAGE LambdaCase #-}+ {-|  Types and calculations for /capital gains tax/ (CGT).@@ -25,24 +27,83 @@  The main function you need is 'assessCGTEvents'. --}+Things that are __not yet implemented__: +* Small business CGT concessions+* Exemptions, rollovers, and earnout arrangements++-} module Data.Tax.ATO.CGT   (+  -- * CGT assets+    CGTAssetType(..)+  , CGTAssetFlag(..)+  , CGTAsset+  , assetDescription+  , assetShare+  , assetType+  , assetFlag+  , assetUnits+  , assetAcquisitionDate+  , assetAcquisitionPrice+  , assetAcquisitionCosts+  , assetCapitalCosts+  , assetOwnershipCosts+  -- ** Constructors+  , newCGTAsset+   -- * CGT events-    CGTEvent(..)+  , CGTEvent+  , eventAsset+  , eventCode+  , eventDate+  , eventPrice+  , eventCosts+  , CGTExemptionRolloverOrAdditionalDiscountCode(..)+  -- ** Constructors+  , cgtEventA1+  , cgtEventB1+  , cgtEventC1+  , cgtEventC2+  , cgtEventC3+  , cgtEventE10+  -- ** Helper functions+  , eventProceeds +  -- * Capital gains from trusts+  , CapitalGainsFromTrust+  , newCapitalGainsFromTrust+  , trustGrossCapitalGain+  , trustCapitalLossesApplied+  , trustCGTDiscountApplied+  , trustCGTSmallBusinessConcessionApplied+  , prepTrustCGT+   -- * CGT assessments for tax returns   , assessCGTEvents   , CGTAssessment   , nullCGTAssessment-  , HasCapitalLossCarryForward(..)   , cgtNetGain   , cgtTotalCurrentYearGains+  , cgtTotalCurrentYearLosses+  , cgtTotalCurrentYearLossesApplied+  , cgtTotalPriorYearLossesApplied+  , cgtTotalCGTDiscountApplied   , cgtNetLossesCarriedForward+  , cgtGainsAndLossesByCategory +  -- ** Carry-forward+  , HasCapitalLossCarryForward(..)+  , CapitalLossCarryForward+  , newCapitalLossCarryForward+  , capitalLossCarryForwardCollectables+  , capitalLossCarryForwardOther++  -- ** Helper types for CGT Schedule+  , CGTScheduleCategory(..)+   -- * CGT computations-  , HasCapitalGain(..)+  , capitalGain   , capitalLoss   , isCapitalGain   , isCapitalLoss@@ -52,99 +113,389 @@ import Data.Foldable (toList) import Data.List (partition) -import Control.Lens (Getter, Lens', both, lens, over, to, view)+import Control.Lens+  ( Getter, Lens', Traversal'+  , (&), _3, anyOf, both, lens, over, preview, set, to, view, views+  )+import qualified Data.Map as M import Data.Time.Calendar (Day, diffDays) import Data.Tax --- | A CGT Event (usually an asset disposal)+import Data.Tax.ATO.Common (EntityType(..))+++-- | The CGT schedule requires reporting of gains and losses for+-- different asset types.  Also, collectables and personal use+-- assets are subject to different rules from other assets.+-- Specifically, capital losses from personal use assets are+-- disregarded, and capital losses from collectables can only offset+-- capital gains from collectables. ---data CGTEvent a = CGTEvent-  { assetDesc :: String-  , units :: a-  , acquisitionDate :: Day-  , acquisitionPrice :: Money a-  , acquisitionCosts :: Money a-  , disposalDate :: Day-  , disposalPrice :: Money a-  , disposalCosts :: Money a-  , capitalCosts :: Money a-  , ownershipCosts :: Money a+data CGTAssetType+  = AssetTypeSharesAUListed+  | AssetTypeSharesOther+  | AssetTypeUnitsAUListed+  | AssetTypeUnitsOther+  | AssetTypeRealEstateAU+  | AssetTypeRealEstateOther+  | AssetTypeCollectable+  | AssetTypePersonalUse+  | AssetTypeOther+  deriving (Eq, Ord, Show)++-- | Flags for CGT assets that can affect CGT calculations.+--+data CGTAssetFlag+  = MainResidence+  | AffordableHousing+  | SmallBusinessActiveAsset+  | EarlyStageInnovationCompany+  deriving (Eq, Ord, Show)++data CGTAsset a = CGTAsset+  { _assetDescription       :: String+  , _assetShare             :: Rational     -- owner's share of asset+  , _assetType              :: CGTAssetType+  , _assetFlag              :: Maybe CGTAssetFlag+  , _assetUnits             :: Rational -- number of units+  , _assetAcquisitionDate   :: Day+  , _assetAcquisitionPrice  :: Money a  -- acquisition price (per unit)+  , _assetAcquisitionCosts  :: Money a  -- acquisition costs (of parcel)+  , _assetCapitalCosts      :: Money a+  , _assetOwnershipCosts    :: Money a   }+  deriving (Functor, Show)++-- | Construct a new CGT asset.  Capital and ownership costs are set to zero.+-- Use 'assetFlag' to set a flag, if relevant.+newCGTAsset+  :: (Num a)+  => String   -- ^ asset description+  -> Rational -- ^ owner's share (a fraction between 0 and (typically) 1)+  -> CGTAssetType+  -> Rational -- ^ quantity of units/shares+  -> Day      -- ^ acquisition date+  -> Money a  -- ^ price per unit/share+  -> Money a  -- ^ acquisition costs (e.g. brokerage, settlement costs, etc)+  -> CGTAsset a+newCGTAsset desc share typ units date price cost =+  CGTAsset desc share typ Nothing units date price cost mempty mempty++assetDescription :: Lens' (CGTAsset a) String+assetDescription =+  lens _assetDescription (\s b -> s { _assetDescription = b })++assetShare :: Lens' (CGTAsset a) Rational+assetShare =+  lens _assetShare (\s b -> s { _assetShare = b })++assetType :: Lens' (CGTAsset a) CGTAssetType+assetType =+  lens _assetType (\s b -> s { _assetType = b })++assetFlag :: Lens' (CGTAsset a) (Maybe CGTAssetFlag)+assetFlag =+  lens _assetFlag (\s b -> s { _assetFlag = b })++assetUnits :: Lens' (CGTAsset a) Rational+assetUnits =+  lens _assetUnits (\s b -> s { _assetUnits = b })++assetAcquisitionDate :: Lens' (CGTAsset a) Day+assetAcquisitionDate =+  lens _assetAcquisitionDate (\s b -> s { _assetAcquisitionDate = b })++assetAcquisitionPrice :: Lens' (CGTAsset a) (Money a)+assetAcquisitionPrice =+  lens _assetAcquisitionPrice (\s b -> s { _assetAcquisitionPrice = b })++assetAcquisitionCosts :: Lens' (CGTAsset a) (Money a)+assetAcquisitionCosts =+  lens _assetAcquisitionCosts (\s b -> s { _assetAcquisitionCosts = b })++assetCapitalCosts :: Lens' (CGTAsset a) (Money a)+assetCapitalCosts =+  lens _assetCapitalCosts (\s b -> s { _assetCapitalCosts = b })++assetOwnershipCosts :: Lens' (CGTAsset a) (Money a)+assetOwnershipCosts =+  lens _assetOwnershipCosts (\s b -> s { _assetOwnershipCosts = b })+++data CGTExemptionRolloverOrAdditionalDiscountCode+  = {- A -} SmallBusinessActiveAssetReduction+  | {- B -} SmallBusinessRetirementExemption+  | {- C -} SmallBusinessRollover+  | {- D -} SmallBusiness15YearExemption+  | {- E -} ForeignResidentCGTExemption+  | {- F -} ScripForScripRollover+  | {- I -} MainResidenceExemption+  | {- J -} CapitalGainsDisregardedAsAResultOfTheSaleOfAPreCGTAsset+  | {- K -} DisposalOrCreationOfAssetsInAWhollyOwnedCompany+  | {- L -} ReplacementAssetRollovers+  | {- M -} ExchangeOfSharesOrUnits+  | {- N -} ExchangeOfRightsOrOptions+  | {- O -} ExchangeOfSharesInOneCompanyForSharesInAnotherCompany+  | {- P -} ExchangeOfUnitsInAUnitTrustForSharesInACompany+  | {- R -} DemergerRollover+  | {- S -} SameAssetRollovers+  | {- T -} SmallBusinessRestructureRollover+  | {- U -} EarlyStageInvestor+  | {- V -} VentureCapitalInvestment+  | {- W -} AffordableHousingDiscount+  | {- X -} OtherExemptionsAndRollovers+  deriving (Eq, Ord, Show)++data CGTEventType a+  = CGTEventEnd (CGTAsset a)+    -- ^ Ownership of a CGT asset ends (or contracted)+  | CGTEventReAsset (CGTAsset a)+    -- ^ A CGT event relating to the asset, where cost base ignored.+    -- Acquisition date determines discounts, etc.+  | CGTEventNoAsset+    -- ^ A CGT event not relating to an owned asset+  | CGTEventTrustDistribution IsDiscountable+    -- ^ Special purpose constructor for representing distributions+    -- of capital gains from trusts.+  deriving (Functor, Show)++data IsDiscountable = Discountable | NotDiscountable   deriving (Show) -instance Functor CGTEvent where-  fmap f (CGTEvent k n t1 p1 b1 t2 p2 b2 cap own) =-    CGTEvent k (f n)-      t1 (f <$> p1) (f <$> b1)-      t2 (f <$> p2) (f <$> b2)-      (f <$> cap) (f <$> own)+-- | A CGT event (usually an asset disposal)+data CGTEvent a = CGTEvent+  { _eventType  :: CGTEventType a+  , _eventCode  :: Maybe CGTExemptionRolloverOrAdditionalDiscountCode+  , _eventDate  :: Day+  , _eventPrice :: Money a+  , _eventCosts :: Money a+  }+  deriving (Functor, Show) -reducedCostBase :: Num a => CGTEvent a -> Money a-reducedCostBase event =-  (units event *$ acquisitionPrice event)-  $+$ acquisitionCosts event-  $+$ disposalCosts event-  $+$ capitalCosts event+eventType :: Lens' (CGTEvent a) (CGTEventType a)+eventType =+  lens _eventType (\s b -> s { _eventType = b }) -costBase :: Num a => CGTEvent a -> Money a-costBase event = reducedCostBase event $+$ ownershipCosts event+-- | A CGT event could have zero or one related assets.+eventAsset :: Traversal' (CGTEvent a) (CGTAsset a)+eventAsset = eventType . l+  where+  l f = \case+    CGTEventEnd a     -> CGTEventEnd      <$> f a+    CGTEventReAsset a -> CGTEventReAsset  <$> f a+    s                 -> pure s -capitalGain' :: (Num a, Ord a) => CGTEvent a -> Money a-capitalGain' event =-  max mempty (units event *$ disposalPrice event $-$ costBase event)+eventCode :: Lens' (CGTEvent a) (Maybe CGTExemptionRolloverOrAdditionalDiscountCode)+eventCode =+  lens _eventCode (\s b -> s { _eventCode = b }) --- | The capital loss as a /non-negative/ amount.--- /$0/ if the event is not a loss.+eventDate :: Lens' (CGTEvent a) Day+eventDate =+  lens _eventDate (\s b -> s { _eventDate = b })++eventPrice :: Lens' (CGTEvent a) (Money a)+eventPrice =+  lens _eventPrice (\s b -> s { _eventPrice = b })++eventCosts :: Lens' (CGTEvent a) (Money a)+eventCosts =+  lens _eventCosts (\s b -> s { _eventCosts = b })++-- | A1 - Disposal of a CGT asset+cgtEventA1+  :: CGTAsset a+  -- ^ The asset the event is associated with.  If disposing of a+  -- share or fewer shares/units than held, the asset must be split+  -- beforehand.+  -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode+  -- ^ Exemption, rollover or discount code applying to this event, if any.+  -> Day      -- ^ When the disposal contract is entered into or, if none,+              --   when the entity stops being the asset's owner+  -> Money a  -- ^ Capital proceeds (per unit)+  -> Money a  -- ^ Costs of disposal (consolidated; for whole asset)+  -> CGTEvent a+cgtEventA1 asset code date price cost =+  CGTEvent (CGTEventEnd asset) code date price cost++-- | B1 - Use and enjoyment before title passes+cgtEventB1+  :: CGTAsset a+  -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode+  -- ^ Exemption, rollover or discount code applying to this event, if any.+  -> Day      -- ^ When use of the CGT asset passes+  -> Money a  -- ^ Capital proceeds (per unit)+  -> Money a  -- ^ Costs of arrangement+  -> CGTEvent a+cgtEventB1 = cgtEventA1++-- | C1 - Loss or destruction of a CGT asset+cgtEventC1+  :: CGTAsset a+  -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode+  -- ^ Exemption, rollover or discount code applying to this event, if any.+  -> Day      -- ^ When compensation is first received or, if none,+              --   when the loss is discovered or destruction occurred+  -> Money a  -- ^ Capital proceeds (per unit)+  -> Money a  -- ^ Incidental costs relating to the event+  -> CGTEvent a+cgtEventC1 = cgtEventA1++-- | C2 - Cancellation, surrender and similar endings+cgtEventC2+  :: CGTAsset a+  -> Maybe CGTExemptionRolloverOrAdditionalDiscountCode+  -- ^ Exemption, rollover or discount code applying to this event, if any.+  -> Day      -- ^ When the contract ending an asset is entered into or,+              --   if none, when an asset ends+  -> Money a  -- ^ Capital proceeds (per unit)+  -> Money a  -- ^ Costs relating to the event+  -> CGTEvent a+cgtEventC2 = cgtEventA1++-- | C3 - End of an option to acquire shares etc+cgtEventC3+  :: (Num a)+  => CGTAsset a+  -- ^ The option.  Its acqusition price could be /negative/, i.e.+  -- capital proceeds from granting the option.  Acquisition costs+  -- record the expenditure in granting the option.+  -- granting the option is recorded in the a+  -> Day      -- ^ When the option ends+  -> CGTEvent a+cgtEventC3 asset date = CGTEvent (CGTEventEnd asset) Nothing date (Money 0) (Money 0)++-- | E10 - Annual cost base reduction exceeds cost base of interest+-- in attribution managed investment trust.+cgtEventE10+  :: (Num a)+  => CGTAsset a+  -- ^ The asset the event is associated with.+  -> Day+  -> Money a+  -- ^ Amount cost base reduction exceeds cost base (consolidated; for whole asset)+  -> CGTEvent a+cgtEventE10 asset date amount =+  CGTEvent (CGTEventReAsset asset) Nothing date amount (Money 0)++-- | Capital proceeds arising from CGT event+eventProceeds :: CGTEvent Rational -> Money Rational+eventProceeds ev = case preview (eventAsset . assetUnits) ev of+  Just n  -> n *$ view eventPrice ev  -- asset with units (possibly 1)+  Nothing ->      view eventPrice ev  -- bare capital proceeds+++-- | @sub x y@ = subtract @y@ from @x@, clamping to 0 and+-- returning @(result, leftovers)@ ---capitalLoss :: (Num a, Ord a) => CGTEvent a -> Money a-capitalLoss event = over money abs $-  min mempty (units event *$ disposalPrice event $-$ reducedCostBase event)+sub :: (Num a, Ord a) => Money a -> Money a -> (Money a, Money a)+sub x y =+  let r = x $-$ y+  in (max mempty r, over money abs (min mempty r)) ++-- | Reduced cost base of the (whole) asset subject to this CGT event+assetReducedCostBase :: (Fractional a) => CGTAsset a -> Money a+assetReducedCostBase asset =+  ( views assetUnits fromRational asset+    *$ view assetAcquisitionPrice asset )+  $+$ view assetAcquisitionCosts asset+  $+$ view assetCapitalCosts asset++-- | Cost base of the (whole) asset subject to this CGT event+assetCostBase :: (Fractional a) => CGTAsset a -> Money a+assetCostBase asset =+  assetReducedCostBase asset+  $+$ view assetOwnershipCosts asset++-- | Take of the amount in the same proportion as the share of the given asset.+shareOf :: (Fractional a) => CGTAsset a -> Money a -> Money a+shareOf asset = ($* views assetShare fromRational asset)++-- | Capital gain, scaled to the owner's share (per 'assetShare').+-- __Zero__ if there is no capital gain.  Does not apply discounts+-- or exemptions.+capitalGain :: (Fractional a, Ord a) => CGTEvent a -> Money a+capitalGain event =+  max mempty+  $ case view eventType event of+    CGTEventEnd asset ->+      shareOf asset+      $ views assetUnits fromRational asset *$ view eventPrice event+        $-$ assetCostBase asset+        $-$ view eventCosts event+    CGTEventReAsset asset ->+      shareOf asset+      $ view eventPrice event+        $-$ view eventCosts event+    CGTEventNoAsset ->+      view eventPrice event+      $-$ view eventCosts event+    CGTEventTrustDistribution _ ->+      view eventPrice event++-- | The capital loss as a __non-negative__ amount, scaled to the+-- owner's share (per 'assetShare').  __Zero__ if there is no+-- capital loss.+--+-- Capital losses on personal use assets are disregarded;+-- if type is 'AssetTypePersonalUse' this will always be zero.+--+capitalLoss :: (Fractional a, Ord a) => CGTEvent a -> Money a+capitalLoss event =+  fmap abs . min mempty+  $ case view eventType event of+    CGTEventEnd asset ->+      shareOf asset+      $ ( case view assetType asset of AssetTypePersonalUse -> const (Money 0) ; _ -> id )+      $ views assetUnits fromRational asset *$ view eventPrice event+        $-$ assetReducedCostBase asset+        $-$ view eventCosts event+    CGTEventReAsset asset ->+      shareOf asset+      $ view eventPrice event+        $-$ view eventCosts event+    CGTEventNoAsset ->+      view eventPrice event+      $-$ view eventCosts event+    CGTEventTrustDistribution _ ->+      mempty  -- trust cannot distribute a capital loss++ -- | Whether the CGT event is a capital gain.  /Not the opposite -- of 'isCapitalLoss'!/  A CGT event may be neither a loss nor a -- gain. ---isCapitalGain :: (Num a, Ord a) => CGTEvent a -> Bool-isCapitalGain = (> mempty) . capitalGain'+isCapitalGain :: (Fractional a, Ord a) => CGTEvent a -> Bool+isCapitalGain = (> mempty) . capitalGain  -- | Whether the CGT event is a capital loss.  /Not the opposite -- of 'isCapitalGain'!/  A CGT event may be neither a loss nor a -- gain. ---isCapitalLoss :: (Num a, Ord a) => CGTEvent a -> Bool+isCapitalLoss :: (Fractional a, Ord a) => CGTEvent a -> Bool isCapitalLoss = (> mempty) . capitalLoss --- | Whether the 50% CGT discount is applicable to this event (only--- with regard to duration of holding; acquisition date ignored).+-- | Whether the CGT discount is (potentially) applicable to this event.+-- Whether it is actually applicable and the discount proportion depends+-- on the type of the entity being assessed. -- discountApplicable :: CGTEvent a -> Bool discountApplicable ev =-  diffDays (disposalDate ev) (acquisitionDate ev) > 365+  case view eventType ev of+    CGTEventTrustDistribution    Discountable -> True+    CGTEventTrustDistribution NotDiscountable -> False+    _ -> case preview eventAsset ev of+      Nothing -> False+      Just a  -> diffDays (view eventDate ev) (view assetAcquisitionDate a) > 365 --- | Types that may have a capital gain.  Non-discounted, losses ignored.-class HasCapitalGain a b c where-  capitalGain :: Getter (a b) (Money c) --- | Capital gain as a positive amount.  /$0/ if the event not a gain.-instance (Num a, Ord a) => HasCapitalGain CGTEvent a a where-  capitalGain = to capitalGain'---- | Sum of capital gains, ignoring losses.--- Input __H__ at /item 18/ on tax return.+-- | Assess the total capital gains and net capital gain or loss. ---instance (Foldable t, HasCapitalGain x a a, Num a) => HasCapitalGain t (x a) a where-  capitalGain = to (foldMap (view capitalGain))----- | @sub x y@ = subtract @y@ from @x@, clamping to 0 and--- returning @(result, leftovers)@+-- __Assumes all events relate to a particular financial year.__+-- This function does not check or filter the input data. ---sub :: (Num a, Ord a) => Money a -> Money a -> (Money a, Money a)-sub x y =-  let r = x $-$ y-  in (max mempty r, over money abs (min mempty r))---- | Assess the total capital gains and net capital gain or loss.+-- Use 'prepTrustCGT' to process 'CapitalGainsFromTrust' values into+-- CGT events. -- -- Losses are used to offset non-discountable capital gains -- first, then discountable gains, before the discount is applied@@ -154,59 +505,230 @@ -- assessCGTEvents   :: (Fractional a, Ord a, Foldable t)-  => Money a            -- ^ capital loss carried forward+  => EntityType+  -> CapitalLossCarryForward a   -> t (CGTEvent a)   -> CGTAssessment a-assessCGTEvents carry events =+assessCGTEvents etype carry events =   let     l = toList events+    (lC, lO) = partition (anyOf (eventAsset . assetType) (== AssetTypeCollectable)) l+    carryC = view capitalLossCarryForwardCollectables carry+    carryO = view capitalLossCarryForwardOther        carry+    r@(rC, rO) =+      ( applyLossesAndDiscounts etype carryC lC+      , applyLossesAndDiscounts etype carryO lO+      )+    appliedLossC        = view vectorTotalLoss rC $+$ carryC $-$ view vectorUnappliedLoss rC+    appliedLossO        = view vectorTotalLoss rO $+$ carryO $-$ view vectorUnappliedLoss rO+    curFYLossesAppliedC = min appliedLossC (view vectorTotalLoss rC)+    curFYLossesAppliedO = min appliedLossO (view vectorTotalLoss rO)+    priorLossesAppliedC = appliedLossC $-$ curFYLossesAppliedC+    priorLossesAppliedO = appliedLossO $-$ curFYLossesAppliedO+    byCategory =+      M.fromListWith (<>) $ flip fmap l $ \ev ->+        ( scheduleCategory ev, (capitalGain ev, capitalLoss ev) )+  in+    CGTAssessment+      (view (both . vectorTotalGain) r)+      (view (both . vectorTotalLoss) r)++      -- current year losses applied+      ( curFYLossesAppliedC <> curFYLossesAppliedO )++      -- prior year losses applied+      ( priorLossesAppliedC <> priorLossesAppliedO )++      ( newCapitalLossCarryForward+        & set capitalLossCarryForwardCollectables (view vectorUnappliedLoss rC)+        & set capitalLossCarryForwardOther        (view vectorUnappliedLoss rO) )+      (view (both . vectorDiscount) r)+      (view (both . vectorNetGain) r)++      byCategory++-- | Internal data type for asset type-partitioned CGT calculations+data CGTVector a = CGTVector+  { _vectorTotalGain :: Money a+  , _vectorTotalLoss :: Money a+  , _vectorNetGain   :: Money a+  , _vectorUnappliedLoss :: Money a+  , _vectorDiscount  :: Money a+  }+vectorTotalGain, vectorTotalLoss, vectorNetGain, vectorUnappliedLoss, vectorDiscount+  :: Lens' (CGTVector a) (Money a)+vectorTotalGain     = lens _vectorTotalGain     (\s b -> s { _vectorTotalGain = b })+vectorTotalLoss     = lens _vectorTotalLoss     (\s b -> s { _vectorTotalLoss = b })+vectorNetGain       = lens _vectorNetGain       (\s b -> s { _vectorNetGain = b })+vectorUnappliedLoss = lens _vectorUnappliedLoss (\s b -> s { _vectorUnappliedLoss = b })+vectorDiscount      = lens _vectorDiscount      (\s b -> s { _vectorDiscount = b })++-- | Amount of capital gains from a trust or trusts (including managed funds).+--+-- Use 'newCapitalGainsFromTrust' to construct.  Apply 'prepTrustCGT' to+-- produce CGT events representing the grossed-up capital gains.+--+-- The following optics give access to the fields (common use cases should+-- not need them):+--+-- * 'trustGrossCapitalGain'+-- * 'trustCapitalLossesApplied'+-- * 'trustCGTDiscountApplied'+-- * 'trustCGTSmallBusinessConcessionApplied'+--+data CapitalGainsFromTrust a = CapitalGainsFromTrust+  { _trustGrossGain   :: Money a+  , _trustLossesAppl  :: Money a+  , _trustCGTDiscAppl :: Money a+  , _trustSBConcAppl  :: Money a+  }+  deriving (Show)++-- Construct a 'CapitalGainsFromTrust'.+--+-- Values are accepted without checking.  It is possible to+-- construct a value that doesn't make sense (e.g. a CGT+-- discount that is more than half of the gross gain).+--+newCapitalGainsFromTrust+  :: Money a  -- ^ Gross capital gain+  -> Money a  -- ^ Capital losses applied+  -> Money a  -- ^ CGT discount applied+  -> Money a  -- ^ CGT small business concessions applied+  -> CapitalGainsFromTrust a+newCapitalGainsFromTrust = CapitalGainsFromTrust++trustGrossCapitalGain                   :: Lens' (CapitalGainsFromTrust a) (Money a)+trustGrossCapitalGain+  = lens _trustGrossGain (\s b -> s { _trustGrossGain = b })++trustCapitalLossesApplied               :: Lens' (CapitalGainsFromTrust a) (Money a)+trustCapitalLossesApplied+  = lens _trustLossesAppl (\s b -> s { _trustLossesAppl = b })++trustCGTDiscountApplied                 :: Lens' (CapitalGainsFromTrust a) (Money a)+trustCGTDiscountApplied+  = lens _trustCGTDiscAppl (\s b -> s { _trustCGTDiscAppl = b })++trustCGTSmallBusinessConcessionApplied  :: Lens' (CapitalGainsFromTrust a) (Money a)+trustCGTSmallBusinessConcessionApplied+  = lens _trustSBConcAppl (\s b -> s { _trustSBConcAppl = b })+++-- | Produce CGT events representing grossed-up capital gains from+-- the trust distribution.  Could produce multiple events, in cases where+-- the CGT discount or small business concessions have been applied to+-- only a proportion of the distributed gain.+--+prepTrustCGT :: (Fractional a, Eq a) => CapitalGainsFromTrust a -> [CGTEvent a]+prepTrustCGT trust =+  let+    gross = view trustGrossCapitalGain trust+    loss = view trustCapitalLossesApplied trust++    discount = view trustCGTDiscountApplied trust+    discountable = discount $* 2+    nonDiscountable = gross $-$ loss $-$ discountable++    sbc = view trustCGTSmallBusinessConcessionApplied trust+    sbcEligible = sbc $* 2+    sbcProportion = sbcEligible $/$ (gross $-$ loss $-$ discount)+    sbcCode = Just SmallBusinessActiveAssetReduction++    someDay = toEnum 0 :: Day  -- ghastly hack, = 1858-11-17+    mk (t,c,x) = CGTEvent (CGTEventTrustDistribution t) c someDay x mempty+  in+    fmap mk . filter ((/=) mempty . view _3) $+      [ ( NotDiscountable, sbcCode, nonDiscountable $* sbcProportion )+      , ( NotDiscountable, Nothing, nonDiscountable $* (1 - sbcProportion) )+      , (    Discountable, sbcCode,    discountable $* sbcProportion )+      , (    Discountable, Nothing,    discountable $* (1 - sbcProportion) )+      ]+++applyLossesAndDiscounts+  :: (Fractional a, Ord a)+  => EntityType+  -> Money a    -- ^ unapplied losses from previous income years+  -> [CGTEvent a]+  -> CGTVector a+applyLossesAndDiscounts etype carry l =+  let     (discountableGain, nonDiscountableGain) =-      over both (view capitalGain) (partition discountApplicable l)+      over both (foldMap 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+    discount = discountableGainLossesApplied $* discountProportion etype     discountedGain = nonDiscountableGainLossesApplied <> (discountableGainLossesApplied $-$ discount)--    lossesApplied = (totalLoss <> carry) $-$ finalUnappliedLosses-    priorYearLossesApplied = min carry lossesApplied-    currentYearLossesApplied = lossesApplied $-$ priorYearLossesApplied   in-    CGTAssessment-      totalGain-      totalLoss-      currentYearLossesApplied-      priorYearLossesApplied-      finalUnappliedLosses-      discount-      discountedGain+    CGTVector totalGain totalLoss discountedGain finalUnappliedLosses discount --- | Total undiscounted gains and net gain/loss for tax assessment+discountProportion :: (Fractional a) => EntityType -> a+discountProportion etype = fromRational $ case etype of+  Individual  -> 1 / 2+  Trust       -> 1 / 2+  SuperFund   -> 1 / 3+  Company     -> 0+++--+-- CGTAssessment data type+--++data CGTScheduleCategory+  = CGTScheduleCategorySharesAUListed+  | CGTScheduleCategorySharesOther+  | CGTScheduleCategoryUnitsAUListed+  | CGTScheduleCategoryUnitsOther+  | CGTScheduleCategoryRealEstateAU+  | CGTScheduleCategoryRealEstateOther+  | CGTScheduleCategoryTrust+  | CGTScheduleCategoryCollectable+  | CGTScheduleCategoryOther+  | CGTScheduleCategoryDeferred+  deriving (Eq, Ord, Show)++scheduleCategory :: CGTEvent a -> CGTScheduleCategory+scheduleCategory ev =+  case view eventType ev of+    CGTEventTrustDistribution _+      -> CGTScheduleCategoryTrust+    _+      -> case preview (eventAsset . assetType) ev of+        Just AssetTypeSharesAUListed  -> CGTScheduleCategorySharesAUListed+        Just AssetTypeSharesOther     -> CGTScheduleCategorySharesOther+        Just AssetTypeUnitsAUListed   -> CGTScheduleCategoryUnitsAUListed+        Just AssetTypeUnitsOther      -> CGTScheduleCategoryUnitsOther+        Just AssetTypeRealEstateAU    -> CGTScheduleCategoryRealEstateAU+        Just AssetTypeRealEstateOther -> CGTScheduleCategoryRealEstateOther+        Just AssetTypeCollectable     -> CGTScheduleCategoryCollectable+        Just AssetTypePersonalUse     -> CGTScheduleCategoryOther+        Just AssetTypeOther           -> CGTScheduleCategoryOther+        Nothing                       -> CGTScheduleCategoryOther+    -- TODO transitional relief deferrals?+++-- | This data type stores the completed CGT computations for some+-- financial year.  It includes all data required for the /CGT schedule/+-- and the tax return CGT section.+-- data CGTAssessment a = CGTAssessment   { _totalCurrentYearCapitalGains :: Money a   , _totalCurrentYearCapitalLosses :: Money a   , _totalCurrentYearCapitalLossesApplied :: Money a   , _totalPriorYearCapitalLossesApplied :: Money a-  , _netCapitalLossesCarriedForward :: Money a+  , _capitalLossCarryForward :: CapitalLossCarryForward a   , _totalCGTDiscountApplied :: Money a   , _netCapitalGain :: Money a+  , _byCategory :: M.Map CGTScheduleCategory (Money a, Money a)   }-  deriving (Eq)+  deriving (Eq, Functor, Show)  -- | A 'CGTAssessment' whose values are all zero nullCGTAssessment :: (Num a) => CGTAssessment a-nullCGTAssessment = CGTAssessment mempty mempty mempty mempty mempty mempty mempty--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)+nullCGTAssessment = CGTAssessment mempty mempty mempty mempty mempty mempty mempty mempty  -- | __18A__ The net capital gain, or zero if a loss. cgtNetGain :: Lens' (CGTAssessment a) (Money a)@@ -217,16 +739,68 @@ cgtTotalCurrentYearGains =   lens _totalCurrentYearCapitalGains (\s b -> s { _totalCurrentYearCapitalGains = b }) +cgtTotalCurrentYearLosses :: Lens' (CGTAssessment a) (Money a)+cgtTotalCurrentYearLosses =+  lens _totalCurrentYearCapitalLosses (\s b -> s { _totalCurrentYearCapitalLosses = b })++cgtTotalCurrentYearLossesApplied :: Lens' (CGTAssessment a) (Money a)+cgtTotalCurrentYearLossesApplied =+  lens _totalCurrentYearCapitalLossesApplied (\s b -> s { _totalCurrentYearCapitalLossesApplied = b })++cgtTotalCGTDiscountApplied :: Lens' (CGTAssessment a) (Money a)+cgtTotalCGTDiscountApplied =+  lens _totalCGTDiscountApplied (\s b -> s { _totalCGTDiscountApplied = b })++cgtTotalPriorYearLossesApplied :: Lens' (CGTAssessment a) (Money a)+cgtTotalPriorYearLossesApplied =+  lens _totalPriorYearCapitalLossesApplied (\s b -> s { _totalPriorYearCapitalLossesApplied = b })+ -- | __18V__ Net capital losses carried forward to later income years-cgtNetLossesCarriedForward :: Lens' (CGTAssessment a) (Money a)-cgtNetLossesCarriedForward =-  lens _netCapitalLossesCarriedForward (\s b -> s { _netCapitalLossesCarriedForward = b })+cgtNetLossesCarriedForward :: (Num a) => Getter (CGTAssessment a) (Money a)+cgtNetLossesCarriedForward = to $ \o ->+  view (capitalLossCarryForward . capitalLossCarryForwardCollectables) o+  <> view (capitalLossCarryForward . capitalLossCarryForwardOther) o +cgtGainsAndLossesByCategory :: Lens' (CGTAssessment a) (M.Map CGTScheduleCategory (Money a, Money a))+cgtGainsAndLossesByCategory =+  lens _byCategory (\s b -> s { _byCategory = b })+++data CapitalLossCarryForward a = CapitalLossCarryForward+  { _carryC :: Money a -- losses on collectables+  , _carryO :: Money a -- all other losses+  }+  deriving (Eq, Functor, Show)++instance (Num a) => Semigroup (CapitalLossCarryForward a) where+  CapitalLossCarryForward lc lo <> CapitalLossCarryForward rc ro =+    CapitalLossCarryForward (lc <> rc) (lo <> ro)++instance (Num a) => Monoid (CapitalLossCarryForward a) where+  mempty = CapitalLossCarryForward mempty mempty+++-- | Create a new capital loss carry-forward object with+-- all components (collectables and other) set to zero.+--+-- @+-- newCapitalLossCarryForward = mempty+-- @+--+newCapitalLossCarryForward :: (Num a) => CapitalLossCarryForward a+newCapitalLossCarryForward = mempty++capitalLossCarryForwardCollectables :: Lens' (CapitalLossCarryForward a) (Money a)+capitalLossCarryForwardCollectables = lens _carryC (\s b -> s { _carryC = b })+capitalLossCarryForwardOther :: Lens' (CapitalLossCarryForward a) (Money a)+capitalLossCarryForwardOther = lens _carryO (\s b -> s { _carryO = 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)+  capitalLossCarryForward :: Lens' (a b) (CapitalLossCarryForward b)  instance HasCapitalLossCarryForward CGTAssessment a where   capitalLossCarryForward =-    lens _netCapitalLossesCarriedForward (\s b -> s { _netCapitalLossesCarriedForward = b })+    lens _capitalLossCarryForward (\s b -> s { _capitalLossCarryForward = b })
src/Data/Tax/ATO/Common.hs view
@@ -26,8 +26,11 @@  module Data.Tax.ATO.Common   (+  -- * Taxable entity types+    EntityType(..)+   -- * Tax tables-    TaxTables(..)+  , TaxTables(..)    -- * Classes   , HasTaxableIncome(..)@@ -69,6 +72,13 @@ import Data.Tax.ATO.PrivateHealthInsuranceRebate import Data.Tax.ATO.FY ++-- | Some tax calculations depend on the type of entity being assessed.+data EntityType = Individual | Company | Trust | SuperFund+  deriving (Eq, Ord, Show)+++ -- | A set of tax tables for a particular financial year data TaxTables y a = TaxTables   { ttIndividualIncomeTax :: Tax (Money a) (Money a)@@ -76,6 +86,8 @@   , ttMedicareLevySurcharge :: Tax (Money a) (Money a)   , ttHelp :: Tax (Money a) (Money a)   , ttSfss :: Tax (Money a) (Money a)+  -- ^ Ignored since FY2020 (uses consolidated rate from @ttHelp@).+  -- Just set it to @ttHelp@ or @undefined@.   , ttAdditional :: Tax (Money a) (Money a)   -- ^ Additional taxes and offsets that apply at EOY   , ttPHIRebateRates :: PrivateHealthInsuranceRebateRates a@@ -183,9 +195,11 @@ class HasCentsPerKilometreMethod y where   centsPerKilometre :: Num a => a -instance (2016 <= y, y <= 2025, FinancialYear y) => HasCentsPerKilometreMethod y where+instance (2016 <= y, y <= 2027, FinancialYear y) => HasCentsPerKilometreMethod y where   centsPerKilometre = case fromProxy (Proxy @y) of-    y | y == 2025           -> 88+    y | y == 2027           -> 88  -- TODO confirm+      | y == 2026           -> 88+      | y == 2025           -> 88       | y == 2024           -> 85       | y == 2023           -> 78       | y > 2020, y <= 2022 -> 72@@ -214,12 +228,14 @@ 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+instance (2023 <= y, y <= 2027, FinancialYear y) => HasFixedRateMethod y where+  fixedRateMethodCentsPerHour = case fromProxy (Proxy @y) of+    y | y == 2023           -> 67+      | y == 2024           -> 67+      | y == 2025           -> 70+      | y == 2026           -> 70+      | y == 2027           -> 70  -- TODO confirm+      | otherwise           ->  0  -- can't happen  -- | The updated fixed rate method available from the 2022–23 income -- year.  It covers:
src/Data/Tax/ATO/FY/FY2025.hs view
@@ -17,10 +17,6 @@ {-# 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@@ -79,8 +75,8 @@   , (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.+-- Rebate adjustment factor = 0.987+-- https://www.health.gov.au/news/phi-circulars/phi-2125-private-health-insurance-rebate-adjustment-factor-effective-1-april-2025 privateHealthInsuranceRebateRates   :: (Fractional a) => PrivateHealthInsuranceRebateRates a privateHealthInsuranceRebateRates =
+ src/Data/Tax/ATO/FY/FY2026.hs view
@@ -0,0 +1,84 @@+-- 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 DataKinds #-}++-- | Tax tables for 2025–26 financial year.+--+-- Apart from the usual Medicare levy and private health insurance+-- rebate adjustments, study loan repayments changed to a marginal+-- tax (previously a threshold tax).+--+module Data.Tax.ATO.FY.FY2026 (FY, fyProxy, tables) where++import Data.Proxy+import Data.Tax+import Data.Tax.ATO.Common+import Data.Tax.ATO.PrivateHealthInsuranceRebate+import qualified Data.Tax.ATO.FY.FY2025 as FY2025++type FY = 2026+fyProxy :: Proxy FY+fyProxy = Proxy++help :: (Fractional a, Ord a) => Tax (Money a) (Money a)+help =+  lesserOf+    ( flat 0.10 )+    ( marginal'+        [ ( 67_000, 0.15       )+        , (125_000, 0.17 - 0.15)+        ]+    )++medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 28011+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 44268+  , medicareLevyThresholdFamily                       = Money 47238+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 61623+  , medicareLevyThresholdDependentChildIncrease       = Money  4338+  }++-- | Medicare levy surcharge thresholds for 2025–26+medicareLevySurcharge :: (Fractional a, Ord a) => Tax (Money a) (Money a)+medicareLevySurcharge =+  threshold (Money 101000) 0.01+  <> threshold (Money 118000) 0.0025+  <> threshold (Money 158000) 0.0025++-- Rebate adjustment factor = 0.993.+-- https://www.health.gov.au/news/phi-circulars/phi-1226-private-health-insurance-rebate-adjustment-factor-effective-1-april-2026+privateHealthInsuranceRebateRates+  :: (Fractional a) => PrivateHealthInsuranceRebateRates a+privateHealthInsuranceRebateRates =+  [ (101000, (0.24288, 0.24118), (0.28337, 0.28139), (0.32385, 0.32158) )+  , (118000, (0.16192, 0.16079), (0.20240, 0.20098), (0.24288, 0.24118) )+  , (158000, (0.08095, 0.08095), (0.12143, 0.12058), (0.16192, 0.16079) )+  ]++tables :: (Ord a, Fractional a) => TaxTables FY a+tables = TaxTables+  (ttIndividualIncomeTax FY2025.tables)+  medicare+  medicareLevySurcharge+  help+  help++  lowIncomeTaxOffset2021++  privateHealthInsuranceRebateRates
+ src/Data/Tax/ATO/FY/FY2027.hs view
@@ -0,0 +1,95 @@+-- This file is part of hs-tax-ato+-- Copyright (C) 2026  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 2026–27 financial year.+--+-- The 16% personal income tax bracket drops to 15%.+--+-- These data are NOT YET FINAL.  We await the federal+-- budget to confirm Medicare Levy thresholds, and the PHI+-- rebate adjustment factor (~1 April 2027), and there could+-- be other changes.+--+module Data.Tax.ATO.FY.FY2027 (FY, fyProxy, tables) where++import Data.Proxy+import Data.Tax+import Data.Tax.ATO.Common+import Data.Tax.ATO.PrivateHealthInsuranceRebate++type FY = 2027+fyProxy :: Proxy FY+fyProxy = Proxy++-- | In 2026–27 the 16% rate dropped to 15%+individualIncomeTax :: (Fractional a, Ord a) => Tax (Money a) (Money a)+individualIncomeTax = marginal'+  [ (18200, 0.15)+  , (45000, 0.30 - 0.15)+  , (135000, 0.37 - 0.30)+  , (190000, 0.45 - 0.37) ]++help :: (Fractional a, Ord a) => Tax (Money a) (Money a)+help =+  lesserOf+    ( flat 0.10 )+    ( marginal'+        [ ( 69_528, 0.15       )  -- TODO confirm these numbers+        , (129_717, 0.17 - 0.15)+        ]+    )++-- TODO update (budget night)+medicare :: (Fractional a) => MedicareLevyRatesAndThresholds a+medicare = MedicareLevyRatesAndThresholds+  { medicareLevyRate                                  = 0.02+  , medicareLevyThresholdIndividual                   = Money 28011+  , medicareLevyThresholdIndividualSeniorAndPensioner = Money 44268+  , medicareLevyThresholdFamily                       = Money 47238+  , medicareLevyThresholdFamilySeniorAndPensioner     = Money 61623+  , medicareLevyThresholdDependentChildIncrease       = Money  4338+  }++-- | Medicare levy surcharge thresholds for 2025–26+-- TODO update+medicareLevySurcharge :: (Fractional a, Ord a) => Tax (Money a) (Money a)+medicareLevySurcharge =+  threshold (Money 101000) 0.01+  <> threshold (Money 118000) 0.0025+  <> threshold (Money 158000) 0.0025++-- TODO update (~April 1 PHI circular)+privateHealthInsuranceRebateRates+  :: (Fractional a) => PrivateHealthInsuranceRebateRates a+privateHealthInsuranceRebateRates =+  [ (101000, (0.24288, 0.24118), (0.28337, 0.28139), (0.32385, 0.32158) )+  , (118000, (0.16192, 0.16079), (0.20240, 0.20098), (0.24288, 0.24118) )+  , (158000, (0.08095, 0.08095), (0.12143, 0.12058), (0.16192, 0.16079) )+  ]++tables :: (Ord a, Fractional a) => TaxTables FY a+tables = TaxTables+  individualIncomeTax+  medicare+  medicareLevySurcharge+  help+  help++  lowIncomeTaxOffset2021++  privateHealthInsuranceRebateRates
src/Data/Tax/ATO/Pretty.hs view
@@ -26,16 +26,21 @@  module Data.Tax.ATO.Pretty   ( summariseTaxReturnInfo+  , summariseCGTSchedule   , summariseAssessment   , formatMoney   ) where  import Data.List.NonEmpty as NE (NonEmpty, groupAllWith, head) -import Control.Lens (ALens', cloneLens, foldOf, view, views)+import Control.Lens+  ( ALens'+  , _2, allOf, at, both, cloneLens, foldOf, nullOf, view, views+  ) import qualified Text.PrettyPrint as P  import Data.Tax.ATO+import Data.Tax.ATO.Common (EntityType(..)) import Data.Tax.ATO.CGT  @@ -58,20 +63,48 @@     putCommas (a:b:c:d:rest) | d /= '-' = a:b:c:',':putCommas (d:rest)     putCommas rest                      = rest +omitIfZero :: ((a, Money Rational) -> P.Doc) -> (a, Money Rational) -> P.Doc+omitIfZero = omitIf ((== mempty) . snd)++omitIf :: (a -> Bool) -> (a -> P.Doc) -> a -> P.Doc+omitIf test f a+  | test a    = P.empty+  | otherwise = f a++data Formatter a = Formatter Int (a -> P.Doc)++prepend :: String -> Formatter a -> Formatter a+prepend s (Formatter w f) = Formatter (w + length s) ((P.text s <>) . f)++append :: String -> Formatter a -> Formatter a+append s (Formatter w f) = Formatter (w + length s) ((<> P.text s) . f)++moneyFormatter :: Formatter (Money Rational)+moneyFormatter = Formatter colWidthMoney formatMoney++-- | Make a formatter that has a same width as the given formatter,+-- but outputs blank space.+blank :: Formatter a -> Formatter a+blank (Formatter w _) = Formatter w (\_ -> P.text $ replicate w ' ')++ twoCol :: (P.Doc, Money Rational) -> P.Doc-twoCol (label, value) = label P.$$ P.nest (80 - colWidthMoney) (formatMoney value)+twoCol = twoCol' id moneyFormatter -omitIfZero :: ((a, Money Rational) -> P.Doc) -> (a, Money Rational) -> P.Doc-omitIfZero f rec@(_,x)-  | x == mempty = P.empty-  | otherwise   = f rec+twoCol' :: (a -> P.Doc) -> Formatter b -> (a, b) -> P.Doc+twoCol' fa (Formatter wb fb) (a, b) =+  fa a+  P.$$ P.nest (80 - wb) (fb b)  threeCol :: (P.Doc, Money Rational, Money Rational) -> P.Doc-threeCol (label, v1, v2) =-  label-  P.$$ P.nest (80 - 2 * colWidthMoney) (formatMoney v1)-  P.<> formatMoney v2+threeCol = threeCol' id moneyFormatter moneyFormatter +threeCol' :: (a -> P.Doc) -> Formatter b -> Formatter c -> (a, b, c) -> P.Doc+threeCol' fa (Formatter wb fb) (Formatter wc fc) (a, b, c) =+  fa a+  P.$$ P.nest (80 - wb - wc) (fb b)+  P.<> fc c+ -- | 3-column layout with rightmost column blank threeColLeft :: (P.Doc, Money Rational) -> P.Doc threeColLeft (label, v1) =@@ -84,27 +117,31 @@ summariseTaxReturnInfo :: TaxReturnInfo y Rational -> P.Doc summariseTaxReturnInfo info =   "Income"-  P.$+$ vcatWith threeCol+  P.$+$ vcatWith (omitIf (allOf both (== mempty)) threeCol)     [ ( "  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.$+$ ( if nullOf dividends info then P.empty else "  11  Dividends" )   P.$+$ views dividends summariseDividends info   P.$+$ views ess summariseESS info   P.$+$ summariseCGT info-  P.$+$ vcatWith twoCol+  P.$+$ vcatWith (omitIfZero twoCol)     [ ("  20M Other net foreign source income" , view foreignIncome info)     ]+  P.$+$ views otherIncome summariseOtherIncome info+  P.$+$ views businessAndProfessionalItems summariseBPI info   P.$+$ "Deductions"   P.$+$ P.vcat (uncurry (summariseDeduction (view deductions info)) <$> deductionsTable)-  P.$+$ "Tax offsets"-  P.$+$ vcatWith threeColLeft-    [ ("  20O Foreign income tax offset"  , view (offsets . foreignTaxOffset) info)-    ] +  P.$+$ ( \doc -> if P.isEmpty doc then P.empty else "Tax offsets" P.$+$ doc )+    ( vcatWith (omitIfZero threeColLeft)+        [ ("  20O Foreign income tax offset"  , view (offsets . foreignTaxOffset) info)+        ]+    )+ summariseDividends :: [Dividend Rational] -> P.Doc summariseDividends =   vcatWith (threeCol . prep)@@ -122,23 +159,132 @@ summariseESS l =   "  12  Employee share schemes"   P.$+$ P.vcat-    [ twoCol+    [ omitIfZero twoCol         ( "    D Discount from upfront schemes - eligible for reduction"         , foldOf (traverse . essTaxedUpfrontReduction) l )-    , twoCol+    , omitIfZero twoCol         ( "    E Discount from upfront schemes - ineligible for reduction"         , foldOf (traverse . essTaxedUpfrontNoReduction) l )-    , twoCol+    , omitIfZero twoCol         ( "    F Discount from deferral schemes"         , foldOf (traverse . essDeferral) l )-    , threeColLeft+    , omitIfZero threeColLeft         ( "    C TFN amounts withheld from discounts"         , foldOf (traverse . essTFNAmounts) l )-    , twoCol+    , omitIfZero twoCol         ( "    A Foreign source discounts"         , foldOf (traverse . essForeignSourceDiscounts) l )     ] +summariseOtherIncome :: OtherIncome Rational -> P.Doc+summariseOtherIncome oi | view taxableIncome oi == Money (0 :: Rational)+                        = P.empty+summariseOtherIncome oi =+  P.vcat+    [ "  24  Other income"+    , case view otherIncomeCategory1 oi of+        [] -> P.empty+        [(s, x)] -> twoCol ("    Y - Category 1 - " <> P.text s, x)+        l -> twoCol ("    Y - Category 1 - <multiple>", foldOf (traverse . _2) l)+    , case view otherIncomeCategory2 oi of+        [] -> P.empty+        [(s, x)] -> twoCol ("    X - Category 2 (ATO interest) - " <> P.text s, x)+        l -> twoCol ("    X - Category 2 (ATO interest) - <multiple>", foldOf (traverse . _2) l)+    , omitIfZero twoCol ("    R - Category 3 (FHSS)", view otherIncomeCategory3 oi)+    , case view otherIncomeCategory4 oi of+        [] -> P.empty+        [(s, x)] -> twoCol ("    V - Category 4 - " <> P.text s, x)+        l -> twoCol ("    V - Category 4 - <multiple>", foldOf (traverse . _2) l)+    , omitIfZero threeColLeft+        ("    E Tax withheld - LSPIA", view taxWithheldLumpSumPaymentsInArrears oi)+    , omitIfZero threeColLeft+        ("    Z Taxable professional income", view taxableProfessionalIncome oi)+    , omitIfZero threeColLeft+        ("    S Tax withheld - FHSS released amount", view taxWithheldAssessableFHSSReleasedAmount oi)+    ]++summariseBPI :: BusinessAndProfessionalItemsSchedule Rational -> P.Doc+summariseBPI bpi =+  views personalServicesIncome summarisePSI bpi++summarisePSI :: PersonalServicesIncome Rational -> P.Doc+summarisePSI psi | netPSI psi == mempty+                 = P.empty+summarisePSI psi =+  "  P1  Personal services income"+  P.$+$ vcatWith (omitIfZero twoCol)+    [ ("    M PSI - voluntary agreement", view psiVoluntaryAgreement psi)+    , ("    N PSI - where Australian business number not quoted", view psiWhereABNNotQuoted psi)+    , ("    O PSI - labour hire or other specified payments", view psiLabourHireOrOtherSpecifiedPayments psi)+    , ("    J PSI - other", view psiOther psi)+    , ("    K Deductions for payments to associates for principal work", view psiDeductionsForPaymentsToAssociatesForPrincipalWork psi)+    , ("    L Total amount of other deductions against PSI", view psiTotalAmountOfOtherDeductions psi)+    ]+  P.$+$ twoCol ("    Net PSI", netPSI psi)++summariseCGTSchedule :: CGTAssessment Rational -> P.Doc+summariseCGTSchedule o = P.vcat+  [ "1  Current year capital gains and capital losses"+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategorySharesAUListed . traverse) o+    in print3 "A" "K" ("  Australian listed shares", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategorySharesOther . traverse) o+    in print3 "B" "L" ("  Other shares", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryUnitsAUListed . traverse) o+    in print3 "C" "M" ("  Australian listed units", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryUnitsOther . traverse) o+    in print3 "D" "N" ("  Other units", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryRealEstateAU . traverse) o+    in print3 "E" "O" ("  Australian real estate", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryRealEstateOther . traverse) o+    in print3 "F" "P" ("  Other real estate", g, l)+  , let (g,_) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryTrust . traverse) o+    in print2_ "G" ("  Capital gains from trusts", g)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryCollectable . traverse) o+    in print3 "H" "Q" ("  Collectables", g, l)+  , let (g,l) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryOther . traverse) o+    in print3 "I" "R" ("  Other CGT assets and CGT events", g, l)+  , let (g,_) = view (cgtGainsAndLossesByCategory . at CGTScheduleCategoryOther . traverse) o+    in print2_ "S" ("  Previously deferred CGT relief", g)+  , print2_ "J" ("  Total current year capital gains",  view cgtTotalCurrentYearGains o)++  , P.empty+  , "2  Capital losses"+  , print2 "A" ("  Total current year capital losses",  view cgtTotalCurrentYearLosses o)+  , print2 "B" ("  Total current year capital losses applied",   view cgtTotalCurrentYearLossesApplied o)+  , print2 "C" ("  Total prior year net capital losses applied", view cgtTotalPriorYearLossesApplied o)+  , let total = view cgtTotalCurrentYearLossesApplied o <> view cgtTotalPriorYearLossesApplied o+    in print2 "E" ("  Total capital losses applied", total)++  , P.empty+  , "3  Unapplied net capital losses carried forward"+  , print2 "A"+      ("  Net capital losses from collectables carried forward"+      , view (capitalLossCarryForward . capitalLossCarryForwardCollectables) o)+  , print2 "B"+      ("  Other capital losses carried forward"+      , view (capitalLossCarryForward . capitalLossCarryForwardOther) o)++  , P.empty+  , "4  CGT discount"+  , print2 "A" ("  Total CGT discount applied", view cgtTotalCGTDiscountApplied o)++  , P.empty+  , "6  Net capital gain"+  , print2 "A" ("  Net capital gain", view cgtNetGain o)+  ]+  where+    prepLabel s = "  " <> s <> " $"+    print3 labelL labelR =+      threeCol' id+        (prepend (prepLabel labelL) moneyFormatter)+        (prepend (prepLabel labelR) moneyFormatter)+    print2_ labelL (k, v) =+      threeCol' id+        (prepend (prepLabel labelL) moneyFormatter)+        (blank $ prepend (prepLabel labelL) moneyFormatter)+        (k, v, mempty)+    print2 label = twoCol' id (prepend (prepLabel label) moneyFormatter)+ summariseCGT :: TaxReturnInfo y Rational -> P.Doc summariseCGT info   | o == nullCGTAssessment = P.empty@@ -150,7 +296,7 @@         , threeColLeft  ("    V Net capital losses carried forward", view cgtNetLossesCarriedForward o)         ]   where-    o = assessCGTEvents (view capitalLossCarryForward info) (view cgtEvents info)+    o = assessCGTEvents Individual (view capitalLossCarryForward info) (view cgtEvents info)  deductionsTable :: [(ALens' (Deductions Rational) (Money Rational), String)] deductionsTable =@@ -207,4 +353,4 @@     ]   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)+  P.$+$ "Net capital loss to carry forward" P.$$ P.nest colWidthLabel (views (taxCGTAssessment . cgtNetLossesCarriedForward) formatMoney assessment)
tax-ato.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                tax-ato-version:             2025.1+version:             2026.1 synopsis:            Tax types and computations for Australia description:   This library provides types and tax computations for tax@@ -11,10 +11,10 @@ license-file:        LICENSE author:              Fraser Tweedale maintainer:          frase@frase.id.au-copyright:           Copyright (C) 2018-2023 Fraser Tweedale+copyright:           Copyright (C) 2018-2026 Fraser Tweedale category:            Finance build-type:          Simple-tested-with:         GHC ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2+tested-with:         GHC ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.4 || ==9.14.1 extra-source-files:   .hlint.yaml extra-doc-files:@@ -56,6 +56,7 @@   exposed-modules:     Data.Tax.ATO     Data.Tax.ATO.ABN+    Data.Tax.ATO.BPI     Data.Tax.ATO.TFN     Data.Tax.ATO.CGT     Data.Tax.ATO.Common@@ -74,8 +75,11 @@     Data.Tax.ATO.FY.FY2023     Data.Tax.ATO.FY.FY2024     Data.Tax.ATO.FY.FY2025+    Data.Tax.ATO.FY.FY2026+    Data.Tax.ATO.FY.FY2027   build-depends:+    , containers >= 0.6 && < 0.9     , lens >= 4.18 && < 6-    , time >= 1.11 && < 1.15+    , time >= 1.11 && < 1.16     , tax >= 0.2 && < 0.3     , pretty >= 1.1.3.6 && < 2