MoneyWiseUKTaxAnalysis.java
/*
* MoneyWise: Finance Application
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.moneywise.tax.uk;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceKey;
import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceManager;
import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceSet;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticResource;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxClass;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxAnalysis;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxDueBucket;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxResource;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxSource;
import io.github.tonywasher.joceanus.moneywise.tax.uk.MoneyWiseUKChargeableGainsScheme.MoneyWiseUKSlicedTaxDueBucket;
import java.time.Month;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* UK Tax Analysis.
*/
public class MoneyWiseUKTaxAnalysis
implements MetisFieldItem, MoneyWiseTaxAnalysis {
/**
* Local Report fields.
*/
private static final MetisFieldSet<MoneyWiseUKTaxAnalysis> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKTaxAnalysis.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXYEAR_NAME, MoneyWiseUKTaxAnalysis::getTaxYear);
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXCONFIG_NAME, MoneyWiseUKTaxAnalysis::getTaxConfig);
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXANALYSIS_TAXBUCKETS, MoneyWiseUKTaxAnalysis::getTaxBuckets);
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXBANDS_INCOME, MoneyWiseUKTaxAnalysis::getTaxableIncome);
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXBANDS_TAXDUE, MoneyWiseUKTaxAnalysis::getTaxDue);
FIELD_DEFS.declareLocalField(MoneyWiseStaticResource.TAXBASIS_TAXPAID, MoneyWiseUKTaxAnalysis::getTaxPaid);
FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.TAXANALYSIS_TAXPROFIT, MoneyWiseUKTaxAnalysis::getTaxProfit);
}
/**
* The TaxYear.
*/
private final MoneyWiseUKTaxYear theTaxYear;
/**
* The TaxSource.
*/
private final MoneyWiseTaxSource theTaxSource;
/**
* The TaxConfig.
*/
private final MoneyWiseUKTaxConfig theTaxConfig;
/**
* The TaxDueBuckets.
*/
private final List<MoneyWiseTaxDueBucket> theTaxBuckets;
/**
* The Total TaxableIncome.
*/
private final OceanusMoney theTaxableIncome;
/**
* The Total TaxDue.
*/
private final OceanusMoney theTaxDue;
/**
* The Total Tax Paid.
*/
private final OceanusMoney theTaxPaid;
/**
* The TaxProfit/Loss.
*/
private final OceanusMoney theTaxProfit;
/**
* TaxPreferenceKeys.
*/
public enum MoneyWiseUKTaxPreferenceKey implements MetisPreferenceKey {
/**
* Birth Date.
*/
BIRTHDATE("BirthDate", MoneyWiseTaxResource.TAXPREF_BIRTH);
/**
* The name of the Preference.
*/
private final String theName;
/**
* The display string.
*/
private final String theDisplay;
/**
* Constructor.
*
* @param pName the name
* @param pDisplay the display string;
*/
MoneyWiseUKTaxPreferenceKey(final String pName,
final MoneyWiseTaxResource pDisplay) {
theName = pName;
theDisplay = pDisplay.getValue();
}
@Override
public String getName() {
return theName;
}
@Override
public String getDisplay() {
return theDisplay;
}
}
/**
* Taxation Preferences.
*/
public static class MoneyWiseUKTaxPreferences
extends MetisPreferenceSet {
/**
* Default year.
*/
private static final int YEAR = 1970;
/**
* Constructor.
*
* @param pManager the preference manager
* @throws OceanusException on error
*/
public MoneyWiseUKTaxPreferences(final MetisPreferenceManager pManager) throws OceanusException {
super(pManager, MoneyWiseTaxResource.TAXPREF_NAME);
}
@Override
protected void definePreferences() {
defineDatePreference(MoneyWiseUKTaxPreferenceKey.BIRTHDATE);
}
@Override
public void autoCorrectPreferences() {
/* Make sure that the birthDate is specified */
final MetisDatePreference myPref = getDatePreference(MoneyWiseUKTaxPreferenceKey.BIRTHDATE);
if (!myPref.isAvailable()) {
myPref.setValue(new OceanusDate(YEAR, Month.JANUARY, 1));
}
}
}
/**
* Constructor.
*
* @param pTaxSource the taxSource
* @param pPrefMgr the preference manager
* @param pTaxYear the tax year
*/
protected MoneyWiseUKTaxAnalysis(final MoneyWiseTaxSource pTaxSource,
final MetisPreferenceManager pPrefMgr,
final MoneyWiseUKTaxYear pTaxYear) {
/* Store the parameters */
theTaxYear = pTaxYear;
theTaxSource = pTaxSource;
/* Create the TaxDue Buckets */
theTaxBuckets = new ArrayList<>();
/* Determine the client birthday */
final MoneyWiseUKTaxPreferences myPreferences = pPrefMgr.getPreferenceSet(MoneyWiseUKTaxPreferences.class);
final OceanusDate myBirthday = myPreferences.getDateValue(MoneyWiseUKTaxPreferenceKey.BIRTHDATE);
theTaxConfig = new MoneyWiseUKTaxConfig(theTaxYear, theTaxSource, myBirthday);
/* Create the totals */
theTaxPaid = pTaxSource.getAmountForTaxBasis(MoneyWiseTaxClass.TAXPAID);
theTaxableIncome = new OceanusMoney(theTaxPaid);
theTaxableIncome.setZero();
theTaxDue = new OceanusMoney(theTaxPaid);
theTaxDue.setZero();
theTaxProfit = new OceanusMoney(theTaxPaid);
theTaxProfit.setZero();
}
@Override
public MoneyWiseUKTaxYear getTaxYear() {
return theTaxYear;
}
/**
* Obtain the taxConfig.
*
* @return the taxConfig
*/
public MoneyWiseUKTaxConfig getTaxConfig() {
return theTaxConfig;
}
@Override
public Iterator<MoneyWiseTaxDueBucket> taxDueIterator() {
return theTaxBuckets.iterator();
}
/**
* Obtain the taxBuckets.
*
* @return the taxBuckets
*/
private List<MoneyWiseTaxDueBucket> getTaxBuckets() {
return theTaxBuckets;
}
@Override
public OceanusMoney getTaxableIncome() {
return theTaxableIncome;
}
@Override
public OceanusMoney getTaxDue() {
return theTaxDue;
}
@Override
public OceanusMoney getTaxPaid() {
return theTaxPaid;
}
@Override
public OceanusMoney getTaxProfit() {
return theTaxProfit;
}
/**
* Calculate the taxDue.
*/
protected void calculateTaxDue() {
/* Reset the tax Due */
theTaxableIncome.setZero();
theTaxDue.setZero();
/* Loop through the tax bands */
final Iterator<MoneyWiseTaxDueBucket> myIterator = theTaxBuckets.iterator();
while (myIterator.hasNext()) {
final MoneyWiseTaxDueBucket myBucket = myIterator.next();
/* Add the values */
theTaxableIncome.addAmount(myBucket.getTaxableIncome());
theTaxDue.addAmount(myBucket.getTaxDue());
/* If this is a sliced tax bucket */
if (myBucket instanceof MoneyWiseUKSlicedTaxDueBucket mySliced) {
/* Apply Tax Relief */
theTaxDue.subtractAmount(mySliced.getTaxRelief());
}
}
}
/**
* Calculate the taxProfit.
*/
protected void calculateTaxProfit() {
/* Calculate the profit */
theTaxProfit.setZero();
theTaxProfit.addAmount(theTaxDue);
theTaxProfit.addAmount(theTaxPaid);
}
/**
* Process the item.
*
* @param pBasis the tax basis
* @param pScheme the income scheme
*/
protected void processItem(final MoneyWiseTaxClass pBasis,
final MoneyWiseUKIncomeScheme pScheme) {
/* Obtain the amount */
final OceanusMoney myAmount = theTaxSource.getAmountForTaxBasis(pBasis);
/* Ignore zero or negative amounts */
if (myAmount.isZero()
|| !myAmount.isPositive()) {
return;
}
/* Take a clone of the taxConfig */
final MoneyWiseUKTaxConfig myConfig = theTaxConfig.cloneIt();
/* Allocate the amount to the various taxBands */
final MoneyWiseTaxBandSet myBands = pScheme.allocateToTaxBands(theTaxConfig, pBasis, myAmount);
/* Create the TaxDueBucket */
MoneyWiseTaxDueBucket myBucket = new MoneyWiseTaxDueBucket(pBasis, myBands, myConfig);
/* If this is ChargeableGains, and we have multiple Bands */
if (MoneyWiseTaxClass.CHARGEABLEGAINS.equals(pBasis)
&& myBands.multipleBands()) {
/* Analyse the Slices */
myBucket = new MoneyWiseUKSlicedTaxDueBucket(myBucket, theTaxSource);
}
/* Add the bucket to the list */
theTaxBuckets.add(myBucket);
}
@Override
public MetisFieldSet<MoneyWiseUKTaxAnalysis> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return FIELD_DEFS.getName();
}
}