1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.oceanus.format.OceanusDataFormatter;
22 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
23 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
24 import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxClass;
25 import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet;
26 import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxBandSet.MoneyWiseTaxBand;
27 import io.github.tonywasher.joceanus.moneywise.tax.MoneyWiseTaxResource;
28
29 import java.util.Iterator;
30
31
32
33
34 public class MoneyWiseUKIncomeScheme
35 implements MetisFieldItem {
36
37
38
39 private static final MetisFieldSet<MoneyWiseUKIncomeScheme> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseUKIncomeScheme.class);
40
41
42
43
44 static {
45 FIELD_DEFS.declareLocalField(MoneyWiseTaxResource.SCHEME_RELIEF_AVAILABLE, MoneyWiseUKIncomeScheme::taxReliefAvailable);
46 }
47
48
49
50
51 private final Boolean reliefAvailable;
52
53
54
55
56 protected MoneyWiseUKIncomeScheme() {
57 this(Boolean.TRUE);
58 }
59
60
61
62
63
64
65 protected MoneyWiseUKIncomeScheme(final Boolean pReliefAvailable) {
66 reliefAvailable = pReliefAvailable;
67 }
68
69
70
71
72
73
74 public Boolean taxReliefAvailable() {
75 return reliefAvailable;
76 }
77
78
79
80
81
82
83
84
85
86 protected MoneyWiseTaxBandSet allocateToTaxBands(final MoneyWiseUKTaxConfig pConfig,
87 final MoneyWiseTaxClass pBasis,
88 final OceanusMoney pAmount) {
89
90 final OceanusMoney myAmount = new OceanusMoney(pAmount);
91 if (!myAmount.isPositive()) {
92 myAmount.setZero();
93 }
94
95
96 final MoneyWiseTaxBandSet myTaxBands = determineTaxBands(pConfig, pBasis, myAmount);
97
98
99 final OceanusMoney myRemaining = adjustAllowances(pConfig, myAmount);
100 adjustTaxBands(pConfig, myRemaining);
101
102
103 return myTaxBands;
104 }
105
106
107
108
109
110
111
112
113
114 private MoneyWiseTaxBandSet determineTaxBands(final MoneyWiseUKTaxConfig pConfig,
115 final MoneyWiseTaxClass pBasis,
116 final OceanusMoney pAmount) {
117
118 final MoneyWiseTaxBandSet myTaxBands = new MoneyWiseTaxBandSet();
119 final OceanusMoney myRemaining = new OceanusMoney(pAmount);
120
121
122 final OceanusMoney myAllowance = new OceanusMoney(getAmountInAllowance(pConfig, myRemaining));
123 if (myAllowance.isNonZero() && reliefAvailable) {
124 myTaxBands.addTaxBand(new MoneyWiseTaxBand(myAllowance, OceanusRate.getWholePercentage(0)));
125 myRemaining.subtractAmount(myAllowance);
126 }
127
128
129 final Iterator<MoneyWiseTaxBand> myIterator = taxBandIterator(pConfig, pBasis);
130 while (myRemaining.isNonZero()
131 && myIterator.hasNext()) {
132
133 final MoneyWiseTaxBand myBand = myIterator.next();
134 OceanusMoney myAmount = getAmountInBand(myBand.getAmount(), myRemaining);
135
136
137 if (!reliefAvailable && myAllowance.isNonZero()) {
138 myAmount = new OceanusMoney(myAmount);
139 myAmount.addAmount(myAllowance);
140 myAllowance.setZero();
141 }
142
143
144 myTaxBands.addTaxBand(new MoneyWiseTaxBand(myAmount, myBand.getRate()));
145 myRemaining.subtractAmount(myAmount);
146 }
147
148
149 return myTaxBands;
150 }
151
152
153
154
155
156
157
158
159 protected Iterator<MoneyWiseTaxBand> taxBandIterator(final MoneyWiseUKTaxConfig pConfig,
160 final MoneyWiseTaxClass pBasis) {
161 return pConfig.getTaxBands().iterator();
162 }
163
164
165
166
167
168
169
170
171 protected OceanusMoney getAmountInAllowance(final MoneyWiseUKTaxConfig pConfig,
172 final OceanusMoney pAmount) {
173
174 return getAmountInBand(pConfig.getAllowance(), pAmount);
175 }
176
177
178
179
180
181
182
183
184 protected OceanusMoney adjustAllowances(final MoneyWiseUKTaxConfig pConfig,
185 final OceanusMoney pAmount) {
186
187 return adjustForAllowance(pConfig.getAllowance(), pAmount);
188 }
189
190
191
192
193
194
195
196 protected void adjustTaxBands(final MoneyWiseUKTaxConfig pConfig,
197 final OceanusMoney pAmount) {
198
199 OceanusMoney myRemaining = pAmount;
200 for (MoneyWiseTaxBand myBand : pConfig.getTaxBands()) {
201
202 if (myRemaining.isZero()
203 || myBand.getAmount() == null) {
204 break;
205 }
206
207
208 myRemaining = adjustForAllowance(myBand.getAmount(), myRemaining);
209 }
210 }
211
212
213
214
215
216
217
218
219 protected OceanusMoney adjustForAllowance(final OceanusMoney pAllowance,
220 final OceanusMoney pAmount) {
221
222 final OceanusMoney myRemaining = new OceanusMoney(pAmount);
223
224
225 if (myRemaining.compareTo(pAllowance) > 0) {
226
227 myRemaining.subtractAmount(pAllowance);
228 pAllowance.setZero();
229
230
231 } else {
232
233 pAllowance.subtractAmount(myRemaining);
234 myRemaining.setZero();
235 }
236
237
238 return myRemaining;
239 }
240
241
242
243
244
245
246
247
248 protected static OceanusMoney getAmountInBand(final OceanusMoney pBand,
249 final OceanusMoney pAmount) {
250
251 return pBand != null && pAmount.compareTo(pBand) > 0
252 ? pBand
253 : pAmount;
254 }
255
256 @Override
257 public MetisFieldSet<? extends MoneyWiseUKIncomeScheme> getDataFieldSet() {
258 return FIELD_DEFS;
259 }
260
261 @Override
262 public String formatObject(final OceanusDataFormatter pFormatter) {
263 return getDataFieldSet().getName();
264 }
265 }