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