View Javadoc
1   /*
2    * MoneyWise: Finance Application
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.moneywise.tax.uk;
18  
19  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
20  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
21  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
22  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
23  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseChargeableGainSlice;
24  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet;
25  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet.MoneyWiseTaxBand;
26  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxDueBucket;
27  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxResource;
28  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxSource;
29  
30  import java.util.Iterator;
31  
32  /**
33   * Taxable Gains Scheme.
34   */
35  public class MoneyWiseUKChargeableGainsScheme
36          extends MoneyWiseUKIncomeScheme {
37      /**
38       * Constructor.
39       */
40      protected MoneyWiseUKChargeableGainsScheme() {
41          super(Boolean.FALSE);
42      }
43  
44      /**
45       * Chargeable Gains Sliced Tax Due.
46       */
47      public static class MoneyWiseUKSlicedTaxDueBucket
48              extends MoneyWiseTaxDueBucket {
49          /**
50           * Local Report fields.
51           */
52          private static final MetisFieldSet<MoneyWiseUKSlicedTaxDueBucket> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKSlicedTaxDueBucket.class);
53  
54          /*
55           * Declare Fields.
56           */
57          static {
58              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_TOTALGAINS, MoneyWiseUKSlicedTaxDueBucket::getTotalGains);
59              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_TOTALSLICES, MoneyWiseUKSlicedTaxDueBucket::getTotalSlices);
60              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_RATIO, MoneyWiseUKSlicedTaxDueBucket::getRatio);
61              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_TAXEDSLICES, MoneyWiseUKSlicedTaxDueBucket::getTaxedSlices);
62              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_NETTTAXDUE, MoneyWiseUKSlicedTaxDueBucket::getNettTaxDue);
63              FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.CHARGEABLEGAIN_TAXRELIEF, MoneyWiseUKSlicedTaxDueBucket::getTaxRelief);
64          }
65  
66          /**
67           * The total gains.
68           */
69          private final OceanusMoney theTotalGains;
70  
71          /**
72           * The total slices.
73           */
74          private final OceanusMoney theTotalSlices;
75  
76          /**
77           * The ratio.
78           */
79          private final OceanusRatio theRatio;
80  
81          /**
82           * The slices taxDueBucket.
83           */
84          private final MoneyWiseTaxDueBucket theSliceBucket;
85  
86          /**
87           * The taxRelief.
88           */
89          private final OceanusMoney theTaxRelief;
90  
91          /**
92           * The nett taxDue.
93           */
94          private final OceanusMoney theNettTaxDue;
95  
96          /**
97           * Constructor.
98           *
99           * @param pBase   the underlying bucket
100          * @param pSource the tax source
101          */
102         protected MoneyWiseUKSlicedTaxDueBucket(final MoneyWiseTaxDueBucket pBase,
103                                                 final MoneyWiseTaxSource pSource) {
104             /* Initialise underlying bucket */
105             super(pBase);
106 
107             /* Create the totals */
108             final OceanusMoney myZero = new OceanusMoney(pBase.getTaxDue());
109             theTotalGains = new OceanusMoney(myZero);
110             theTotalSlices = new OceanusMoney(myZero);
111             theTaxRelief = new OceanusMoney(myZero);
112             theNettTaxDue = new OceanusMoney(myZero);
113 
114             /* Process the slices */
115             for (MoneyWiseChargeableGainSlice mySlice : pSource.getGainSlices().getUnderlyingList()) {
116                 processSlice(mySlice);
117             }
118 
119             /* Calculate the ratio */
120             theRatio = new OceanusRatio(theTotalGains, theTotalSlices);
121 
122             /* Determine tax due on slices */
123             theSliceBucket = buildSliceBucket();
124             calculateTax();
125         }
126 
127         /**
128          * Obtain the total gains.
129          *
130          * @return the gains
131          */
132         public OceanusMoney getTotalGains() {
133             return theTotalGains;
134         }
135 
136         /**
137          * Obtain the total slices.
138          *
139          * @return the slices
140          */
141         public OceanusMoney getTotalSlices() {
142             return theTotalSlices;
143         }
144 
145         /**
146          * Obtain the ratio.
147          *
148          * @return the ratio
149          */
150         public OceanusRatio getRatio() {
151             return theRatio;
152         }
153 
154         /**
155          * Obtain the taxed slices.
156          *
157          * @return the taxed slices
158          */
159         public MoneyWiseTaxDueBucket getTaxedSlices() {
160             return theSliceBucket;
161         }
162 
163         /**
164          * Obtain the tax due.
165          *
166          * @return the tax due
167          */
168         public OceanusMoney getNettTaxDue() {
169             return theNettTaxDue;
170         }
171 
172         /**
173          * Obtain the tax relief.
174          *
175          * @return the tax relief
176          */
177         public OceanusMoney getTaxRelief() {
178             return theTaxRelief;
179         }
180 
181         /**
182          * Process slice.
183          *
184          * @param pSlice the slice
185          */
186         private void processSlice(final MoneyWiseChargeableGainSlice pSlice) {
187             /* Adjust totals */
188             theTotalGains.addAmount(pSlice.getGain());
189             theTotalSlices.addAmount(pSlice.getSlice());
190         }
191 
192         /**
193          * build slice bucket.
194          *
195          * @return the slice bucket
196          */
197         private MoneyWiseTaxDueBucket buildSliceBucket() {
198             /* Create a new taxBand set */
199             final MoneyWiseTaxBandSet myTaxBands = new MoneyWiseTaxBandSet();
200             final OceanusMoney myRemaining = new OceanusMoney(theTotalSlices);
201 
202             /* Calculate new tax allocation */
203             final Iterator<MoneyWiseTaxBandBucket> myIterator = taxBandIterator();
204             while (myRemaining.isNonZero()
205                     && myIterator.hasNext()) {
206                 final MoneyWiseTaxBandBucket myBucket = myIterator.next();
207 
208                 /* Determine amount in band */
209                 OceanusMoney myAmount = getAmountInBand(myBucket.getAmount(), myRemaining);
210                 myAmount = new OceanusMoney(myAmount);
211 
212                 /* allocate band and adjust */
213                 myTaxBands.addTaxBand(new MoneyWiseTaxBand(myAmount, myBucket.getRate()));
214                 myRemaining.subtractAmount(myAmount);
215             }
216 
217             /* Create the new tax bucket */
218             return new MoneyWiseTaxDueBucket(getTaxBasis(), myTaxBands, getTaxConfig());
219         }
220 
221         /**
222          * calculate the tax.
223          */
224         private void calculateTax() {
225             /* Calculate tax due */
226             theNettTaxDue.add(theSliceBucket.getTaxDue().valueAtRatio(theRatio));
227 
228             /* Calculate tax relief */
229             theTaxRelief.addAmount(getTaxDue());
230             theTaxRelief.subtractAmount(theNettTaxDue);
231         }
232 
233         @Override
234         public String formatObject(final OceanusDataFormatter pFormatter) {
235             return FIELD_DEFS.getName();
236         }
237 
238         @Override
239         public MetisFieldSet<MoneyWiseUKSlicedTaxDueBucket> getDataFieldSet() {
240             return FIELD_DEFS;
241         }
242     }
243 }