MoneyWiseAnalysisTaxBasisBucket.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.lethe.data.analysis.data;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldTableItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.metis.list.MetisListIndexed;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetDirection;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxBasis;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxBasis.MoneyWiseTaxBasisList;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxClass;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.base.MoneyWiseAnalysisHistory;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisTaxBasisAccountBucket.MoneyWiseAnalysisTaxBasisAccountBucketList;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisTaxBasisAttr;
import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.values.MoneyWiseAnalysisTaxBasisValues;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseChargeableGainSlice.MoneyWiseChargeableGainSliceList;
import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxSource;
import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
import java.util.Currency;
import java.util.Iterator;
import java.util.List;
/**
* The TaxBasis Bucket class.
*/
public class MoneyWiseAnalysisTaxBasisBucket
implements MetisFieldTableItem {
/**
* Local Report fields.
*/
private static final MetisFieldSet<MoneyWiseAnalysisTaxBasisBucket> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseAnalysisTaxBasisBucket.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_NAME, MoneyWiseAnalysisTaxBasisBucket::getAnalysis);
FIELD_DEFS.declareLocalField(MoneyWiseStaticDataType.TAXBASIS, MoneyWiseAnalysisTaxBasisBucket::getTaxBasis);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.BUCKET_BASEVALUES, MoneyWiseAnalysisTaxBasisBucket::getBaseValues);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.BUCKET_HISTORY, MoneyWiseAnalysisTaxBasisBucket::getHistoryMap);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.TAXBASIS_ACCOUNTLIST, MoneyWiseAnalysisTaxBasisBucket::getAccounts);
FIELD_DEFS.declareLocalFieldsForEnum(MoneyWiseAnalysisTaxBasisAttr.class, MoneyWiseAnalysisTaxBasisBucket::getAttributeValue);
}
/**
* Totals bucket name.
*/
private static final MetisDataFieldId NAME_TOTALS = MoneyWiseAnalysisDataResource.ANALYSIS_TOTALS;
/**
* The analysis.
*/
private final MoneyWiseAnalysis theAnalysis;
/**
* Tax Basis.
*/
private final MoneyWiseTaxBasis theTaxBasis;
/**
* Values.
*/
private final MoneyWiseAnalysisTaxBasisValues theValues;
/**
* The base values.
*/
private final MoneyWiseAnalysisTaxBasisValues theBaseValues;
/**
* History Map.
*/
private final MoneyWiseAnalysisHistory<MoneyWiseAnalysisTaxBasisValues, MoneyWiseAnalysisTaxBasisAttr> theHistory;
/**
* Do we have accounts?
*/
private final boolean hasAccounts;
/**
* Are we an expense bucket?
*/
private final boolean isExpense;
/**
* AccountBucketList.
*/
private final MoneyWiseAnalysisTaxBasisAccountBucketList theAccounts;
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pTaxBasis the basis
*/
protected MoneyWiseAnalysisTaxBasisBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseTaxBasis pTaxBasis) {
/* Store the parameters */
theTaxBasis = pTaxBasis;
theAnalysis = pAnalysis;
isExpense = theTaxBasis != null
&& theTaxBasis.getTaxClass().isExpense();
/* Create the history map */
final MoneyWiseCurrency myDefault = theAnalysis.getCurrency();
final Currency myCurrency = myDefault == null
? MoneyWiseAnalysisAccountBucket.DEFAULT_CURRENCY
: myDefault.getCurrency();
final MoneyWiseAnalysisTaxBasisValues myValues = new MoneyWiseAnalysisTaxBasisValues(myCurrency);
theHistory = new MoneyWiseAnalysisHistory<>(myValues);
/* Create the account list */
hasAccounts = theTaxBasis != null
&& !(this instanceof MoneyWiseAnalysisTaxBasisAccountBucket)
&& theTaxBasis.getTaxClass().analyseAccounts();
theAccounts = hasAccounts
? new MoneyWiseAnalysisTaxBasisAccountBucketList(theAnalysis, this)
: null;
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pBase the underlying bucket
* @param pDate the date for the bucket
*/
protected MoneyWiseAnalysisTaxBasisBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisTaxBasisBucket pBase,
final OceanusDate pDate) {
/* Copy details from base */
theTaxBasis = pBase.getTaxBasis();
theAnalysis = pAnalysis;
isExpense = pBase.isExpense();
/* Access the relevant history */
theHistory = new MoneyWiseAnalysisHistory<>(pBase.getHistoryMap(), pDate);
/* Create the account list */
hasAccounts = pBase.hasAccounts();
theAccounts = hasAccounts
? new MoneyWiseAnalysisTaxBasisAccountBucketList(theAnalysis, this, pBase.getAccounts(), pDate)
: null;
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
/**
* Constructor.
*
* @param pAnalysis the analysis
* @param pBase the underlying bucket
* @param pRange the range for the bucket
*/
protected MoneyWiseAnalysisTaxBasisBucket(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisTaxBasisBucket pBase,
final OceanusDateRange pRange) {
/* Copy details from base */
theTaxBasis = pBase.getTaxBasis();
theAnalysis = pAnalysis;
isExpense = pBase.isExpense();
/* Access the relevant history */
theHistory = new MoneyWiseAnalysisHistory<>(pBase.getHistoryMap(), pRange);
/* Create the account list */
hasAccounts = pBase.hasAccounts();
theAccounts = hasAccounts
? new MoneyWiseAnalysisTaxBasisAccountBucketList(theAnalysis, this, pBase.getAccounts(), pRange)
: null;
/* Access the key value maps */
theValues = theHistory.getValues();
theBaseValues = theHistory.getBaseValues();
}
@Override
public MetisFieldSet<? extends MoneyWiseAnalysisTaxBasisBucket> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return toString();
}
@Override
public String toString() {
return getName();
}
@Override
public Integer getIndexedId() {
return theTaxBasis.getIndexedId();
}
/**
* Obtain name.
*
* @return the name
*/
public String getName() {
return theTaxBasis == null
? NAME_TOTALS.getId()
: theTaxBasis.getName();
}
/**
* Obtain tax basis.
*
* @return the basis
*/
public MoneyWiseTaxBasis getTaxBasis() {
return theTaxBasis;
}
/**
* Do we have accounts.
*
* @return true/false
*/
public boolean hasAccounts() {
return hasAccounts;
}
/**
* Is this an expense bucket.
*
* @return true/false
*/
public boolean isExpense() {
return isExpense;
}
/**
* Obtain account list.
*
* @return the account list
*/
private MoneyWiseAnalysisTaxBasisAccountBucketList getAccounts() {
return theAccounts;
}
/**
* Obtain account list iterator.
*
* @return the iterator
*/
public Iterator<MoneyWiseAnalysisTaxBasisAccountBucket> accountIterator() {
return hasAccounts
? theAccounts.iterator()
: null;
}
/**
* find an account bucket.
*
* @param pAccount the account
* @return the bucket
*/
public MoneyWiseAnalysisTaxBasisAccountBucket findAccountBucket(final MoneyWiseTransAsset pAccount) {
return hasAccounts
? theAccounts.findBucket(pAccount)
: null;
}
/**
* Is this bucket idle?
*
* @return true/false
*/
public Boolean isIdle() {
return theHistory.isIdle();
}
/**
* Obtain the value map.
*
* @return the value map
*/
public MoneyWiseAnalysisTaxBasisValues getValues() {
return theValues;
}
/**
* Obtain the value for a particular attribute.
*
* @param pAttr the attribute
* @return the value
*/
public OceanusMoney getMoneyValue(final MoneyWiseAnalysisTaxBasisAttr pAttr) {
return theValues.getMoneyValue(pAttr);
}
/**
* Obtain the base value map.
*
* @return the base value map
*/
public MoneyWiseAnalysisTaxBasisValues getBaseValues() {
return theBaseValues;
}
/**
* Obtain values for transaction.
*
* @param pTrans the event
* @return the values (or null)
*/
public MoneyWiseAnalysisTaxBasisValues getValuesForTransaction(final MoneyWiseTransaction pTrans) {
/* Obtain values for event */
return theHistory.getValuesForTransaction(pTrans);
}
/**
* Obtain previous values for transaction.
*
* @param pTrans the transaction
* @return the values (or null)
*/
public MoneyWiseAnalysisTaxBasisValues getPreviousValuesForTransaction(final MoneyWiseTransaction pTrans) {
return theHistory.getPreviousValuesForTransaction(pTrans);
}
/**
* Obtain delta for transaction.
*
* @param pTrans the transaction
* @param pAttr the attribute
* @return the delta (or null)
*/
public OceanusDecimal getDeltaForTransaction(final MoneyWiseTransaction pTrans,
final MoneyWiseAnalysisTaxBasisAttr pAttr) {
/* Obtain delta for event */
return theHistory.getDeltaValue(pTrans, pAttr);
}
/**
* Obtain the history map.
*
* @return the history map
*/
private MoneyWiseAnalysisHistory<MoneyWiseAnalysisTaxBasisValues, MoneyWiseAnalysisTaxBasisAttr> getHistoryMap() {
return theHistory;
}
/**
* Obtain the analysis.
*
* @return the analysis
*/
protected MoneyWiseAnalysis getAnalysis() {
return theAnalysis;
}
/**
* Obtain date range.
*
* @return the range
*/
public OceanusDateRange getDateRange() {
return theAnalysis.getDateRange();
}
/**
* Set Attribute.
*
* @param pAttr the attribute
* @param pValue the value of the attribute
*/
protected void setValue(final MoneyWiseAnalysisTaxBasisAttr pAttr,
final OceanusMoney pValue) {
/* Set the value into the list */
theValues.setValue(pAttr, pValue);
}
/**
* Get an attribute value.
*
* @param pAttr the attribute
* @return the value to set
*/
private Object getAttributeValue(final MoneyWiseAnalysisTaxBasisAttr pAttr) {
/* Access value of object */
final Object myValue = getValue(pAttr);
/* Return the value */
return myValue != null
? myValue
: MetisDataFieldValue.SKIP;
}
/**
* Obtain an attribute value.
*
* @param pAttr the attribute
* @return the value of the attribute or null
*/
private Object getValue(final MoneyWiseAnalysisTaxBasisAttr pAttr) {
/* Obtain the attribute */
return theValues.getValue(pAttr);
}
/**
* Add income transaction.
*
* @param pTrans the transaction
*/
protected void addIncomeTransaction(final MoneyWiseAnalysisTransactionHelper pTrans) {
/* Access details */
final OceanusMoney myAmount = pTrans.getCreditAmount();
final OceanusMoney myTaxCredit = pTrans.getTaxCredit();
final OceanusMoney myNatIns = pTrans.getEmployeeNatIns();
final OceanusMoney myBenefit = pTrans.getDeemedBenefit();
final OceanusMoney myWithheld = pTrans.getWithheld();
/* Determine style of transaction */
MoneyWiseAssetDirection myDir = pTrans.getDirection();
/* If the account is special */
final MoneyWiseTransCategoryClass myClass = pTrans.getCategoryClass();
if (myClass.isSwitchDirection()) {
/* switch the direction */
myDir = myDir.reverse();
}
/* Obtain zeroed counters */
OceanusMoney myGross = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
myGross = new OceanusMoney(myGross);
myGross.setZero();
final OceanusMoney myNett = new OceanusMoney(myGross);
final OceanusMoney myTax = new OceanusMoney(myGross);
/* If this is an expense */
if (myDir.isTo()) {
/* Adjust the gross and net */
myGross.subtractAmount(myAmount);
myNett.subtractAmount(myAmount);
/* If we have a tax credit */
if (myTaxCredit != null
&& myTaxCredit.isNonZero()) {
/* Adjust the gross */
myGross.subtractAmount(myTaxCredit);
myTax.subtractAmount(myTaxCredit);
}
/* If we have a natInsurance payment */
if (myNatIns != null
&& myNatIns.isNonZero()) {
/* Adjust the gross */
myGross.subtractAmount(myNatIns);
}
/* If we have a Benefit payment */
if (myBenefit != null
&& myBenefit.isNonZero()) {
/* Adjust the gross */
myGross.subtractAmount(myBenefit);
}
/* If we have a Withheld */
if (myWithheld != null
&& myWithheld.isNonZero()) {
/* Adjust the gross and net */
myGross.subtractAmount(myWithheld);
myNett.subtractAmount(myWithheld);
}
/* else this is a standard income */
} else {
/* Adjust the gross and net */
myGross.addAmount(myAmount);
myNett.addAmount(myAmount);
/* If we have a tax credit */
if (myTaxCredit != null
&& myTaxCredit.isNonZero()) {
/* Adjust the values */
myGross.addAmount(myTaxCredit);
myTax.addAmount(myTaxCredit);
}
/* If we have a natInsurance payment */
if (myNatIns != null
&& myNatIns.isNonZero()) {
/* Adjust the gross */
myGross.addAmount(myNatIns);
}
/* If we have a Benefit payment */
if (myBenefit != null
&& myBenefit.isNonZero()) {
/* Adjust the gross */
myGross.addAmount(myBenefit);
}
/* If we have a Withheld */
if (myWithheld != null
&& myWithheld.isNonZero()) {
/* Adjust the gross and net */
myGross.addAmount(myWithheld);
myNett.addAmount(myWithheld);
}
}
/* Register the delta values */
registerDeltaValues(pTrans, myGross, myNett, myTax);
/* If we have accounts */
if (hasAccounts) {
/* register the changes against the accounts */
theAccounts.registerDeltaValues(pTrans, myGross, myNett, myTax);
}
}
/**
* Add expense transaction.
*
* @param pTrans the transaction
*/
protected void addExpenseTransaction(final MoneyWiseAnalysisTransactionHelper pTrans) {
/* Access details */
final OceanusMoney myAmount = pTrans.getDebitAmount();
final OceanusMoney myTaxCredit = pTrans.getTaxCredit();
/* Determine style of event */
final MoneyWiseAssetDirection myDir = pTrans.getDirection();
/* Obtain zeroed counters */
OceanusMoney myGross = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
myGross = new OceanusMoney(myGross);
myGross.setZero();
final OceanusMoney myNett = new OceanusMoney(myGross);
final OceanusMoney myTax = new OceanusMoney(myGross);
/* If this is a refunded expense */
if (myDir.isFrom()) {
/* Adjust the gross and net */
myGross.addAmount(myAmount);
myNett.addAmount(myAmount);
/* If we have a tax relief */
if (myTaxCredit != null
&& myTaxCredit.isNonZero()) {
/* Adjust the values */
myGross.addAmount(myTaxCredit);
myNett.addAmount(myTaxCredit);
myTax.addAmount(myTaxCredit);
}
/* else this is a standard expense */
} else {
/* Adjust the gross and net */
myGross.subtractAmount(myAmount);
myNett.subtractAmount(myAmount);
/* If we have a tax relief */
if (myTaxCredit != null
&& myTaxCredit.isNonZero()) {
/* Adjust the values */
myGross.subtractAmount(myTaxCredit);
myNett.subtractAmount(myTaxCredit);
myTax.subtractAmount(myTaxCredit);
}
}
/* Register the delta values */
registerDeltaValues(pTrans, myGross, myNett, myTax);
/* If we have accounts */
if (hasAccounts) {
/* register the changes against the accounts */
theAccounts.registerDeltaValues(pTrans, myGross, myNett, myTax);
}
}
/**
* Register delta transaction value.
*
* @param pTrans the transaction helper
* @param pGross the gross delta value
* @param pNett the net delta value
* @param pTax the tax delta value
*/
protected void registerDeltaValues(final MoneyWiseAnalysisTransactionHelper pTrans,
final OceanusMoney pGross,
final OceanusMoney pNett,
final OceanusMoney pTax) {
/* If we have a change to the gross value */
if (pGross.isNonZero()) {
/* Adjust Gross figure */
OceanusMoney myGross = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
myGross = new OceanusMoney(myGross);
myGross.addAmount(pGross);
setValue(MoneyWiseAnalysisTaxBasisAttr.GROSS, myGross);
}
/* If we have a change to the net value */
if (pNett.isNonZero()) {
/* Adjust Net figure */
OceanusMoney myNett = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.NETT);
myNett = new OceanusMoney(myNett);
myNett.addAmount(pNett);
setValue(MoneyWiseAnalysisTaxBasisAttr.NETT, myNett);
}
/* If we have a change to the tax value */
if (pTax.isNonZero()) {
/* Adjust Tax figure */
OceanusMoney myTax = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.TAXCREDIT);
myTax = new OceanusMoney(myTax);
myTax.addAmount(pTax);
setValue(MoneyWiseAnalysisTaxBasisAttr.TAXCREDIT, myTax);
}
/* Register the transaction */
registerTransaction(pTrans);
}
/**
* Adjust transaction value.
*
* @param pTrans the transaction
* @param pValue the value
* @param pAdjust adjustment control
*/
protected void adjustValue(final MoneyWiseAnalysisTransactionHelper pTrans,
final OceanusMoney pValue,
final MoneyWiseTaxBasisAdjust pAdjust) {
/* Adjust the value */
adjustValue(pValue, pAdjust);
/* Register the transaction */
registerTransaction(pTrans);
/* If we have accounts */
if (hasAccounts) {
/* register the adjustment against the accounts */
theAccounts.adjustValue(pTrans, pValue, pAdjust);
}
}
/**
* Adjust value.
*
* @param pValue the value
* @param pAdjust adjustment control
*/
protected void adjustValue(final OceanusMoney pValue,
final MoneyWiseTaxBasisAdjust pAdjust) {
/* If we are adjusting Gross */
if (pAdjust.adjustGross()) {
/* Access the existing value */
OceanusMoney myGross = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
myGross = new OceanusMoney(myGross);
/* Subtract or add the value depending as to whether we are an expense bucket */
if (isExpense) {
myGross.subtractAmount(pValue);
} else {
myGross.addAmount(pValue);
}
/* Record the new value */
setValue(MoneyWiseAnalysisTaxBasisAttr.GROSS, myGross);
}
/* If we are adjusting Nett */
if (pAdjust.adjustNett()) {
/* Access the existing value */
OceanusMoney myNett = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.NETT);
myNett = new OceanusMoney(myNett);
/* Subtract or add the value depending as to whether we are an expense bucket */
if (isExpense) {
myNett.subtractAmount(pValue);
} else {
myNett.addAmount(pValue);
}
/* Record the new value */
setValue(MoneyWiseAnalysisTaxBasisAttr.NETT, myNett);
}
}
/**
* Register the transaction.
*
* @param pTrans the transaction helper
*/
protected void registerTransaction(final MoneyWiseAnalysisTransactionHelper pTrans) {
/* Register the transaction in the history */
theHistory.registerTransaction(pTrans.getTransaction(), theValues);
}
/**
* Add values.
*
* @param pBucket tax category bucket
*/
protected void addValues(final MoneyWiseAnalysisTaxBasisBucket pBucket) {
/* Add the values */
OceanusMoney myAmount = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
myAmount.addAmount(pBucket.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS));
myAmount = theValues.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.NETT);
myAmount.addAmount(pBucket.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.NETT));
}
/**
* Adjust to base.
*/
protected void adjustToBase() {
/* Adjust to base values */
theValues.adjustToBaseValues(theBaseValues);
theBaseValues.resetBaseValues();
}
/**
* Is the bucket active?
*
* @return true/false
*/
public boolean isActive() {
return theValues.isActive();
}
/**
* Value adjust Modes.
*/
protected enum MoneyWiseTaxBasisAdjust {
/**
* Adjust both Gross and Nett.
*/
STANDARD,
/**
* Only adjust Nett figure.
*/
NETT,
/**
* Only adjust Gross figure.
*/
GROSS;
/**
* should we adjust Gross?
*
* @return true/false
*/
private boolean adjustGross() {
return this != NETT;
}
/**
* should we adjust Nett?
*
* @return true/false
*/
private boolean adjustNett() {
return this != GROSS;
}
}
/**
* TaxBasisBucketList class.
*/
public static class MoneyWiseAnalysisTaxBasisBucketList
implements MetisFieldItem, MoneyWiseTaxSource, MetisDataList<MoneyWiseAnalysisTaxBasisBucket> {
/**
* Local Report fields.
*/
private static final MetisFieldSet<MoneyWiseAnalysisTaxBasisBucketList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseAnalysisTaxBasisBucketList.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_NAME, MoneyWiseAnalysisTaxBasisBucketList::getAnalysis);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_CHARGES, MoneyWiseAnalysisTaxBasisBucketList::getGainSlices);
FIELD_DEFS.declareLocalField(MoneyWiseAnalysisDataResource.ANALYSIS_TOTALS, MoneyWiseAnalysisTaxBasisBucketList::getTotals);
}
/**
* The analysis.
*/
private final MoneyWiseAnalysis theAnalysis;
/**
* The list.
*/
private final MetisListIndexed<MoneyWiseAnalysisTaxBasisBucket> theList;
/**
* The editSet.
*/
private final PrometheusEditSet theEditSet;
/**
* The chargeableGains.
*/
private final MoneyWiseChargeableGainSliceList theCharges;
/**
* The tax basis.
*/
private final MoneyWiseAnalysisTaxBasisBucket theTotals;
/**
* Construct a top-level List.
*
* @param pAnalysis the analysis
* @param pGains the new Gains list
*/
private MoneyWiseAnalysisTaxBasisBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseChargeableGainSliceList pGains) {
theAnalysis = pAnalysis;
theEditSet = theAnalysis.getEditSet();
theCharges = pGains;
theTotals = allocateTotalsBucket();
theList = new MetisListIndexed<>();
theList.setComparator((l, r) -> l.getTaxBasis().compareTo(r.getTaxBasis()));
}
/**
* Construct a top-level List.
*
* @param pAnalysis the analysis
*/
protected MoneyWiseAnalysisTaxBasisBucketList(final MoneyWiseAnalysis pAnalysis) {
this(pAnalysis, new MoneyWiseChargeableGainSliceList());
}
/**
* Construct a dated List.
*
* @param pAnalysis the analysis
* @param pBase the base list
* @param pDate the Date
*/
protected MoneyWiseAnalysisTaxBasisBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisTaxBasisBucketList pBase,
final OceanusDate pDate) {
/* Initialise class */
this(pAnalysis, new MoneyWiseChargeableGainSliceList(pBase.getGainSlices(), pAnalysis.getDateRange()));
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisTaxBasisBucket> myIterator = pBase.iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisTaxBasisBucket myCurr = myIterator.next();
/* Access the bucket for this date */
final MoneyWiseAnalysisTaxBasisBucket myBucket = new MoneyWiseAnalysisTaxBasisBucket(pAnalysis, myCurr, pDate);
/* If the bucket is non-idle */
if (Boolean.FALSE.equals(myBucket.isIdle())) {
/* Calculate the delta and add to the list */
theList.add(myBucket);
}
}
}
/**
* Construct a ranged List.
*
* @param pAnalysis the analysis
* @param pBase the base list
* @param pRange the Date Range
*/
protected MoneyWiseAnalysisTaxBasisBucketList(final MoneyWiseAnalysis pAnalysis,
final MoneyWiseAnalysisTaxBasisBucketList pBase,
final OceanusDateRange pRange) {
/* Initialise class */
this(pAnalysis, new MoneyWiseChargeableGainSliceList(pBase.getGainSlices(), pAnalysis.getDateRange()));
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisTaxBasisBucket> myIterator = pBase.iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisTaxBasisBucket myCurr = myIterator.next();
/* Access the bucket for this range */
final MoneyWiseAnalysisTaxBasisBucket myBucket = new MoneyWiseAnalysisTaxBasisBucket(pAnalysis, myCurr, pRange);
/* If the bucket is non-idle */
if (Boolean.FALSE.equals(myBucket.isIdle())) {
/* Adjust to the base */
myBucket.adjustToBase();
theList.add(myBucket);
}
}
}
@Override
public MetisFieldSet<MoneyWiseAnalysisTaxBasisBucketList> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public List<MoneyWiseAnalysisTaxBasisBucket> getUnderlyingList() {
return theList.getUnderlyingList();
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return getDataFieldSet().getName();
}
/**
* Obtain the analysis.
*
* @return the analysis
*/
protected MoneyWiseAnalysis getAnalysis() {
return theAnalysis;
}
/**
* Obtain item by id.
*
* @param pId the id to lookup
* @return the item (or null if not present)
*/
public MoneyWiseAnalysisTaxBasisBucket findItemById(final Integer pId) {
/* Return results */
return theList.getItemById(pId);
}
@Override
public MoneyWiseChargeableGainSliceList getGainSlices() {
return theCharges;
}
/**
* Obtain the Totals.
*
* @return the totals bucket
*/
public MoneyWiseAnalysisTaxBasisBucket getTotals() {
return theTotals;
}
/**
* Allocate the Totals EventCategoryBucket.
*
* @return the bucket
*/
private MoneyWiseAnalysisTaxBasisBucket allocateTotalsBucket() {
/* Obtain the totals category */
return new MoneyWiseAnalysisTaxBasisBucket(theAnalysis, null);
}
/**
* Obtain the TaxBasisBucket for a given taxBasis.
*
* @param pClass the taxBasis
* @return the bucket
*/
public MoneyWiseAnalysisTaxBasisBucket getBucket(final MoneyWiseTaxClass pClass) {
/* Locate the bucket in the list */
final MoneyWiseTaxBasis myBasis = theEditSet.getDataList(MoneyWiseStaticDataType.TAXBASIS, MoneyWiseTaxBasisList.class).findItemByClass(pClass);
MoneyWiseAnalysisTaxBasisBucket myItem = findItemById(myBasis.getIndexedId());
/* If the item does not yet exist */
if (myItem == null) {
/* Create the new bucket */
myItem = new MoneyWiseAnalysisTaxBasisBucket(theAnalysis, myBasis);
/* Add to the list */
theList.add(myItem);
}
/* Return the bucket */
return myItem;
}
/**
* Obtain the matching BasisBucket.
*
* @param pTaxBasis the taxBasis
* @return the matching bucket
*/
public MoneyWiseAnalysisTaxBasisBucket getMatchingBasis(final MoneyWiseAnalysisTaxBasisBucket pTaxBasis) {
/* Access the matching taxBasis bucket */
MoneyWiseAnalysisTaxBasisBucket myBasis = findItemById(pTaxBasis.getTaxBasis().getIndexedId());
if (myBasis == null) {
myBasis = new MoneyWiseAnalysisTaxBasisBucket(theAnalysis, pTaxBasis.getTaxBasis());
}
/* If we are matching a TaxBasisAccount Bucket */
if (pTaxBasis instanceof MoneyWiseAnalysisTaxBasisAccountBucket) {
/* Look up the asset bucket */
final MoneyWiseTransAsset myAsset = ((MoneyWiseAnalysisTaxBasisAccountBucket) pTaxBasis).getAccount();
MoneyWiseAnalysisTaxBasisAccountBucket myAccountBucket = myBasis.findAccountBucket(myAsset);
/* If there is no such bucket in the analysis */
if (myAccountBucket == null) {
/* Allocate an orphan bucket */
myAccountBucket = new MoneyWiseAnalysisTaxBasisAccountBucket(theAnalysis, myBasis, myAsset);
}
/* Set bucket as the account bucket */
myBasis = myAccountBucket;
}
/* Return the basis */
return myBasis;
}
/**
* Obtain the default BasisBucket.
*
* @return the default bucket
*/
public MoneyWiseAnalysisTaxBasisBucket getDefaultBasis() {
/* Return the first basis in the list if it exists */
return isEmpty()
? null
: theList.getUnderlyingList().get(0);
}
/**
* Adjust basis buckets.
*
* @param pTrans the transaction helper
* @param pCategory primary category
*/
protected void adjustBasis(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTransCategory pCategory) {
/* Switch on the category type */
switch (pCategory.getCategoryTypeClass()) {
case TAXEDINCOME:
case GROSSINCOME:
addIncome(pTrans, MoneyWiseTaxClass.SALARY);
break;
case OTHERINCOME:
addIncome(pTrans, MoneyWiseTaxClass.OTHERINCOME);
break;
case INTEREST:
case TAXEDINTEREST:
case TAXEDLOYALTYBONUS:
addIncome(pTrans, MoneyWiseTaxClass.TAXEDINTEREST);
break;
case GROSSINTEREST:
case GROSSLOYALTYBONUS:
addIncome(pTrans, MoneyWiseTaxClass.UNTAXEDINTEREST);
break;
case PEER2PEERINTEREST:
addIncome(pTrans, MoneyWiseTaxClass.PEER2PEERINTEREST);
break;
case DIVIDEND:
case SHAREDIVIDEND:
addIncome(pTrans, MoneyWiseTaxClass.DIVIDEND);
break;
case UNITTRUSTDIVIDEND:
addIncome(pTrans, MoneyWiseTaxClass.UNITTRUSTDIVIDEND);
break;
case FOREIGNDIVIDEND:
addIncome(pTrans, MoneyWiseTaxClass.FOREIGNDIVIDEND);
break;
case RENTALINCOME:
addIncome(pTrans, MoneyWiseTaxClass.RENTALINCOME);
break;
case ROOMRENTALINCOME:
addIncome(pTrans, MoneyWiseTaxClass.ROOMRENTAL);
break;
case INCOMETAX:
addExpense(pTrans, MoneyWiseTaxClass.TAXPAID);
break;
case TAXFREEINTEREST:
case TAXFREEDIVIDEND:
case LOANINTERESTEARNED:
case INHERITED:
case CASHBACK:
case LOYALTYBONUS:
case TAXFREELOYALTYBONUS:
case GIFTEDINCOME:
addIncome(pTrans, MoneyWiseTaxClass.TAXFREE);
break;
case PENSIONCONTRIB:
addIncome(pTrans, MoneyWiseTaxClass.TAXFREE);
break;
case BADDEBTCAPITAL:
addExpense(pTrans, MoneyWiseTaxClass.CAPITALGAINS);
break;
case BADDEBTINTEREST:
addExpense(pTrans, MoneyWiseTaxClass.PEER2PEERINTEREST);
break;
case EXPENSE:
case LOCALTAXES:
case WRITEOFF:
case LOANINTERESTCHARGED:
case TAXRELIEF:
case RECOVEREDEXPENSES:
addExpense(pTrans, MoneyWiseTaxClass.EXPENSE);
break;
case RENTALEXPENSE:
addExpense(pTrans, MoneyWiseTaxClass.RENTALINCOME);
break;
case UNITSADJUST:
case SECURITYREPLACE:
case STOCKTAKEOVER:
case STOCKSPLIT:
case STOCKDEMERGER:
case STOCKRIGHTSISSUE:
case PORTFOLIOXFER:
case TRANSFER:
default:
break;
}
}
/**
* Adjust basis for income.
*
* @param pClass the class
* @param pTrans the transaction
*/
private void addIncome(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTaxClass pClass) {
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(pClass);
myBucket.addIncomeTransaction(pTrans);
}
/**
* Adjust basis for expense.
*
* @param pClass the class
* @param pTrans the transaction
*/
private void addExpense(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTaxClass pClass) {
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(pClass);
myBucket.addExpenseTransaction(pTrans);
}
/**
* Adjust basis buckets.
*
* @param pTrans the transaction
* @param pClass the class
* @param pIncome the income
*/
protected void adjustValue(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTaxClass pClass,
final OceanusMoney pIncome) {
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(pClass);
myBucket.adjustValue(pTrans, pIncome, MoneyWiseTaxBasisAdjust.STANDARD);
}
/**
* Adjust basis buckets for Gross only.
*
* @param pTrans the transaction
* @param pClass the class
* @param pIncome the income
*/
protected void adjustGrossValue(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTaxClass pClass,
final OceanusMoney pIncome) {
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(pClass);
myBucket.adjustValue(pTrans, pIncome, MoneyWiseTaxBasisAdjust.GROSS);
}
/**
* Adjust basis buckets for Nett only.
*
* @param pTrans the transaction
* @param pClass the class
* @param pIncome the income
*/
protected void adjustNettValue(final MoneyWiseAnalysisTransactionHelper pTrans,
final MoneyWiseTaxClass pClass,
final OceanusMoney pIncome) {
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(pClass);
myBucket.adjustValue(pTrans, pIncome, MoneyWiseTaxBasisAdjust.NETT);
}
/**
* Adjust autoExpense.
*
* @param pTrans the transaction
* @param isExpense true/false
*/
public void adjustAutoExpense(final MoneyWiseAnalysisTransactionHelper pTrans,
final boolean isExpense) {
/* Determine value */
OceanusMoney myAmount = pTrans.getLocalAmount();
if (!isExpense) {
myAmount = new OceanusMoney(myAmount);
myAmount.negate();
}
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(MoneyWiseTaxClass.EXPENSE);
myBucket.adjustValue(pTrans, myAmount, MoneyWiseTaxBasisAdjust.STANDARD);
}
/**
* Adjust for market growth.
*
* @param pIncome the income
* @param pExpense the expense
*/
protected void adjustMarket(final OceanusMoney pIncome,
final OceanusMoney pExpense) {
/* Calculate the delta */
final OceanusMoney myDelta = new OceanusMoney(pIncome);
myDelta.subtractAmount(pExpense);
/* Access the bucket and adjust it */
final MoneyWiseAnalysisTaxBasisBucket myBucket = getBucket(MoneyWiseTaxClass.MARKET);
myBucket.adjustValue(myDelta, MoneyWiseTaxBasisAdjust.STANDARD);
}
/**
* record ChargeableGain.
*
* @param pTrans the transaction
* @param pGain the gain
*/
public void recordChargeableGain(final MoneyWiseTransaction pTrans,
final OceanusMoney pGain) {
/* record the chargeable gain */
theCharges.addTransaction(pTrans, pGain);
}
/**
* produce Totals.
*/
protected void produceTotals() {
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisTaxBasisBucket> myIterator = iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisTaxBasisBucket myBucket = myIterator.next();
/* Sort the accounts */
if (myBucket.hasAccounts()) {
myBucket.getAccounts().sortBuckets();
}
/* Adjust the Total Profit buckets */
theTotals.addValues(myBucket);
}
/* Sort the bases */
theList.sortList();
}
/**
* Prune the list to remove irrelevant items.
*/
protected void prune() {
/* Loop through the buckets */
final Iterator<MoneyWiseAnalysisTaxBasisBucket> myIterator = iterator();
while (myIterator.hasNext()) {
final MoneyWiseAnalysisTaxBasisBucket myCurr = myIterator.next();
/* Remove the bucket if it is inactive */
if (!myCurr.isActive()) {
myIterator.remove();
}
}
}
@Override
public OceanusMoney getAmountForTaxBasis(final MoneyWiseTaxClass pBasis) {
/* Access the bucket */
final MoneyWiseAnalysisTaxBasisBucket myItem = findItemById(pBasis.getClassId());
/* If the bucket is not found */
if (myItem == null) {
final MoneyWiseCurrency myAssetCurrency = theAnalysis.getCurrency();
final Currency myCurrency = myAssetCurrency == null
? OceanusMoney.getDefaultCurrency()
: myAssetCurrency.getCurrency();
return new OceanusMoney(myCurrency);
}
return myItem.getMoneyValue(MoneyWiseAnalysisTaxBasisAttr.GROSS);
}
}
}