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   * Capital Gains Tax Scheme.
32   */
33  public abstract class MoneyWiseUKCapitalScheme
34          extends MoneyWiseUKIncomeScheme {
35      /*
36       * Local Report fields.
37       */
38      static {
39          MetisFieldSet.newFieldSet(MoneyWiseUKCapitalScheme.class);
40      }
41  
42      /**
43       * Constructor.
44       */
45      protected MoneyWiseUKCapitalScheme() {
46      }
47  
48      @Override
49      protected OceanusMoney adjustAllowances(final MoneyWiseUKTaxConfig pConfig,
50                                              final OceanusMoney pAmount) {
51          /* Adjust against the capital allowance */
52          OceanusMoney myRemaining = adjustForAllowance(pConfig.getCapitalAllowance(), pAmount);
53  
54          /* If we have any gains left */
55          if (myRemaining.isNonZero()) {
56              /* Adjust the basic allowance */
57              myRemaining = super.adjustAllowances(pConfig, myRemaining);
58          }
59  
60          /* Return unallocated income */
61          return myRemaining;
62      }
63  
64      @Override
65      protected OceanusMoney getAmountInAllowance(final MoneyWiseUKTaxConfig pConfig,
66                                                  final OceanusMoney pAmount) {
67          /* Obtain the amount covered by the capital allowance */
68          OceanusMoney myAmount = getAmountInBand(pConfig.getCapitalAllowance(), pAmount);
69  
70          /* If we have income left over */
71          if (myAmount.compareTo(pAmount) < 0) {
72              /* Calculate remaining amount */
73              final OceanusMoney myRemaining = new OceanusMoney(pAmount);
74              myRemaining.subtractAmount(myAmount);
75  
76              /* Calculate the amount covered by basic allowance */
77              final OceanusMoney myXtra = super.getAmountInAllowance(pConfig, myRemaining);
78  
79              /* Determine the total amount covered by the allowance */
80              myAmount = new OceanusMoney(myAmount);
81              myAmount.addAmount(myXtra);
82          }
83  
84          /* return the amount */
85          return myAmount;
86      }
87  
88      /**
89       * Flat Rate Scheme.
90       */
91      public static class MoneyWiseUKCapitalFlatRateScheme
92              extends MoneyWiseUKCapitalScheme {
93          /**
94           * Local Report fields.
95           */
96          private static final MetisFieldSet<MoneyWiseUKCapitalFlatRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKCapitalFlatRateScheme.class);
97  
98          /*
99           * Declare Fields.
100          */
101         static {
102             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_BASE_RATE, MoneyWiseUKCapitalFlatRateScheme::getBasicRate);
103         }
104 
105         /**
106          * The Base Rate.
107          */
108         private final OceanusRate theBaseRate;
109 
110         /**
111          * Constructor.
112          *
113          * @param pRate the base rate
114          */
115         protected MoneyWiseUKCapitalFlatRateScheme(final OceanusRate pRate) {
116             theBaseRate = pRate;
117         }
118 
119         /**
120          * Obtain the base rate.
121          *
122          * @return the base rate
123          */
124         protected OceanusRate getBasicRate() {
125             return theBaseRate;
126         }
127 
128         @Override
129         public MetisFieldSet<? extends MoneyWiseUKCapitalFlatRateScheme> getDataFieldSet() {
130             return FIELD_DEFS;
131         }
132 
133         @Override
134         protected Iterator<MoneyWiseTaxBand> taxBandIterator(final MoneyWiseUKTaxConfig pConfig,
135                                                              final MoneyWiseTaxClass pBasis) {
136             /* Create a new List */
137             final List<MoneyWiseTaxBand> myList = new ArrayList<>();
138 
139             /* Add the single band */
140             myList.add(new MoneyWiseTaxBand(getBasicRate()));
141 
142             /* Return the iterator */
143             return myList.iterator();
144         }
145     }
146 
147     /**
148      * Split Rate Scheme.
149      */
150     public static class MoneyWiseUKCapitalSplitRateScheme
151             extends MoneyWiseUKCapitalFlatRateScheme {
152         /**
153          * Local Report fields.
154          */
155         private static final MetisFieldSet<MoneyWiseUKCapitalSplitRateScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKCapitalSplitRateScheme.class);
156 
157         /*
158          * Declare Fields.
159          */
160         static {
161             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_HIGH_RATE, MoneyWiseUKCapitalSplitRateScheme::getHighRate);
162         }
163 
164         /**
165          * The High Rate.
166          */
167         private final OceanusRate theHighRate;
168 
169         /**
170          * Constructor.
171          *
172          * @param pRate     the base rate
173          * @param pHighRate the high rate
174          */
175         protected MoneyWiseUKCapitalSplitRateScheme(final OceanusRate pRate,
176                                                     final OceanusRate pHighRate) {
177             super(pRate);
178             theHighRate = pHighRate;
179         }
180 
181         /**
182          * Obtain the high rate.
183          *
184          * @return the high rate
185          */
186         protected OceanusRate getHighRate() {
187             return theHighRate;
188         }
189 
190         @Override
191         public MetisFieldSet<? extends MoneyWiseUKCapitalSplitRateScheme> getDataFieldSet() {
192             return FIELD_DEFS;
193         }
194 
195         @Override
196         protected Iterator<MoneyWiseTaxBand> taxBandIterator(final MoneyWiseUKTaxConfig pConfig,
197                                                              final MoneyWiseTaxClass pBasis) {
198             /* Create a new List */
199             final List<MoneyWiseTaxBand> myList = new ArrayList<>();
200 
201             /* Access underlying iterator and obtain first band */
202             final Iterator<MoneyWiseTaxBand> myIterator = super.taxBandIterator(pConfig, pBasis);
203             final MoneyWiseTaxBand myFirstBand = myIterator.next();
204 
205             /* Add the two bands */
206             myList.add(new MoneyWiseTaxBand(myFirstBand.getAmount(), getBasicRate()));
207             myList.add(new MoneyWiseTaxBand(getHighRate()));
208 
209             /* Return the iterator */
210             return myList.iterator();
211         }
212     }
213 
214     /**
215      * As Income Scheme.
216      */
217     public static class MoneyWiseUKCapitalAsIncomeScheme
218             extends MoneyWiseUKCapitalScheme {
219         /**
220          * Local Report fields.
221          */
222         private static final MetisFieldSet<MoneyWiseUKCapitalAsIncomeScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKCapitalAsIncomeScheme.class);
223 
224         /**
225          * Constructor.
226          */
227         public MoneyWiseUKCapitalAsIncomeScheme() {
228         }
229 
230         @Override
231         public MetisFieldSet<MoneyWiseUKCapitalAsIncomeScheme> getDataFieldSet() {
232             return FIELD_DEFS;
233         }
234     }
235 
236     /**
237      * Residential Scheme.
238      */
239     public static class MoneyWiseUKCapitalResidentialScheme
240             extends MoneyWiseUKCapitalSplitRateScheme {
241         /**
242          * Local Report fields.
243          */
244         private static final MetisFieldSet<MoneyWiseUKCapitalResidentialScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKCapitalResidentialScheme.class);
245 
246         /*
247          * Declare Fields.
248          */
249         static {
250             FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_RESIDENTIAL, MoneyWiseUKCapitalResidentialScheme::getResidentialScheme);
251         }
252 
253         /**
254          * The Residential Scheme.
255          */
256         private final MoneyWiseUKCapitalSplitRateScheme theResidential;
257 
258         /**
259          * Constructor.
260          *
261          * @param pRate        the base rate
262          * @param pHighRate    the high rate
263          * @param pResRate     the base rate
264          * @param pHighResRate the high rate
265          */
266         protected MoneyWiseUKCapitalResidentialScheme(final OceanusRate pRate,
267                                                       final OceanusRate pHighRate,
268                                                       final OceanusRate pResRate,
269                                                       final OceanusRate pHighResRate) {
270             super(pRate, pHighRate);
271             theResidential = new MoneyWiseUKCapitalSplitRateScheme(pResRate, pHighResRate);
272         }
273 
274         /**
275          * Obtain the high rate.
276          *
277          * @return the high rate
278          */
279         protected MoneyWiseUKCapitalSplitRateScheme getResidentialScheme() {
280             return theResidential;
281         }
282 
283         @Override
284         public MetisFieldSet<MoneyWiseUKCapitalResidentialScheme> getDataFieldSet() {
285             return FIELD_DEFS;
286         }
287 
288         @Override
289         protected Iterator<MoneyWiseTaxBand> taxBandIterator(final MoneyWiseUKTaxConfig pConfig,
290                                                              final MoneyWiseTaxClass pBasis) {
291             /* Switch on taxBasis */
292             return MoneyWiseTaxClass.RESIDENTIALGAINS.equals(pBasis)
293                     ? theResidential.taxBandIterator(pConfig, pBasis)
294                     : super.taxBandIterator(pConfig, pBasis);
295         }
296     }
297 }