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.OceanusRate;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxClass;
23  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet.MoneyWiseTaxBand;
24  import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxResource;
25  
26  import java.util.ArrayList;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  /**
31   * Dividend Tax Scheme.
32   */
33  public abstract class MoneyWiseUKDividendScheme
34          extends MoneyWiseUKIncomeScheme {
35      /*
36       * Local Report fields.
37       */
38      static {
39          MetisFieldSet.newFieldSet(MoneyWiseUKDividendScheme.class);
40      }
41  
42      /**
43       * Constructor.
44       */
45      protected MoneyWiseUKDividendScheme() {
46          this(Boolean.TRUE);
47      }
48  
49      /**
50       * Constructor.
51       *
52       * @param pReliefAvailable Is tax relief available?
53       */
54      protected MoneyWiseUKDividendScheme(final Boolean pReliefAvailable) {
55          super(pReliefAvailable);
56      }
57  
58      /**
59       * Obtain theTaxCredit rate for dividend.
60       *
61       * @param pTaxYear the taxYear
62       * @return the taxCredit rate
63       */
64      protected abstract OceanusRate getTaxCreditRate(MoneyWiseUKTaxYear pTaxYear);
65  
66      @Override
67      protected OceanusMoney adjustAllowances(final MoneyWiseUKTaxConfig pConfig,
68                                              final OceanusMoney pAmount) {
69          /* Adjust against the basic allowance */
70          final OceanusMoney myRemaining = super.adjustAllowances(pConfig, pAmount);
71  
72          /* If we have any dividends left */
73          if (myRemaining.isNonZero()) {
74              /* Adjust the dividend allowance noting that it still counts against the taxBand */
75              adjustForAllowance(pConfig.getDividendAllowance(), myRemaining);
76          }
77  
78          /* Return unallocated income */
79          return myRemaining;
80      }
81  
82      @Override
83      protected OceanusMoney getAmountInAllowance(final MoneyWiseUKTaxConfig pConfig,
84                                                  final OceanusMoney pAmount) {
85          /* Obtain the amount covered by the basic allowance */
86          OceanusMoney myAmount = super.getAmountInAllowance(pConfig, pAmount);
87  
88          /* If we have income left over */
89          if (myAmount.compareTo(pAmount) < 0) {
90              /* Calculate remaining amount */
91              final OceanusMoney myRemaining = new OceanusMoney(pAmount);
92              myRemaining.subtractAmount(myAmount);
93  
94              /* Calculate the amount covered by dividend allowance */
95              final OceanusMoney myXtra = getAmountInBand(pConfig.getDividendAllowance(), myRemaining);
96  
97              /* Determine the total amount covered by the allowance */
98              myAmount = new OceanusMoney(myAmount);
99              myAmount.addAmount(myXtra);
100         }
101 
102         /* return the amount */
103         return myAmount;
104     }
105 
106     /**
107      * Obtain the base rate.
108      *
109      * @return the base rate
110      */
111     protected OceanusRate getBaseRate() {
112         return null;
113     }
114 
115     /**
116      * Obtain the higher rate.
117      *
118      * @return the higher rate
119      */
120     protected OceanusRate getHigherRate() {
121         return null;
122     }
123 
124     /**
125      * Obtain the additional rate.
126      *
127      * @return the additional rate
128      */
129     protected OceanusRate getAdditionalRate() {
130         return null;
131     }
132 
133     @Override
134     protected Iterator<MoneyWiseTaxBand> taxBandIterator(final MoneyWiseUKTaxConfig pConfig,
135                                                          final MoneyWiseTaxClass pBasis) {
136 
137         /* Create a new List */
138         final List<MoneyWiseTaxBand> myList = new ArrayList<>();
139 
140         /* Access underlying iterator */
141         final Iterator<MoneyWiseTaxBand> myIterator = super.taxBandIterator(pConfig, pBasis);
142         MoneyWiseTaxBand myBand = myIterator.next();
143         OceanusMoney myAmount = myBand.getAmount();
144         OceanusRate myRate = getBaseRate();
145 
146         /* If we are a LoHigher instance */
147         if (this instanceof MoneyWiseUKDividendLoHigherRateScheme) {
148             /* Access the true basic band and merge in the lower rate */
149             myBand = myIterator.next();
150             myAmount = new OceanusMoney(myAmount);
151             myAmount.addAmount(myBand.getAmount());
152         }
153 
154         /* Add the basic band */
155         if (myRate == null) {
156             myRate = myBand.getRate();
157         }
158         myList.add(new MoneyWiseTaxBand(myAmount, myRate));
159 
160         /* If we have a "higher" band */
161         if (myIterator.hasNext()) {
162             /* Add the higher band */
163             myBand = myIterator.next();
164             myRate = getHigherRate();
165             if (myRate == null) {
166                 myRate = myBand.getRate();
167             }
168             myList.add(new MoneyWiseTaxBand(myBand.getAmount(), myRate));
169         }
170 
171         /* If we have an "additional" band */
172         if (myIterator.hasNext()) {
173             /* Add the higher band */
174             myBand = myIterator.next();
175             myRate = getAdditionalRate();
176             if (myRate == null) {
177                 myRate = myBand.getRate();
178             }
179             myList.add(new MoneyWiseTaxBand(myBand.getAmount(), myRate));
180         }
181 
182         /* Loop through remaining tax bands */
183         while (myIterator.hasNext()) {
184             myBand = myIterator.next();
185             myList.add(myBand);
186         }
187 
188         /* Return the iterator */
189         return myList.iterator();
190     }
191 
192     /**
193      * As Income Scheme.
194      */
195     public static class MoneyWiseUKDividendAsIncomeScheme
196             extends MoneyWiseUKDividendScheme {
197         /**
198          * Local Report fields.
199          */
200         private static final MetisFieldSet<MoneyWiseUKDividendAsIncomeScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKDividendAsIncomeScheme.class);
201 
202         /**
203          * Constructor.
204          */
205         protected MoneyWiseUKDividendAsIncomeScheme() {
206         }
207 
208         @Override
209         protected OceanusRate getTaxCreditRate(final MoneyWiseUKTaxYear pTaxYear) {
210             return pTaxYear.getTaxBands().getBasicTaxRate();
211         }
212 
213         @Override
214         public MetisFieldSet<MoneyWiseUKDividendAsIncomeScheme> getDataFieldSet() {
215             return FIELD_DEFS;
216         }
217     }
218 
219     /**
220      * Base Rate Scheme.
221      */
222     public static class MoneyWiseUKDividendBaseRateScheme
223             extends MoneyWiseUKDividendScheme {
224         /**
225          * Local Report fields.
226          */
227         private static final MetisFieldSet<MoneyWiseUKDividendBaseRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKDividendBaseRateScheme.class);
228 
229         /*
230          * Declare Fields.
231          */
232         static {
233             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_BASE_RATE, MoneyWiseUKDividendBaseRateScheme::getBaseRate);
234         }
235 
236         /**
237          * The Base Rate.
238          */
239         private final OceanusRate theBaseRate;
240 
241         /**
242          * Constructor.
243          *
244          * @param pRate            the base rate
245          * @param pReliefAvailable Is tax relief available?
246          */
247         protected MoneyWiseUKDividendBaseRateScheme(final OceanusRate pRate,
248                                                     final Boolean pReliefAvailable) {
249             super(pReliefAvailable);
250             theBaseRate = pRate;
251         }
252 
253         /**
254          * Constructor.
255          *
256          * @param pRate the base rate
257          */
258         protected MoneyWiseUKDividendBaseRateScheme(final OceanusRate pRate) {
259             this(pRate, Boolean.TRUE);
260         }
261 
262         @Override
263         protected OceanusRate getBaseRate() {
264             return theBaseRate;
265         }
266 
267         @Override
268         protected OceanusRate getTaxCreditRate(final MoneyWiseUKTaxYear pTaxYear) {
269             return theBaseRate;
270         }
271 
272         @Override
273         public MetisFieldSet<? extends MoneyWiseUKDividendBaseRateScheme> getDataFieldSet() {
274             return FIELD_DEFS;
275         }
276     }
277 
278     /**
279      * Higher Rate Scheme.
280      */
281     public static class MoneyWiseUKDividendHigherRateScheme
282             extends MoneyWiseUKDividendBaseRateScheme {
283         /**
284          * Local Report fields.
285          */
286         private static final MetisFieldSet<MoneyWiseUKDividendHigherRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKDividendHigherRateScheme.class);
287 
288         /*
289          * Declare Fields.
290          */
291         static {
292             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_HIGH_RATE, MoneyWiseUKDividendHigherRateScheme::getHigherRate);
293         }
294 
295         /**
296          * The Higher Rate.
297          */
298         private final OceanusRate theHighRate;
299 
300         /**
301          * Constructor.
302          *
303          * @param pRate     the base rate
304          * @param pHighRate the higher rate
305          */
306         protected MoneyWiseUKDividendHigherRateScheme(final OceanusRate pRate,
307                                                       final OceanusRate pHighRate) {
308             this(pRate, pHighRate, Boolean.FALSE);
309         }
310 
311         /**
312          * Constructor.
313          *
314          * @param pRate            the base rate
315          * @param pHighRate        the higher rate
316          * @param pReliefAvailable Is tax relief available?
317          */
318         protected MoneyWiseUKDividendHigherRateScheme(final OceanusRate pRate,
319                                                       final OceanusRate pHighRate,
320                                                       final Boolean pReliefAvailable) {
321             super(pRate, pReliefAvailable);
322             theHighRate = pHighRate;
323         }
324 
325         @Override
326         protected OceanusRate getHigherRate() {
327             return theHighRate;
328         }
329 
330         @Override
331         public MetisFieldSet<? extends MoneyWiseUKDividendHigherRateScheme> getDataFieldSet() {
332             return FIELD_DEFS;
333         }
334     }
335 
336     /**
337      * LoHigher Rate Scheme.
338      */
339     public static class MoneyWiseUKDividendLoHigherRateScheme
340             extends MoneyWiseUKDividendHigherRateScheme {
341         /**
342          * Local Report fields.
343          */
344         private static final MetisFieldSet<MoneyWiseUKDividendLoHigherRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKDividendLoHigherRateScheme.class);
345 
346         /**
347          * Constructor.
348          *
349          * @param pRate       the base rate
350          * @param pHigherRate the higher rate
351          */
352         protected MoneyWiseUKDividendLoHigherRateScheme(final OceanusRate pRate,
353                                                         final OceanusRate pHigherRate) {
354             super(pRate, pHigherRate);
355         }
356 
357         @Override
358         public MetisFieldSet<MoneyWiseUKDividendLoHigherRateScheme> getDataFieldSet() {
359             return FIELD_DEFS;
360         }
361     }
362 
363     /**
364      * Additional Rate Scheme.
365      */
366     public static class MoneyWiseUKDividendAdditionalRateScheme
367             extends MoneyWiseUKDividendHigherRateScheme {
368         /**
369          * Local Report fields.
370          */
371         private static final MetisFieldSet<MoneyWiseUKDividendAdditionalRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKDividendAdditionalRateScheme.class);
372 
373         /*
374          * Declare Fields.
375          */
376         static {
377             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_ADDITIONAL_RATE, MoneyWiseUKDividendHigherRateScheme::getAdditionalRate);
378         }
379 
380         /**
381          * The Additional Rate.
382          */
383         private final OceanusRate theAdditionalRate;
384 
385         /**
386          * Constructor.
387          *
388          * @param pRate     the base rate
389          * @param pHighRate the higher rate
390          * @param pAddRate  the additional rate
391          */
392         protected MoneyWiseUKDividendAdditionalRateScheme(final OceanusRate pRate,
393                                                           final OceanusRate pHighRate,
394                                                           final OceanusRate pAddRate) {
395             this(pRate, pHighRate, pAddRate, Boolean.FALSE);
396         }
397 
398         /**
399          * Constructor.
400          *
401          * @param pRate            the base rate
402          * @param pHighRate        the higher rate
403          * @param pAddRate         the additional rate
404          * @param pReliefAvailable Is tax relief available?
405          */
406         protected MoneyWiseUKDividendAdditionalRateScheme(final OceanusRate pRate,
407                                                           final OceanusRate pHighRate,
408                                                           final OceanusRate pAddRate,
409                                                           final Boolean pReliefAvailable) {
410             super(pRate, pHighRate, pReliefAvailable);
411             theAdditionalRate = pAddRate;
412         }
413 
414         @Override
415         protected OceanusRate getAdditionalRate() {
416             return theAdditionalRate;
417         }
418 
419         @Override
420         public MetisFieldSet<MoneyWiseUKDividendAdditionalRateScheme> getDataFieldSet() {
421             return FIELD_DEFS;
422         }
423     }
424 }